utilrb 1.3 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +4 -1
- data/ext/weakref.cc +142 -0
- data/lib/utilrb/common.rb +1 -1
- data/lib/utilrb/weakref.rb +18 -0
- metadata +5 -2
data/Manifest.txt
CHANGED
@@ -6,11 +6,12 @@ Rakefile
|
|
6
6
|
bm/allocation.rb
|
7
7
|
bm/speed.rb
|
8
8
|
ext/extconf.rb
|
9
|
-
ext/utilrb_ext.cc
|
10
9
|
ext/ruby_internals-1.8.h
|
11
10
|
ext/ruby_internals-1.9.h
|
12
11
|
ext/swap.cc
|
12
|
+
ext/utilrb_ext.cc
|
13
13
|
ext/value_set.cc
|
14
|
+
ext/weakref.cc
|
14
15
|
lib/utilrb.rb
|
15
16
|
lib/utilrb/array.rb
|
16
17
|
lib/utilrb/array/to_s.rb
|
@@ -65,6 +66,7 @@ lib/utilrb/time/to_hms.rb
|
|
65
66
|
lib/utilrb/unbound_method.rb
|
66
67
|
lib/utilrb/unbound_method/call.rb
|
67
68
|
lib/utilrb/value_set.rb
|
69
|
+
lib/utilrb/weakref.rb
|
68
70
|
patches/gc_live_objects.patch
|
69
71
|
test/data/test_pkgconfig.pc
|
70
72
|
test/test_array.rb
|
@@ -84,3 +86,4 @@ test/test_proc.rb
|
|
84
86
|
test/test_set.rb
|
85
87
|
test/test_time.rb
|
86
88
|
test/test_unbound_method.rb
|
89
|
+
test/test_weakref.rb
|
data/ext/weakref.cc
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
#include <set>
|
2
|
+
#include <map>
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <intern.h>
|
5
|
+
|
6
|
+
using std::set;
|
7
|
+
using std::map;
|
8
|
+
|
9
|
+
static VALUE cWeakRef;
|
10
|
+
static VALUE cRefError;
|
11
|
+
|
12
|
+
/* Weakref internal structure. +obj+ is Qnil before initialization and Qundef
|
13
|
+
* after finalization */
|
14
|
+
struct WeakRef {
|
15
|
+
VALUE obj;
|
16
|
+
};
|
17
|
+
|
18
|
+
// Map from real objects to the set of associated WeakRef objects
|
19
|
+
typedef set<VALUE> ObjSet;
|
20
|
+
typedef map< VALUE, ObjSet > RefFromObjID;
|
21
|
+
typedef map< VALUE, VALUE > ObjFromRefID;
|
22
|
+
RefFromObjID from_obj_id;
|
23
|
+
ObjFromRefID from_ref_id;
|
24
|
+
|
25
|
+
static void weakref_free(WeakRef const* set) { delete set; }
|
26
|
+
static VALUE weakref_alloc(VALUE klass)
|
27
|
+
{
|
28
|
+
WeakRef* ref = new WeakRef;
|
29
|
+
ref->obj = Qnil;
|
30
|
+
return Data_Wrap_Struct(klass, NULL, weakref_free, ref);
|
31
|
+
}
|
32
|
+
|
33
|
+
static WeakRef& get_weakref(VALUE self)
|
34
|
+
{
|
35
|
+
WeakRef* object = 0;
|
36
|
+
Data_Get_Struct(self, WeakRef, object);
|
37
|
+
return *object;
|
38
|
+
}
|
39
|
+
|
40
|
+
static VALUE do_object_finalize(VALUE mod, VALUE obj_id)
|
41
|
+
{
|
42
|
+
RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
|
43
|
+
if (ref_set != from_obj_id.end())
|
44
|
+
{
|
45
|
+
ObjSet::iterator it = ref_set->second.begin();
|
46
|
+
ObjSet::iterator const end = ref_set->second.end();
|
47
|
+
for (; it != end; ++it)
|
48
|
+
{
|
49
|
+
/* During GC, objects are garbage collected and *then* the finalizers are called. It means that, even though *it is referenced in from_obj_id, it may be invalid.
|
50
|
+
*
|
51
|
+
* When an object is marked for deferred finalization, its flags
|
52
|
+
* are reset to a special value (flags = FL_MARK). FL_FINALIZE
|
53
|
+
* should therefore not be set on it anymore.
|
54
|
+
*/
|
55
|
+
if (FL_TEST(*it, FL_FINALIZE))
|
56
|
+
{
|
57
|
+
WeakRef& ref = get_weakref(*it);
|
58
|
+
ref.obj = Qundef;
|
59
|
+
}
|
60
|
+
from_ref_id.erase(rb_obj_id(*it));
|
61
|
+
}
|
62
|
+
|
63
|
+
from_obj_id.erase(obj_id);
|
64
|
+
}
|
65
|
+
return Qnil;
|
66
|
+
}
|
67
|
+
|
68
|
+
static VALUE do_weakref_finalize(VALUE mod, VALUE ref_id)
|
69
|
+
{
|
70
|
+
ObjFromRefID::iterator obj_it = from_ref_id.find(ref_id);
|
71
|
+
if (obj_it != from_ref_id.end())
|
72
|
+
{
|
73
|
+
VALUE obj_id = rb_obj_id(obj_it->second);
|
74
|
+
RefFromObjID::iterator ref_set = from_obj_id.find(obj_id);
|
75
|
+
ref_set->second.erase(ref_id & ~FIXNUM_FLAG);
|
76
|
+
from_ref_id.erase(obj_it);
|
77
|
+
}
|
78
|
+
return Qnil;
|
79
|
+
}
|
80
|
+
|
81
|
+
// Note: the Ruby code has already registered +do_object_finalize+ as the
|
82
|
+
// finalizer for +obj+, and +do_weakref_finalize+ for +self+.
|
83
|
+
//
|
84
|
+
// It is forbidden to make a weakref-of-weakref or a weakref of an immediate
|
85
|
+
// object
|
86
|
+
static VALUE weakref_do_initialize(VALUE self, VALUE obj)
|
87
|
+
{
|
88
|
+
if (!FL_ABLE(obj))
|
89
|
+
{
|
90
|
+
VALUE str = rb_any_to_s(obj);
|
91
|
+
rb_raise(rb_eArgError, "%s cannot be finalized", StringValuePtr(str));
|
92
|
+
}
|
93
|
+
|
94
|
+
WeakRef& ref = get_weakref(self);
|
95
|
+
ref.obj = obj;
|
96
|
+
|
97
|
+
RefFromObjID::iterator it = from_obj_id.find(rb_obj_id(obj));
|
98
|
+
if (it == from_obj_id.end())
|
99
|
+
it = from_obj_id.insert( make_pair(rb_obj_id(obj), ObjSet()) ).first;
|
100
|
+
|
101
|
+
it->second.insert(self);
|
102
|
+
from_ref_id.insert( std::make_pair(rb_obj_id(self), obj) );
|
103
|
+
|
104
|
+
return Qnil;
|
105
|
+
}
|
106
|
+
|
107
|
+
static VALUE weakref_get(VALUE self)
|
108
|
+
{
|
109
|
+
WeakRef const& ref = get_weakref(self);
|
110
|
+
|
111
|
+
if (ref.obj == Qnil)
|
112
|
+
rb_raise(cRefError, "initialized weakref");
|
113
|
+
if (ref.obj == Qundef)
|
114
|
+
rb_raise(cRefError, "finalized object");
|
115
|
+
return ref.obj;
|
116
|
+
}
|
117
|
+
|
118
|
+
static VALUE refcount(VALUE mod, VALUE obj)
|
119
|
+
{
|
120
|
+
if (0 == obj & FIXNUM_FLAG)
|
121
|
+
obj = rb_obj_id(obj);
|
122
|
+
|
123
|
+
RefFromObjID::const_iterator it = from_obj_id.find(obj);
|
124
|
+
if (it == from_obj_id.end())
|
125
|
+
return Qnil;
|
126
|
+
else
|
127
|
+
return INT2FIX(it->second.size());
|
128
|
+
}
|
129
|
+
|
130
|
+
extern "C" void Init_weakref(VALUE mUtilrb)
|
131
|
+
{
|
132
|
+
cWeakRef = rb_define_class_under(mUtilrb, "WeakRef", rb_cObject);
|
133
|
+
cRefError = rb_define_class_under(cWeakRef, "RefError", rb_eStandardError);
|
134
|
+
rb_define_alloc_func(cWeakRef, weakref_alloc);
|
135
|
+
|
136
|
+
rb_define_singleton_method(cWeakRef, "do_object_finalize", RUBY_METHOD_FUNC(do_object_finalize), 1);
|
137
|
+
rb_define_singleton_method(cWeakRef, "do_weakref_finalize", RUBY_METHOD_FUNC(do_weakref_finalize), 1);
|
138
|
+
rb_define_singleton_method(cWeakRef, "refcount", RUBY_METHOD_FUNC(refcount), 1);
|
139
|
+
rb_define_method(cWeakRef, "do_initialize", RUBY_METHOD_FUNC(weakref_do_initialize), 1);
|
140
|
+
rb_define_method(cWeakRef, "get", RUBY_METHOD_FUNC(weakref_get), 0);
|
141
|
+
}
|
142
|
+
|
data/lib/utilrb/common.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'utilrb/common'
|
2
|
+
|
3
|
+
Utilrb.require_ext("Utilrb::WeakRef") do
|
4
|
+
module Utilrb
|
5
|
+
class WeakRef
|
6
|
+
def initialize(obj)
|
7
|
+
if obj.kind_of?(WeakRef)
|
8
|
+
raise ArgumentError, "cannot create a weakref of a weakref"
|
9
|
+
end
|
10
|
+
|
11
|
+
ObjectSpace.define_finalizer(obj, self.class.method(:do_object_finalize))
|
12
|
+
ObjectSpace.define_finalizer(self, self.class.method(:do_weakref_finalize))
|
13
|
+
do_initialize(obj)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: utilrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Joyeux
|
@@ -60,11 +60,12 @@ files:
|
|
60
60
|
- bm/allocation.rb
|
61
61
|
- bm/speed.rb
|
62
62
|
- ext/extconf.rb
|
63
|
-
- ext/utilrb_ext.cc
|
64
63
|
- ext/ruby_internals-1.8.h
|
65
64
|
- ext/ruby_internals-1.9.h
|
66
65
|
- ext/swap.cc
|
66
|
+
- ext/utilrb_ext.cc
|
67
67
|
- ext/value_set.cc
|
68
|
+
- ext/weakref.cc
|
68
69
|
- lib/utilrb.rb
|
69
70
|
- lib/utilrb/array.rb
|
70
71
|
- lib/utilrb/array/to_s.rb
|
@@ -119,6 +120,7 @@ files:
|
|
119
120
|
- lib/utilrb/unbound_method.rb
|
120
121
|
- lib/utilrb/unbound_method/call.rb
|
121
122
|
- lib/utilrb/value_set.rb
|
123
|
+
- lib/utilrb/weakref.rb
|
122
124
|
- patches/gc_live_objects.patch
|
123
125
|
- test/data/test_pkgconfig.pc
|
124
126
|
- test/test_array.rb
|
@@ -138,6 +140,7 @@ files:
|
|
138
140
|
- test/test_set.rb
|
139
141
|
- test/test_time.rb
|
140
142
|
- test/test_unbound_method.rb
|
143
|
+
- test/test_weakref.rb
|
141
144
|
has_rdoc: true
|
142
145
|
homepage: " http://utilrb.rubyforge.org"
|
143
146
|
post_install_message:
|