Initial implementation of zero-cost unique_ptr with exploding weak references.
[zcpointer.git] / zcpointer.h
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <memory>
16 #include <forward_list>
17 #include <stdexcept>
18
19 namespace zc {
20
21 #if defined(ZCPOINTER_TRACK_REFS) && ZCPOINTER_TRACK_REFS
22
23 template <typename T> class ref;
24
25 namespace internal {
26
27 template <typename T>
28 class OwnedPtrDeleter {
29 public:
30 OwnedPtrDeleter() {}
31 ~OwnedPtrDeleter() {}
32
33 OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)) {
34 }
35
36 void operator()(T* t) const {
37 for (auto& ref : refs_) {
38 ref->MarkDeleted();
39 }
40 delete t;
41 }
42
43 protected:
44 friend class ref<T>;
45
46 void AddRef(ref<T>* ref) {
47 refs_.push_front(ref);
48 }
49
50 void RemoveRef(ref<T>* ref) {
51 refs_.remove(ref);
52 }
53
54 private:
55 std::forward_list<ref<T>*> refs_;
56 };
57
58 } // namespace internal
59
60 using UseAfterFreeException = std::logic_error;
61
62 template <typename T>
63 class owned : public std::unique_ptr<T, internal::OwnedPtrDeleter<T>> {
64 private:
65 using Deleter = internal::OwnedPtrDeleter<T>;
66
67 public:
68 using std::unique_ptr<T, Deleter>::unique_ptr;
69
70 ref<T> get() {
71 return ref<T>(*this);
72 }
73
74 protected:
75 friend class ref<T>;
76
77 T* GetRawPointer() const {
78 return get();
79 }
80
81 private:
82 T* get() const {
83 return this->std::unique_ptr<T, Deleter>::get();
84 }
85 };
86
87 template <typename T>
88 class ref {
89 public:
90 ref(owned<T>& o) : ptr_(o.GetRawPointer()), deleter_(o.get_deleter()) {
91 deleter_.AddRef(this);
92 }
93
94 ref(const ref<T>& o) : ptr_(o.ptr_), deleter_(o.deleter_), deleted_(o.deleted_) {
95 if (!deleted_) {
96 deleter_.AddRef(this);
97 }
98 }
99
100 ref<T>& operator=(ref<T> o) {
101 ptr_ = o.ptr_;
102 deleter_ = o.deleter_;
103 deleted_ = o.deleted_;
104 if (!deleted_) {
105 deleter_.AddRef(this);
106 }
107 return *this;
108 }
109
110 ~ref() {
111 deleter_.RemoveRef(this);
112 }
113
114 #if 0
115 operator T*() const {
116 CheckDeleted();
117 return ptr_;
118 }
119 #endif
120
121 T* operator->() const {
122 CheckDeleted();
123 return ptr_;
124 }
125
126 #if 0
127 T* get() {
128 CheckDeleted();
129 return ptr_;
130 }
131 #endif
132
133 protected:
134 friend class internal::OwnedPtrDeleter<T>;
135
136 void MarkDeleted() {
137 deleted_ = true;
138 }
139
140 private:
141 void CheckDeleted() const {
142 if (deleted_) {
143 throw UseAfterFreeException("attempt to access deleted pointer");
144 }
145 }
146
147 T* ptr_;
148 internal::OwnedPtrDeleter<T>& deleter_;
149 bool deleted_ = false;
150 };
151
152 #else
153
154 template <typename T>
155 using owned = std::unique_ptr<T>;
156
157 template <typename T>
158 using ref = T*;
159
160 #endif
161
162 } // namespace zc