66
77#include < memory>
88#include < nan.h>
9+ #include < memory>
10+ #include < type_traits>
11+ #include < forward_list>
12+
913using namespace node ;
1014using namespace v8 ;
1115
1216class 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{
5432public:
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
6255template <typename ParentClass, typename HandleType, typename CleanupHandler>
6356class NLVObject : public NLVObjectBase
6457{
58+ std::shared_ptr<NLVObjectBase> selfPtr;
6559public:
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 handle () 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)) {
@@ -125,34 +122,12 @@ class NLVObject : public NLVObjectBase
125122 return Unwrap (val)->handle ();
126123 }
127124
128- virtual void ClearHandle () {
125+ void ClearHandle () {
129126 handle_.reset ();
130127 }
131128
132- virtual void ClearChildren () {
133- std::vector<NLVObjectBasePtr*>::const_iterator it;
134- for (it = children_.begin (); it != children_.end (); ++it) {
135- NLVObjectBasePtr *ptr = *it;
136- if (ptr->IsValid ()) {
137- NLVObjectBase *obj = ptr->GetPointer ();
138- obj->ClearChildren ();
139- obj->ClearHandle ();
140- obj->SetParentReference (NULL );
141- delete ptr;
142- }
143- }
144-
145- children_.clear ();
146- }
147-
148- virtual void SetParentReference (NLVObjectBasePtr *parentReference) {
149- parentReference_ = parentReference;
150- }
151-
152129protected:
153130 std::unique_ptr<HandleValue, decltype (&CleanupHandler::cleanup)> handle_;
154- NLVObjectBasePtr* parentReference_;
155-
156131};
157132
158133namespace NLV {
0 commit comments