Skip to content

Commit 63b9559

Browse files
author
Bradley Meck
committed
ephemerons merged in
1 parent df4169b commit 63b9559

File tree

5 files changed

+763
-450
lines changed

5 files changed

+763
-450
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ Files are in __lib__ directory
3838
>
3939
> Set obj's prototype to proto
4040
41+
> ##OnCollect(Object,collector)
42+
> Calls the collector when the Object is about to be Garbage Collected
43+
44+
> * undefined collector(theObject)
45+
46+
> ##new EphemeronTable()
47+
> Creates an ephemeron table that only keeps its keys until that key is garbage collected
48+
49+
> * Value get(Object)
50+
> * Value set(Object,Value)
51+
> * Boolean has(Object)
52+
> * Object[] keys()
53+
4154
####proxy.js
4255

4356
Partial implementation of ES Harmony Proxy API.
@@ -99,3 +112,7 @@ Partial implementation of ES Harmony Proxy API.
99112
100113
#### ReadOnly
101114
> 1. Making arrays that cant be messed with
115+
116+
#### TODO
117+
118+
> 1. EphemeronTable is too generous in allocating memory for it's hash table.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{ "name" : "overload"
22
, "directories" : { "lib" : "./lib" }
3-
, "version" : "1.0.2"
3+
, "version" : "1.2.3"
44
, "author": "bradleymeck"
55
, "main": "lib/overload.node"
66
, "scripts": {

src/ephemeron.cc

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// http://wiki.ecmascript.org/doku.php?id=harmony:ephemeron_tables
2+
// node-overload
3+
// @exports
4+
// OnCollect(Object,function(theObject))
5+
//
6+
7+
#include <v8.h>
8+
#include <map>
9+
#include <vector>
10+
using namespace v8;
11+
using namespace std;
12+
13+
typedef pair<Persistent<Object>*, Persistent<Value>*> EphemeronPair;
14+
typedef vector<EphemeronPair > EphemeronVector;
15+
typedef map<int,EphemeronVector*> EphemeronMap;
16+
17+
Persistent<ObjectTemplate> table_instance_template;
18+
19+
void OurWeakReferenceCallback(
20+
Persistent<Value> object
21+
, void* parameter
22+
) {
23+
HandleScope scope;
24+
Persistent<Function>* callback = (Persistent<Function>*)parameter;
25+
26+
Handle<Value> values[0];
27+
values[0] = object;
28+
//object.ClearWeak();
29+
//puts("CB INVOKING");
30+
(*callback)->Call(Context::GetCurrent()->Global(),1,values);
31+
//puts("OBJ BRANCHING");
32+
if(object.IsNearDeath()) {
33+
object.Dispose();
34+
delete callback;
35+
}
36+
//callback->ClearWeak();
37+
//object.Dispose();
38+
//delete callback;
39+
scope.Close(Undefined());
40+
}
41+
42+
void KeepingWeakReferenceCallback(
43+
Persistent<Value> callback
44+
, void* parameter
45+
) {
46+
HandleScope scope;
47+
Persistent<Object>* object = (Persistent<Object>*)parameter;
48+
//puts("CB BRANCHING");
49+
if(object->IsNearDeath()) {
50+
//puts("CB CLEARED");
51+
callback.Dispose();
52+
delete object;
53+
}
54+
else {
55+
//puts("CB REVIVED");
56+
//Revive this object so long as there is a dependant weak reference
57+
callback.MakeWeak(parameter,KeepingWeakReferenceCallback);
58+
}
59+
scope.Close(Undefined());
60+
}
61+
62+
Handle<Value> Weak(
63+
const Arguments& args
64+
) {
65+
HandleScope scope;
66+
Handle<Value> obj = args[0];
67+
if(!obj->IsObject() || obj->IsNull() || obj->IsUndefined()) {
68+
return scope.Close(ThrowException(Exception::Error(String::New("First argument must be an object"))));
69+
}
70+
Handle<Value> onCollect = args[1];
71+
if(onCollect->IsFunction()) {
72+
Persistent<Object>* persistent_obj = new Persistent<Object>();
73+
*persistent_obj = Persistent<Object>::New(Handle<Object>::Cast(obj));
74+
Persistent<Function>* persistent_cb = new Persistent<Function>();
75+
*persistent_cb = Persistent<Function>::New(Handle<Function>::Cast(onCollect));
76+
77+
persistent_obj->MakeWeak(
78+
persistent_cb
79+
, OurWeakReferenceCallback
80+
);
81+
//bind a weak ref of cb to the obj
82+
persistent_cb->MakeWeak(
83+
persistent_obj
84+
, KeepingWeakReferenceCallback
85+
);
86+
return scope.Close(*persistent_obj);
87+
}
88+
else {
89+
return scope.Close(ThrowException(Exception::Error(String::New("Collect callback must be a function"))));
90+
}
91+
}
92+
93+
Handle<Object> WrapMap(EphemeronMap* obj,Handle<Object> table) {
94+
HandleScope scope;
95+
table->SetInternalField(
96+
0,
97+
External::New(obj)
98+
);
99+
return scope.Close(table);
100+
}
101+
102+
EphemeronMap* UnwrapMap(Handle<Object> obj) {
103+
Handle<External> mymap_wrap = Handle<External>::Cast(obj->GetInternalField(0));
104+
void* mymap_ptr = mymap_wrap->Value();
105+
return static_cast<EphemeronMap*>(
106+
mymap_ptr
107+
);
108+
}
109+
110+
//Remove the object's pair from the map
111+
void EphemeronScrub(
112+
Persistent<Value> object
113+
, void* parameter
114+
) {
115+
EphemeronMap* mymap = static_cast<EphemeronMap*>(parameter);
116+
Handle<Object> obj = Handle<Object>::Cast(object);
117+
int id = obj->GetIdentityHash();
118+
EphemeronMap::iterator i = mymap->find(id);
119+
if(i != mymap->end()) {
120+
EphemeronVector* vector = (*i).second;
121+
EphemeronVector::iterator ii = vector->begin();
122+
while(ii != vector->end()) {
123+
if(obj->StrictEquals(*((*ii).first))) {
124+
vector->erase(ii);
125+
if(vector->size()==0) {
126+
mymap->erase(id);
127+
}
128+
object.Dispose();
129+
//puts("dispose + erase");
130+
return;
131+
}
132+
ii++;
133+
}
134+
}
135+
//puts("dispose");
136+
object.Dispose();
137+
}
138+
139+
Handle<Value> EphemeronInit(
140+
const Arguments& args
141+
) {
142+
HandleScope scope;
143+
if(args.IsConstructCall()) {
144+
EphemeronMap* mymap = new EphemeronMap();
145+
return scope.Close(WrapMap(mymap,args.This()));
146+
}
147+
return scope.Close(ThrowException(Exception::Error(String::New("Must be called through the 'new' operator."))));
148+
}
149+
150+
Handle<Value> EphemeronSet(
151+
const Arguments& args
152+
) {
153+
HandleScope scope;
154+
Handle<Value> key = args[0];
155+
if (key->IsUndefined() || key->IsNull()) {
156+
return scope.Close(ThrowException(Exception::Error(String::New("Key must be an Object"))));
157+
}
158+
Handle<Object> obj = key->ToObject();
159+
Handle<Value> value = args[1];
160+
161+
EphemeronMap* mymap = UnwrapMap(args.This());
162+
163+
Persistent<Object>* obj_ptr = new Persistent<Object>();
164+
*obj_ptr = Persistent<Object>::New(obj);
165+
obj_ptr->MakeWeak(mymap,EphemeronScrub);
166+
167+
Persistent<Value>* value_ptr = new Persistent<Value>();
168+
*value_ptr = Persistent<Value>::New(value);
169+
value_ptr->MakeWeak(obj_ptr,KeepingWeakReferenceCallback);
170+
171+
int id = obj->GetIdentityHash();
172+
173+
EphemeronPair mypair = EphemeronPair(obj_ptr,value_ptr);
174+
EphemeronVector* vector = NULL;
175+
EphemeronMap::iterator i = mymap->find(id);
176+
177+
if(i != mymap->end()) {
178+
vector = (*i).second;
179+
EphemeronVector::iterator ii = vector->begin();
180+
int j = 0;
181+
while(ii != vector->end()) {
182+
EphemeronPair original_pair = *ii;
183+
if((*original_pair.first)->StrictEquals(obj)) {
184+
vector->at(j) = mypair;
185+
return scope.Close(obj);
186+
}
187+
ii++;
188+
j++;
189+
}
190+
i++;
191+
}
192+
else {
193+
vector = new EphemeronVector();
194+
mymap->insert( pair<int,EphemeronVector*>(id,vector) );
195+
}
196+
vector->push_back( mypair );
197+
return scope.Close(obj);
198+
}
199+
200+
Handle<Value> EphemeronGet(
201+
const Arguments& args
202+
) {
203+
HandleScope scope;
204+
Handle<Value> key = args[0];
205+
if (key->IsUndefined() || key->IsNull()) {
206+
return scope.Close(ThrowException(Exception::Error(String::New("Key must be an Object"))));
207+
}
208+
Handle<Object> obj = key->ToObject();
209+
EphemeronMap* mymap = UnwrapMap(args.This());
210+
EphemeronMap::iterator i = mymap->find(obj->GetIdentityHash());
211+
if(i != mymap->end()) {
212+
EphemeronVector* vector = (*i).second;
213+
EphemeronVector::iterator ii = vector->begin();
214+
while(ii != vector->end()) {
215+
EphemeronPair pair = *ii;
216+
if((*pair.first)->StrictEquals(obj)) {
217+
return scope.Close(*pair.second);
218+
}
219+
ii++;
220+
}
221+
i++;
222+
}
223+
return scope.Close(Undefined());
224+
}
225+
226+
Handle<Value> EphemeronHas(
227+
const Arguments& args
228+
) {
229+
HandleScope scope;
230+
Handle<Value> key = args[0];
231+
if (key->IsUndefined() || key->IsNull()) {
232+
return scope.Close(ThrowException(Exception::Error(String::New("Key must be an Object"))));
233+
}
234+
Handle<Object> obj = key->ToObject();
235+
EphemeronMap* mymap = UnwrapMap(args.This());
236+
EphemeronMap::iterator i = mymap->find(obj->GetIdentityHash());
237+
if(i != mymap->end()) {
238+
EphemeronVector* vector = (*i).second;
239+
EphemeronVector::iterator ii = vector->begin();
240+
while(ii != vector->end()) {
241+
if((*(*ii).first)->StrictEquals(obj)) {
242+
return scope.Close(Boolean::New(true));
243+
}
244+
ii++;
245+
}
246+
i++;
247+
}
248+
return scope.Close(Boolean::New(false));
249+
}
250+
251+
Handle<Value> EphemeronKeys(
252+
const Arguments& args
253+
) {
254+
HandleScope scope;
255+
EphemeronMap* mymap = UnwrapMap(args.This());
256+
EphemeronMap::iterator i = mymap->begin();
257+
int j = 0;
258+
Handle<Array> keys = Array::New(mymap->size());
259+
while(i != mymap->end()) {
260+
EphemeronVector* vector = (*i).second;
261+
EphemeronVector::iterator ii = vector->begin();
262+
while(ii != vector->end()) {
263+
keys->Set(j,*((*ii).first));
264+
ii++;
265+
j++;
266+
}
267+
i++;
268+
}
269+
return scope.Close(keys);
270+
}

0 commit comments

Comments
 (0)