bug-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC/base] GSClassList()


From: David Ayers
Subject: [RFC/base] GSClassList()
Date: Thu, 06 May 2004 19:29:05 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113

Hello everyone,

This extension is intended to provide a common runtime interface to access the list of available classes. The GNU runtime uses objc_next_class() iteration mechanism where the Apple runtime has a objc_getClassList() API. GSClassList() API is similar to the apple version (simply because it's easier to model use the GNU version to imitate the apple version rather than the other way around.) I'd still advise anyone to use #ifdef's and use the native API if performance is a factor. I've provided caching for the GNU runtime though, so it may not be too bad. One important difference is that GSClassList() expects a buffer that's one element larger than objc_getClassList() would as the array is nil terminated.

Anyway, any comments before I commit?

Cheers,
David


Index: Headers/Additions/GNUstepBase/GSObjCRuntime.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/core/base/Headers/Additions/GNUstepBase/GSObjCRuntime.h,v
retrieving revision 1.4
diff -u -r1.4 GSObjCRuntime.h
--- Headers/Additions/GNUstepBase/GSObjCRuntime.h       6 May 2004 15:25:01 
-0000       1.4
+++ Headers/Additions/GNUstepBase/GSObjCRuntime.h       6 May 2004 16:47:54 
-0000
@@ -124,6 +124,24 @@
 #define GS_STATIC_INLINE static inline
 
 /**
+ * Fills a nil terminated array of Class objects referenced by buffer
+ * with max number of classes registered with the objc runtime.  
+ * The provided buffer must be large enough to hold max + 1 Class objects.
+ * If buffer is nil, the function returns the number of Class
+ * objects that would be inserted if the buffer is large enough.
+ * Otherwise returns the number of Class objects that did not fit
+ * into the provided buffer.  This function keeps a cache of the class
+ * list for future invocations when used with the GNU runtime.  If
+ * clearCache is YES, this cache will be invalidated and rebuild.  The
+ * flag has no effect for the NeXT runtime.
+ * This function is provided as consistent API to both runtimes.  
+ * In the case of the GNU runtime it is likely more efficient to use
+ * objc_next_class() to iterate over the classes.
+ */
+GS_EXPORT unsigned int
+GSClassList(Class *buffer, unsigned int max, BOOL clearCache);
+
+/**
  * GSObjCClass() return the class of an instance.
  * Returns a nul pointer if the argument is nil.
  */
Index: Source/Additions/GSObjCRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSObjCRuntime.m,v
retrieving revision 1.33
diff -u -r1.33 GSObjCRuntime.m
--- Source/Additions/GSObjCRuntime.m    6 May 2004 15:25:01 -0000       1.33
+++ Source/Additions/GSObjCRuntime.m    6 May 2004 16:48:27 -0000
@@ -323,6 +323,89 @@
   memcpy(((void*)obj) + offset, data, size);
 }
 
+GS_EXPORT unsigned int
+GSClassList(Class *buffer, unsigned int max, BOOL clearCache)
+{
+#ifdef NeXT_RUNTIME
+  int num;
+
+  if (buffer != NULL)
+    {
+      memset(buffer, 0, sizeof(Class) * (max + 1));
+    }
+
+  num = objc_getClassList(buffer, max);
+  num = (num < 0) ? 0 : num;
+
+#else
+  static Class *cache = 0;
+  static unsigned cacheClassCount = 0;
+  static volatile objc_mutex_t cache_lock = NULL;
+  unsigned int num;
+
+  if (cache_lock == NULL)
+    {
+      GSAllocateMutexAt((void*)&cache_lock);
+    }
+
+  objc_mutex_lock(cache_lock);
+
+  if (clearCache)
+    {
+      if (cache)
+       {
+         objc_free(cache);
+         cache = NULL;
+       }
+      cacheClassCount = 0;
+    }
+
+  if (cache == NULL)
+    {
+      void *iterator = 0;
+      Class cls;
+      unsigned int i;
+
+      cacheClassCount = 0;
+      while ((cls = objc_next_class(&iterator)))
+       {
+         cacheClassCount++;
+       }
+      cache = objc_malloc(sizeof(Class) * (cacheClassCount + 1));
+      /* Be extra careful as another thread may be loading classes.  */
+      for (i = 0, iterator = 0, cls = objc_next_class(&iterator); 
+          i < cacheClassCount && cls != NULL; 
+          i++, cls = objc_next_class(&iterator))
+       {
+         cache[i] = cls;
+       }
+      cache[i] = NULL;
+    }
+
+  if (buffer == NULL)
+    {
+      num = cacheClassCount;
+    }
+  else
+    {
+      size_t       cpySize;
+      unsigned int cpyCnt;
+
+      cpyCnt = MIN(max, cacheClassCount);
+      cpySize = sizeof(Class) * cpyCnt;
+      memcpy(buffer, cache, cpySize);
+      buffer[cpyCnt] = NULL;
+
+      num = (max > cacheClassCount) ? 0 : (cacheClassCount - max);
+    }
+
+  objc_mutex_unlock(cache_lock);
+
+#endif
+
+  return num;
+}
+
 /*
  *     NOTE - OBJC_VERSION needs to be defined to be the version of the
  *     Objective-C runtime you are using.  You can find this in the file

reply via email to

[Prev in Thread] Current Thread [Next in Thread]