shared-pointer.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #pragma once
  2. #include <nall/function.hpp>
  3. #include <nall/maybe.hpp>
  4. #include <nall/traits.hpp>
  5. #include <nall/vector.hpp>
  6. namespace nall {
  7. template<typename T> struct shared_pointer;
  8. struct shared_pointer_manager {
  9. void* pointer = nullptr;
  10. function<void (void*)> deleter;
  11. uint strong = 0;
  12. uint weak = 0;
  13. shared_pointer_manager(void* pointer) : pointer(pointer) {
  14. }
  15. };
  16. template<typename T> struct shared_pointer;
  17. template<typename T> struct shared_pointer_weak;
  18. template<typename T> struct shared_pointer_this;
  19. struct shared_pointer_this_base{};
  20. template<typename T>
  21. struct shared_pointer {
  22. template<typename... P> static auto create(P&&... p) {
  23. return shared_pointer<T>{new T{forward<P>(p)...}};
  24. }
  25. using type = T;
  26. shared_pointer_manager* manager = nullptr;
  27. template<typename U>
  28. struct is_compatible {
  29. static constexpr bool value = is_base_of<T, U>::value || is_base_of<U, T>::value;
  30. };
  31. shared_pointer() {
  32. }
  33. shared_pointer(T* source) {
  34. operator=(source);
  35. }
  36. shared_pointer(T* source, const function<void (T*)>& deleter) {
  37. operator=(source);
  38. manager->deleter = function<void (void*)>([=](void* p) {
  39. deleter((T*)p);
  40. });
  41. }
  42. shared_pointer(const shared_pointer& source) {
  43. operator=(source);
  44. }
  45. shared_pointer(shared_pointer&& source) {
  46. operator=(move(source));
  47. }
  48. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  49. shared_pointer(const shared_pointer<U>& source) {
  50. operator=<U>(source);
  51. }
  52. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  53. shared_pointer(shared_pointer<U>&& source) {
  54. operator=<U>(move(source));
  55. }
  56. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  57. shared_pointer(const shared_pointer_weak<U>& source) {
  58. operator=<U>(source);
  59. }
  60. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  61. shared_pointer(const shared_pointer<U>& source, T* pointer) {
  62. if((bool)source && (T*)source.manager->pointer == pointer) {
  63. manager = source.manager;
  64. manager->strong++;
  65. }
  66. }
  67. ~shared_pointer() {
  68. reset();
  69. }
  70. auto operator=(T* source) -> shared_pointer& {
  71. reset();
  72. if(source) {
  73. manager = new shared_pointer_manager((void*)source);
  74. manager->strong++;
  75. if constexpr(is_base_of_v<shared_pointer_this_base, T>) {
  76. source->weak = *this;
  77. }
  78. }
  79. return *this;
  80. }
  81. auto operator=(const shared_pointer& source) -> shared_pointer& {
  82. if(this != &source) {
  83. reset();
  84. if((bool)source) {
  85. manager = source.manager;
  86. manager->strong++;
  87. }
  88. }
  89. return *this;
  90. }
  91. auto operator=(shared_pointer&& source) -> shared_pointer& {
  92. if(this != &source) {
  93. reset();
  94. manager = source.manager;
  95. source.manager = nullptr;
  96. }
  97. return *this;
  98. }
  99. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  100. auto operator=(const shared_pointer<U>& source) -> shared_pointer& {
  101. if((uintptr)this != (uintptr)&source) {
  102. reset();
  103. if((bool)source) {
  104. manager = source.manager;
  105. manager->strong++;
  106. }
  107. }
  108. return *this;
  109. }
  110. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  111. auto operator=(shared_pointer&& source) -> shared_pointer& {
  112. if((uintptr)this != (uintptr)&source) {
  113. reset();
  114. manager = source.manager;
  115. source.manager = nullptr;
  116. }
  117. return *this;
  118. }
  119. template<typename U, typename = enable_if_t<is_compatible<U>::value>>
  120. auto operator=(const shared_pointer_weak<U>& source) -> shared_pointer& {
  121. reset();
  122. if((bool)source) {
  123. manager = source.manager;
  124. manager->strong++;
  125. }
  126. return *this;
  127. }
  128. auto data() -> T* {
  129. if(manager) return (T*)manager->pointer;
  130. return nullptr;
  131. }
  132. auto data() const -> const T* {
  133. if(manager) return (T*)manager->pointer;
  134. return nullptr;
  135. }
  136. auto operator->() -> T* { return data(); }
  137. auto operator->() const -> const T* { return data(); }
  138. auto operator*() -> T& { return *data(); }
  139. auto operator*() const -> const T& { return *data(); }
  140. auto operator()() -> T& { return *data(); }
  141. auto operator()() const -> const T& { return *data(); }
  142. template<typename U>
  143. auto operator==(const shared_pointer<U>& source) const -> bool {
  144. return manager == source.manager;
  145. }
  146. template<typename U>
  147. auto operator!=(const shared_pointer<U>& source) const -> bool {
  148. return manager != source.manager;
  149. }
  150. explicit operator bool() const {
  151. return manager && manager->strong;
  152. }
  153. auto unique() const -> bool {
  154. return manager && manager->strong == 1;
  155. }
  156. auto references() const -> uint {
  157. return manager ? manager->strong : 0;
  158. }
  159. auto reset() -> void {
  160. if(manager && manager->strong) {
  161. //pointer may contain weak references; if strong==0 it may destroy manager
  162. //as such, we must destroy strong before decrementing it to zero
  163. if(manager->strong == 1) {
  164. if(manager->deleter) {
  165. manager->deleter(manager->pointer);
  166. } else {
  167. delete (T*)manager->pointer;
  168. }
  169. manager->pointer = nullptr;
  170. }
  171. if(--manager->strong == 0) {
  172. if(manager->weak == 0) {
  173. delete manager;
  174. }
  175. }
  176. }
  177. manager = nullptr;
  178. }
  179. template<typename U>
  180. auto cast() -> shared_pointer<U> {
  181. if(auto pointer = dynamic_cast<U*>(data())) {
  182. return {*this, pointer};
  183. }
  184. return {};
  185. }
  186. };
  187. template<typename T>
  188. struct shared_pointer_weak {
  189. using type = T;
  190. shared_pointer_manager* manager = nullptr;
  191. shared_pointer_weak() {
  192. }
  193. shared_pointer_weak(const shared_pointer<T>& source) {
  194. operator=(source);
  195. }
  196. auto operator=(const shared_pointer<T>& source) -> shared_pointer_weak& {
  197. reset();
  198. if(manager = source.manager) manager->weak++;
  199. return *this;
  200. }
  201. ~shared_pointer_weak() {
  202. reset();
  203. }
  204. auto operator==(const shared_pointer_weak& source) const -> bool {
  205. return manager == source.manager;
  206. }
  207. auto operator!=(const shared_pointer_weak& source) const -> bool {
  208. return manager != source.manager;
  209. }
  210. explicit operator bool() const {
  211. return manager && manager->strong;
  212. }
  213. auto acquire() const -> shared_pointer<T> {
  214. return shared_pointer<T>(*this);
  215. }
  216. auto reset() -> void {
  217. if(manager && --manager->weak == 0) {
  218. if(manager->strong == 0) {
  219. delete manager;
  220. }
  221. }
  222. manager = nullptr;
  223. }
  224. };
  225. template<typename T>
  226. struct shared_pointer_this : shared_pointer_this_base {
  227. shared_pointer_weak<T> weak;
  228. auto shared() -> shared_pointer<T> { return weak; }
  229. auto shared() const -> shared_pointer<T const> { return weak; }
  230. };
  231. template<typename T, typename... P>
  232. auto shared_pointer_make(P&&... p) -> shared_pointer<T> {
  233. return shared_pointer<T>{new T{forward<P>(p)...}};
  234. }
  235. template<typename T>
  236. struct shared_pointer_new : shared_pointer<T> {
  237. shared_pointer_new(const shared_pointer<T>& source) : shared_pointer<T>(source) {}
  238. template<typename... P> shared_pointer_new(P&&... p) : shared_pointer<T>(new T(forward<P>(p)...)) {}
  239. };
  240. }