1 /* ----------------------------------------------------------------------------- 2 * rubytracking.swg 3 * 4 * This file contains support for tracking mappings from 5 * Ruby objects to C++ objects. This functionality is needed 6 * to implement mark functions for Ruby's mark and sweep 7 * garbage collector. 8 * ----------------------------------------------------------------------------- */ 9 10 #ifdef __cplusplus 11 extern "C" { 12 #endif 13 14 /* Ruby 1.8 actually assumes the first case. */ 15 #if SIZEOF_VOIDP == SIZEOF_LONG 16 # define SWIG2NUM(v) LONG2NUM((unsigned long)v) 17 # define NUM2SWIG(x) (unsigned long)NUM2LONG(x) 18 #elif SIZEOF_VOIDP == SIZEOF_LONG_LONG 19 # define SWIG2NUM(v) LL2NUM((unsigned long long)v) 20 # define NUM2SWIG(x) (unsigned long long)NUM2LL(x) 21 #else 22 # error sizeof(void*) is not the same as long or long long 23 #endif 24 25 26 /* Global Ruby hash table to store Trackings from C/C++ 27 structs to Ruby Objects. 28 */ 29 static VALUE swig_ruby_trackings = Qnil; 30 31 /* Global variable that stores a reference to the ruby 32 hash table delete function. */ 33 static ID swig_ruby_hash_delete; 34 35 /* Setup a Ruby hash table to store Trackings */ 36 SWIGRUNTIME void SWIG_RubyInitializeTrackings(void) { 37 /* Create a ruby hash table to store Trackings from C++ 38 objects to Ruby objects. */ 39 40 /* Try to see if some other .so has already created a 41 tracking hash table, which we keep hidden in an instance var 42 in the SWIG module. 43 This is done to allow multiple DSOs to share the same 44 tracking table. 45 */ 46 ID trackings_id = rb_intern( "@__trackings__" ); 47 VALUE verbose = rb_gv_get("VERBOSE"); 48 rb_gv_set("VERBOSE", Qfalse); 49 swig_ruby_trackings = rb_ivar_get( _mSWIG, trackings_id ); 50 rb_gv_set("VERBOSE", verbose); 51 52 /* No, it hasn't. Create one ourselves */ 53 if ( swig_ruby_trackings == Qnil ) 54 { 55 swig_ruby_trackings = rb_hash_new(); 56 rb_ivar_set( _mSWIG, trackings_id, swig_ruby_trackings ); 57 } 58 59 /* Now store a reference to the hash table delete function 60 so that we only have to look it up once.*/ 61 swig_ruby_hash_delete = rb_intern("delete"); 62 } 63 64 /* Get a Ruby number to reference a pointer */ 65 SWIGRUNTIME VALUE SWIG_RubyPtrToReference(void* ptr) { 66 /* We cast the pointer to an unsigned long 67 and then store a reference to it using 68 a Ruby number object. */ 69 70 /* Convert the pointer to a Ruby number */ 71 return SWIG2NUM(ptr); 72 } 73 74 /* Get a Ruby number to reference an object */ 75 SWIGRUNTIME VALUE SWIG_RubyObjectToReference(VALUE object) { 76 /* We cast the object to an unsigned long 77 and then store a reference to it using 78 a Ruby number object. */ 79 80 /* Convert the Object to a Ruby number */ 81 return SWIG2NUM(object); 82 } 83 84 /* Get a Ruby object from a previously stored reference */ 85 SWIGRUNTIME VALUE SWIG_RubyReferenceToObject(VALUE reference) { 86 /* The provided Ruby number object is a reference 87 to the Ruby object we want.*/ 88 89 /* Convert the Ruby number to a Ruby object */ 90 return NUM2SWIG(reference); 91 } 92 93 /* Add a Tracking from a C/C++ struct to a Ruby object */ 94 SWIGRUNTIME void SWIG_RubyAddTracking(void* ptr, VALUE object) { 95 /* In a Ruby hash table we store the pointer and 96 the associated Ruby object. The trick here is 97 that we cannot store the Ruby object directly - if 98 we do then it cannot be garbage collected. So 99 instead we typecast it as a unsigned long and 100 convert it to a Ruby number object.*/ 101 102 /* Get a reference to the pointer as a Ruby number */ 103 VALUE key = SWIG_RubyPtrToReference(ptr); 104 105 /* Get a reference to the Ruby object as a Ruby number */ 106 VALUE value = SWIG_RubyObjectToReference(object); 107 108 /* Store the mapping to the global hash table. */ 109 rb_hash_aset(swig_ruby_trackings, key, value); 110 } 111 112 /* Get the Ruby object that owns the specified C/C++ struct */ 113 SWIGRUNTIME VALUE SWIG_RubyInstanceFor(void* ptr) { 114 /* Get a reference to the pointer as a Ruby number */ 115 VALUE key = SWIG_RubyPtrToReference(ptr); 116 117 /* Now lookup the value stored in the global hash table */ 118 VALUE value = rb_hash_aref(swig_ruby_trackings, key); 119 120 if (value == Qnil) { 121 /* No object exists - return nil. */ 122 return Qnil; 123 } 124 else { 125 /* Convert this value to Ruby object */ 126 return SWIG_RubyReferenceToObject(value); 127 } 128 } 129 130 /* Remove a Tracking from a C/C++ struct to a Ruby object. It 131 is very important to remove objects once they are destroyed 132 since the same memory address may be reused later to create 133 a new object. */ 134 SWIGRUNTIME void SWIG_RubyRemoveTracking(void* ptr) { 135 /* Get a reference to the pointer as a Ruby number */ 136 VALUE key = SWIG_RubyPtrToReference(ptr); 137 138 /* Delete the object from the hash table by calling Ruby's 139 do this we need to call the Hash.delete method.*/ 140 rb_funcall(swig_ruby_trackings, swig_ruby_hash_delete, 1, key); 141 } 142 143 /* This is a helper method that unlinks a Ruby object from its 144 underlying C++ object. This is needed if the lifetime of the 145 Ruby object is longer than the C++ object */ 146 SWIGRUNTIME void SWIG_RubyUnlinkObjects(void* ptr) { 147 VALUE object = SWIG_RubyInstanceFor(ptr); 148 149 if (object != Qnil) { 150 DATA_PTR(object) = 0; 151 } 152 } 153 154 155 #ifdef __cplusplus 156 } 157 #endif 158