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.

184 lines
4.6 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*), dummy_allocator> 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*), dummy_allocator>([](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*), dummy_allocator>([](void* thing){((U*)thing)->~U();});
  31. }
  32. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  33. void operator=(U& value)
  34. {
  35. if(index != std::numeric_limits<std::size_t>::max())
  36. {
  37. dtor((void*)buffer);
  38. }
  39. index = r_index_of<U, T...>::value;
  40. new(buffer) U(value);
  41. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  42. }
  43. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  44. void operator=(U&& value)
  45. {
  46. if(index != std::numeric_limits<std::size_t>::max())
  47. {
  48. dtor((void*)buffer);
  49. }
  50. index = r_index_of<U, T...>::value;
  51. new(buffer) U(std::move(value));
  52. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  53. }
  54. ~fixed_variant()
  55. {
  56. if(index != std::numeric_limits<std::size_t>::max())
  57. {
  58. dtor((void*)buffer);
  59. }
  60. }
  61. template<typename U>
  62. constexpr U& value()
  63. {
  64. if constexpr (gp_config::has_exceptions)
  65. {
  66. if(r_index_of<U, T...>::value != index)
  67. {
  68. throw bad_variant_access<U>{};
  69. }
  70. }
  71. return *reinterpret_cast<U*>(buffer);
  72. }
  73. template<typename U>
  74. constexpr U& is_a()
  75. {
  76. if(r_index_of<U, T...>::value == index)
  77. {
  78. return true;
  79. }
  80. else
  81. {
  82. return false;
  83. }
  84. }
  85. };
  86. /*template<typename allocator_t = gp_config::memory_module::default_allocator, typename ...T>
  87. class variant{
  88. std::size_t index = std::numeric_limits<std::size_t>::max();
  89. void* ptr;
  90. gp::function<void(void*)> dtor = [](void*){};
  91. allocator_t allocator;
  92. public:
  93. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  94. constexpr variant(U& value)
  95. : index{r_index_of<U, T...>::value}
  96. {
  97. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  98. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  99. }
  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(std::move(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. void operator=(U& value)
  109. {
  110. if(index != std::numeric_limits<std::size_t>::max())
  111. {
  112. dtor(ptr);
  113. allocator.deallocate(ptr);
  114. }
  115. index = r_index_of<U, T...>::value;
  116. ptr = (void*)new(allocator.allocate(sizeof(U))) U(value);
  117. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO:replae with delete(p,t)
  118. }
  119. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  120. void operator=(U&& value)
  121. {
  122. if(index != std::numeric_limits<std::size_t>::max())
  123. {
  124. dtor(ptr);
  125. allocator.deallocate(ptr);
  126. }
  127. index = r_index_of<U, T...>::value;
  128. ptr = (void*)new(allocator.allocate(sizeof(U))) U(std::move(value));
  129. dtor = gp::function([](void* thing){((U*)thing)->~U();}); // TODO: replace with delete(p, t)
  130. }
  131. ~variant()
  132. {
  133. if(index != std::numeric_limits<std::size_t>::max())
  134. {
  135. dtor(ptr);
  136. allocator.deallocate(ptr);
  137. }
  138. }
  139. template<typename U>
  140. constexpr U& value()
  141. {
  142. if constexpr (gp_config::has_exceptions)
  143. {
  144. if(r_index_of<U, T...>::value != index)
  145. {
  146. throw bad_variant_access<U>{};
  147. }
  148. }
  149. return *reinterpret_cast<U*>(ptr);
  150. }
  151. template<typename U>
  152. constexpr U& is_a()
  153. {
  154. if(r_index_of<U, T...>::value == index)
  155. {
  156. return true;
  157. }
  158. else
  159. {
  160. return false;
  161. }
  162. }
  163. };*/
  164. }