spla
Loading...
Searching...
No Matches
ref.hpp
Go to the documentation of this file.
1/**********************************************************************************/
2/* This file is part of spla project */
3/* https://github.com/SparseLinearAlgebra/spla */
4/**********************************************************************************/
5/* MIT License */
6/* */
7/* Copyright (c) 2023 SparseLinearAlgebra */
8/* */
9/* Permission is hereby granted, free of charge, to any person obtaining a copy */
10/* of this software and associated documentation files (the "Software"), to deal */
11/* in the Software without restriction, including without limitation the rights */
12/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
13/* copies of the Software, and to permit persons to whom the Software is */
14/* furnished to do so, subject to the following conditions: */
15/* */
16/* The above copyright notice and this permission notice shall be included in all */
17/* copies or substantial portions of the Software. */
18/* */
19/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
20/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
21/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
22/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
23/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
24/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */
25/* SOFTWARE. */
26/**********************************************************************************/
27
28#ifndef SPLA_REF_HPP
29#define SPLA_REF_HPP
30
31#include <atomic>
32#include <cassert>
33#include <functional>
34#include <stdexcept>
35#include <utility>
36
37namespace spla {
38
55 class RefCnt {
56 public:
57 virtual ~RefCnt() {
58#ifdef SPLA_DEBUG
59 assert(m_refs.load() == 0);
60 m_refs.store(0);
61#endif
62 }
63
64 bool is_unique() const {
65 return get_refs() == 1;
66 }
67
68 std::int32_t get_refs() const {
69 return m_refs.load(std::memory_order_relaxed);
70 }
71
72 std::int32_t add_ref() const {
73 assert(get_refs() >= 0);
74 return m_refs.fetch_add(1);
75 }
76
77 std::int32_t rel_ref() const {
78 assert(get_refs() > 0);
79 auto refs = m_refs.fetch_sub(1);
80
81 if (refs == 1) {
82 // Was last reference
83 // Destroy object and release memory
84 delete this;
85 }
86
87 return refs;
88 }
89
90 private:
91 // This type of object after creation always has no reference
92 mutable std::atomic_int32_t m_refs{0};
93 };
94
95 template<typename T>
96 static inline T* safe_ref(T* object) {
97 if (object)
98 object->add_ref();
99 return object;
100 }
101
102 template<typename T>
103 static inline void unref(T* object) {
104 if (object)
105 object->rel_ref();
106 }
107
116 template<typename T>
117 class ref_ptr {
118 public:
119 ref_ptr() = default;
120
121 explicit ref_ptr(T* object) {
122 m_object = safe_ref(object);
123 }
124
125 ref_ptr(const ref_ptr& other) {
126 m_object = safe_ref(other.m_object);
127 }
128
129 ref_ptr(ref_ptr&& other) noexcept {
130 m_object = other.m_object;
131 other.m_object = nullptr;
132 }
134 unref(m_object);
135 m_object = nullptr;
136 }
137
138 ref_ptr<T>& operator=(const ref_ptr& other) {
139 if (this != &other)
140 this->reset(safe_ref(other.get()));
141 return *this;
142 }
143
144 template<typename G>
146 if (get() != other.get())
147 this->reset(safe_ref(other.get()));
148 return *this;
149 }
150
151 ref_ptr<T>& operator=(ref_ptr&& other) noexcept {
152 if (this != &other)
153 this->reset(other.release());
154 return *this;
155 }
156
157 bool operator==(const ref_ptr& other) const {
158 return m_object == other.m_object;
159 }
160 bool operator!=(const ref_ptr& other) const {
161 return m_object != other.m_object;
162 }
163
164 [[nodiscard]] bool is_null() const {
165 return m_object == nullptr;
166 }
167
168 [[nodiscard]] bool is_not_null() const {
169 return m_object;
170 }
171
172 T* operator->() const {
173 assert(m_object);
174 return m_object;
175 }
176
177 T& operator*() const {
178 assert(m_object);
179 return *m_object;
180 }
181
182 explicit operator bool() const {
183 return m_object != nullptr;
184 }
185
186 void acquire(T* safe_ref_ptr = nullptr) {
187 reset(safe_ref(safe_ref_ptr));
188 }
189
190 void reset(T* ptr = nullptr) {
191 T* old = m_object;
192 m_object = ptr;
193 unref(old);
194 }
195
196 T* release() {
197 T* ptr = m_object;
198 m_object = nullptr;
199 return ptr;
200 }
201
202 T* get() const {
203 return m_object;
204 }
205
207 return safe_ref(m_object);
208 }
209
210 template<typename G>
211 [[nodiscard]] bool is() const {
212 return !m_object || dynamic_cast<G*>(m_object);
213 }
214
215 template<class G>
216 ref_ptr<G> as() const {
217 return ref_ptr<G>(m_object);
218 }
219
220 template<class G>
222 auto casted = dynamic_cast<G*>(m_object);
223
224 if (!casted && m_object) {
225 throw std::runtime_error("failed to do dynamic cast");
226 }
227
228 return ref_ptr<G>(casted);
229 }
230
231 template<class G>
232 ref_ptr<G> cast() const {
233 return ref_ptr<G>(dynamic_cast<G*>(m_object));
234 }
235
236 template<class G>
238 return ref_ptr<G>((G*) m_object);
239 }
240
241 private:
242 T* m_object = nullptr;
243 };
244
245 template<typename T, typename... TArgs>
246 ref_ptr<T> make_ref(TArgs&&... args) {
247 return ref_ptr<T>(new T(std::forward<TArgs>(args)...));
248 }
249
254}// namespace spla
255
256#endif//SPLA_REF_HPP
Base class for object with built-in reference counting mechanism.
Definition ref.hpp:55
virtual ~RefCnt()
Definition ref.hpp:57
bool is_unique() const
Definition ref.hpp:64
std::int32_t get_refs() const
Definition ref.hpp:68
std::int32_t add_ref() const
Definition ref.hpp:72
std::int32_t rel_ref() const
Definition ref.hpp:77
Automates reference counting and behaves as shared smart pointer.
Definition ref.hpp:117
T * operator->() const
Definition ref.hpp:172
ref_ptr< G > cast_safe() const
Definition ref.hpp:221
void acquire(T *safe_ref_ptr=nullptr)
Definition ref.hpp:186
bool is_null() const
Definition ref.hpp:164
T & operator*() const
Definition ref.hpp:177
ref_ptr(T *object)
Definition ref.hpp:121
void reset(T *ptr=nullptr)
Definition ref.hpp:190
T * ref_and_get()
Definition ref.hpp:206
ref_ptr< G > as() const
Definition ref.hpp:216
ref_ptr< G > cast_static() const
Definition ref.hpp:237
bool operator==(const ref_ptr &other) const
Definition ref.hpp:157
bool is() const
Definition ref.hpp:211
ref_ptr< T > & operator=(const ref_ptr< G > &other)
Definition ref.hpp:145
bool is_not_null() const
Definition ref.hpp:168
ref_ptr< T > & operator=(ref_ptr &&other) noexcept
Definition ref.hpp:151
T * get() const
Definition ref.hpp:202
ref_ptr()=default
T * release()
Definition ref.hpp:196
ref_ptr< G > cast() const
Definition ref.hpp:232
ref_ptr(ref_ptr &&other) noexcept
Definition ref.hpp:129
~ref_ptr()
Definition ref.hpp:133
ref_ptr(const ref_ptr &other)
Definition ref.hpp:125
ref_ptr< T > & operator=(const ref_ptr &other)
Definition ref.hpp:138
bool operator!=(const ref_ptr &other) const
Definition ref.hpp:160
ref_ptr< T > make_ref(TArgs &&... args)
Definition ref.hpp:246
Definition algorithm.hpp:37