#pragma once #include #include #include #include namespace nall { template struct shared_pointer; struct shared_pointer_manager { void* pointer = nullptr; function deleter; uint strong = 0; uint weak = 0; shared_pointer_manager(void* pointer) : pointer(pointer) { } }; template struct shared_pointer; template struct shared_pointer_weak; template struct shared_pointer_this; struct shared_pointer_this_base{}; template struct shared_pointer { template static auto create(P&&... p) { return shared_pointer{new T{forward

(p)...}}; } using type = T; shared_pointer_manager* manager = nullptr; template struct is_compatible { static constexpr bool value = is_base_of::value || is_base_of::value; }; shared_pointer() { } shared_pointer(T* source) { operator=(source); } shared_pointer(T* source, const function& deleter) { operator=(source); manager->deleter = function([=](void* p) { deleter((T*)p); }); } shared_pointer(const shared_pointer& source) { operator=(source); } shared_pointer(shared_pointer&& source) { operator=(move(source)); } template::value>> shared_pointer(const shared_pointer& source) { operator=(source); } template::value>> shared_pointer(shared_pointer&& source) { operator=(move(source)); } template::value>> shared_pointer(const shared_pointer_weak& source) { operator=(source); } template::value>> shared_pointer(const shared_pointer& source, T* pointer) { if((bool)source && (T*)source.manager->pointer == pointer) { manager = source.manager; manager->strong++; } } ~shared_pointer() { reset(); } auto operator=(T* source) -> shared_pointer& { reset(); if(source) { manager = new shared_pointer_manager((void*)source); manager->strong++; if constexpr(is_base_of_v) { source->weak = *this; } } return *this; } auto operator=(const shared_pointer& source) -> shared_pointer& { if(this != &source) { reset(); if((bool)source) { manager = source.manager; manager->strong++; } } return *this; } auto operator=(shared_pointer&& source) -> shared_pointer& { if(this != &source) { reset(); manager = source.manager; source.manager = nullptr; } return *this; } template::value>> auto operator=(const shared_pointer& source) -> shared_pointer& { if((uintptr)this != (uintptr)&source) { reset(); if((bool)source) { manager = source.manager; manager->strong++; } } return *this; } template::value>> auto operator=(shared_pointer&& source) -> shared_pointer& { if((uintptr)this != (uintptr)&source) { reset(); manager = source.manager; source.manager = nullptr; } return *this; } template::value>> auto operator=(const shared_pointer_weak& source) -> shared_pointer& { reset(); if((bool)source) { manager = source.manager; manager->strong++; } return *this; } auto data() -> T* { if(manager) return (T*)manager->pointer; return nullptr; } auto data() const -> const T* { if(manager) return (T*)manager->pointer; return nullptr; } auto operator->() -> T* { return data(); } auto operator->() const -> const T* { return data(); } auto operator*() -> T& { return *data(); } auto operator*() const -> const T& { return *data(); } auto operator()() -> T& { return *data(); } auto operator()() const -> const T& { return *data(); } template auto operator==(const shared_pointer& source) const -> bool { return manager == source.manager; } template auto operator!=(const shared_pointer& source) const -> bool { return manager != source.manager; } explicit operator bool() const { return manager && manager->strong; } auto unique() const -> bool { return manager && manager->strong == 1; } auto references() const -> uint { return manager ? manager->strong : 0; } auto reset() -> void { if(manager && manager->strong) { //pointer may contain weak references; if strong==0 it may destroy manager //as such, we must destroy strong before decrementing it to zero if(manager->strong == 1) { if(manager->deleter) { manager->deleter(manager->pointer); } else { delete (T*)manager->pointer; } manager->pointer = nullptr; } if(--manager->strong == 0) { if(manager->weak == 0) { delete manager; } } } manager = nullptr; } template auto cast() -> shared_pointer { if(auto pointer = dynamic_cast(data())) { return {*this, pointer}; } return {}; } }; template struct shared_pointer_weak { using type = T; shared_pointer_manager* manager = nullptr; shared_pointer_weak() { } shared_pointer_weak(const shared_pointer& source) { operator=(source); } auto operator=(const shared_pointer& source) -> shared_pointer_weak& { reset(); if(manager = source.manager) manager->weak++; return *this; } ~shared_pointer_weak() { reset(); } auto operator==(const shared_pointer_weak& source) const -> bool { return manager == source.manager; } auto operator!=(const shared_pointer_weak& source) const -> bool { return manager != source.manager; } explicit operator bool() const { return manager && manager->strong; } auto acquire() const -> shared_pointer { return shared_pointer(*this); } auto reset() -> void { if(manager && --manager->weak == 0) { if(manager->strong == 0) { delete manager; } } manager = nullptr; } }; template struct shared_pointer_this : shared_pointer_this_base { shared_pointer_weak weak; auto shared() -> shared_pointer { return weak; } auto shared() const -> shared_pointer { return weak; } }; template auto shared_pointer_make(P&&... p) -> shared_pointer { return shared_pointer{new T{forward

(p)...}}; } template struct shared_pointer_new : shared_pointer { shared_pointer_new(const shared_pointer& source) : shared_pointer(source) {} template shared_pointer_new(P&&... p) : shared_pointer(new T(forward

(p)...)) {} }; }