General Purpose library for Freestanding C++ and POSIX systems
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

265 linhas
5.7 KiB

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