1 /*
2  * Copyright (c) 2024 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_REFCNT_PTR_H
17 #define API_BASE_CONTAINERS_REFCNT_PTR_H
18 
19 #include <base/containers/type_traits.h>
20 #include <base/namespace.h>
21 
BASE_BEGIN_NAMESPACE()22 BASE_BEGIN_NAMESPACE()
23 template<class T>
24 class refcnt_ptr {
25 public:
26     using pointer = BASE_NS::remove_reference_t<T>*;
27     using element_type = T;
28 
29     constexpr refcnt_ptr() noexcept {}
30 
31     constexpr refcnt_ptr(nullptr_t) noexcept {}
32 
33     explicit constexpr refcnt_ptr(pointer ptr) noexcept : ptr_(ptr)
34     {
35         if (ptr) {
36             ptr->Ref();
37         }
38     }
39 
40     refcnt_ptr(const refcnt_ptr& ptr) : refcnt_ptr(ptr.get()) {}
41 
42     template<class U>
43     refcnt_ptr(const refcnt_ptr<U>& ptr) : refcnt_ptr(static_cast<T*>(ptr.get()))
44     {}
45 
46     refcnt_ptr(refcnt_ptr&& ptr) noexcept : ptr_(exchange(ptr.ptr_, nullptr)) {}
47 
48     template<class U>
49     refcnt_ptr(refcnt_ptr<U>&& ptr) noexcept : ptr_(static_cast<T*>(ptr.release()))
50     {}
51 
52     ~refcnt_ptr()
53     {
54         if (ptr_) {
55             ptr_->Unref();
56         }
57     }
58 
59     pointer get() const noexcept
60     {
61         return ptr_;
62     }
63 
64     pointer release() noexcept
65     {
66         pointer res = ptr_;
67         ptr_ = nullptr;
68         return res;
69     }
70 
71     void reset(pointer ptr = pointer()) noexcept
72     {
73         if (ptr_ != ptr) {
74             pointer old_ptr = ptr_;
75             ptr_ = ptr;
76             if (ptr_) {
77                 ptr_->Ref();
78             }
79             if (old_ptr) {
80                 old_ptr->Unref();
81             }
82         }
83     }
84 
85     refcnt_ptr& operator=(nullptr_t) noexcept
86     {
87         reset();
88         return *this;
89     }
90 
91     refcnt_ptr& operator=(const refcnt_ptr& r) noexcept
92     {
93         reset(r.get());
94         return *this;
95     }
96 
97     template<class U>
98     refcnt_ptr& operator=(const refcnt_ptr<U>& r) noexcept
99     {
100         reset(r.get());
101         return *this;
102     }
103 
104     refcnt_ptr& operator=(refcnt_ptr&& r) noexcept
105     {
106         reset();
107         ptr_ = exchange(r.ptr_, nullptr);
108         return *this;
109     }
110 
111     template<class U>
112     refcnt_ptr& operator=(refcnt_ptr<U>&& r) noexcept
113     {
114         reset();
115         ptr_ = r.release();
116         return *this;
117     }
118 
119     void swap(refcnt_ptr& other) noexcept
120     {
121         ptr_ = exchange(other.ptr_, ptr_);
122     }
123 
124     explicit operator bool() const noexcept
125     {
126         return (ptr_ != nullptr);
127     }
128 
129     bool operator==(const refcnt_ptr& other) const noexcept
130     {
131         return (ptr_ == other.ptr_);
132     }
133 
134     bool operator!=(const refcnt_ptr& other) const noexcept
135     {
136         return (ptr_ != other.ptr_);
137     }
138 
139     pointer operator->() const noexcept
140     {
141         return ptr_;
142     }
143 
144     typename BASE_NS::add_lvalue_reference<T>::type operator*() const
145     {
146         return *ptr_;
147     }
148 
149     bool operator!=(nullptr_t) const noexcept
150     {
151         return ptr_ != nullptr;
152     }
153 
154     bool operator==(nullptr_t) const noexcept
155     {
156         return ptr_ == nullptr;
157     }
158 
159 protected:
160     pointer ptr_ { nullptr };
161 };
162 BASE_END_NAMESPACE()
163 
164 #endif // API_BASE_CONTAINERS_REFCNT_PTR_H
165