Move the message for internal::RaiseUseAfterFree to the implementation.
[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 #ifndef ZCPOINTER_ZCPOINTER_H_
16 #define ZCPOINTER_ZCPOINTER_H_
17
18 #include <limits>
19 #include <memory>
20 #include <forward_list>
21 #include <stdexcept>
22 #include <utility>
23
24 namespace zc {
25
26 class UseAfterFreeError : public std::logic_error {
27 public:
28 using std::logic_error::logic_error;
29 };
30
31 #if defined(ZCPOINTER_TRACK_REFS) && ZCPOINTER_TRACK_REFS
32
33 template <typename T> class ref;
34
35 namespace internal {
36
37 enum class OwnershipBehavior {
38 DELETE_POINTER,
39 BORROW_POINTER,
40 };
41
42 template <typename T>
43 class OwnedPtrDeleter {
44 public:
45 OwnedPtrDeleter() : refs_(), behavior_(OwnershipBehavior::DELETE_POINTER) {}
46 ~OwnedPtrDeleter() {}
47
48 explicit OwnedPtrDeleter(OwnershipBehavior behavior)
49 : refs_(),
50 behavior_(behavior) {
51 }
52
53 OwnedPtrDeleter(OwnedPtrDeleter&& other)
54 : refs_(std::move(other.refs_)),
55 behavior_(other.behavior_) {
56 }
57
58 void operator=(const OwnedPtrDeleter& o) {
59 refs_ = o.refs_;
60 behavior_ = o.behavior_;
61 }
62
63 void operator()(T* t) const {
64 for (auto& ref : refs_) {
65 ref->MarkDeleted();
66 }
67 if (behavior_ == OwnershipBehavior::DELETE_POINTER) {
68 delete t;
69 }
70 }
71
72 protected:
73 friend class ref<T>;
74
75 void AddRef(ref<T>* ref) {
76 refs_.push_front(ref);
77 }
78
79 void RemoveRef(ref<T>* ref) {
80 refs_.remove(ref);
81 }
82
83 private:
84 std::forward_list<ref<T>*> refs_;
85 OwnershipBehavior behavior_;
86 };
87
88 void RaiseUseAfterFree() __attribute__((noreturn));
89
90 } // namespace internal
91
92 template <typename T>
93 class owned : public std::unique_ptr<T, internal::OwnedPtrDeleter<T>> {
94 private:
95 using Deleter = internal::OwnedPtrDeleter<T>;
96
97 public:
98 using std::unique_ptr<T, Deleter>::unique_ptr;
99
100 ref<T> get() {
101 return ref<T>(*this);
102 }
103
104 private:
105 T* get() const {
106 return this->std::unique_ptr<T, Deleter>::get();
107 }
108 };
109
110 template <typename T>
111 class ref {
112 public:
113 ref() : ptr_(nullptr) {}
114
115 ref(std::nullptr_t) : ref() {}
116
117 explicit ref(owned<T>& o) : ptr_(nullptr) {
118 if (o != nullptr) {
119 ptr_ = &o;
120 ptr_->get_deleter().AddRef(this);
121 }
122 }
123
124 ref(const ref<T>& r) {
125 *this = r;
126 }
127
128 ref<T>& operator=(const ref<T>& o) {
129 ptr_ = o.ptr_;
130 if (ptr_ != nullptr && !IsDeleted()) {
131 ptr_->get_deleter().AddRef(this);
132 }
133 return *this;
134 }
135
136 ~ref() {
137 if (ptr_ != nullptr && !IsDeleted()) {
138 ptr_->get_deleter().RemoveRef(this);
139 }
140 MarkDeleted();
141 }
142
143 T* operator->() const {
144 CheckDeleted();
145 return ptr_->operator->();
146 }
147
148 bool operator==(const ref<T>& r) const {
149 if (ptr_ == nullptr) {
150 return r.ptr_ == nullptr;
151 } else {
152 return ptr_ == r.ptr_ && *ptr_ == *r.ptr_;
153 }
154 }
155
156 bool operator==(std::nullptr_t) const {
157 return ptr_ == nullptr;
158 }
159
160 bool operator!=(const ref<T>& r) const {
161 return !(*this == r);
162 }
163
164 protected:
165 friend class internal::OwnedPtrDeleter<T>;
166
167 void MarkDeleted() {
168 ptr_ = DeletedSentinel();
169 }
170
171 private:
172 void CheckDeleted() const {
173 if (IsDeleted()) {
174 internal::RaiseUseAfterFree();
175 }
176 }
177
178 bool IsDeleted() const {
179 return ptr_ == DeletedSentinel();
180 }
181
182 inline static owned<T>* DeletedSentinel() {
183 return reinterpret_cast<owned<T>*>(std::numeric_limits<uintptr_t>::max());
184 }
185
186 owned<T>* ptr_;
187 };
188
189 template <typename T>
190 class member : public T {
191 public:
192 using T::T;
193
194 ref<T> operator&() {
195 return ptr_.get();
196 }
197
198 private:
199 owned<T> ptr_ = owned<T>(this,
200 internal::OwnedPtrDeleter<T>(
201 internal::OwnershipBehavior::BORROW_POINTER));
202 };
203
204 #else
205
206 template <typename T>
207 using owned = std::unique_ptr<T>;
208
209 template <typename T>
210 using ref = T*;
211
212 template <typename T>
213 using member = T;
214
215 #endif
216
217 } // namespace zc
218
219 #endif // ZCPOINTER_ZCPOINTER_H_