1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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 
16 #ifndef MAPLE_UTIL_PTR_H
17 #define MAPLE_UTIL_PTR_H
18 #include <functional>
19 
20 namespace maple {
21 namespace utils {
22 template <typename T>
23 using PtrCheckerType = void (*)(const T *);
24 
25 template <typename T>
CheckNothing(const T *)26 inline constexpr void CheckNothing(const T *)
27 {
28 }
29 
30 template <typename T, PtrCheckerType<T> Check = CheckNothing<T>>
31 class Ptr {
32 public:
33     using Pointer = T *;
34     using ElementType = T;
35 
pointer(nullptr)36     constexpr Ptr() noexcept : pointer(nullptr)
37     {
38         Check(nullptr);
39     }
40 
pointer(nullptr)41     constexpr explicit Ptr(std::nullptr_t) noexcept : pointer(nullptr)
42     {
43         Check(nullptr);
44     }
45 
Ptr(Pointer ptr)46     explicit Ptr(Pointer ptr) : pointer(ptr)
47     {
48         Check(ptr);
49     }
50 
Ptr(Pointer ref, PtrCheckerType<T> checker)51     Ptr(Pointer ref, PtrCheckerType<T> checker) : pointer(ref)
52     {
53         checker(pointer);
54     }
55 
Ptr(T &ref)56     explicit Ptr(T &ref) : pointer(&ref)
57     {
58         Check(pointer);
59     }
60 
Ptr(T &ref, PtrCheckerType<T> checker)61     Ptr(T &ref, PtrCheckerType<T> checker) : pointer(&ref)
62     {
63         checker(pointer);
64     }
65 
66     explicit Ptr(T &&ref) = delete;
67 
68     template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(U *ptr)69     explicit Ptr(U *ptr) : pointer(ptr)
70     {
71         Check(pointer);
72     }
73 
74     template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(U &ref)75     explicit Ptr(U &ref) : pointer(&ref)
76     {
77         Check(pointer);
78     }
79 
80     template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(U &ref, PtrCheckerType<T> checker)81     Ptr(U &ref, PtrCheckerType<T> checker) : pointer(&ref)
82     {
83         checker(pointer);
84     }
85 
86     template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
87     explicit Ptr(U &&ref) = delete;
88 
Ptr(const Ptr &other)89     explicit Ptr(const Ptr &other) : pointer(other.get()) {}
90 
pointer(other.get())91     explicit Ptr(Ptr &&other) noexcept : pointer(other.get()) {}
92 
93     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(const Ptr<U, CheckU> &other)94     explicit Ptr(const Ptr<U, CheckU> &other) : pointer(other.get())
95     {
96         Check(pointer);
97     }
98 
99     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(const Ptr<U, CheckU> &other, PtrCheckerType<T> checker)100     Ptr(const Ptr<U, CheckU> &other, PtrCheckerType<T> checker) : pointer(other.get())
101     {
102         checker(pointer);
103     }
104 
105     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(Ptr<U, CheckU> &&other)106     explicit Ptr(Ptr<U, CheckU> &&other) : pointer(other.get())
107     {
108         Check(pointer);
109     }
110 
111     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
Ptr(Ptr<U, CheckU> &&other, PtrCheckerType<T> checker)112     Ptr(Ptr<U, CheckU> &&other, PtrCheckerType<T> checker) : pointer(other.get())
113     {
114         checker(pointer);
115     }
116 
117     ~Ptr() = default;
118 
119     Ptr &operator=(Pointer ptr) noexcept
120     {
121         Check(ptr);
122         pointer = ptr;
123         return *this;
124     }
125 
126     Ptr &operator=(std::nullptr_t) noexcept
127     {
128         Check(nullptr);
129         reset();
130         return *this;
131     }
132 
133     Ptr &operator=(const Ptr &ptr) noexcept
134     {
135         if (&ptr != this) {
136             pointer = ptr.pointer;
137         }
138         return *this;
139     }
140 
141     Ptr &operator=(Ptr &&ptr) noexcept
142     {
143         if (&ptr != this) {
144             pointer = std::move(ptr.pointer);
145         }
146         return *this;
147     }
148 
149     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
150     Ptr &operator=(const Ptr<U, CheckU> &ptr) noexcept
151     {
152         if (this->get() != ptr.get()) {
153             Check(ptr.get());
154             pointer = ptr.get();
155         }
156         return *this;
157     }
158 
159     template <typename U, PtrCheckerType<U> CheckU, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
160     Ptr &operator=(Ptr<U, CheckU> &&ptr) noexcept
161     {
162         if (this->get() != ptr.get()) {
163             Check(ptr.get());
164             pointer = std::move(ptr.get());
165         }
166         return *this;
167     }
168 
169     Pointer release() noexcept = delete;
170 
171     void reset(Pointer ptr = Pointer()) noexcept
172     {
173         Check(ptr);
174         pointer = ptr;
175     }
176 
177     void swap(Ptr &other) noexcept
178     {
179         std::swap(pointer, other.pointer);
180     }
181 
182     T *get() const noexcept
183     {
184         return pointer;
185     }
186 
187     explicit operator bool() const noexcept
188     {
189         return get() != nullptr;
190     }
191 
operator *() const192     T &operator*() const
193     {
194         return *get();
195     }
196 
197     T *operator->() const noexcept
198     {
199         return get();
200     }
201 
202     T &operator[](size_t i) const = delete;
203 
204     Ptr &operator++() = delete;
205 
206     const Ptr operator++(int) = delete;
207 
208     Ptr &operator--() = delete;
209 
210     const Ptr operator--(int) = delete;
211 
212     Ptr &operator+=(std::ptrdiff_t) = delete;
213 
214     Ptr &operator-=(std::ptrdiff_t) = delete;
215 
216 private:
217     T *pointer;
218 };
219 
220 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator ==(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)221 inline bool operator==(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
222 {
223     return lhs.get() == rhs.get();
224 }
225 
226 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator !=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)227 inline bool operator!=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
228 {
229     return !(lhs == rhs);
230 }
231 
232 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator <(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)233 inline bool operator<(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
234 {
235     return lhs.get() < rhs.get();
236 }
237 
238 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator <=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)239 inline bool operator<=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
240 {
241     return lhs.get() <= rhs.get();
242 }
243 
244 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator >(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)245 inline bool operator>(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
246 {
247     return !(lhs <= rhs);
248 }
249 
250 template <typename T, PtrCheckerType<T> CheckT, typename U, PtrCheckerType<U> CheckU>
operator >=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)251 inline bool operator>=(const Ptr<T, CheckT> &lhs, const Ptr<U, CheckU> &rhs)
252 {
253     return !(lhs < rhs);
254 }
255 
256 template <typename T, PtrCheckerType<T> CheckT>
operator ==(const Ptr<T, CheckT> &lhs, std::nullptr_t)257 inline bool operator==(const Ptr<T, CheckT> &lhs, std::nullptr_t)
258 {
259     return !static_cast<bool>(lhs);
260 }
261 
262 template <typename T, PtrCheckerType<T> CheckT>
operator ==(std::nullptr_t, const Ptr<T, CheckT> &rhs)263 inline bool operator==(std::nullptr_t, const Ptr<T, CheckT> &rhs)
264 {
265     return !static_cast<bool>(rhs);
266 }
267 
268 template <typename T, PtrCheckerType<T> CheckT>
operator !=(const Ptr<T, CheckT> &lhs, std::nullptr_t)269 inline bool operator!=(const Ptr<T, CheckT> &lhs, std::nullptr_t)
270 {
271     return static_cast<bool>(lhs);
272 }
273 
274 template <typename T, PtrCheckerType<T> CheckT>
operator !=(std::nullptr_t, const Ptr<T, CheckT> &rhs)275 inline bool operator!=(std::nullptr_t, const Ptr<T, CheckT> &rhs)
276 {
277     return static_cast<bool>(rhs);
278 }
279 
280 template <typename T, PtrCheckerType<T> CheckT>
operator <(const Ptr<T, CheckT> &lhs, std::nullptr_t)281 inline bool operator<(const Ptr<T, CheckT> &lhs, std::nullptr_t)
282 {
283     return std::less<typename Ptr<T, CheckT>::Pointer>()(lhs.get(), nullptr);
284 }
285 
286 template <typename T, PtrCheckerType<T> CheckT>
operator <(std::nullptr_t, const Ptr<T, CheckT> &rhs)287 inline bool operator<(std::nullptr_t, const Ptr<T, CheckT> &rhs)
288 {
289     return std::less<typename Ptr<T, CheckT>::Pointer>()(nullptr, rhs.get());
290 }
291 
292 template <typename T, PtrCheckerType<T> CheckT>
operator <=(const Ptr<T, CheckT> &lhs, std::nullptr_t)293 inline bool operator<=(const Ptr<T, CheckT> &lhs, std::nullptr_t)
294 {
295     return !(lhs > nullptr);
296 }
297 
298 template <typename T, PtrCheckerType<T> CheckT>
operator <=(std::nullptr_t, const Ptr<T, CheckT> &rhs)299 inline bool operator<=(std::nullptr_t, const Ptr<T, CheckT> &rhs)
300 {
301     return !(rhs < nullptr);
302 }
303 
304 template <typename T, PtrCheckerType<T> CheckT>
operator >(const Ptr<T, CheckT> &lhs, std::nullptr_t)305 inline bool operator>(const Ptr<T, CheckT> &lhs, std::nullptr_t)
306 {
307     return !(lhs <= nullptr);
308 }
309 
310 template <typename T, PtrCheckerType<T> CheckT>
operator >(std::nullptr_t, const Ptr<T, CheckT> &rhs)311 inline bool operator>(std::nullptr_t, const Ptr<T, CheckT> &rhs)
312 {
313     return !(rhs >= nullptr);
314 }
315 
316 template <typename T, PtrCheckerType<T> CheckT>
operator >=(const Ptr<T, CheckT> &lhs, std::nullptr_t)317 inline bool operator>=(const Ptr<T, CheckT> &lhs, std::nullptr_t)
318 {
319     return !(lhs < nullptr);
320 }
321 
322 template <typename T, PtrCheckerType<T> CheckT>
operator >=(std::nullptr_t, const Ptr<T, CheckT> &rhs)323 inline bool operator>=(std::nullptr_t, const Ptr<T, CheckT> &rhs)
324 {
325     return !(rhs > nullptr);
326 }
327 }  // namespace utils
328 }  // namespace maple
329 #endif  // DIY_CPLUSPLUS_SAFE_PTR_H