Guest User

any.h

a guest
Nov 16th, 2022
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.80 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <cstddef>
  4. #include <cstring>
  5. #include <typeinfo>
  6. #include <utility>
  7.  
  8. struct Any_tag {
  9. };
  10.  
  11. template<std::size_t STORAGE_SIZE> class Any: Any_tag {
  12. typedef void *(*AllocFunc)();
  13. typedef void (*CopyFunc)(void *dst, const void *src);
  14. typedef void (*MoveFunc)(void *dst, void *src);
  15. typedef void (*DestroyFunc)(void *val);
  16. typedef void (*FreeFunc)(void *val);
  17.  
  18. struct Operations {
  19. const std::type_info &typeInfo;
  20. std::size_t size;
  21. std::size_t align;
  22. AllocFunc alloc;
  23. CopyFunc copy;
  24. MoveFunc move;
  25. DestroyFunc destroy;
  26. FreeFunc free;
  27. };
  28.  
  29. template<typename T> static inline constexpr Operations OPERATIONS = {
  30. .typeInfo = typeid(T),
  31. .size = ([]() {
  32. if constexpr (std::is_same_v<T, void>) {
  33. return 0;
  34. } else {
  35. return sizeof(T);
  36. }
  37. })(),
  38. .align = ([]() {
  39. if constexpr (std::is_same_v<T, void>) {
  40. return 0;
  41. } else {
  42. return alignof(T);
  43. }
  44. })(),
  45. .alloc = []() -> void* {
  46. if constexpr (std::is_same_v<T, void>) {
  47. return nullptr;
  48. } else {
  49. return new std::aligned_storage<sizeof(T), alignof(T)>;
  50. }
  51. },
  52. .copy = ([]() {
  53. if constexpr (std::is_same_v<T, void> || std::is_trivially_copy_constructible_v<T>) {
  54. return nullptr;
  55. } else {
  56. return static_cast<CopyFunc>([](void *dst, const void *src) {
  57. new (dst) T(*reinterpret_cast<const T*>(src));
  58. });
  59. }
  60. })(),
  61. .move = ([]() {
  62. if constexpr (std::is_same_v<T, void> || std::is_trivially_move_constructible_v<T>) {
  63. return nullptr;
  64. } else {
  65. return static_cast<MoveFunc>([](void *dst, void *src) {
  66. new (dst) T(std::move(*reinterpret_cast<T*>(src)));
  67. });
  68. }
  69. })(),
  70. .destroy = ([]() {
  71. if constexpr (std::is_same_v<T, void> || std::is_trivially_destructible_v<T>) {
  72. return nullptr;
  73. } else {
  74. return static_cast<DestroyFunc>([](void *arg) {
  75. (reinterpret_cast<T*>(arg))->~T();
  76. });
  77. }
  78. })(),
  79. .free = [](void *arg) {
  80. if constexpr (!std::is_same_v<T, void>) {
  81. delete reinterpret_cast<T*>(arg);
  82. }
  83. }
  84. };
  85.  
  86. std::size_t m_storage[(STORAGE_SIZE + sizeof(std::size_t) - 1) / sizeof(std::size_t)];
  87. char *m_heapStorage = nullptr;
  88. const Operations *m_operations = &OPERATIONS<void>;
  89.  
  90. template<std::size_t N> friend class Any;
  91.  
  92. [[nodiscard]] const void *storage() const {
  93. return m_heapStorage ? m_heapStorage : reinterpret_cast<const char*>(m_storage);
  94. }
  95.  
  96. [[nodiscard]] void *storage() {
  97. return m_heapStorage ? m_heapStorage : reinterpret_cast<char*>(m_storage);
  98. }
  99.  
  100. public:
  101. Any() = default;
  102.  
  103. template<std::size_t N> Any(const Any<N> &value) {
  104. if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
  105. m_heapStorage = reinterpret_cast<char*>(value.m_operations->alloc());
  106. }
  107. if (value.m_operations->copy) {
  108. value.m_operations->copy(storage(), value.storage());
  109. } else {
  110. std::memcpy(storage(), value.storage(), value.m_operations->size);
  111. }
  112. m_operations = reinterpret_cast<const Operations*>(value.m_operations);
  113. }
  114.  
  115. template<std::size_t N> Any(Any<N> &&value) noexcept {
  116. m_operations = reinterpret_cast<const Operations*>(value.m_operations);
  117. if (value.m_heapStorage) {
  118. m_heapStorage = value.m_heapStorage;
  119. value.m_heapStorage = nullptr;
  120. value.m_operations = &OPERATIONS<void>;
  121. } else {
  122. if (value.m_operations->size > STORAGE_SIZE) {
  123. m_heapStorage = reinterpret_cast<char*>(value.m_operations->alloc());
  124. }
  125. if (m_operations->move) {
  126. m_operations->move(storage(), value.storage());
  127. } else {
  128. std::memcpy(storage(), value.storage(), value.m_operations->size);
  129. }
  130. }
  131. }
  132.  
  133. template<typename T> Any(T &&value) requires (!std::is_base_of_v<Any_tag, typename std::remove_reference<T>::type>) {
  134. using TT = typename std::remove_reference<T>::type;
  135. if constexpr (sizeof(TT) > sizeof(m_storage) || alignof(TT) > alignof(std::size_t)) {
  136. m_heapStorage = reinterpret_cast<char*>(new TT(std::forward<T>(value)));
  137. } else {
  138. new (m_storage) TT(std::forward<T>(value));
  139. }
  140. m_operations = &OPERATIONS<TT>;
  141. }
  142.  
  143. ~Any() {
  144. if (!m_heapStorage) {
  145. if (m_operations->destroy) {
  146. m_operations->destroy(storage());
  147. }
  148. } else {
  149. m_operations->free(m_heapStorage);
  150. }
  151. }
  152.  
  153. [[nodiscard]] const std::type_info &type() const {
  154. return m_operations->typeInfo;
  155. }
  156.  
  157. [[nodiscard]] std::size_t size() const {
  158. return m_operations->size;
  159. }
  160.  
  161. [[nodiscard]] std::size_t align() const {
  162. return m_operations->align;
  163. }
  164.  
  165. [[nodiscard]] bool isHeapAllocated() const {
  166. return m_heapStorage != nullptr;
  167. }
  168.  
  169. template<typename T> [[nodiscard]] const T *get() const {
  170. if (m_operations->typeInfo == typeid(T)) {
  171. return reinterpret_cast<const T*>(storage());
  172. } else {
  173. return nullptr;
  174. }
  175. }
  176.  
  177. template<typename T> [[nodiscard]] T *get() {
  178. if (m_operations->typeInfo == typeid(T)) {
  179. return reinterpret_cast<T*>(storage());
  180. } else {
  181. return nullptr;
  182. }
  183. }
  184.  
  185. void clear() {
  186. if (!m_heapStorage) {
  187. if (m_operations->destroy) {
  188. m_operations->destroy(storage());
  189. }
  190. } else {
  191. m_operations->free(m_heapStorage);
  192. m_heapStorage = nullptr;
  193. }
  194. m_operations = &OPERATIONS<void>;
  195. }
  196.  
  197. template<typename T, typename... Args> void emplace(Args &&...args) {
  198. clear();
  199. if constexpr (sizeof(T) > sizeof(m_storage) || alignof(T) > alignof(std::size_t)) {
  200. m_heapStorage = reinterpret_cast<char*>(new T(std::forward<Args...>(args)...));
  201. } else {
  202. new (m_storage) T(std::forward<Args...>(args)...);
  203. }
  204. m_operations = &OPERATIONS<T>;
  205. }
  206.  
  207. template<std::size_t N> Any<STORAGE_SIZE> &operator=(const Any<N> &value) {
  208. clear();
  209. if (value.m_heapStorage || value.m_operations->size > sizeof(m_storage)) {
  210. m_heapStorage = value.m_operations->alloc();
  211. }
  212. if (value.m_operations) {
  213. value.m_operations->copy(storage(), value.storage());
  214. } else {
  215. std::memcpy(storage(), value.storage(), value.m_operations->size);
  216. }
  217. m_operations = value.m_operations;
  218. return *this;
  219. }
  220.  
  221. template<std::size_t N> Any<STORAGE_SIZE> &operator=(Any<N> &&value) noexcept {
  222. clear();
  223. m_operations = value.m_operations;
  224. if (value.m_heapStorage) {
  225. m_heapStorage = value.m_heapStorage;
  226. value.m_heapStorage = nullptr;
  227. value.m_operations = &OPERATIONS<void>;
  228. } else {
  229. if (value.m_operations->size > STORAGE_SIZE) {
  230. m_heapStorage = value.m_operations->alloc();
  231. }
  232. if (m_operations->move) {
  233. m_operations->move(storage(), value.storage());
  234. } else {
  235. std::memcpy(storage(), value.storage(), value.m_operations->size);
  236. }
  237. }
  238. return *this;
  239. }
  240.  
  241. template<typename T> Any &operator=(T &&value) {
  242. using TT = typename std::remove_reference<T>::type;
  243. emplace<TT>(std::forward<T>(value));
  244. return *this;
  245. }
  246. };
  247.  
Advertisement
Add Comment
Please, Sign In to add comment