12#include <promeki/config.h>
13#if PROMEKI_ENABLE_CORE
22PROMEKI_NAMESPACE_BEGIN
44template <
typename T> T *promekiCloneOrAbort(
const T *self) {
45 if constexpr (std::is_copy_constructible_v<T>) {
84#define PROMEKI_SHARED_BASE(BASE) \
86 RefCount _promeki_refct; \
87 virtual BASE *_promeki_clone() const { \
88 return ::promeki::promekiCloneOrAbort<BASE>(this); \
116#define PROMEKI_SHARED_DERIVED(DERIVED) \
118 DERIVED *_promeki_clone() const override { \
119 return ::promeki::promekiCloneOrAbort<DERIVED>(this); \
144#define PROMEKI_SHARED_ABSTRACT(INTERMEDIATE) \
146 INTERMEDIATE *_promeki_clone() const override = 0;
173#define PROMEKI_SHARED_FINAL(TYPE) \
175 RefCount _promeki_refct; \
176 TYPE *_promeki_clone() const { \
177 return ::promeki::promekiCloneOrAbort<TYPE>(this); \
191 static constexpr int Immortal = 0x40000000;
197 RefCount(
const RefCount &o) : v(1) {}
200 RefCount &operator=(
const RefCount &) {
201 v.store(1, MemoryOrder::Relaxed);
212 if (v.load(MemoryOrder::Relaxed) >= Immortal)
return;
213 v.fetchAndAdd(1, MemoryOrder::Relaxed);
224 if (v.load(MemoryOrder::Relaxed) >= Immortal)
return false;
225 return v.fetchAndSub(1, MemoryOrder::AcqRel) == 1;
229 int value()
const {
return v.load(MemoryOrder::Relaxed); }
232 bool isImmortal()
const {
return v.load(MemoryOrder::Relaxed) >= Immortal; }
235 void setImmortal() { v.store(Immortal, MemoryOrder::Relaxed); }
257template <
typename T>
class SharedPtrProxy {
259 RefCount _promeki_refct;
261 SharedPtrProxy(T *o) : _object(o) {}
262 ~SharedPtrProxy() {
delete _object; }
263 T *_promeki_clone()
const {
266 assert(
typeid(*_object) ==
typeid(T));
267 return new T(*_object);
269 T *object()
const {
return _object; }
272 T *_object =
nullptr;
275template <
typename T,
typename =
void>
struct IsSharedObject : std::false_type {};
276template <
typename T>
struct IsSharedObject<T, std::void_t<decltype(&T::_promeki_refct)>> : std::true_type {};
335template <
typename T,
bool CopyOnWrite =
true,
336 typename ST = std::conditional_t<IsSharedObject<T>::value, T, SharedPtrProxy<T>>>
342 template <
typename OT,
bool OCoW,
typename OST>
friend class SharedPtr;
346 template <
typename DerivedT,
typename BaseT,
bool CoWT,
typename STT>
347 friend SharedPtr<DerivedT, CoWT, DerivedT> sharedPointerCast(
const SharedPtr<BaseT, CoWT, STT> &sp);
349 static constexpr bool isNative = IsSharedObject<T>::value;
354 static constexpr bool isCopyOnWrite = CopyOnWrite;
356 SharedPtr() =
default;
358 SharedPtr(
const SharedPtr &sp) : _data(sp._data) { acquire(); }
359 SharedPtr(SharedPtr &&sp) noexcept : _data(sp._data) { sp._data =
nullptr; }
371 template <
typename U,
bool UCoW,
typename UST,
372 typename = std::enable_if_t<std::is_base_of_v<T, U> && !std::is_same_v<T, U> &&
373 IsSharedObject<T>::value && IsSharedObject<U>::value &&
374 std::is_same_v<UST, U>>>
375 SharedPtr(
const SharedPtr<U, UCoW, UST> &sp) : _data(sp._data) {
379 template <
typename U,
bool UCoW,
typename UST,
380 typename = std::enable_if_t<std::is_base_of_v<T, U> && !std::is_same_v<T, U> &&
381 IsSharedObject<T>::value && IsSharedObject<U>::value &&
382 std::is_same_v<UST, U>>>
383 SharedPtr(SharedPtr<U, UCoW, UST> &&sp) noexcept : _data(sp._data) {
387 ~SharedPtr() { release(); }
389 template <
typename... Args>
static SharedPtr create(Args &&...args) {
391 sp.setData(
new T(std::forward<Args>(args)...));
395 static SharedPtr takeOwnership(T *obj) {
397 if (obj !=
nullptr) sp.setData(obj);
401 SharedPtr &operator=(
const SharedPtr &sp) {
402 if (&sp ==
this)
return *
this;
409 SharedPtr &operator=(SharedPtr &&sp)
noexcept {
410 if (&sp ==
this)
return *
this;
417 void swap(SharedPtr &other)
noexcept { std::swap(_data, other._data); }
427 if (_data ==
nullptr || _data->_promeki_refct.value() < 2)
return;
428 T *copy = _data->_promeki_clone();
435 bool isNull()
const {
return _data ==
nullptr; }
437 bool isValid()
const {
return _data !=
nullptr; }
439 explicit operator bool()
const {
return _data !=
nullptr; }
441 bool operator==(
const SharedPtr &other)
const {
return _data == other._data; }
443 bool operator!=(
const SharedPtr &other)
const {
return _data != other._data; }
445 bool operator==(std::nullptr_t)
const {
return _data ==
nullptr; }
447 bool operator!=(std::nullptr_t)
const {
return _data !=
nullptr; }
449 int referenceCount()
const {
return _data ==
nullptr ? 0 : _data->_promeki_refct.value(); }
451 const T *ptr()
const {
452 assert(_data !=
nullptr);
453 if constexpr (IsSharedObject<T>::value) {
456 return _data->object();
461 assert(_data !=
nullptr);
462 if constexpr (CopyOnWrite) detach();
463 if constexpr (IsSharedObject<T>::value) {
466 return _data->object();
470 const T *operator->()
const {
return ptr(); }
472 const T &operator*()
const {
return *ptr(); }
479 if (_data ==
nullptr)
return;
480 _data->_promeki_refct.inc();
488 if (_data ==
nullptr)
return;
489 if (_data->_promeki_refct.dec())
delete _data;
493 constexpr void setData(T *obj) {
494 if constexpr (IsSharedObject<T>::value) {
521template <
typename Derived,
typename Base,
bool CoW,
typename ST>
522SharedPtr<Derived, CoW, Derived> sharedPointerCast(
const SharedPtr<Base, CoW, ST> &sp) {
523 static_assert(IsSharedObject<Base>::value,
"sharedPointerCast requires native shared objects");
524 static_assert(IsSharedObject<Derived>::value,
"sharedPointerCast requires native shared objects");
525 static_assert(std::is_base_of_v<Base, Derived>,
"Derived must publicly derive from Base");
526 SharedPtr<Derived, CoW, Derived> result;
527 if (sp.isNull())
return result;
528 Derived *d =
dynamic_cast<Derived *
>(sp._data);
529 if (d ==
nullptr)
return result;
531 result._data->_promeki_refct.inc();