[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC/base] GSProtocolFromName()
From: |
David Ayers |
Subject: |
[RFC/base] GSProtocolFromName() |
Date: |
Fri, 07 May 2004 19:55:35 +0200 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113 |
Hello everyone,
next in the series is:
Protocol *GSProtocolFromName(const char *name);
Which searches all available classes for a protocol with the
corresponding name. This would make an NSCoding implementation possible
for Protocol.
because of the inefficiency of the search, you can explicitly register a
protocol in the cache that this function uses, if you know that you may
need to search for this protocol later.
void GSRegisterProtocol(Protocol *);
I haven't had a chance to test this final version on Cocoa yet. I will
test it before I commit, but I though I'll post it anyway already.
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.5
diff -u -r1.5 GSObjCRuntime.h
--- Headers/Additions/GNUstepBase/GSObjCRuntime.h 7 May 2004 16:26:50
-0000 1.5
+++ Headers/Additions/GNUstepBase/GSObjCRuntime.h 7 May 2004 17:41:48
-0000
@@ -337,6 +337,24 @@
return sel_get_type(this);
}
+/**
+ * Returns a protocol object with the corresponding name.
+ * This function searches the registered classes for any protocol
+ * with the supplied name. If one is found, it is cached in
+ * for future requests. If efficiency is a factor then use
+ * GSRegisterProtocol() to insert a protocol explicitly into the cache
+ * used by this function. If no protocol is found this function returns
+ * nil.
+ */
+GS_EXPORT Protocol *
+GSProtocolFromName(const char *name);
+
+/**
+ * Registers proto in the cache used by GSProtocolFromName().
+ */
+GS_EXPORT void
+GSRegisterProtocol(Protocol *proto);
+
/*
* Unfortunately the definition of the symbol 'Method' "IVar(_t)"
Index: Source/Additions/GSObjCRuntime.m
===================================================================
RCS file: /cvsroot/gnustep/gnustep/core/base/Source/Additions/GSObjCRuntime.m,v
retrieving revision 1.34
diff -u -r1.34 GSObjCRuntime.m
--- Source/Additions/GSObjCRuntime.m 7 May 2004 16:26:50 -0000 1.34
+++ Source/Additions/GSObjCRuntime.m 7 May 2004 17:41:51 -0000
@@ -49,6 +49,9 @@
#include "GNUstepBase/GSObjCRuntime.h"
#include "GNUstepBase/GNUstep.h"
#include "GNUstepBase/GSCategories.h"
+
+#include <objc/Protocol.h>
+
#include <string.h>
@class NSNull;
@@ -848,6 +851,186 @@
return GSCGetInstanceVariableDefinition(class, [name cString]);
}
+typedef struct {
+ @defs(Protocol)
+} *pcl;
+
+GS_STATIC_INLINE unsigned int
+gs_string_hash(const char *s)
+{
+ unsigned int val = 0;
+ while (*s != 0)
+ {
+ val = (val << 5) + val + *s++;
+ }
+ return val;
+}
+
+GS_STATIC_INLINE pcl
+gs_find_protocol_named_in_protocol_list(const char *name,
+ struct objc_protocol_list *pcllist)
+{
+ pcl p = NULL;
+ size_t i;
+
+ while (pcllist != NULL)
+ {
+ for (i=0; i<pcllist->count; i++)
+ {
+ p = (pcl)pcllist->list[i];
+ if (strcmp(p->protocol_name, name) == 0)
+ {
+ return p;
+ }
+ }
+ pcllist = pcllist->next;
+ }
+ return NULL;
+}
+
+GS_STATIC_INLINE pcl
+gs_find_protocol_named(const char *name)
+{
+ pcl p = NULL;
+ Class cls;
+#ifdef NeXT_RUNTIME
+ Class *clsList, *clsListStart;
+ unsigned int num;
+
+ /* Setting the clearCache flag is a noop for the Apple runtime. */
+ num = GSClassList(NULL, 0, NO);
+ clsList = objc_malloc(sizeof(Class) * (num + 1));
+ GSClassList(clsList, num, NO);
+
+ clsListStart = clsList;
+
+ while(p == NULL && (cls = *clsList++))
+ {
+ p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
+ }
+
+ objc_free(clsListStart);
+
+#else
+ void *iterator = NULL;
+
+ while(p == NULL && (cls = objc_next_class(&iterator)))
+ {
+ p = gs_find_protocol_named_in_protocol_list(name, cls->protocols);
+ }
+
+#endif
+ return p;
+}
+
+#define GSI_MAP_HAS_VALUE 1
+#define GSI_MAP_RETAIN_KEY(M, X)
+#define GSI_MAP_RETAIN_VAL(M, X)
+#define GSI_MAP_RELEASE_KEY(M, X)
+#define GSI_MAP_RELEASE_VAL(M, X)
+#define GSI_MAP_HASH(M, X) (gs_string_hash(X.ptr))
+#define GSI_MAP_EQUAL(M, X,Y) (strcmp(X.ptr, Y.ptr) == 0)
+#define GSI_MAP_NOCLEAN 1
+
+#define GSI_MAP_KTYPES GSUNION_PTR
+#define GSI_MAP_VTYPES GSUNION_PTR
+
+#include "GNUstepBase/GSIMap.h"
+
+static GSIMapTable_t protocol_by_name;
+static BOOL protocol_by_name_init = NO;
+static volatile objc_mutex_t protocol_by_name_lock = NULL;
+
+/* Not sure about the semantics of inlining
+ functions with static variables. */
+static void
+gs_init_protocol_lock(void)
+{
+ if (protocol_by_name_lock == NULL)
+ {
+ GSAllocateMutexAt((void *)&protocol_by_name_lock);
+ objc_mutex_lock(protocol_by_name_lock);
+ if (protocol_by_name_init == NO)
+ {
+ GSIMapInitWithZoneAndCapacity (&protocol_by_name,
+ NSDefaultMallocZone(),
+ 128);
+ protocol_by_name_init = YES;
+ }
+ objc_mutex_unlock(protocol_by_name_lock);
+ }
+}
+
+void
+GSRegisterProtocol(Protocol *proto)
+{
+ if (protocol_by_name_init == NO)
+ {
+ gs_init_protocol_lock();
+ }
+
+ if (proto != nil)
+ {
+ GSIMapNode node;
+ pcl p;
+
+ p = (pcl)proto;
+ objc_mutex_lock(protocol_by_name_lock);
+ node = GSIMapNodeForKey(&protocol_by_name,
+ (GSIMapKey) p->protocol_name);
+ if (node == 0)
+ {
+ GSIMapAddPairNoRetain(&protocol_by_name,
+ (GSIMapKey) (void *) p->protocol_name,
+ (GSIMapVal) (void *) p);
+ }
+ objc_mutex_unlock(protocol_by_name_lock);
+ }
+}
+
+Protocol *
+GSProtocolFromName(const char *name)
+{
+ GSIMapNode node;
+ pcl p;
+
+ if (protocol_by_name_init == NO)
+ {
+ gs_init_protocol_lock();
+ }
+
+ node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
+ if (node)
+ {
+ p = node->value.ptr;
+ }
+ else
+ {
+ objc_mutex_lock(protocol_by_name_lock);
+ node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name);
+
+ if (node)
+ {
+ p = node->value.ptr;
+ }
+ else
+ {
+ p = gs_find_protocol_named(name);
+ if (p)
+ {
+ /* Use the protocol's name to save us from allocating
+ a copy of the parameter 'name'. */
+ GSIMapAddPairNoRetain(&protocol_by_name,
+ (GSIMapKey) (void *) p->protocol_name,
+ (GSIMapVal) (void *) p);
+ }
+ }
+ objc_mutex_unlock(protocol_by_name_lock);
+
+ }
+
+ return (Protocol *)p;
+}
/**
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [RFC/base] GSProtocolFromName(),
David Ayers <=