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.

191 lines
4.7 KiB

  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include <gp/algorithm/tmp_manip.hpp>
  4. #include "gp/allocator/dummy.hpp"
  5. #include "gp/exception.hpp"
  6. #include "gp/function.hpp"
  7. #include "gp/memory.hpp"
  8. #include <type_traits>
  9. #include <new>
  10. namespace gp{
  11. template<typename ...T>
  12. class fixed_variant{
  13. std::size_t index = std::numeric_limits<std::size_t>::max();
  14. char buffer[max_size<T...>()];
  15. gp::function<void(void*)> dtor = [](void*){};
  16. static_assert(all_of_fixed_size<T...>::value, "not fixed");
  17. public:
  18. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  19. constexpr fixed_variant(U& value)
  20. : index{r_index_of<U, T...>::value}
  21. {
  22. new(buffer) U(value);
  23. dtor = gp::function<void(void*)>([](void* thing){((U*)thing)->~U();});
  24. }
  25. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  26. constexpr fixed_variant(U&& value)
  27. : index{r_index_of<U, T...>::value}
  28. {
  29. new(buffer) U(std::move(value));
  30. dtor = gp::function<void(void*)>([](void* thing){((U*)thing)->~U();});
  31. }
  32. template<typename U>
  33. constexpr size_t alt() const {
  34. return r_index_of<U, T...>::value;
  35. }
  36. size_t type() const {
  37. return index;
  38. }
  39. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  40. void operator=(U& value)
  41. {
  42. if(index != std::numeric_limits<std::size_t>::max())
  43. {
  44. dtor((void*)buffer);
  45. }
  46. index = r_index_of<U, T...>::value;
  47. new(buffer) U(value);
  48. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  49. }
  50. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  51. void operator=(U&& value)
  52. {
  53. if(index != std::numeric_limits<std::size_t>::max())
  54. {
  55. dtor((void*)buffer);
  56. }
  57. index = r_index_of<U, T...>::value;
  58. new(buffer) U(std::move(value));
  59. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  60. }
  61. ~fixed_variant()
  62. {
  63. if(index != std::numeric_limits<std::size_t>::max())
  64. {
  65. dtor((void*)buffer);
  66. }
  67. }
  68. template<typename U>
  69. constexpr U& value()
  70. {
  71. if constexpr (gp_config::has_exceptions)
  72. {
  73. if(r_index_of<U, T...>::value != index)
  74. {
  75. throw bad_variant_access<U>{};
  76. }
  77. }
  78. return *reinterpret_cast<U*>(buffer);
  79. }
  80. template<typename U>
  81. constexpr U& is_a()
  82. {
  83. if(r_index_of<U, T...>::value == index)
  84. {
  85. return true;
  86. }
  87. else
  88. {
  89. return false;
  90. }
  91. }
  92. };
  93. /*template<typename allocator_t = gp_config::memory_module::default_allocator, typename ...T>
  94. class variant{
  95. std::size_t index = std::numeric_limits<std::size_t>::max();
  96. void* ptr;
  97. gp::function<void(void*)> dtor = [](void*){};
  98. allocator_t allocator;
  99. public:
  100. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  101. constexpr variant(U& value)
  102. : index{r_index_of<U, T...>::value}
  103. {
  104. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  105. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  106. }
  107. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  108. constexpr variant(U&& value)
  109. : index{r_index_of<U, T...>::value}
  110. {
  111. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  112. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  113. }
  114. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  115. void operator=(U& value)
  116. {
  117. if(index != std::numeric_limits<std::size_t>::max())
  118. {
  119. dtor(ptr);
  120. allocator.deallocate(ptr);
  121. }
  122. index = r_index_of<U, T...>::value;
  123. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  124. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  125. }
  126. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  127. void operator=(U&& value)
  128. {
  129. if(index != std::numeric_limits<std::size_t>::max())
  130. {
  131. dtor(ptr);
  132. allocator.deallocate(ptr);
  133. }
  134. index = r_index_of<U, T...>::value;
  135. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  136. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO: replace with delete(p, t)
  137. }
  138. ~variant()
  139. {
  140. if(index != std::numeric_limits<std::size_t>::max())
  141. {
  142. dtor(ptr);
  143. allocator.deallocate(ptr);
  144. }
  145. }
  146. template<typename U>
  147. constexpr U& value()
  148. {
  149. if constexpr (gp_config::has_exceptions)
  150. {
  151. if(r_index_of<U, T...>::value != index)
  152. {
  153. throw bad_variant_access<U>{};
  154. }
  155. }
  156. return *reinterpret_cast<U*>(ptr);
  157. }
  158. template<typename U>
  159. constexpr U& is_a()
  160. {
  161. if(r_index_of<U, T...>::value == index)
  162. {
  163. return true;
  164. }
  165. else
  166. {
  167. return false;
  168. }
  169. }
  170. };*/
  171. }