General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
3.0 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  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. namespace gp {
  8. template<typename T>
  9. class unique_ptr {
  10. T* data;
  11. gp::allocator& owner;
  12. unique_ptr(T* _data, gp::allocator& _owner)
  13. : data(_data)
  14. , owner(_owner)
  15. {}
  16. void dirty_clear() {
  17. if(data) {
  18. data->~T();
  19. owner.deallocate(data);
  20. }
  21. }
  22. public:
  23. template<typename ...U>
  24. static unique_ptr make(gp::allocator& owner, U&&... args) {
  25. auto ptr = owner.allocate(sizeof(T));
  26. return unique_ptr(new(ptr) T(gp::forward<U>(args)...), owner);
  27. }
  28. template<typename U>
  29. unique_ptr<U> cast() {
  30. auto save = data;
  31. data = nullptr;
  32. return unique_ptr<U>(safe, owner);
  33. }
  34. T* operator->() {
  35. return data;
  36. }
  37. T& operator*() {
  38. return *data;
  39. }
  40. operator bool() {
  41. return data != nullptr;
  42. }
  43. unique_ptr(unique_ptr&) = delete;
  44. unique_ptr(unique_ptr&& oth)
  45. : data(oth.data)
  46. , owner(oth.owner)
  47. {
  48. oth.data = nullptr;
  49. }
  50. unique_ptr& operator=(unique_ptr&) = delete;
  51. unique_ptr& operator=(unique_ptr&& oth) {
  52. dirty_clear();
  53. data = oth.data;
  54. owner = oth.owner;
  55. }
  56. ~unique_ptr() {
  57. dirty_clear();
  58. }
  59. };
  60. template<typename T>
  61. class shared_ptr {
  62. T* data;
  63. std::atomic_int* refcounter;
  64. gp::allocator& owner;
  65. shared_ptr(T* _data, gp::allocator& _owner)
  66. : data(_data)
  67. , refcounter((std::atomic_int*)owner.allocate(sizeof(std::atomic_int)))
  68. , owner(_owner)
  69. {
  70. refcounter->store(1);
  71. }
  72. shared_ptr(T* _data, std::atomic_int* refctr, gp::allocator& _owner)
  73. : data(_data)
  74. , refcounter(refctr)
  75. , owner(_owner)
  76. {
  77. refcounter->store(1);
  78. }
  79. void dirty_clear() {
  80. if(!refcounter) return;
  81. if(refcounter->fetch_sub(1, std::memory_order::acq_rel) == 0) {
  82. if(data) {
  83. data->~T();
  84. owner.deallocate(refcounter);
  85. owner.deallocate(data);
  86. }
  87. }
  88. }
  89. public:
  90. template<typename ...U>
  91. static shared_ptr make(gp::allocator& owner, U&&... args) {
  92. auto ptr = owner.allocate(sizeof(T));
  93. return shared_ptr(new(ptr) T(gp::forward<U>(args)...), owner);
  94. }
  95. template<typename U>
  96. shared_ptr<U> cast() {
  97. return shared_ptr<U>(data, refcounter, owner);
  98. }
  99. T* operator->() {
  100. return data;
  101. }
  102. T& operator*() {
  103. return *data;
  104. }
  105. operator bool() {
  106. return data != nullptr;
  107. }
  108. shared_ptr(shared_ptr& oth) {
  109. oth.refcounter->fetch_add(1, std::memory_order::acquire);
  110. data = oth.data;
  111. refcounter = oth.refcounter;
  112. owner = oth.owner;
  113. }
  114. shared_ptr(shared_ptr&& oth)
  115. : data(oth.data)
  116. , owner(oth.owner)
  117. {
  118. oth.data = nullptr;
  119. oth.refcounter = nullptr;
  120. }
  121. shared_ptr& operator=(shared_ptr& oth) {
  122. dirty_clear();
  123. (*oth.refcounter)++;
  124. data = oth.data;
  125. refcounter = oth.refcounter;
  126. owner = oth.owner;
  127. }
  128. shared_ptr& operator=(shared_ptr&& oth) {
  129. dirty_clear();
  130. data = oth.data;
  131. owner = oth.owner;
  132. }
  133. ~shared_ptr() {
  134. dirty_clear();
  135. }
  136. };
  137. }