[Rubycocoa-devel 195] Single RBObject per Ruby Object

Zurück zum Archiv-Index

Jonathan Paisley jp-ww****@dcs*****
Sat Feb 11 20:17:15 JST 2006


Hi,

I've been playing with a patch that ensures that RBObject instances  
created for Ruby objects are unique, rather than creating a new  
RBObject each time a Ruby object is passed through the bridge.

I had initially hoped this might make it easier to use an  
NSOutlineView with non-NSObject-derived Ruby objects, but because  
NSOutlineView doesn't retain the items this doesn't really work.

In any case, I think it's nice to have a 1-1 mapping between Ruby  
objects and RBObject. Perhaps it might be worth doing the same for  
ObjCID instances too (using another hash table to map from 'id' to  
VALUE).

I've included the current patch below. If you think it's worth  
pursuing further, I'll add test cases etc. If not, I'll keep the  
patch around in case it becomes useful in the future.

Cheers,
Jonathan


=== src/objc/RBObject.m
==================================================================
--- src/objc/RBObject.m	(revision 32)
+++ src/objc/RBObject.m	(local)
@@ -16,6 +16,8 @@
#import "ocdata_conv.h"
#import "DummyProtocolHandler.h"
+#import "st.h"
+
#if 1
#  define DLOG0(f)          if (ruby_debug == Qtrue) debug_log((f))
#  define DLOG1(f,a1)       if (ruby_debug == Qtrue) debug_log((f),(a1))
@@ -28,6 +30,12 @@
#  define DLOG3(f,a1,a2,a3) debug_log((f),(a1),(a2),(a3))
#endif
+// Hash table mapping VALUE to id, so it's possible
+// to get the same RBObject for each VALUE that
+// isn't a number, string, hash, array etc (since
+// these are dealt with specially elsewhere).
+static struct st_table *rbobject_map;
+
static void debug_log(const char* fmt,...)
{
    //  if (ruby_debug == Qtrue) {
@@ -301,15 +309,39 @@
    DLOG1("   --> rb_result=%s", STR2CSTR(rb_inspect(rb_result)));
}
+
+// internal initialiser (doesn't lookup hash)
+- (id) initWithRubyObjectInternal: (VALUE)rbobj
+{
+  m_rbobj = rbobj;
+  rb_gc_register_address (&m_rbobj);
+  st_insert(rbobject_map, (st_data_t) rbobj, (st_data_t) self);
+  return self;
+}
+
++ (void) load
+{
+  rbobject_map = st_init_numtable();
+}
+
// public class methods
++ RBObjectWithRubyObject: (VALUE)rbobj
+{
+  st_data_t result;
+  if (st_lookup(rbobject_map, rbobj, &result)) {
+    return (RBObject*)result;
+  }
+  return [[[RBObject alloc] initWithRubyObjectInternal: rbobj]  
autorelease];
+}
+
+ RBObjectWithRubyScriptCString: (const char*) cstr
{
-  return [[self alloc] initWithRubyScriptCString: cstr];
+  return [self RBObjectWithRubyObject: rb_eval_string(cstr)];
}
+ RBObjectWithRubyScriptString: (NSString*) str
{
-  return [[self alloc] initWithRubyScriptString: str];
+  return [self RBObjectWithRubyScriptCString: [str UTF8String]];
}
// public methods
@@ -318,15 +350,23 @@
- (void) dealloc
{
-  rb_gc_unregister_address (&m_rbobj);
+  if (m_rbobj) { // check in case we get released in  
initWithRubyObject:
+    rb_gc_unregister_address (&m_rbobj);
+    st_data_t key = (st_data_t) m_rbobj;
+    st_delete(rbobject_map, &key, NULL);
+  }
    [super dealloc];
}
- initWithRubyObject: (VALUE)rbobj
{
-  m_rbobj = rbobj;
-  rb_gc_register_address (&m_rbobj);
-  return self;
+  st_data_t result;
+  if (st_lookup(rbobject_map, rbobj, &result)) {
+    // Release self, return some other object
+    [self release];
+    return [(RBObject*)result retain];
+  }
+  return [self initWithRubyObjectInternal: rbobj];
}
- initWithRubyScriptCString: (const char*) cstr
=== src/objc/ocdata_conv.m
==================================================================
--- src/objc/ocdata_conv.m	(revision 32)
+++ src/objc/ocdata_conv.m	(local)
@@ -389,7 +389,7 @@
    case T_FALSE:
    case RB_T_DATA:
    default:
-    *nsobj = [[[RBObject alloc] initWithRubyObject: obj] autorelease];
+    *nsobj = [RBObject RBObjectWithRubyObject: obj];
      return YES;
    }
    return YES;




More information about the Rubycocoa-devel mailing list
Zurück zum Archiv-Index