General Purpose library for Freestanding C++ and POSIX systems
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

180 wiersze
4.5 KiB

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