#pragma once #include #include #include #include namespace nall { template struct shared_pointer; struct shared_pointer_manager { void* pointer = nullptr; function void> 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 { 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 = [=](void* p) { deleter((T*)p); }; } shared_pointer(const shared_pointer& source) { operator=(source); } shared_pointer(shared_pointer&& source) { operator=(move(source)); } template>> shared_pointer(const shared_pointer& source) { operator=(source); } template>> shared_pointer(shared_pointer&& source) { operator=(move(source)); } template>> shared_pointer(const shared_pointer_weak& source) { operator=(source); } template>> 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++; } 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>> auto operator=(const shared_pointer& source) -> shared_pointer& { if((uintptr_t)this != (uintptr_t)&source) { reset(); if((bool)source) { manager = source.manager; manager->strong++; } } return *this; } template>> auto operator=(shared_pointer&& source) -> shared_pointer& { if((uintptr_t)this != (uintptr_t)&source) { reset(); manager = source.manager; source.manager = nullptr; } return *this; } template>> 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 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_new : shared_pointer { template shared_pointer_new(P&&... p) : shared_pointer(new T(forward

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