6
6
7
7
#include < memory>
8
8
#include < nan.h>
9
+ #include < memory>
10
+ #include < type_traits>
11
+ #include < forward_list>
12
+
9
13
using namespace node ;
10
14
using namespace v8 ;
11
15
12
16
class NLVObjectBase ;
13
17
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
-
40
18
#define NLV_STRINGIFY0 (v ) #v
41
19
#define NLV_STRINGIFY (v ) NLV_STRINGIFY0(v)
42
20
@@ -49,38 +27,58 @@ class NLVObjectBasePtr
49
27
friend class NLVObject ;
50
28
51
29
52
- class NLVObjectBase : public Nan ::ObjectWrap
30
+ class NLVObjectBase : public Nan ::ObjectWrap, public std::enable_shared_from_this<NLVObjectBase>
53
31
{
54
32
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
+
55
47
virtual void ClearHandle () = 0;
56
- virtual void ClearChildren () = 0;
57
- virtual void SetParentReference (NLVObjectBasePtr *parentReference) = 0;
58
48
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_;
60
53
};
61
54
62
55
template <typename ParentClass, typename HandleType, typename CleanupHandler>
63
56
class NLVObject : public NLVObjectBase
64
57
{
58
+ std::shared_ptr<NLVObjectBase> selfPtr;
65
59
public:
66
60
typedef HandleType handle_type;
67
-
68
61
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
+
71
66
~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 ();
77
71
}
78
72
79
73
static v8::Local<v8::Object> NewInstance (handle_type handle) {
80
74
Nan::EscapableHandleScope scope;
81
75
Local<Function> ctor = Nan::New<Function>(ParentClass::constructor);
82
76
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 ();
84
82
class_instance->Wrap (object);
85
83
return scope.Escape (object);
86
84
}
@@ -92,8 +90,7 @@ class NLVObject : public NLVObjectBase
92
90
93
91
const HandleType virHandle () const {
94
92
return handle_.get ();
95
- }
96
-
93
+ }
97
94
98
95
NAN_INLINE static ParentClass* Unwrap (v8::Local<v8::Object> val) {
99
96
if (!ParentClass::IsInstanceOf (val)) {
@@ -126,34 +123,12 @@ class NLVObject : public NLVObjectBase
126
123
return Unwrap (val)->virHandle ();
127
124
}
128
125
129
- virtual void ClearHandle () {
126
+ void ClearHandle () {
130
127
handle_.reset ();
131
128
}
132
129
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
-
153
130
protected:
154
131
std::unique_ptr<HandleValue, decltype (&CleanupHandler::cleanup)> handle_;
155
- NLVObjectBasePtr* parentReference_;
156
-
157
132
};
158
133
159
134
namespace NLV {
0 commit comments