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.

283 lines
7.8 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include <gp/algorithm/move.hpp>
  4. #include <gp/algorithm/tmp_manip.hpp>
  5. #include "gp/allocator/dummy.hpp"
  6. #include "gp/exception.hpp"
  7. #include "gp/function.hpp"
  8. #include "gp/memory.hpp"
  9. #include <type_traits>
  10. #include <new>
  11. namespace gp{
  12. template<typename ...T>
  13. class fixed_variant final {
  14. std::size_t index = std::numeric_limits<std::size_t>::max();
  15. char buffer[max_size<T...>()];
  16. gp::function<void(void*, void*)> cpytor = {[](void*, void*){}, nullopt};
  17. gp::function<void(void*, void*)> mvtor = {[](void*, void*){}, nullopt};
  18. gp::function<void(void*)> dtor = {[](void*){}, nullopt};
  19. static_assert(all_of_fixed_size<T...>::value, "not fixed");
  20. public:
  21. fixed_variant()
  22. : fixed_variant(typename first_of<T...>::type{})
  23. {}
  24. template<typename U, std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int> = 0>
  25. fixed_variant(U& value)
  26. : index{r_index_of<U, T...>::value}
  27. {
  28. using actual = gp::remove_cvref_t<U>;
  29. dtor = gp::function<void(void*)>([](void* thing){
  30. ((actual*)thing)->~actual();
  31. }, nullopt);
  32. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){
  33. new(dest) actual(*(actual*)src);
  34. }, nullopt);
  35. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){
  36. new(dest) actual(gp::move(*(actual*)src));
  37. }, nullopt);
  38. cpytor((char*)&value, buffer);
  39. }
  40. static_assert(list_contains_class<int, int>::value, "list_contains_class doesn't work properly");
  41. static_assert(list_contains_class<int, char, int>::value, "list_contains_class doesn't work properly");
  42. static_assert(list_contains_class<int, int, char>::value, "list_contains_class doesn't work properly");
  43. static_assert(list_contains_class<int, char, int, char>::value, "list_contains_class doesn't work properly");
  44. static_assert(!list_contains_class<int, char, char>::value, "list_contains_class doesn't work properly");
  45. template<typename U, std::enable_if_t<list_contains_class<gp::remove_cvref_t<U>,T...>::value,int> = 0>
  46. fixed_variant(U&& value)
  47. : index{r_index_of<U, T...>::value}
  48. {
  49. using actual = gp::remove_cvref_t<U>;
  50. dtor = gp::function<void(void*)>([](void* thing){
  51. ((actual*)thing)->~actual();
  52. }, nullopt);
  53. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){
  54. new(dest) actual(*(actual*)src);
  55. }, nullopt);
  56. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){
  57. new(dest) actual(gp::move(*(actual*)src));
  58. }, nullopt);
  59. mvtor((char*)&value, buffer);
  60. }
  61. fixed_variant(const fixed_variant& oth)
  62. : index{oth.index}
  63. , dtor{oth.dtor}
  64. , cpytor{oth.cpytor}
  65. , mvtor{oth.mvtor}
  66. {
  67. cpytor((char*)oth.buffer, (char*)buffer);
  68. }
  69. fixed_variant(fixed_variant& oth)
  70. : index{oth.index}
  71. , dtor{oth.dtor}
  72. , cpytor{oth.cpytor}
  73. , mvtor{oth.mvtor}
  74. {
  75. cpytor(oth.buffer, buffer);
  76. }
  77. fixed_variant(fixed_variant&& oth)
  78. : index{oth.index}
  79. , dtor{oth.dtor}
  80. , cpytor{oth.cpytor}
  81. , mvtor{oth.mvtor}
  82. {
  83. oth.index = std::numeric_limits<std::size_t>::max();
  84. mvtor(oth.buffer, buffer);
  85. }
  86. template<typename U>
  87. constexpr size_t alt() const {
  88. return r_index_of<U, T...>::value;
  89. }
  90. size_t type() const {
  91. return index;
  92. }
  93. void operator=(fixed_variant& value)
  94. {
  95. if(index != std::numeric_limits<std::size_t>::max())
  96. {
  97. dtor((void*)buffer);
  98. }
  99. index = value.index;
  100. cpytor = value.cpytor;
  101. dtor = value.dtor;
  102. mvtor = value.mvtor;
  103. cpytor(value.buffer, buffer);
  104. }
  105. void operator=(fixed_variant&& value)
  106. {
  107. if(index != std::numeric_limits<std::size_t>::max())
  108. {
  109. dtor((void*)buffer);
  110. }
  111. dtor = value.dtor;
  112. cpytor = value.cpytor;
  113. mvtor = value.mvtor;
  114. index = value.index;
  115. value.index = std::numeric_limits<std::size_t>::max();
  116. mvtor(value.buffer, buffer);
  117. }
  118. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  119. void operator=(U& value)
  120. {
  121. if(index != std::numeric_limits<std::size_t>::max())
  122. {
  123. dtor((void*)buffer);
  124. }
  125. index = r_index_of<U, T...>::value;
  126. new(buffer) U(value);
  127. dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt);
  128. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
  129. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
  130. }
  131. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  132. void operator=(U&& value)
  133. {
  134. if(index != std::numeric_limits<std::size_t>::max())
  135. {
  136. dtor((void*)buffer);
  137. }
  138. new(buffer) U(gp::move(value));
  139. index = r_index_of<U, T...>::value;
  140. dtor = gp::function([](void* thing){((U*)thing)->~U();}, nullopt);
  141. cpytor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(*(U*)src);}, nullopt);
  142. mvtor = gp::function<void(void*, void*)>([](void* src, void* dest){new(dest) U(gp::move(*(U*)src));}, nullopt);
  143. }
  144. ~fixed_variant()
  145. {
  146. if(index != std::numeric_limits<std::size_t>::max() && dtor.ready())
  147. {
  148. dtor((void*)buffer);
  149. index = std::numeric_limits<std::size_t>::max();
  150. }
  151. }
  152. template<typename U>
  153. constexpr U& value()
  154. {
  155. if constexpr (gp_config::has_exceptions)
  156. {
  157. if(r_index_of<U, T...>::value != index)
  158. {
  159. throw bad_variant_access<U>{};
  160. }
  161. }
  162. return *reinterpret_cast<U*>(buffer);
  163. }
  164. template<typename U>
  165. constexpr bool is_a()
  166. {
  167. if(r_index_of<U, T...>::value == index)
  168. {
  169. return true;
  170. }
  171. else
  172. {
  173. return false;
  174. }
  175. }
  176. };
  177. /*template<typename allocator_t = gp_config::memory_module::default_allocator, typename ...T>
  178. class variant{
  179. std::size_t index = std::numeric_limits<std::size_t>::max();
  180. void* ptr;
  181. gp::function<void(void*)> dtor = [](void*){};
  182. allocator_t allocator;
  183. public:
  184. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  185. constexpr variant(U& value)
  186. : index{r_index_of<U, T...>::value}
  187. {
  188. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  189. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  190. }
  191. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  192. constexpr variant(U&& value)
  193. : index{r_index_of<U, T...>::value}
  194. {
  195. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  196. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  197. }
  198. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  199. void operator=(U& value)
  200. {
  201. if(index != std::numeric_limits<std::size_t>::max())
  202. {
  203. dtor(ptr);
  204. allocator.deallocate(ptr);
  205. }
  206. index = r_index_of<U, T...>::value;
  207. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  208. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  209. }
  210. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  211. void operator=(U&& value)
  212. {
  213. if(index != std::numeric_limits<std::size_t>::max())
  214. {
  215. dtor(ptr);
  216. allocator.deallocate(ptr);
  217. }
  218. index = r_index_of<U, T...>::value;
  219. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  220. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO: replace with delete(p, t)
  221. }
  222. ~variant()
  223. {
  224. if(index != std::numeric_limits<std::size_t>::max())
  225. {
  226. dtor(ptr);
  227. allocator.deallocate(ptr);
  228. }
  229. }
  230. template<typename U>
  231. constexpr U& value()
  232. {
  233. if constexpr (gp_config::has_exceptions)
  234. {
  235. if(r_index_of<U, T...>::value != index)
  236. {
  237. throw bad_variant_access<U>{};
  238. }
  239. }
  240. return *reinterpret_cast<U*>(ptr);
  241. }
  242. template<typename U>
  243. constexpr U& is_a()
  244. {
  245. if(r_index_of<U, T...>::value == index)
  246. {
  247. return true;
  248. }
  249. else
  250. {
  251. return false;
  252. }
  253. }
  254. };*/
  255. }