General Purpose library for Freestanding C++ and POSIX systems
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

277 righe
6.0 KiB

3 anni fa
3 anni fa
  1. #pragma once
  2. #include "gp/functional/bind_front.hpp"
  3. #include "gp/algorithms/move.hpp"
  4. #include "gp/containers/buffer.hpp"
  5. #include "gp/functional/function.hpp"
  6. #include "gp/utils/allocators/dummy.hpp"
  7. #include <atomic>
  8. #include <concepts>
  9. namespace gp {
  10. template<typename T>
  11. class unique_ptr {
  12. T* data;
  13. gp::allocator& owner;
  14. void dirty_clear() {
  15. if(data) {
  16. data->~T();
  17. owner.deallocate(data);
  18. }
  19. }
  20. public:
  21. unique_ptr(T* _data, gp::allocator& _owner)
  22. : data(_data)
  23. , owner(_owner)
  24. {}
  25. template<typename ...U>
  26. static unique_ptr make(gp::allocator& owner, U&&... args) {
  27. auto ptr = owner.allocate(sizeof(T));
  28. return unique_ptr(new(ptr) T(gp::forward<U>(args)...), owner);
  29. }
  30. template<typename U>
  31. unique_ptr<U> cast() {
  32. auto save = data;
  33. data = nullptr;
  34. return unique_ptr<U>(save, owner);
  35. }
  36. T* operator->() {
  37. return data;
  38. }
  39. T& operator*() {
  40. return *data;
  41. }
  42. operator bool() {
  43. return data != nullptr;
  44. }
  45. unique_ptr(unique_ptr&) = delete;
  46. unique_ptr(unique_ptr&& oth)
  47. : data(oth.data)
  48. , owner(oth.owner)
  49. {
  50. oth.data = nullptr;
  51. }
  52. unique_ptr& operator=(unique_ptr&) = delete;
  53. unique_ptr& operator=(unique_ptr&& oth) {
  54. dirty_clear();
  55. data = oth.data;
  56. owner = oth.owner;
  57. }
  58. ~unique_ptr() {
  59. dirty_clear();
  60. }
  61. };
  62. template<typename T>
  63. class shared_ptr {
  64. T* data;
  65. std::atomic_int* refcounter;
  66. gp::optional<gp::reference_wrapper<gp::allocator>> owner;
  67. shared_ptr(T* _data, gp::allocator& _owner)
  68. : data(_data)
  69. , refcounter((std::atomic_int*)_owner.allocate(sizeof(std::atomic_int)))
  70. , owner(_owner)
  71. {
  72. refcounter->store(1);
  73. }
  74. shared_ptr(T* _data, std::atomic_int* refctr, gp::allocator& _owner)
  75. : data(_data)
  76. , refcounter(refctr)
  77. , owner(_owner)
  78. {
  79. refcounter->store(1);
  80. }
  81. void dirty_clear() {
  82. if(!refcounter) return;
  83. if(refcounter->fetch_sub(1, std::memory_order::acq_rel) == 0) {
  84. if(data) {
  85. data->~T();
  86. owner.value().get().deallocate(refcounter);
  87. owner.value().get().deallocate(data);
  88. }
  89. }
  90. }
  91. public:
  92. template<typename ...U>
  93. static shared_ptr make(gp::allocator& owner, U&&... args) {
  94. auto ptr = owner.allocate(sizeof(T));
  95. return shared_ptr(new(ptr) T(gp::forward<U>(args)...), owner);
  96. }
  97. template<typename U>
  98. shared_ptr<U> cast() {
  99. return shared_ptr<U>(data, refcounter, owner);
  100. }
  101. T* operator->() {
  102. return data;
  103. }
  104. T& operator*() {
  105. return *data;
  106. }
  107. operator bool() {
  108. return data != nullptr;
  109. }
  110. shared_ptr()
  111. : data{nullptr}
  112. , owner{gp::nullopt}
  113. , refcounter(nullptr)
  114. {}
  115. shared_ptr(shared_ptr& oth) {
  116. oth.refcounter->fetch_add(1, std::memory_order::acquire);
  117. data = oth.data;
  118. refcounter = oth.refcounter;
  119. owner = oth.owner;
  120. }
  121. shared_ptr(shared_ptr&& oth)
  122. : data(oth.data)
  123. , owner(oth.owner)
  124. {
  125. oth.data = nullptr;
  126. oth.refcounter = nullptr;
  127. }
  128. shared_ptr& operator=(shared_ptr& oth) {
  129. dirty_clear();
  130. (*oth.refcounter)++;
  131. data = oth.data;
  132. refcounter = oth.refcounter;
  133. owner = oth.owner;
  134. return *this;
  135. }
  136. shared_ptr& operator=(shared_ptr&& oth) {
  137. dirty_clear();
  138. (*oth.refcounter)++;
  139. data = oth.data;
  140. refcounter = oth.refcounter;
  141. owner = oth.owner;
  142. return *this;
  143. }
  144. ~shared_ptr() {
  145. dirty_clear();
  146. }
  147. };
  148. template<std::copyable T>
  149. struct resource_traits {
  150. using identifier = uint64_t;
  151. static constexpr bool create_if_not_exist = false;
  152. static T* create(const identifier&, gp::allocator&);
  153. static T* retrieve(const identifier&, gp::allocator&);
  154. static bool imprint(const identifier&, const T& value);
  155. static bool annihilate(const identifier&);
  156. };
  157. template<std::copyable T>
  158. requires std::copyable<typename resource_traits<T>::identifier>
  159. class resource_ptr
  160. {
  161. typename resource_traits<T>::identifier _identifier;
  162. gp::allocator& _alloc;
  163. T* value = nullptr;
  164. operator T&() {
  165. if(!value) {
  166. value = resource_traits<T>::retrieve(_identifier, _alloc);
  167. }
  168. if(value) return *value;
  169. else if constexpr (resource_traits<T>::create_if_not_exist) {
  170. value = resource_traits<T>::create(_identifier, _alloc);
  171. if(value) return *value;
  172. }
  173. gp_config::assertion(false, "unavailable resource lead to crash");
  174. }
  175. gp::optional<T&> read() {
  176. if(!value) {
  177. value = resource_traits<T>::retrieve(_identifier, _alloc);
  178. }
  179. if(value) return *value;
  180. else if constexpr (resource_traits<T>::create_if_not_exist) {
  181. value = resource_traits<T>::create(_identifier, _alloc);
  182. if(value) return *value;
  183. }
  184. return gp::nullopt;
  185. }
  186. gp::optional<T&> force_read() {
  187. value = resource_traits<T>::retrieve(_identifier, _alloc);
  188. if(value) return *value;
  189. return gp::nullopt;
  190. }
  191. template<typename U>
  192. requires std::is_base_of_v<T, U>
  193. gp::optional<T&> operator=(U& new_value) {
  194. if(resource_traits<T>::imprint(_identifier, new_value)) {
  195. if(value) {
  196. value->~T();
  197. gp_config::assertion(_alloc.deallocate((void*)value), "deallocation failure during exchange");
  198. }
  199. value = _alloc.allocate(sizeof(U));
  200. gp_config::assertion(value != nullptr, "could not allocate during resource transcription");
  201. new(value) U(new_value);
  202. return *value;
  203. }
  204. return gp::nullopt;
  205. }
  206. template<typename U>
  207. requires std::is_base_of_v<T, U>
  208. gp::optional<T&> operator=(const U& new_value) {
  209. if(resource_traits<T>::imprint(_identifier, new_value)) {
  210. if(value) {
  211. value->~T();
  212. gp_config::assertion(_alloc.deallocate((void*)value), "deallocation failure during exchange");
  213. }
  214. value = _alloc.allocate(sizeof(U));
  215. gp_config::assertion(value != nullptr, "could not allocate during resource transcription");
  216. new(value) U(new_value);
  217. return *value;
  218. }
  219. return gp::nullopt;
  220. }
  221. template<>
  222. gp::optional<T&> operator=<gp::nullopt_t>(const gp::nullopt_t) {
  223. if(resource_traits<T>::annihilate(_identifier)) {
  224. if(value) {
  225. value->~T();
  226. gp_config::assertion(_alloc.deallocate((void*)value), "deallocation failure during exchange");
  227. }
  228. value = nullptr;
  229. }
  230. return gp::nullopt;
  231. }
  232. };
  233. }