• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 API_BASE_CONTAINERS_SHARED_PTR_H
17 #define API_BASE_CONTAINERS_SHARED_PTR_H
18 
19 #include <base/containers/shared_ptr_internals.h>
20 #include <base/containers/type_traits.h>
21 #include <base/containers/unique_ptr.h>
22 #include <base/namespace.h>
23 
24 CORE_BEGIN_NAMESPACE()
25 class IInterface;
26 CORE_END_NAMESPACE()
27 
28 BASE_BEGIN_NAMESPACE()
29 template<typename T>
30 class shared_ptr;
31 template<typename T>
32 class weak_ptr;
33 
34 /**
35  * @brief C++ standard like weak_ptr.
36  */
37 template<typename T>
38 class weak_ptr final : public Internals::PtrCountedBase<T> {
39 public:
40     using element_type = BASE_NS::remove_extent_t<T>;
41     constexpr weak_ptr() noexcept = default;
~weak_ptr()42     ~weak_ptr()
43     {
44         if (this->control_) {
45             this->control_->ReleaseWeak();
46         }
47     }
48 
weak_ptr(nullptr_t)49     weak_ptr(nullptr_t) {}
weak_ptr(const shared_ptr<T> & p)50     weak_ptr(const shared_ptr<T>& p) : Internals::PtrCountedBase<T>(p)
51     {
52         if (this->control_) {
53             this->control_->AddWeak();
54         }
55     }
weak_ptr(const weak_ptr & p)56     weak_ptr(const weak_ptr& p) noexcept : Internals::PtrCountedBase<T>(p)
57     {
58         if (this->control_) {
59             this->control_->AddWeak();
60         }
61     }
weak_ptr(weak_ptr && p)62     weak_ptr(weak_ptr&& p) noexcept : Internals::PtrCountedBase<T>(p)
63     {
64         p.InternalReset();
65     }
66 
67     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
lock()68     shared_ptr<T> lock() const
69     {
70         return shared_ptr<T>(*this);
71     }
72     weak_ptr& operator=(weak_ptr&& p) noexcept
73     {
74         if (this != &p) {
75             reset();
76             this->control_ = p.control_;
77             this->pointer_ = p.pointer_;
78             p.InternalReset();
79         }
80         return *this;
81     }
82     weak_ptr& operator=(const weak_ptr& p) noexcept
83     {
84         if (this != &p) {
85             reset();
86             this->control_ = p.control_;
87             this->pointer_ = p.pointer_;
88             if (this->control_) {
89                 this->control_->AddWeak();
90             }
91         }
92         return *this;
93     }
94     weak_ptr& operator=(const shared_ptr<T>& p)
95     {
96         reset();
97         this->control_ = p.control_;
98         this->pointer_ = p.pointer_;
99         if (this->control_) {
100             this->control_->AddWeak();
101         }
102         return *this;
103     }
104 
105     weak_ptr& operator=(nullptr_t) noexcept
106     {
107         reset();
108         return *this;
109     }
110     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
reset()111     void reset()
112     {
113         if (this->control_) {
114             this->control_->ReleaseWeak();
115             this->InternalReset();
116         }
117     }
118 
119     /*"implicit" casting constructors */
120     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
weak_ptr(const shared_ptr<U> & p)121     weak_ptr(const shared_ptr<U>& p)
122         // handle casting by using functionality in shared_ptr. (creates an aliased shared_ptr to original.)
123         : weak_ptr(shared_ptr<T>(p))
124     {}
125 
126     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
weak_ptr(const weak_ptr<U> & p)127     weak_ptr(const weak_ptr<U>& p) : weak_ptr(shared_ptr<T>(p.lock()))
128     {}
129 
130     /* "implicit" casting move */
131     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
weak_ptr(weak_ptr<U> && p)132     weak_ptr(weak_ptr<U>&& p) noexcept : weak_ptr(shared_ptr<T>(p.lock()))
133     {
134         p.reset();
135     }
136 
137     /* "implicit" casting operators */
138     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
139     weak_ptr& operator=(const shared_ptr<U>& p)
140     {
141         // handle casting by using functionality in shared_ptr. (creates an aliased shared_ptr to original.)
142         *this = shared_ptr<T>(p);
143         return *this;
144     }
145 
146     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
147     weak_ptr& operator=(const weak_ptr<U>& p)
148     {
149         // first lock the given weak ptr. (to see if it has expired, and to get a pointer that can be cast)
150         *this = shared_ptr<T>(p.lock());
151         return *this;
152     }
153 
154     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
expired()155     bool expired() const noexcept
156     {
157         return this->use_count() == 0;
158     }
159 
160 private:
161     friend class shared_ptr<T>;
162     template<typename>
163     friend class weak_ptr;
164 };
165 
166 /**
167  * @brief C++ standard like shared_ptr with IInterface support for reference counting.
168  */
169 template<typename T>
170 class shared_ptr final : public Internals::PtrCountedBase<T> {
171 public:
172     using element_type = BASE_NS::remove_extent_t<T>;
173     using weak_type = weak_ptr<T>;
174 
175     constexpr shared_ptr() noexcept = default;
shared_ptr(nullptr_t)176     constexpr shared_ptr(nullptr_t) noexcept {}
shared_ptr(const shared_ptr & p)177     shared_ptr(const shared_ptr& p) noexcept : Internals::PtrCountedBase<T>(p)
178     {
179         if (this->control_) {
180             this->control_->AddStrongCopy();
181         }
182     }
shared_ptr(shared_ptr && p)183     shared_ptr(shared_ptr&& p) noexcept : Internals::PtrCountedBase<T>(p)
184     {
185         p.InternalReset();
186     }
shared_ptr(T * ptr)187     explicit shared_ptr(T* ptr)
188     {
189         if (ptr) {
190             ConstructBlock(ptr);
191         }
192     }
193 
194     template<typename Deleter>
shared_ptr(T * ptr,Deleter deleter)195     shared_ptr(T* ptr, Deleter deleter)
196     {
197         if (ptr) {
198             ConstructBlock(ptr, BASE_NS::move(deleter));
199         }
200     }
201 
shared_ptr(const weak_type & p)202     explicit shared_ptr(const weak_type& p) noexcept : Internals::PtrCountedBase<T>(p)
203     {
204         if (this->control_) {
205             if (!this->control_->AddStrongLock()) {
206                 this->InternalReset();
207             }
208         }
209     }
210     template<class Y>
shared_ptr(const shared_ptr<Y> & r,T * ptr)211     shared_ptr(const shared_ptr<Y>& r, T* ptr) noexcept : Internals::PtrCountedBase<T>(r.control_)
212     {
213         if (this->control_ && ptr) {
214             this->control_->AddStrongCopy();
215             this->pointer_ = const_cast<deletableType*>(ptr);
216         } else {
217             this->InternalReset();
218         }
219     }
220     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
shared_ptr(shared_ptr<U> && p)221     shared_ptr(shared_ptr<U>&& p) noexcept : Internals::PtrCountedBase<T>(p.control_)
222     {
223         if (this->control_) {
224             void* ptr = nullptr;
225             if constexpr (BASE_NS::is_same_v<T, const BASE_NS::remove_const_t<U>> ||
226                           !BASE_NS::is_base_of_v<CORE_NS::IInterface, T>) {
227                 ptr = p.get();
228             } else {
229                 // make a proper interface cast here.
230                 if constexpr (BASE_NS::is_const_v<T>) {
231                     ptr = const_cast<void*>(static_cast<const void*>(p->GetInterface(T::UID)));
232                 } else {
233                     ptr = static_cast<void*>(p->GetInterface(T::UID));
234                 }
235             }
236             if (ptr) {
237                 this->pointer_ = static_cast<deletableType*>(ptr);
238                 p.InternalReset();
239             } else {
240                 this->InternalReset();
241                 p.reset();
242             }
243         }
244     }
245     template<class U, class = Internals::EnableIfPointerConvertible<U, T>>
shared_ptr(const shared_ptr<U> & p)246     shared_ptr(const shared_ptr<U>& p) noexcept : shared_ptr(shared_ptr<U>(p)) // use the above move constructor
247     {}
248 
249     template<class U, class D, class = Internals::EnableIfPointerConvertible<U, T>>
shared_ptr(unique_ptr<U,D> && p)250     shared_ptr(unique_ptr<U, D>&& p) noexcept
251     {
252         if (p) {
253             ConstructBlock(p.release(), BASE_NS::move(p.get_deleter()));
254         }
255     }
256 
~shared_ptr()257     ~shared_ptr()
258     {
259         if (this->control_) {
260             this->control_->Release();
261         }
262     }
263     T* operator->() const noexcept
264     {
265         return get();
266     }
267     T& operator*() const noexcept
268     {
269         return *get();
270     }
271     explicit operator bool() const noexcept
272     {
273         return get();
274     }
275     bool operator==(const shared_ptr& other) const noexcept
276     {
277         return get() == other.get();
278     }
279     bool operator!=(const shared_ptr& other) const noexcept
280     {
281         return !(*this == other);
282     }
283     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
reset()284     void reset()
285     {
286         if (this->control_) {
287             this->control_->Release();
288             this->InternalReset();
289         }
290     }
291     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
reset(T * ptr)292     void reset(T* ptr)
293     {
294         if (ptr != this->pointer_) {
295             reset();
296             if (ptr) {
297                 ConstructBlock(ptr);
298             }
299         }
300     }
301     template<typename Deleter>
302     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
reset(T * ptr,Deleter deleter)303     void reset(T* ptr, Deleter deleter)
304     {
305         if (ptr != this->pointer_) {
306             reset();
307             if (ptr) {
308                 ConstructBlock(ptr, BASE_NS::move(deleter));
309             }
310         }
311     }
312 
313     shared_ptr& operator=(nullptr_t) noexcept
314     {
315         reset();
316         return *this;
317     }
318     shared_ptr& operator=(const shared_ptr& o) noexcept
319     {
320         if (this != &o) {
321             reset();
322             this->control_ = o.control_;
323             this->pointer_ = o.pointer_;
324             if (this->control_) {
325                 this->control_->AddStrongCopy();
326             }
327         }
328         return *this;
329     }
330     shared_ptr& operator=(shared_ptr&& o) noexcept
331     {
332         if (this != &o) {
333             reset();
334             this->control_ = o.control_;
335             this->pointer_ = o.pointer_;
336             o.InternalReset();
337         }
338         return *this;
339     }
340     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
swap(shared_ptr & p)341     void swap(shared_ptr& p) noexcept
342     {
343         auto tp = p.pointer_;
344         auto tc = p.control_;
345         p.pointer_ = this->pointer_;
346         p.control_ = this->control_;
347         this->pointer_ = tp;
348         this->control_ = tc;
349     }
350     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
get()351     element_type* get() const noexcept
352     {
353         return this->pointer_;
354     }
355 
356     // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
weak_count()357     int32_t weak_count() const noexcept
358     {
359         if (!this->control_) {
360             return 0;
361         }
362         int32_t c = this->control_->GetWeakCount();
363         if (c > 0) {
364             // strong references are counted as single weak reference for the internal bookkeeping.
365             --c;
366         }
367         return c;
368     }
369 
370 private:
371     using deletableType = BASE_NS::remove_const_t<T>;
372 
ConstructBlock(T * ptr)373     void ConstructBlock(T* ptr)
374     {
375         static_assert(sizeof(T), "type has to be complete when constructing control block");
376         if constexpr (BASE_NS::is_base_of_v<CORE_NS::IInterface, T>) {
377             this->control_ = new Internals::RefCountedObjectStorageBlock(ptr);
378         } else {
379             this->control_ = new Internals::StorageBlock(ptr);
380         }
381         this->pointer_ = ptr;
382     }
383     template<typename Deleter>
ConstructBlock(T * ptr,Deleter deleter)384     void ConstructBlock(T* ptr, Deleter deleter)
385     {
386         this->control_ = new Internals::StorageBlockWithDeleter(ptr, BASE_NS::move(deleter));
387         this->pointer_ = ptr;
388     }
389 
390     template<typename>
391     friend class weak_ptr;
392     template<typename>
393     friend class shared_ptr;
394 };
395 
396 template<typename T, typename... Args>
make_shared(Args &&...args)397 BASE_NS::shared_ptr<T> make_shared(Args&&... args)
398 {
399     return BASE_NS::shared_ptr<T>(new T(BASE_NS::forward<Args>(args)...));
400 }
BASE_END_NAMESPACE()401 BASE_END_NAMESPACE()
402 
403 // NOLINTNEXTLINE(readability-identifier-naming) to keep std like syntax
404 template<class U, class T>
405 BASE_NS::shared_ptr<U> static_pointer_cast(const BASE_NS::shared_ptr<T>& ptr)
406 {
407     if (ptr) {
408         return BASE_NS::shared_ptr<U>(ptr, static_cast<U*>(ptr.get()));
409     }
410     return {};
411 }
412 
413 template<typename T, typename... Args>
CreateShared(Args &&...args)414 BASE_NS::shared_ptr<T> CreateShared(Args&&... args)
415 {
416     return BASE_NS::make_shared<T>(BASE_NS::forward<Args>(args)...);
417 }
418 #endif // API_BASE_CONTAINERS_SHARED_PTR_H
419