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