Skip to content

Commit 925e37e

Browse files
Rushmbroadst
authored andcommitted
refactor(NLVObject): use shared and weak pointers for tracking children
1 parent 7039cbb commit 925e37e

File tree

3 files changed

+41
-74
lines changed

3 files changed

+41
-74
lines changed

src/nlv_async_worker.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ class NLVAsyncWorker : public NLVAsyncWorkerBase
4747

4848
private:
4949
T handle_;
50-
5150
};
5251

5352
/**
@@ -304,11 +303,8 @@ class NLVLookupInstanceByValueWorker : public NLVAsyncWorkerBase
304303
if (parentObject->IsObject()) {
305304
childObject->Set(Nan::New("_parent").ToLocalChecked(), parentObject);
306305
}
307-
308306
InstanceClass *child = Nan::ObjectWrap::Unwrap<InstanceClass>(childObject);
309-
NLVObjectBasePtr *childPtr = new NLVObjectBasePtr(child);
310-
child->SetParentReference(childPtr);
311-
parent_->children_.push_back(childPtr);
307+
child->AddToParent(parent_);
312308
v8::Local<v8::Value> argv[] = { Nan::Null(), childObject };
313309
callback->Call(2, argv);
314310
}

src/nlv_object.h

Lines changed: 39 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,15 @@
66

77
#include <memory>
88
#include <nan.h>
9+
#include <memory>
10+
#include <type_traits>
11+
#include <forward_list>
12+
913
using namespace node;
1014
using namespace v8;
1115

1216
class NLVObjectBase;
1317

14-
// hold a reference to a "child" object in a way that can be safely invalidated
15-
// if the child is destroyed by the GC before the parent.
16-
class NLVObjectBasePtr
17-
{
18-
public:
19-
NLVObjectBasePtr(NLVObjectBase *ref) : ref_(ref), valid_(true) {}
20-
bool IsValid() const { return valid_; }
21-
NLVObjectBase* GetPointer() const {
22-
if (!valid_) {
23-
//Nan::ThrowReferenceError("attempt to access invalid NLVObjectBase pointer");
24-
return NULL;
25-
}
26-
27-
return ref_;
28-
}
29-
30-
void SetInvalid() {
31-
ref_ = NULL;
32-
valid_ = false;
33-
}
34-
35-
protected:
36-
NLVObjectBase *ref_;
37-
bool valid_;
38-
};
39-
4018
#define NLV_STRINGIFY0(v) #v
4119
#define NLV_STRINGIFY(v) NLV_STRINGIFY0(v)
4220

@@ -49,38 +27,58 @@ class NLVObjectBasePtr
4927
friend class NLVObject;
5028

5129

52-
class NLVObjectBase : public Nan::ObjectWrap
30+
class NLVObjectBase : public Nan::ObjectWrap, public std::enable_shared_from_this<NLVObjectBase>
5331
{
5432
public:
33+
void AddToParent(NLVObjectBase* parent) {
34+
parent->PushChild(shared_from_this());
35+
}
36+
37+
void ClearChildren() {
38+
for (auto& ptr: children_) {
39+
if (auto object = ptr.lock()) {
40+
object->ClearHandle();
41+
object->ClearChildren();
42+
}
43+
}
44+
children_.clear();
45+
}
46+
5547
virtual void ClearHandle() = 0;
56-
virtual void ClearChildren() = 0;
57-
virtual void SetParentReference(NLVObjectBasePtr *parentReference) = 0;
5848

59-
std::vector<NLVObjectBasePtr*> children_;
49+
void PushChild(const std::shared_ptr<NLVObjectBase>& child) {
50+
children_.emplace_front(child);
51+
}
52+
std::forward_list<std::weak_ptr<NLVObjectBase>> children_;
6053
};
6154

6255
template <typename ParentClass, typename HandleType, typename CleanupHandler>
6356
class NLVObject : public NLVObjectBase
6457
{
58+
std::shared_ptr<NLVObjectBase> selfPtr;
6559
public:
6660
typedef HandleType handle_type;
67-
6861
typedef typename std::remove_pointer<HandleType>::type HandleValue;
69-
70-
NLVObject(HandleType handle) : handle_(handle, CleanupHandler::cleanup), parentReference_(NULL) {}
62+
63+
NLVObject(HandleType handle) : handle_(handle, CleanupHandler::cleanup) {
64+
}
65+
7166
~NLVObject() {
72-
// calling virtual ClearHandle() will break if overridden by subclasses
73-
ClearHandle();
74-
if (parentReference_ != NULL) {
75-
parentReference_->SetInvalid();
76-
}
67+
}
68+
69+
void RegisterSelf() {
70+
selfPtr = shared_from_this();
7771
}
7872

7973
static v8::Local<v8::Object> NewInstance(handle_type handle) {
8074
Nan::EscapableHandleScope scope;
8175
Local<Function> ctor = Nan::New<Function>(ParentClass::constructor);
8276
Local<Object> object = Nan::NewInstance(ctor).ToLocalChecked();
83-
ParentClass *class_instance = new ParentClass(handle);
77+
auto shared = std::shared_ptr<ParentClass>(new ParentClass(handle), [=](ParentClass*) {
78+
// here we can now if GC has destroyed our object
79+
});
80+
ParentClass *class_instance = shared.get();
81+
class_instance->RegisterSelf();
8482
class_instance->Wrap(object);
8583
return scope.Escape(object);
8684
}
@@ -92,8 +90,7 @@ class NLVObject : public NLVObjectBase
9290

9391
const HandleType virHandle() const {
9492
return handle_.get();
95-
}
96-
93+
}
9794

9895
NAN_INLINE static ParentClass* Unwrap(v8::Local<v8::Object> val) {
9996
if(!ParentClass::IsInstanceOf(val)) {
@@ -126,34 +123,12 @@ class NLVObject : public NLVObjectBase
126123
return Unwrap(val)->virHandle();
127124
}
128125

129-
virtual void ClearHandle() {
126+
void ClearHandle() {
130127
handle_.reset();
131128
}
132129

133-
virtual void ClearChildren() {
134-
std::vector<NLVObjectBasePtr*>::const_iterator it;
135-
for (it = children_.begin(); it != children_.end(); ++it) {
136-
NLVObjectBasePtr *ptr = *it;
137-
if (ptr->IsValid()) {
138-
NLVObjectBase *obj = ptr->GetPointer();
139-
obj->ClearChildren();
140-
obj->ClearHandle();
141-
obj->SetParentReference(NULL);
142-
delete ptr;
143-
}
144-
}
145-
146-
children_.clear();
147-
}
148-
149-
virtual void SetParentReference(NLVObjectBasePtr *parentReference) {
150-
parentReference_ = parentReference;
151-
}
152-
153130
protected:
154131
std::unique_ptr<HandleValue, decltype(&CleanupHandler::cleanup)> handle_;
155-
NLVObjectBasePtr* parentReference_;
156-
157132
};
158133

159134
namespace NLV {

src/worker.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,13 @@ namespace NLV {
5858
Local<Object> childObject = T::NewInstance(val);
5959
Local<Value> parentObject = worker->GetFromPersistent("parent");
6060
T* child = T::Unwrap(childObject);
61-
NLVObjectBasePtr* childPtr = new NLVObjectBasePtr(child);
6261
if (parentObject->IsObject()) {
6362
childObject->Set(Nan::New("_parent").ToLocalChecked(), parentObject);
6463

6564
auto parent = Nan::ObjectWrap::Unwrap<NLVObjectBase>(parentObject->ToObject());
66-
if (parent) {
67-
parent->children_.push_back(childPtr);
68-
}
65+
child->AddToParent(parent);
6966
}
7067

71-
child->SetParentReference(childPtr);
7268

7369
if (try_catch.HasCaught()) {
7470
v8::Local<v8::Value> argv[] = { try_catch.Exception() };

0 commit comments

Comments
 (0)