weakref.cc
Go to the documentation of this file.
00001 #include <set>
00002 #include <map>
00003 #include <ruby.h>
00004 #ifdef RUBY_IS_18
00005 #include <intern.h>
00006 #else
00007 #include <ruby/intern.h>
00008 #endif
00009 
00010 using std::set;
00011 using std::map;
00012 
00013 static VALUE cWeakRef;
00014 static VALUE cRefError;
00015 
00016 /* Weakref internal structure. +obj+ is Qnil before initialization and Qundef
00017  * after finalization */
00018 struct WeakRef {
00019     VALUE ruby_ref;
00020     VALUE obj;
00021 };
00022 
00023 // Map from real objects to the set of associated WeakRef objects
00024 typedef set<VALUE> ObjSet;
00025 typedef map< VALUE, ObjSet > RefFromObjID;
00026 typedef map< VALUE, VALUE > ObjFromRefID;
00027 RefFromObjID from_obj_id;
00028 ObjFromRefID from_ref_id;
00029 
00030 static void weakref_free(WeakRef const* ref)
00031 {
00032     VALUE ref_id = rb_obj_id(ref->ruby_ref);
00033     ObjFromRefID::iterator obj_it = from_ref_id.find(ref_id);
00034     if (obj_it != from_ref_id.end())
00035     {
00036         VALUE obj_id = rb_obj_id(obj_it->second);
00037         RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
00038         ref_set->second.erase(ref->ruby_ref);
00039         from_ref_id.erase(obj_it);
00040     }
00041     delete ref;
00042 }
00043 static VALUE weakref_alloc(VALUE klass)
00044 {
00045     WeakRef* ref = new WeakRef;
00046     ref->obj = Qnil;
00047     ref->ruby_ref = Data_Wrap_Struct(klass, NULL, weakref_free, ref);
00048     return ref->ruby_ref;
00049 }
00050 
00051 static WeakRef& get_weakref(VALUE self)
00052 {
00053     WeakRef* object = 0;
00054     Data_Get_Struct(self, WeakRef, object);
00055     return *object;
00056 }
00057 
00058 static VALUE do_object_finalize(VALUE mod, VALUE obj_id)
00059 {
00060     RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
00061     if (ref_set != from_obj_id.end())
00062     {
00063         ObjSet::iterator it = ref_set->second.begin();
00064         ObjSet::iterator const end = ref_set->second.end();
00065         for (; it != end; ++it)
00066         {
00067             // Do NOT use Data_Wrap_Struct here, it would break on recent Ruby
00068             // interpreters. The reason is that the object type is reset during
00069             // GC -- and the call to free functions is deferred.
00070             //
00071             // So, at this point, we're sure we have a RDATA in *it (otherwise
00072             // weakref_free would have been called), but we can't use
00073             // Data_Wrap_Struct because that would crash.
00074             WeakRef& ref = *reinterpret_cast<WeakRef*>(RDATA(*it)->data);;
00075             ref.obj = Qundef;
00076             from_ref_id.erase(rb_obj_id(*it));
00077         }
00078         from_obj_id.erase(obj_id);
00079     }
00080     return Qnil;
00081 }
00082 
00083 // Note: the Ruby code has already registered +do_object_finalize+ as the
00084 // finalizer for +obj+.
00085 //
00086 // It is forbidden to make a weakref-of-weakref or a weakref of an immediate
00087 // object
00088 static VALUE weakref_do_initialize(VALUE self, VALUE obj)
00089 {
00090     if (!FL_ABLE(obj))
00091     {
00092         VALUE str = rb_any_to_s(obj);
00093         rb_raise(rb_eArgError, "%s cannot be finalized", StringValuePtr(str));
00094     }
00095 
00096     WeakRef& ref = get_weakref(self);
00097     ref.obj = obj;
00098 
00099     RefFromObjID::iterator it = from_obj_id.find(rb_obj_id(obj));
00100     if (it == from_obj_id.end())
00101         it = from_obj_id.insert( make_pair(rb_obj_id(obj), ObjSet()) ).first;
00102 
00103     it->second.insert(self);
00104     from_ref_id.insert( std::make_pair(rb_obj_id(self), obj) );
00105 
00106     return Qnil;
00107 }
00108 
00109 static VALUE weakref_get(VALUE self)
00110 {
00111     WeakRef const& ref = get_weakref(self);
00112 
00113     if (ref.obj == Qnil)
00114         rb_raise(cRefError, "initialized weakref");
00115     if (ref.obj == Qundef)
00116         rb_raise(cRefError, "finalized object");
00117     return ref.obj;
00118 }
00119 
00120 static VALUE refcount(VALUE mod, VALUE obj)
00121 {
00122     if (0 == (obj & FIXNUM_FLAG))
00123         obj = rb_obj_id(obj);
00124 
00125     RefFromObjID::const_iterator it = from_obj_id.find(obj);
00126     if (it == from_obj_id.end())
00127         return Qnil;
00128     else
00129         return INT2FIX(it->second.size());
00130 }
00131 
00132 extern "C" void Init_weakref(VALUE mUtilrb)
00133 {
00134     cWeakRef = rb_define_class_under(mUtilrb, "WeakRef", rb_cObject);
00135     cRefError = rb_define_class_under(cWeakRef, "RefError", rb_eStandardError);
00136     rb_define_alloc_func(cWeakRef, weakref_alloc);
00137 
00138     rb_define_singleton_method(cWeakRef, "do_object_finalize", RUBY_METHOD_FUNC(do_object_finalize), 1);
00139     rb_define_singleton_method(cWeakRef, "refcount", RUBY_METHOD_FUNC(refcount), 1);
00140     rb_define_method(cWeakRef, "do_initialize", RUBY_METHOD_FUNC(weakref_do_initialize), 1);
00141     rb_define_method(cWeakRef, "get", RUBY_METHOD_FUNC(weakref_get), 0);
00142 }
00143 


utilrb
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:20