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.

326 lines
9.4 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
  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include <gp/algorithms/move.hpp>
  4. #include <gp/algorithms/tmp_manip.hpp>
  5. #include "gp/utils/allocators/dummy.hpp"
  6. #include "gp/exception.hpp"
  7. #include "gp/functional/function.hpp"
  8. #include <type_traits>
  9. #include <new>
  10. namespace gp{
  11. /**
  12. * @brief A form of variant that expect only classes whose size is strictly defined at compile time
  13. *
  14. * @tparam T The list of types accepted by the variant
  15. */
  16. template<typename ...T>
  17. class fixed_variant final {
  18. std::size_t index = std::numeric_limits<std::size_t>::max();
  19. char buffer[max_size<T...>()];
  20. gp::function<void(void*, void*)> cpytor = {[](void*, void*){}, nullopt};
  21. gp::function<void(void*, void*)> mvtor = {[](void*, void*){}, nullopt};
  22. gp::function<void(void*)> dtor = {[](void*){}, nullopt};
  23. static_assert(all_of_fixed_size<T...>::value, "not fixed");
  24. public:
  25. fixed_variant()
  26. : fixed_variant(typename first_of<T...>::type{})
  27. {}
  28. /**
  29. * @brief Construct a new fixed variant from an object that is legal in it
  30. *
  31. * @tparam U A type that belongs in the list of types the variant supports
  32. * @param value The copied value
  33. */
  34. template<typename U, std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int> = 0>
  35. fixed_variant(U& value)
  36. : index{r_index_of<gp::remove_cvref_t<U>, T...>::value}
  37. {
  38. using actual = gp::remove_cvref_t<U>;
  39. dtor = gp::function<void(void*)>([](void* thing){
  40. ((actual*)thing)->~actual();
  41. }, nullopt);
  42. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){
  43. new(dest) actual(*(actual*)src);
  44. }, nullopt);
  45. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){
  46. new(dest) actual(gp::move(*(actual*)src));
  47. }, nullopt);
  48. cpytor((char*)&value, buffer);
  49. }
  50. static_assert(list_contains_class<int, int>::value, "list_contains_class doesn't work properly");
  51. static_assert(list_contains_class<int, char, int>::value, "list_contains_class doesn't work properly");
  52. static_assert(list_contains_class<int, int, char>::value, "list_contains_class doesn't work properly");
  53. static_assert(list_contains_class<int, char, int, char>::value, "list_contains_class doesn't work properly");
  54. static_assert(!list_contains_class<int, char, char>::value, "list_contains_class doesn't work properly");
  55. /**
  56. * @brief Construct a new fixed variant from an object that is legal in it by moving said object
  57. *
  58. * @tparam U A type that belongs in the list of types the variant supports
  59. * @param value The moved value
  60. */
  61. template<typename U, std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int> = 0>
  62. fixed_variant(U&& value)
  63. : index{r_index_of<gp::remove_cvref_t<U>, T...>::value}
  64. {
  65. using actual = gp::remove_cvref_t<U>;
  66. dtor = gp::function<void(void*)>([](void* thing){
  67. ((actual*)thing)->~actual();
  68. }, nullopt);
  69. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){
  70. new(dest) actual(*(actual*)src);
  71. }, nullopt);
  72. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){
  73. new(dest) actual(gp::move(*(actual*)src));
  74. }, nullopt);
  75. mvtor((char*)&value, buffer);
  76. }
  77. fixed_variant(const fixed_variant& oth)
  78. : index{oth.index}
  79. , dtor{oth.dtor}
  80. , cpytor{oth.cpytor}
  81. , mvtor{oth.mvtor}
  82. {
  83. cpytor((char*)oth.buffer, (char*)buffer);
  84. }
  85. fixed_variant(fixed_variant& oth)
  86. : index{oth.index}
  87. , dtor{oth.dtor}
  88. , cpytor{oth.cpytor}
  89. , mvtor{oth.mvtor}
  90. {
  91. cpytor(oth.buffer, buffer);
  92. }
  93. fixed_variant(fixed_variant&& oth)
  94. : index{oth.index}
  95. , dtor{oth.dtor}
  96. , cpytor{oth.cpytor}
  97. , mvtor{oth.mvtor}
  98. {
  99. oth.index = std::numeric_limits<std::size_t>::max();
  100. mvtor(oth.buffer, buffer);
  101. }
  102. /**
  103. * @brief Gives an alternative (value usable in a switch statement) representing the given type
  104. *
  105. * @tparam U the type to match against
  106. * @return constexpr size_t a value that can be used in the case part of a switch case statement
  107. * @see type()
  108. */
  109. template<typename U>
  110. constexpr static size_t alt() {
  111. return r_index_of<U, T...>::value;
  112. }
  113. /**
  114. * @brief Gives the type as can be matched in a switch statement using alternatives
  115. *
  116. * @return size_t a value that can be used in the switch part of a switch case statement
  117. * @see alt()
  118. */
  119. size_t type() const {
  120. return index;
  121. }
  122. void operator=(fixed_variant& value)
  123. {
  124. if(index != std::numeric_limits<std::size_t>::max())
  125. {
  126. dtor((void*)buffer);
  127. }
  128. index = value.index;
  129. cpytor = value.cpytor;
  130. dtor = value.dtor;
  131. mvtor = value.mvtor;
  132. cpytor(value.buffer, buffer);
  133. }
  134. void operator=(fixed_variant&& value)
  135. {
  136. if(index != std::numeric_limits<std::size_t>::max())
  137. {
  138. dtor((void*)buffer);
  139. }
  140. dtor = value.dtor;
  141. cpytor = value.cpytor;
  142. mvtor = value.mvtor;
  143. index = value.index;
  144. value.index = std::numeric_limits<std::size_t>::max();
  145. mvtor(value.buffer, buffer);
  146. }
  147. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  148. void operator=(U& value)
  149. {
  150. if(index != std::numeric_limits<std::size_t>::max())
  151. {
  152. dtor((void*)buffer);
  153. }
  154. index = r_index_of<gp::remove_cvref_t<U>, T...>::value;
  155. new(buffer) U(value);
  156. dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt);
  157. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
  158. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
  159. }
  160. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  161. void operator=(U&& value)
  162. {
  163. if(index != std::numeric_limits<std::size_t>::max())
  164. {
  165. dtor((void*)buffer);
  166. }
  167. new(buffer) U(gp::move(value));
  168. index = r_index_of<gp::remove_cvref_t<U>, T...>::value;
  169. dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt);
  170. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
  171. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
  172. }
  173. ~fixed_variant()
  174. {
  175. if(index != std::numeric_limits<std::size_t>::max() && dtor.ready())
  176. {
  177. dtor((void*)buffer);
  178. index = std::numeric_limits<std::size_t>::max();
  179. }
  180. }
  181. /**
  182. * @brief Brutally decay the variant into the given type.
  183. Will throw (@see bad_variant_access) if exceptions are enabled, else behaviour is undefined.
  184. *
  185. * @tparam U the type to decay towards
  186. * @return constexpr U& a decayed reference to the variant
  187. */
  188. template<typename U>
  189. constexpr U& value()
  190. {
  191. if constexpr (gp_config::has_exceptions)
  192. {
  193. if(r_index_of<gp::remove_cvref_t<U>, T...>::value != index)
  194. {
  195. throw bad_variant_access<U>{};
  196. }
  197. }
  198. return *reinterpret_cast<U*>(buffer);
  199. }
  200. /**
  201. * @brief Tests if the variant is of a particular type.
  202. *
  203. * @tparam U the type to match against
  204. * @return true if the types match
  205. * @return false if the types don't match
  206. */
  207. template<typename U>
  208. constexpr bool is_a()
  209. {
  210. if(r_index_of<gp::remove_cvref_t<U>, T...>::value == index)
  211. {
  212. return true;
  213. }
  214. else
  215. {
  216. return false;
  217. }
  218. }
  219. };
  220. /*template<typename allocator_t = gp_config::memory_module::default_allocator, typename ...T>
  221. class variant{
  222. std::size_t index = std::numeric_limits<std::size_t>::max();
  223. void* ptr;
  224. gp::function<void(void*)> dtor = [](void*){};
  225. allocator_t allocator;
  226. public:
  227. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  228. constexpr variant(U& value)
  229. : index{r_index_of<U, T...>::value}
  230. {
  231. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  232. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  233. }
  234. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  235. constexpr variant(U&& value)
  236. : index{r_index_of<U, T...>::value}
  237. {
  238. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  239. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  240. }
  241. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  242. void operator=(U& value)
  243. {
  244. if(index != std::numeric_limits<std::size_t>::max())
  245. {
  246. dtor(ptr);
  247. allocator.deallocate(ptr);
  248. }
  249. index = r_index_of<U, T...>::value;
  250. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  251. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  252. }
  253. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  254. void operator=(U&& value)
  255. {
  256. if(index != std::numeric_limits<std::size_t>::max())
  257. {
  258. dtor(ptr);
  259. allocator.deallocate(ptr);
  260. }
  261. index = r_index_of<U, T...>::value;
  262. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  263. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO: replace with delete(p, t)
  264. }
  265. ~variant()
  266. {
  267. if(index != std::numeric_limits<std::size_t>::max())
  268. {
  269. dtor(ptr);
  270. allocator.deallocate(ptr);
  271. }
  272. }
  273. template<typename U>
  274. constexpr U& value()
  275. {
  276. if constexpr (gp_config::has_exceptions)
  277. {
  278. if(r_index_of<U, T...>::value != index)
  279. {
  280. throw bad_variant_access<U>{};
  281. }
  282. }
  283. return *reinterpret_cast<U*>(ptr);
  284. }
  285. template<typename U>
  286. constexpr U& is_a()
  287. {
  288. if(r_index_of<U, T...>::value == index)
  289. {
  290. return true;
  291. }
  292. else
  293. {
  294. return false;
  295. }
  296. }
  297. };*/
  298. }