gnustep-dev
[Top][All Lists]
Advanced

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

[RFC/base] GSObjCMethodList manipulation functions


From: David Ayers
Subject: [RFC/base] GSObjCMethodList manipulation functions
Date: Fri, 21 Nov 2003 20:16:52 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031007

Hello everyone,

prompted by problems with GDL2 on OS X, Philip Moetteli and I came up with some runtime functions to help insure that the "correct" category will be used by the runtime. The first function returns the method lists of class associated with a selector. It uses a void * as an iterator to keep track of its postion in the search if multiple categories implement the method. The other two methods are used to remove and to add the list. Whether these functions operate on class or instance method list is currently determined by a flag.


typedef struct objc_method_list *GSMethodList;

GSMethodList
GSObjCMethodListForSelector(Class class,
                           SEL selector,
                           BOOL isClass,
                           void **iterator);
void
GSObjCAddMethodList(Class class,
                   GSMethodList list,
                   BOOL isClass);
void
GSObjCRemoveMethodList(Class class,
              GSMethodList list,
              BOOL isClass);



Using the flag is actually inconsistent with the current GSObjCRuntime API. Yet that would introduce 6 functions:

GSMethodList
GSObjCInstanceMethodListForSelector(Class class, SEL selector, void **iterator);
GSMethodList
GSObjCClassMethodListForSelector(Class class, SEL selector, void **iterator);

void
GSObjCAddInstanceMethodList(Class class, GSMethodList list);
void
GSObjCAddClassMethodList(Class class, GSMethodList list);

void
GSObjCRemoveInstanceMethodList(Class class,GSMethodList list);
void
GSObjCRemoveClassMethodList(Class class,GSMethodList list);

I don't really mind either way.

Anyway, with this we can do the following in GDL2 and currently insure that our category is used instead of Foundations:

@implementation NSObject (EOClassDescriptionPrimitives)

- (void)_GDL2EOClassDescriptionPrimitivesMethodListLocator
{
}

+ (void)load
{
GSMethodList method_list;
SEL locator = @selector(_GDL2EOClassDescriptionPrimitivesMethodListLocator);

method_list = GSObjCMethodListForSelector(self, locator, NO, 0);
GSObjCRemoveMethodList(self, method_list, NO);
GSObjCAddMethodList(self, method_list, NO);
GSFlushMethodCacheForClass(self);
}

Comments?

Cheers,
David

Index: Headers/Additions/GNUstepBase/GSObjCRuntime.h
===================================================================
RCS file: 
/cvsroot/gnustep/gnustep/core/base/Headers/Additions/GNUstepBase/GSObjCRuntime.h,v
retrieving revision 1.3
diff -u -r1.3 GSObjCRuntime.h
--- Headers/Additions/GNUstepBase/GSObjCRuntime.h       10 Sep 2003 09:29:39 
-0000      1.3
+++ Headers/Additions/GNUstepBase/GSObjCRuntime.h       21 Nov 2003 19:38:43 
-0000
@@ -323,10 +323,11 @@
 /*
  * Unfortunately the definition of the symbol 'Method' "IVar(_t)"
  * is incompatible between the GNU and NeXT/Apple runtimes.
- * We introduce GSMethod and GSIVar to allow portability.
+ * We introduce GSMethod, GSMethodList and GSIVar to allow portability.
  */
-typedef struct objc_method *GSMethod;
-typedef struct objc_ivar   *GSIVar;
+typedef struct objc_method      *GSMethod;
+typedef struct objc_method_list *GSMethodList;
+typedef struct objc_ivar        *GSIVar;
 
 /**
  * Returns the pointer to the instance method structure
@@ -489,6 +490,20 @@
  */
 GS_EXPORT BOOL
 GSPrintf (FILE *fptr, NSString *format, ...);
