NDEVR
API Documentation
Pointer.hpp
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: Pointer
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/ConcurrentOperation.h>
34#include <NDEVR/BaseValues.h>
35#include <NDEVR/LibAssert.h>
36#ifdef NDEVR_USE_STD_POINTER
37 #include <memory>
38#endif
39#ifndef NDEVR_USE_STD_POINTER
40namespace NDEVR
41{
45 struct PointerCore
46 {
47 PointerCore()
48 : reference_count(1)
49 {}
50 volatile uint04 reference_count;
51 };
52
53 template< class t_other_type, class t_type>
54 constexpr typename std::enable_if<std::is_polymorphic<t_type>::value, bool>::type CheckCanCast(t_type* other)
55 {
56 return dynamic_cast<t_other_type*>(other) != nullptr;
57 }
58 template<class t_other_type, class t_type>
59 constexpr typename std::enable_if<!std::is_polymorphic<t_type>::value, bool>::type CheckCanCast(t_type*)
60 {
61 return true;
62 }
63
69 template<class t_type>
70 class Pointer
71 {
72 protected:
73 template<class> friend class Pointer;
74 Pointer() noexcept
75 : m_core(nullptr)
76 , m_object(nullptr)
77 {}
78 Pointer(t_type* value) noexcept
79 : m_core(value == nullptr ? nullptr : new PointerCore())
80 , m_object(value)
81 {}
82 template<class t_parent_type>
83 Pointer(t_parent_type* value) noexcept
84 : m_core(value == nullptr ? nullptr : new PointerCore())
85 , m_object(value)
86 {}
87 Pointer(const Pointer<t_type>& value) noexcept
88 : m_core(value.m_core)
89 , m_object(value.m_object)
90 {
91 if (m_core != nullptr)
92 ConcurrentOperation::increment(m_core->reference_count);
93 }
94 Pointer(Pointer<t_type>&& value) noexcept
95 : m_core(nullptr)
96 , m_object(nullptr)
97 {
98 std::swap(m_core, value.m_core);
99 std::swap(m_object, value.m_object);
100 }
101 Pointer(t_type&& value) noexcept
102 : m_core(new PointerCore())
103 , m_object(new t_type(std::move(value)))
104 {
105 }
106 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
107 Pointer(t_parent_type&& value) noexcept
108 : m_core(new PointerCore())
109 , m_object(new t_parent_type(std::move(value)))
110 {}
111 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
112 Pointer(Pointer<t_parent_type>&& value) noexcept
113 : m_core(nullptr)
114 , m_object(nullptr)
115 {
116 std::swap(m_core, value.m_core);
117 m_object = value.m_object;
118 value.m_object = nullptr;
119 }
120 t_type& get() const
121 {
122 lib_assert(m_object != nullptr, "Tried to access null pointer");
123 return *m_object;
124 }
125 constexpr t_type* rawptr() const
126 {
127 return m_object;
128 }
129 void set(t_type&& value)
130 {
131 setToNull();
132 m_core = new PointerCore();
133 m_object = new t_type(std::move(value));
134 }
135 Pointer& operator=(const Pointer& pointer)
136 {
137 if (pointer.m_core == m_core)
138 return *this;
139 setToNull();
140 m_core = pointer.m_core;
141 m_object = pointer.m_object;
142 if(m_core)
143 ConcurrentOperation::increment(m_core->reference_count);
144 lib_assert((m_core == nullptr) == (m_object == nullptr), "Pointer core null mismatch");
145 return *this;
146 }
147 Pointer& operator=(t_type* pointer)
148 {
149 setToNull();
150 if (pointer)
151 {
152 m_core = new PointerCore();
153 m_object = pointer;
154 }
155 lib_assert((m_core == nullptr) == (m_object == nullptr), "Pointer core null mismatch");
156 return *this;
157 }
158
159 ~Pointer()
160 {
161 setToNull();
162 }
163 public:
164 bool isNull() const { return m_object == nullptr; }
165 void setToNull()
166 {
167 if (m_core == nullptr)
168 return;
169 ConcurrentOperation::decrement(m_core->reference_count);
170 if (m_core->reference_count == 0)
171 {
172 delete m_core;
173 delete m_object;
174 }
175 m_core = nullptr;
176 m_object = nullptr;
177 }
178 [[nodiscard]] uint04 referenceCount() const
179 {
180 if (m_core)
181 return m_core->reference_count;
182 else
183 return 0;
184 }
185 bool operator==(const Pointer<t_type>& pointer) const
186 {
187 return pointer.m_object == m_object;
188 }
189 bool operator!=(const Pointer<t_type>& pointer) const
190 {
191 return pointer.m_object != m_object;
192 }
193 void swap(Pointer<t_type>& pointer)
194 {
195 std::swap(m_core, pointer.m_core);
196 std::swap(m_object, pointer.m_object);
197 }
198 protected:
199 PointerCore* m_core = nullptr;
200 t_type* m_object = nullptr;
201 };
202#else
203 template<class t_type>
204 class Pointer
205 {
206 template<class T>
207 friend class ConstPointer;
208 template<class T>
209 friend class DynamicPointer;
210 protected:
211 Pointer() noexcept
212 : m_ptr(nullptr)
213 {}
214 Pointer(t_type* value) noexcept
215 : m_ptr(value)
216 {}
217 Pointer(t_type&& value) noexcept
218 : m_ptr(new t_type(std::move(value)))
219 {}
220 Pointer(const Pointer<t_type>& value) noexcept
221 : m_ptr(value.m_ptr)
222 {
223 }
224 t_type& get() const
225 {
226 lib_assert(m_ptr != nullptr, "Tried to access null pointer");
227 return *m_ptr.get();
228 }
229 void set(t_type&& value)
230 {
231 m_ptr = std::shared_ptr<t_type>(new t_type(std::move(value)));
232 }
233 Pointer& operator=(const Pointer& pointer)
234 {
235 m_ptr = pointer.m_ptr;
236 return *this;
237 }
238 Pointer& operator=(t_type*&& pointer)
239 {
240 m_ptr = pointer;
241 return *this;
242 }
243
244 ~Pointer()
245 {
246 }
247 public:
248 bool isNull() const { return m_ptr == nullptr; }
249 void setToNull()
250 {
251 m_ptr = std::shared_ptr<t_type>();
252 }
253 bool operator==(const Pointer<t_type>& pointer) const
254 {
255 return pointer.m_ptr == m_ptr;
256 }
257 bool operator!=(const Pointer<t_type>& pointer) const
258 {
259 return pointer.m_ptr != m_ptr;
260 }
261 void swap(Pointer<t_type>& pointer)
262 {
263 std::swap(m_ptr, pointer.m_ptr);
264 }
265 protected:
266 std::shared_ptr<t_type> m_ptr;
267 };
268#endif
274 template<class t_type>
275 class ConstPointer : public Pointer<t_type>
276 {
277 public:
278 ConstPointer()
279 {}
280 ConstPointer(const t_type* value) noexcept
281 : Pointer<t_type>(const_cast<t_type*>(value))
282 {}
283 template<class t_parent_type>
284 ConstPointer(t_parent_type* value) noexcept
285 : Pointer<t_type>(value)
286 {}
287 ConstPointer(const Pointer<t_type>& value) noexcept
288 : Pointer<t_type>(value)
289 {}
290 ConstPointer(t_type&& value) noexcept
291 : Pointer<t_type>(std::move(value))
292 {}
293 ConstPointer(Pointer<t_type>&& value) noexcept
294 : Pointer<t_type>(std::move(value))
295 {}
296 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
297 ConstPointer(t_parent_type&& value) noexcept
298 : Pointer<t_type>(std::move(value))
299 {}
300 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
301 ConstPointer(Pointer<t_parent_type>&& value) noexcept
302 : Pointer<t_type>(std::move(value))
303 {}
304 const t_type& get() const
305 {
306 lib_assert(!Pointer<t_type>::isNull(), "Tried to access nullptr");
307 return Pointer<t_type>::get();
308 }
309 constexpr const t_type* rawptr() const
310 {
311 return Pointer<t_type>::rawptr();
312 }
313 void set(t_type&& value) noexcept
314 {
315 Pointer<t_type>::set(std::move(value));
316 }
317 const t_type* operator->() const
318 {
319 lib_assert(!Pointer<t_type>::isNull(), "Tried to access nullptr");
320 return &Pointer<t_type>::get();
321 }
322
323 ConstPointer<t_type>& operator=(const Pointer<t_type>& pointer) noexcept
324 {
325 Pointer<t_type>::operator=(pointer);
326 return (*this);
327 }
328 ConstPointer<t_type>& operator=(t_type* pointer)
329 {
330 Pointer<t_type>::operator=(pointer);
331 return (*this);
332 }
333 template<class t_other_type>
334 ConstPointer<t_other_type> as() const
335 {
336 ConstPointer<t_other_type> pointer;
337#ifndef NDEVR_USE_STD_POINTER
338 if (Pointer<t_type>::m_core && CheckCanCast<t_other_type>(Pointer<t_type>::m_object))
339 {
340 memcpy(&pointer, this, sizeof(ConstPointer<t_type>));
341 ConcurrentOperation::increment(Pointer<t_type>::m_core->reference_count);
342 }
343#else
344 pointer.m_ptr = std::dynamic_pointer_cast<t_other_type>(Pointer<t_type>::m_ptr);
345#endif
346 return pointer;
347 }
348 };
349
354 template<class t_type>
355 class DynamicPointer : public ConstPointer<t_type>
356 {
357 public:
358 DynamicPointer()
359 {}
360 DynamicPointer(t_type* value) noexcept
361 : ConstPointer<t_type>(value)
362 {}
363 template<class t_parent_type>
364 DynamicPointer(t_parent_type* value) noexcept
365 : ConstPointer<t_type>(value)
366 {}
367 DynamicPointer(t_type&& value) noexcept
368 : ConstPointer<t_type>(std::move(value))
369 {}
370 DynamicPointer(const DynamicPointer<t_type>& value) noexcept
371 : ConstPointer<t_type>(value)
372 {}
373 DynamicPointer(DynamicPointer<t_type>&& value) noexcept
374 : ConstPointer<t_type>(std::move(value))
375 {}
376 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
377 DynamicPointer(t_parent_type&& value) noexcept
378 : ConstPointer<t_type>(std::move(value))
379 {}
380 template<class t_parent_type, std::enable_if_t<std::is_base_of_v<t_type, t_parent_type>, int> = 0>
381 DynamicPointer(DynamicPointer<t_parent_type>&& value) noexcept
382 : ConstPointer<t_type>(std::move(value))
383 {}
384 public:
385 constexpr t_type& get() const
386 {
387 return Pointer<t_type>::get();
388 }
389 constexpr t_type* rawptr() const
390 {
391 return Pointer<t_type>::rawptr();
392 }
393
394 void set(t_type&& value)
395 {
396 Pointer<t_type>::set(std::move(value));
397 }
398 t_type* operator->() const
399 {
400 lib_assert(!Pointer<t_type>::isNull(), "Tried to access nullptr");
401 return &Pointer<t_type>::get();
402 }
403
404 DynamicPointer& operator=(const DynamicPointer& pointer)
405 {
406 Pointer<t_type>::operator=(pointer);
407 return (*this);
408 }
409 DynamicPointer& operator=(t_type* pointer)
410 {
411 Pointer<t_type>::operator=(pointer);
412 return (*this);
413 }
414
415 template<class t_other_type>
416 DynamicPointer<t_other_type> as() const
417 {
418 DynamicPointer<t_other_type> pointer;
419#ifndef NDEVR_USE_STD_POINTER
420 if (Pointer<t_type>::m_core && CheckCanCast<t_other_type>(Pointer<t_type>::m_object))
421 {
422 memcpy(&pointer, this, sizeof(DynamicPointer<t_type>));
423 ConcurrentOperation::increment(Pointer<t_type>::m_core->reference_count);
424 }
425#else
426 pointer.m_ptr = std::dynamic_pointer_cast<t_other_type>(Pointer<t_type>::m_ptr);
427#endif
428 return pointer;
429 }
430 };
431
432}
433
static uint04 decrement(volatile uint04 &value)
Atomically decrements a shared value by one.
static uint04 increment(volatile uint04 &value)
Atomically increments a shared value by one.
Provides a constant, unmodifiable pointer that has shared ownership of a dynamically allocated object...
Definition Pointer.hpp:276
Provides a modifiable pointer that has shared ownership of a dynamically allocated object.
Definition Pointer.hpp:356
Provides shared ownership of a dynamically allocated object.
Definition Pointer.hpp:71
The primary namespace for the NDEVR SDK.
@ type
The type identifier string for this model node.
Definition Model.h:58
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Used by Pointer to store the reference count of the pointer.
Definition Pointer.hpp:46