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.

181 wiersze
4.6 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 Enable, typename ...T>
  11. class variant;
  12. template<typename ...T>
  13. class variant<typename std::enable_if<!gp_config::memory_module::is_ok && all_of_fixed_size<T...>::value,int>::type, T...>{
  14. std::size_t index = std::numeric_limits<std::size_t>::max();
  15. char buffer[max_size<T...>];
  16. gp::function<void(void*)> dtor = [](void*){};
  17. public:
  18. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  19. constexpr variant(U& value)
  20. : index{r_index_of<U, T...>::value}
  21. {
  22. new(buffer) U(value);
  23. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  24. }
  25. template<typename U, typename std::enable_if<list_contains_class<U,T...>::value,int>::type>
  26. constexpr variant(U&& value)
  27. : index{r_index_of<U, T...>::value}
  28. {
  29. new(buffer) U(std::move(value));
  30. dtor = gp::function([](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. ~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 ...T>
  87. class variant<typename std::enable_if<gp_config::memory_module::is_ok,default_memory_allocator<>>::type, T...>{
  88. std::size_t index = std::numeric_limits<std::size_t>::max();
  89. void* ptr;
  90. gp::function<void(void*)> dtor = [](void*){};
  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(default_memory_allocator<>{}.allocate(sizeof(U))) U(value);
  97. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  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(default_memory_allocator<>{}.allocate(sizeof(U))) U(std::move(value));
  104. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  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. default_memory_allocator<>{}.deallocate(ptr);
  113. }
  114. index = r_index_of<U, T...>::value;
  115. ptr = (void*)new(default_memory_allocator<>{}.allocate(sizeof(U))) U(value);
  116. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  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. default_memory_allocator<>{}.deallocate(ptr);
  125. }
  126. index = r_index_of<U, T...>::value;
  127. ptr = (void*)new(default_memory_allocator<>{}.allocate(sizeof(U))) U(std::move(value));
  128. dtor = gp::function([](void* thing){((U*)thing)->~U();});
  129. }
  130. ~variant()
  131. {
  132. if(index != std::numeric_limits<std::size_t>::max())
  133. {
  134. dtor(ptr);
  135. default_memory_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. }