+
+GSMethodList
+GSObjCMethodListForSelector(Class class,
+                            SEL selector,
+                            BOOL isClass,
+                            void **iterator);
+void
+GSObjCAddMethodList(Class class,
+                    GSMethodList list,
+                    BOOL isClass);
+void
+GSObjCRemoveMethodList(Class class,
+                      GSMethodList list,
+                      BOOL isClass);
 
 
 
Index: Source/Additions/GSObjCRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSObjCRuntime.m,v
retrieving revision 1.29
diff -u -r1.29 GSObjCRuntime.m
--- Source/Additions/GSObjCRuntime.m    30 Oct 2003 13:44:54 -0000      1.29
+++ Source/Additions/GSObjCRuntime.m    21 Nov 2003 19:38:43 -0000
@@ -120,10 +120,10 @@
 NSArray *
 GSObjCMethodNames(id obj)
 {
-  NSMutableSet                 *set;
-  NSArray                      *array;
-  Class                                class;
-  struct objc_method_list      *methods;
+  NSMutableSet *set;
+  NSArray      *array;
+  Class                class;
+  GSMethodList methods;
 
   if (obj == nil)
     {
@@ -475,10 +475,10 @@
 static struct objc_method *search_for_method_in_class (Class class, SEL op);
 
 void 
-GSObjCAddMethods (Class class, struct objc_method_list *methods)
+GSObjCAddMethods (Class class, GSMethodList methods)
 {
   static SEL initialize_sel = 0;
-  struct objc_method_list *mlist;
+  GSMethodList mlist;
 
   if (!initialize_sel)
     initialize_sel = sel_register_name ("initialize");
@@ -487,13 +487,13 @@
   mlist = methods;
     {
       int counter;
-      struct objc_method_list *new_list;
+      GSMethodList new_list;
 
       counter = mlist->method_count ? mlist->method_count - 1 : 1;
 
       /* This is a little wasteful of memory, since not necessarily 
         all methods will go in here. */
-      new_list = (struct objc_method_list *)
+      new_list = (GSMethodList)
        objc_malloc (sizeof(struct objc_method_list) +
                     sizeof(struct objc_method[counter+1]));
       new_list->method_count = 0;
@@ -544,7 +544,7 @@
 search_for_method_in_class (Class class, SEL op)
 {
   void *iterator = 0;
-  struct objc_method_list *method_list;
+  GSMethodList method_list;
 
   if (! sel_is_mapped (op))
     return NULL;
@@ -581,10 +581,10 @@
 static Method_t search_for_method_in_class (Class class, SEL op);
 
 void
-GSObjCAddMethods (Class class, struct objc_method_list *methods)
+GSObjCAddMethods (Class class, GSMethodList methods)
 {
   static SEL initialize_sel = 0;
-  struct objc_method_list *mlist;
+  GSMethodList mlist;
 
   if (initialize_sel == 0)
     {
@@ -594,14 +594,14 @@
   /* Add methods to class->dtable and class->methods */
   for (mlist = methods; mlist; mlist = mlist->method_next)
     {
-      int                      counter;
-      struct objc_method_list  *new_list;
+      int              counter;
+      GSMethodList     new_list;
 
       counter = mlist->method_count ? mlist->method_count - 1 : 1;
 
       /* This is a little wasteful of memory, since not necessarily 
         all methods will go in here. */
-      new_list = (struct objc_method_list *)
+      new_list = (GSMethodList)
        objc_malloc (sizeof(struct objc_method_list) +
                     sizeof(struct objc_method[counter+1]));
       new_list->method_count = 0;
@@ -771,8 +771,8 @@
     }
 #if NeXT_RUNTIME
   {
-    void                       *iterator = 0;
-    struct objc_method_list    *method_list;
+    void               *iterator = 0;
+    GSMethodList       method_list;
 
     method_list = class_nextMethodList(behavior, &iterator);
     while (method_list != 0)
@@ -793,8 +793,8 @@
     }
 #if NeXT_RUNTIME
   {
-    void                       *iterator = 0;
-    struct objc_method_list    *method_list;
+    void               *iterator = 0;
+    GSMethodList       method_list;
 
     method_list = class_nextMethodList(behavior->class_pointer, &iterator);
     while (method_list != 0)
@@ -1589,3 +1589,150 @@
   RELEASE(arp);
   return ok;
 }
+
+/**
+ * Returns a method list of the class that contains the selector.
+ * If isClass is true, it searches class methods,
+ * otherwise the instance methods.
+ * Returns NULL if none are found.
+ * Call this method with the address of a <code>void *</code>
+ * pointing to NULL to obtain the first (active) method list
+ * containing the selector.  
+ * Subsequent calls will return further method lists which contain the
+ * selector.  If none are found, it returns NULL.
+ * You may instead pass NULL as the iterator in which case the first
+ * method list containing the selecetor will be returned. 
+ * Do not call it with an uninitialized iterator.
+ * If either class or selector are NULL the function returns NULL.
+ */
+GSMethodList 
+GSObjCMethodListForSelector(Class class, 
+                           SEL selector, 
+                           BOOL isClass,
+                           void **iterator)
+{
+  void *local_iterator = 0;
+
+  if (class == 0 || selector == 0)
+    {
+      return 0;
+    }
+
+  if (isClass)
+    {
+      class = class->class_pointer;
+    }
+
+  if(sel_is_mapped(selector))
+    {
+      void **iterator_pointer;
+      GSMethodList method_list;
+
+      iterator_pointer = (iterator ? iterator : &local_iterator);
+      while((method_list 
+            = class_nextMethodList(class, iterator_pointer)))
+       {
+         int i;
+         
+         /* Search the method in the current list.  */
+         for(i = 0; i < method_list->method_count; ++i)
+           {
+             struct objc_method  *method = &method_list->method_list[i];
+             
+             if(method->method_name 
+                && sel_eq(method->method_name, selector))
+               {
+                 return method_list;
+               }
+           }
+       }
+    }
+
+  return 0;
+}
+
+/**
+ * Add the method list to the class as the first list to be 
+ * searched during method invocation for the given class.
+ * If isClass is YES then the method list will be added as
+ * class methods otherwise as instance methods.
+ * If the list is in use by a class, behavior is undefined.
+ * Create a new list or use GSObjCRemoveMethodList()
+ * to remove a list before inserting it in a class.
+ * After any method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.
+ */
+void
+GSObjCAddMethodList(Class class, 
+                   GSMethodList list, 
+                   BOOL isClass)
+{
+  if (class == 0 || list == 0)
+    {
+      return;
+    }
+
+  if (isClass)
+    {
+      class = class->class_pointer;
+    }
+  
+#ifdef NeXT_RUNTIME
+  class_addMethods(class, list);
+#else
+  list->method_next = class->methods;
+  class->methods = list;
+#endif /* NeXT_RUNTIME */
+}
+
+
+/**
+ * Removes the method list from the class.
+ * If isClass is YES then the method list will be removed from
+ * the class methods otherwise from the instance methods.
+ * If the list is not part of the class, behavior is undefined.
+ * After any method list manipulation you should call
+ * GSFlushMethodCacheForClass() for the changes to take effect.
+ */
+void
+GSObjCRemoveMethodList(Class class, 
+                      GSMethodList list, 
+                      BOOL isClass)
+{
+  if (class == 0 || list == 0)
+    {
+      return;
+    }
+
+  if (isClass)
+    {
+      class = class->class_pointer;
+    }
+
+#ifdef NeXT_RUNTIME
+  class_removeMethods(class, list);
+#else
+  if (list == class->methods)
+    {
+      class->methods = list->method_next;
+      list->method_next = 0;
+    }
+  else
+    {
+      GSMethodList current_list;
+
+      for (current_list = class->methods;
+          current_list != 0;
+          current_list = current_list->method_next)
+       {
+         if (current_list->method_next == list)
+           {
+             current_list->method_next = list->method_next;
+             list->method_next = 0;
+           }
+       }
+    }
+#endif /* NeXT_RUNTIME */
+}
+
+

reply via email to

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