#pragma once
#include "cast.h"
#include "traits.h"
#include <memory>
#include <atomic>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
namespace panda {
using std::nullptr_t;
template <typename T>
struct iptr {
template <class U> friend struct iptr;
typedef T element_type;
constexpr iptr () : ptr(NULL) {}
iptr (T* pointer) : ptr(pointer) { if (ptr) refcnt_inc(ptr); }
iptr (const iptr& oth) : ptr(oth.ptr) { if (ptr) refcnt_inc(ptr); }
template <class U, typename = enable_if_convertible_t<U*, T*>>
iptr (const iptr<U>& oth) : ptr(oth.ptr) { if (ptr) refcnt_inc(ptr); }
iptr (iptr&& oth) {
ptr = oth.ptr;
oth.ptr = NULL;
}
template <class U, typename = enable_if_convertible_t<U*, T*>>
iptr (iptr<U>&& oth) {
ptr = oth.ptr;
oth.ptr = NULL;
}
~iptr () { if (ptr) refcnt_dec(ptr); }
iptr& operator= (T* pointer) {
if (pointer) refcnt_inc(pointer);
if (ptr) refcnt_dec(ptr);
ptr = pointer;
return *this;
}
iptr& operator= (const iptr& oth) { return operator=(oth.ptr); }
template <class U, typename = enable_if_convertible_t<U*, T*>>
iptr& operator= (const iptr<U>& oth) { return operator=(oth.ptr); }
iptr& operator= (iptr&& oth) {
std::swap(ptr, oth.ptr);
return *this;
}
template <class U, typename = enable_if_convertible_t<U*, T*>>
iptr& operator= (iptr<U>&& oth) {
if (ptr) {
if (ptr == oth.ptr) return *this;
refcnt_dec(ptr);
}
ptr = oth.ptr;
oth.ptr = NULL;
return *this;
}
void reset () {
if (ptr) refcnt_dec(ptr);
ptr = NULL;
}
void reset (T* p) { operator=(p); }
T* operator-> () const noexcept { return ptr; }
T& operator* () const noexcept { return *ptr; }
operator T* () const noexcept { return ptr; }
explicit
operator bool () const noexcept { return ptr; }
T* get () const noexcept { return ptr; }
uint32_t use_count () const noexcept { return refcnt_get(ptr); }
T* detach () noexcept {
auto ret = ptr;
ptr = nullptr;
return ret;
}
void swap (iptr& oth) noexcept {
std::swap(ptr, oth.ptr);
}
private:
T* ptr;
};
template <class T1, class T2> inline bool operator== (const iptr<T1>& x, const iptr<T2>& y) { return x.get() == y.get(); }
template <class T1, class T2> inline bool operator!= (const iptr<T1>& x, const iptr<T2>& y) { return x.get() != y.get(); }
template <class T1, class T2> inline bool operator< (const iptr<T1>& x, const iptr<T2>& y) { return x.get() < y.get(); }
template <class T1, class T2> inline bool operator<= (const iptr<T1>& x, const iptr<T2>& y) { return x.get() <= y.get(); }
template <class T1, class T2> inline bool operator> (const iptr<T1>& x, const iptr<T2>& y) { return x.get() > y.get(); }
template <class T1, class T2> inline bool operator>= (const iptr<T1>& x, const iptr<T2>& y) { return x.get() >= y.get(); }
template <class T> inline bool operator== (const iptr<T>& x, nullptr_t) noexcept { return !x.get(); }
template <class T> inline bool operator== (nullptr_t, const iptr<T>& x) noexcept { return !x.get(); }
template <class T> inline bool operator!= (const iptr<T>& x, nullptr_t) noexcept { return x.get(); }
template <class T> inline bool operator!= (nullptr_t, const iptr<T>& x) noexcept { return x.get(); }
template <class T> inline bool operator< (const iptr<T>& x, nullptr_t) noexcept { return x.get() < nullptr; }
template <class T> inline bool operator< (nullptr_t, const iptr<T>& x) noexcept { return nullptr < x.get(); }
template <class T> inline bool operator<= (const iptr<T>& x, nullptr_t) noexcept { return x.get() <= nullptr; }
template <class T> inline bool operator<= (nullptr_t, const iptr<T>& x) noexcept { return nullptr <= x.get(); }
template <class T> inline bool operator> (const iptr<T>& x, nullptr_t) noexcept { return x.get() > nullptr; }
template <class T> inline bool operator> (nullptr_t, const iptr<T>& x) noexcept { return nullptr > x.get(); }
template <class T> inline bool operator>= (const iptr<T>& x, nullptr_t) noexcept { return x.get() >= nullptr; }
template <class T> inline bool operator>= (nullptr_t, const iptr<T>& x) noexcept { return nullptr >= x.get(); }
template <typename T, typename... Args>
iptr<T> make_iptr (Args&&... args) {
return iptr<T>(new T(std::forward<Args>(args)...));
}
template <class T>
void swap (iptr<T>& a, iptr<T>& b) noexcept { a.swap(b); }
struct weak_storage;
struct Refcnt {
using weak_storage_type = weak_storage;
//Refcnt (const Refcnt&) : Refcnt() {}
void retain () const { ++_refcnt; }
void release () const {
if (_refcnt > 1) --_refcnt;
else delete this;
}
uint32_t refcnt () const noexcept { return _refcnt; }
protected:
Refcnt () : _refcnt(0) {}
virtual ~Refcnt ();
private:
friend iptr<weak_storage> refcnt_weak (const Refcnt*);
mutable uint32_t _refcnt;
mutable iptr<weak_storage> _weak;
iptr<weak_storage> get_weak () const;
};
struct Refcntd : Refcnt {
void release () const {
if (refcnt() <= 1) const_cast<Refcntd*>(this)->on_delete();
Refcnt::release();
}
protected:
virtual void on_delete () noexcept {}
};
struct weak_storage : public Refcnt {
weak_storage () : valid(true) {}
bool valid;
};
struct atomic_weak_storage;
struct AtomicRefcnt {
using weak_storage_type = atomic_weak_storage;
AtomicRefcnt (const AtomicRefcnt&) : AtomicRefcnt() {}
void retain () const { ++_refcnt; }
void release () const {
if (!--_refcnt) delete this;
}
uint32_t refcnt () const noexcept { return _refcnt; }
protected:
AtomicRefcnt () : _refcnt(0) {}
virtual ~AtomicRefcnt ();
private:
friend iptr<atomic_weak_storage> refcnt_weak (const AtomicRefcnt*);
mutable std::atomic<uint32_t> _refcnt;
mutable iptr<atomic_weak_storage> _weak;
iptr<atomic_weak_storage> get_weak () const;
};
struct atomic_weak_storage : public AtomicRefcnt {
atomic_weak_storage () : valid(true) {}
bool valid;
};
inline void refcnt_inc (const Refcnt* o) { o->retain(); }
inline void refcnt_dec (const Refcnt* o) { o->release(); }
inline uint32_t refcnt_get (const Refcnt* o) { return o->refcnt(); }
inline iptr<weak_storage> refcnt_weak (const Refcnt* o) { return o->get_weak(); }
inline void refcnt_dec (const Refcntd* o) { o->release(); }
inline void refcnt_inc (const AtomicRefcnt* o) { o->retain(); }
inline void refcnt_dec (const AtomicRefcnt* o) { o->release(); }
inline uint32_t refcnt_get (const AtomicRefcnt* o) { return o->refcnt(); }
inline iptr<atomic_weak_storage> refcnt_weak (const AtomicRefcnt* o) { return o->get_weak(); }
template <typename T1, typename T2> inline iptr<T1> static_pointer_cast (const iptr<T2>& ptr) { return iptr<T1>(static_cast<T1*>(ptr.get())); }
template <typename T1, typename T2> inline iptr<T1> const_pointer_cast (const iptr<T2>& ptr) { return iptr<T1>(const_cast<T1*>(ptr.get())); }
template <typename T1, typename T2> inline iptr<T1> dynamic_pointer_cast (const iptr<T2>& ptr) { return iptr<T1>(dyn_cast<T1*>(ptr.get())); }
template <typename T1, typename T2> inline std::shared_ptr<T1> static_pointer_cast (const std::shared_ptr<T2>& shptr) { return std::static_pointer_cast<T1>(shptr); }
template <typename T1, typename T2> inline std::shared_ptr<T1> const_pointer_cast (const std::shared_ptr<T2>& shptr) { return std::const_pointer_cast<T1>(shptr); }
template <typename T1, typename T2> inline std::shared_ptr<T1> dynamic_pointer_cast (const std::shared_ptr<T2>& shptr) { return std::dynamic_pointer_cast<T1>(shptr); }
template <typename T>
struct weak_iptr {
template <class U> friend struct weak_iptr;
using element_type = T;
using storage_type = typename T::weak_storage_type;
weak_iptr() : storage(nullptr), object(nullptr) {}
weak_iptr(const weak_iptr&) = default;
weak_iptr& operator=(const weak_iptr& o) = default;
weak_iptr(weak_iptr&&) = default;
weak_iptr& operator=(weak_iptr&& o) = default;
template <typename U, typename = enable_if_convertible_t<U*, T*>>
weak_iptr(const iptr<U>& src) : storage(src ? refcnt_weak(src.get()) : nullptr), object(src ? src.get() : nullptr) {}
template <typename U, typename = enable_if_convertible_t<U*, T*>>
weak_iptr(const weak_iptr<U>& src) : storage(src.storage), object(src.object) {}
template <class U>
weak_iptr& operator=(const weak_iptr<U>& o) {
storage = o.storage;
object = o.object;
return *this;
}
template <class U>
weak_iptr& operator=(const iptr<U>& src) {
storage = src ? refcnt_weak(src.get()) : nullptr;
object = src ? src.get() : nullptr;
return *this;
}
template <class U>
weak_iptr& operator=(weak_iptr<U>&& o) {
storage = std::move(o.storage);
object = std::move(o.object);
return *this;
}
iptr<T> lock() const {
return expired() ? nullptr : object;
}
bool expired() const {
return !operator bool();
}
explicit operator bool() const {
return storage && storage->valid;
}
size_t use_count() const {
return *this ? refcnt_get(object) : 0;
}
size_t weak_count() const {
if (!storage) return 0;
if (storage->valid) return storage.use_count() - 1; // object itself refers to weak storage, ignore this reference in count
return storage.use_count();
}
void reset() noexcept {
storage.reset();
object = nullptr;
}
void swap(weak_iptr& oth) noexcept {
storage.swap(oth.storage);
std::swap(object, oth.object);
}
private:
iptr<storage_type> storage;
T* object; // it is cache, it never invalidates itself, use storage->object to check validity
};
template <class T>
void swap(weak_iptr<T>& a, weak_iptr<T>& b) noexcept { a.swap(b); }
template <class T> struct _weak_t;
template <class T> struct _weak_t<iptr<T>> {
using type = weak_iptr<T>;
};
template <typename T>
using weak = typename _weak_t<T>::type;
}