The Sparta Modeling Framework
Loading...
Searching...
No Matches
SpartaSharedPointer.hpp
Go to the documentation of this file.
1// <SpartaSharedPointer.hpp> -*- C++ -*-
2
9#pragma once
10
11#include <cinttypes>
12#include <cassert>
13#include <type_traits>
14
15#include "sparta/utils/Utils.hpp"
17#include "sparta/utils/SpartaSharedPointerBaseAllocator.hpp"
18
19namespace sparta
20{
21 // Forward declarations
22 template<class PointerT>
23 class SpartaSharedPointerAllocator;
24
25 template<class PointerT>
26 class SpartaWeakPointer;
27
79 template <class PointerT>
81 {
82 public:
83 template<class PointerT2>
84 friend class SpartaSharedPointer;
85
86 private:
92 struct RefCount
93 {
94 RefCount(PointerT * _p, void * mem_block) :
95 p(_p), mem_block(mem_block)
96 {}
97
98 explicit RefCount(PointerT * _p) :
99 RefCount(_p, nullptr)
100 {}
101
102 // Small cleanup -- set to nullptr
103 ~RefCount() { p = nullptr; }
104
105 int32_t count {1};
106 int32_t wp_count{0}; // For weakpointers
107 PointerT * p = nullptr;
108 void * mem_block = nullptr;
109 };
110
111 public:
113 using element_type = PointerT;
114
122 explicit SpartaSharedPointer(PointerT * p = nullptr) noexcept :
123 ref_count_(p == nullptr ? nullptr : new RefCount(p))
124 {}
125
130 constexpr SpartaSharedPointer(std::nullptr_t) noexcept :
131 ref_count_(nullptr)
132 {}
133
142 template<class PointerT2>
144 ref_count_((SpartaSharedPointer<PointerT>::RefCount*)orig.ref_count_)
145 {
146 static_assert(std::is_base_of<PointerT, PointerT2>::value == true,
147 "Only upcasting (derived class -> base class) of SpartaSharedPointer is supported!");
148 static_assert(std::has_virtual_destructor<PointerT>::value == true,
149 "Base class must have a virtual destructor defined to support upcasting!");
150 if(SPARTA_EXPECT_TRUE(ref_count_ != nullptr)) {
151 ++ref_count_->count;
152 }
153 }
154
162 ref_count_(orig.ref_count_)
163 {
164 if(SPARTA_EXPECT_TRUE(ref_count_ != nullptr)) {
165 ++ref_count_->count;
166 }
167 }
168
177 ref_count_(orig.ref_count_)
178 {
179 // DO NOT unlink.
180 orig.ref_count_ = nullptr;
181 }
182
185 unlink_();
186 }
187
196 {
197 sparta_assert(&orig != this);
198 unlink_();
199 ref_count_ = orig.ref_count_;
200 if(SPARTA_EXPECT_TRUE(ref_count_ != nullptr)) {
201 ++ref_count_->count;
202 }
203 return *this;
204 }
205
215 {
216 sparta_assert(&orig != this);
217 unlink_();
218 ref_count_ = orig.ref_count_;
219 orig.ref_count_ = nullptr;
220 return *this;
221 }
222
232 bool operator!() const {
233 return (ref_count_ == nullptr) || (ref_count_->p == nullptr);
234 }
235
246 explicit operator bool() const {
247 return (ref_count_ && (ref_count_->p == nullptr ? false : true));
248 }
249
254 PointerT * operator->() const {
255 return (ref_count_ ? ref_count_->p : nullptr);
256 }
257
262 PointerT & operator*() const {
263 sparta_assert(ref_count_ != nullptr, "This is a null SpartaSharedPointer");
264 return *(ref_count_->p);
265 }
266
271 PointerT * get() const {
272 return (ref_count_ ? ref_count_->p : nullptr);
273 }
274
279 void reset(PointerT * p = nullptr) {
280 unlink_();
281 ref_count_ = p == nullptr ? nullptr : new RefCount(p);
282 }
283
288 uint32_t use_count() const {
289 if(SPARTA_EXPECT_TRUE(ref_count_ != nullptr)) {
290 return ref_count_->p ? ref_count_->count : 0;
291 }
292 return 0;
293 }
294
295 private:
296
311 static void releaseRefCount_(RefCount *& ref_count)
312 {
313 if(0 == ref_count->count) {
314 // Make it go negative to show there are no
315 // SpartaSharedPointer objects using this ref_count.
316 // We can't set it to nullptr because it might be
317 // allocated on the heap and we need to ensure all
318 // SpartaWeakPointer objects are done with it too.
319 //
320 // This pointer needs to be set here to prevent a weak pointer
321 // from being destructed and calling releaseObject_ in a cycle.
322 --(ref_count->count);
323
324 // Claim a weak-pointer reference on the block. This ensures
325 // that no one else will delete the reference count block out
326 // from under us higher up the call stack.
327 ++ref_count->wp_count;
328
329 BaseAllocator::MemBlockBase * memory_block =
330 static_cast<BaseAllocator::MemBlockBase *>(ref_count->mem_block);
331
332 // These calls are dangerous! When we're destroying our
333 // object, we may arrive at this point in the _same_ shared
334 // pointer _recursively_ further up the call stack if the
335 // pointed-to object contains a weak pointer that points back to
336 // itself.
337 if(SPARTA_EXPECT_TRUE(nullptr != memory_block)) {
338 memory_block->alloc->releaseObject_(memory_block);
339 }
340 else {
341 delete ref_count->p;
342 ref_count->p = nullptr;
343 }
344
345 // Release the weak-pointer reference that we claimed above. Now
346 // we will proceed to release ref_count, and can rest assured
347 // that no recursive call to weak-pointer destruction released
348 // ref_count out from under us.
349 --ref_count->wp_count;
350 }
351
352 if((0 >= ref_count->count) && (0 == ref_count->wp_count))
353 {
354 // Because we claimed the weak-pointer reference above, we can
355 // ensure that we only make one pass through this block---even
356 // if we destroy a weak pointer recursively, it will not try to
357 // destroy this block.
358 BaseAllocator::MemBlockBase * memory_block =
359 static_cast<BaseAllocator::MemBlockBase *>(ref_count->mem_block);
360
361 if(SPARTA_EXPECT_TRUE(nullptr != memory_block)) {
362 memory_block->alloc->releaseBlock_(memory_block);
363 }
364 else {
365 delete ref_count;
366 }
367 ref_count = nullptr;
368 }
369 }
370
372 void unlink_()
373 {
374 if(SPARTA_EXPECT_TRUE(ref_count_ != nullptr))
375 {
376 --ref_count_->count;
377 releaseRefCount_(ref_count_);
378 }
379 }
380
381 // Used by SpartaWeakPointer and Allocator. weak_alloc is
382 // true if from WP
383 explicit SpartaSharedPointer(RefCount * cnt, const bool weak_ptr = false) :
384 ref_count_(cnt)
385 {
386 if(weak_ptr && ref_count_) { ++ref_count_->count; }
387 }
388
389 RefCount * ref_count_ = nullptr;
390
391 friend class SpartaSharedPointerAllocator<PointerT>;
392 friend class SpartaWeakPointer<PointerT>;
393
394 template<typename PtrT, typename... Args>
395 friend SpartaSharedPointer<PtrT>
396 allocate_sparta_shared_pointer(SpartaSharedPointerAllocator<PtrT> &, Args&&...args);
397 };
398
399
406 template<class PointerT>
408 {
409 public:
411 constexpr SpartaWeakPointer() noexcept = default;
412
417 SpartaWeakPointer(const sparta::SpartaSharedPointer<PointerT> & sp) noexcept :
418 wp_ref_cnt_(sp.ref_count_)
419 {
420 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
421 ++(wp_ref_cnt_->wp_count);
422 }
423 }
424
427 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
428 --(wp_ref_cnt_->wp_count);
430 wp_ref_cnt_ = nullptr;
431 }
432 }
433
439 wp_ref_cnt_(orig.wp_ref_cnt_)
440 {
441 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
442 ++(wp_ref_cnt_->wp_count);
443 }
444 }
445
451 wp_ref_cnt_(orig.wp_ref_cnt_)
452 {
453 orig.wp_ref_cnt_ = nullptr;
454 }
455
461 {
462 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
463 --(wp_ref_cnt_->wp_count);
465 }
466 wp_ref_cnt_ = orig.wp_ref_cnt_;
467
468 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
469 ++(wp_ref_cnt_->wp_count);
470 }
471 return *this;
472 }
473
479 {
480 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
481 --(wp_ref_cnt_->wp_count);
483 }
484
485 wp_ref_cnt_ = orig.wp_ref_cnt_;
486 orig.wp_ref_cnt_ = nullptr;
487 return *this;
488 }
489
494 long use_count() const noexcept {
495 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
496 return (wp_ref_cnt_->count <= 0 ? 0 : wp_ref_cnt_->count);
497 }
498 return 0;
499 }
500
505 bool expired() const noexcept {
506 if(SPARTA_EXPECT_TRUE(nullptr != wp_ref_cnt_)) {
507 return wp_ref_cnt_->count <= 0;
508 }
509 return true;
510 }
511
517 return SpartaSharedPointer<PointerT>(wp_ref_cnt_, true);
518 }
519
520 private:
522 typename SpartaSharedPointer<PointerT>::RefCount * wp_ref_cnt_ = nullptr;
523 };
524
525
526 template<typename PtrT, typename Ptr2>
527 bool operator==(const SpartaSharedPointer<PtrT>& ptr1, const SpartaSharedPointer<Ptr2>& ptr2) noexcept
528 { return ptr1.get() == ptr2.get(); }
529
530 template<typename PtrT>
531 bool operator==(const SpartaSharedPointer<PtrT>& ptr1, std::nullptr_t) noexcept
532 { return !ptr1; }
533
534 template<typename PtrT>
535 bool operator==(std::nullptr_t, const SpartaSharedPointer<PtrT>& ptr1) noexcept
536 { return !ptr1; }
537
538 template<typename PtrT, typename Ptr2>
539 bool operator!=(const SpartaSharedPointer<PtrT>& ptr1, const SpartaSharedPointer<Ptr2>& ptr2) noexcept
540 { return ptr1.get() != ptr2.get(); }
541
542 template<typename PtrT>
543 bool operator!=(const SpartaSharedPointer<PtrT>& ptr1, std::nullptr_t) noexcept
544 { return (bool)ptr1; }
545
546 template<typename PtrT>
547 bool operator!=(std::nullptr_t, const SpartaSharedPointer<PtrT>& ptr1) noexcept
548 { return (bool)ptr1; }
549
550 template<typename PtrT>
551 std::ostream& operator<<(std::ostream & os, const SpartaSharedPointer<PtrT> & p)
552 {
553 os << p.get();
554 return os;
555 }
556
557} // sparta namespace
558
559// Helper methods to determine pointer type and/or remove it
560namespace MetaStruct {
561
562 // Helper structs
563 template<typename T>
564 struct is_any_pointer<sparta::SpartaSharedPointer<T>> : public std::true_type {};
565
566 template<typename T>
567 struct is_any_pointer<sparta::SpartaSharedPointer<T> const> : public std::true_type {};
568
569 template<typename T>
570 struct is_any_pointer<sparta::SpartaSharedPointer<T> &> : public std::true_type {};
571
572 template<typename T>
573 struct is_any_pointer<sparta::SpartaSharedPointer<T> const &> : public std::true_type {};
574
575 template<typename T>
576 struct remove_any_pointer<sparta::SpartaSharedPointer<T>> { using type = T; };
577
578 template<typename T>
579 struct remove_any_pointer<sparta::SpartaSharedPointer<T> const> { using type = T; };
580
581 template<typename T>
582 struct remove_any_pointer<sparta::SpartaSharedPointer<T> &> { using type = T; };
583
584 template<typename T>
585 struct remove_any_pointer<sparta::SpartaSharedPointer<T> const &> { using type = T; };
586}
Contains a collection implementation of various compile-time metaprogramming and Type-Detection APIs ...
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_TRUE(x)
A macro for hinting to the compiler a particular condition should be considered most likely true.
Used for garbage collection, will delete the object it points to when all objects are finished using ...
SpartaSharedPointer(SpartaSharedPointer &&orig)
Take ownership of a reference pointer.
SpartaSharedPointer(PointerT *p=nullptr) noexcept
Construct a Reference Pointer with the given memory object.
PointerT & operator*() const
Dereference the RefPointer (const)
PointerT * operator->() const
Dereference the RefPointer (const)
SpartaSharedPointer(const SpartaSharedPointer< PointerT2 > &orig) noexcept
Construct a reference pointer given another implicitly convertable reference pointer.
bool operator!() const
The not ! operator.
SpartaSharedPointer & operator=(SpartaSharedPointer &&orig)
Assignment move operator.
~SpartaSharedPointer()
Detach this shared pointer; if last, delete underlying object.
PointerT element_type
Expected typedef for the resource type.
uint32_t use_count() const
Get the current reference count.
PointerT * get() const
Get the underlying pointer.
constexpr SpartaSharedPointer(std::nullptr_t) noexcept
Constructor for SpartaSharedPointer<T> ptr = nullptr;.
SpartaSharedPointer & operator=(const SpartaSharedPointer &orig)
Assignment operator.
SpartaSharedPointer(const SpartaSharedPointer &orig)
Construct a reference pointer given another reference pointer.
void reset(PointerT *p=nullptr)
Reset this shared pointer.
Like in STL, create a weak pointer to a SpartaSharedPointer.
SpartaWeakPointer & operator=(SpartaWeakPointer &&orig)
Move assign a SpartaWeakPointer from another.
SpartaSharedPointer< PointerT > lock() const noexcept
Lock and return a SpartaSharedPointer this SpartaWeakPointer points to.
constexpr SpartaWeakPointer() noexcept=default
Create an empty, expired weakpointer.
bool expired() const noexcept
Has the SpartaSharedPointer that this weak pointer points to expired?
SpartaWeakPointer(const SpartaWeakPointer &orig)
Create a copy of the SpartaWeakPointer.
~SpartaWeakPointer()
Destroy (and detach) from a SpartaSharedPointer.
long use_count() const noexcept
The use count of the SpartaSharedPointer. Will be 0 if none left.
SpartaWeakPointer & operator=(const SpartaWeakPointer &orig)
Assign a SpartaWeakPointer from another.
SpartaWeakPointer(SpartaWeakPointer &&orig)
Move a SpartaWeakPointer.
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo