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.

305 lines
6.8 KiB

  1. #pragma once
  2. #include <type_traits>
  3. #include <typeinfo>
  4. #include <cstddef>
  5. #include <limits>
  6. #include "gp/algorithms/min_max.hpp"
  7. namespace gp{
  8. /**
  9. * @brief Picks either of the types depending on the condition
  10. *
  11. * @tparam cond the condition
  12. * @tparam T the type picked when the condition is true
  13. * @tparam U the type picked when the condition is false
  14. */
  15. template<bool cond, typename T, typename U>
  16. struct either
  17. {
  18. };
  19. template<typename T, typename U>
  20. struct either<true,T,U>
  21. {
  22. typedef T type;
  23. };
  24. template<typename T, typename U>
  25. struct either<false,T,U>
  26. {
  27. typedef U type;
  28. };
  29. /**
  30. * @brief Checks if the provided booleans are all true at compile time
  31. */
  32. template<bool first, bool ...list>
  33. struct constexpr_all_of
  34. {
  35. static constexpr bool value = first && constexpr_all_of<list...>::value;
  36. };
  37. template<bool first>
  38. struct constexpr_all_of<first>
  39. {
  40. static constexpr bool value = first;
  41. };
  42. /**
  43. * @brief Checks if at least one of the provided booleans is true at compile time
  44. */
  45. template<bool first, bool ...list>
  46. struct constexpr_any_of
  47. {
  48. static constexpr bool value = first || constexpr_any_of<list...>::value;
  49. };
  50. template<bool first>
  51. struct constexpr_any_of<first>
  52. {
  53. static constexpr bool value = first;
  54. };
  55. /**
  56. * @brief Checks if the provided type has a compile time defined size
  57. *
  58. * @tparam T the tested type
  59. * @return true if it has a defined size
  60. * @return false if its size may change due to inheritance or other factors
  61. */
  62. template<typename T>
  63. constexpr bool is_fixed_size()
  64. {
  65. return std::is_final<T>::value
  66. || std::is_fundamental<T>::value;
  67. }
  68. /**
  69. * @brief Checks if the provided typelist is all of fixed size
  70. */
  71. template<typename T, typename ...rest>
  72. struct all_of_fixed_size
  73. {
  74. static constexpr bool value = is_fixed_size<T>() && all_of_fixed_size<rest...>::value;
  75. };
  76. template<typename T>
  77. struct all_of_fixed_size<T>
  78. {
  79. static constexpr bool value = is_fixed_size<T>();
  80. };
  81. /**
  82. * @brief Checks if the provided list contains the provided class
  83. *
  84. * @tparam Univ the class to look for
  85. */
  86. template<typename Univ, typename T, typename ...rest>
  87. struct list_contains_class
  88. {
  89. static constexpr bool value = (
  90. std::is_same<T, Univ>::value
  91. ) || list_contains_class<Univ, rest...>::value;
  92. };
  93. template<typename Univ, typename T>
  94. struct list_contains_class<Univ, T>
  95. {
  96. static constexpr bool value = std::is_same<T, Univ>::value;
  97. };
  98. /**
  99. * @brief gives the index of Univ from the end of the argument list
  100. *
  101. * @tparam Univ The type to look for
  102. */
  103. template<typename Univ, typename T, typename ...rest>
  104. struct r_index_of
  105. {
  106. static constexpr std::size_t value = std::is_same<T, Univ>::value ? sizeof...(rest) : r_index_of<Univ, rest...>::value;
  107. };
  108. template<typename Univ, typename T>
  109. struct r_index_of<Univ, T>
  110. {
  111. static constexpr std::size_t value = std::is_same<T, Univ>::value ? 0 : std::numeric_limits<std::size_t>::max();
  112. };
  113. /**
  114. * @brief gives the type of the idx value from the end of the argument list
  115. *
  116. * @tparam idx The index to return the type of
  117. */
  118. template<size_t idx, typename T, typename ...rest>
  119. struct r_index_at
  120. {
  121. using type =
  122. typename either<
  123. idx==sizeof...(rest),
  124. T,
  125. typename r_index_at<idx,rest...>::type
  126. >::type;
  127. };
  128. /**
  129. * @brief extracts the first type of the list
  130. */
  131. template<typename U, typename ...rest>
  132. struct first_of {
  133. using type = U;
  134. };
  135. /**
  136. * @brief gives the size of the largest element in the provided list
  137. *
  138. * @return constexpr std::size_t equal to the largest size of all
  139. */
  140. template<typename T, typename U, typename ...rest>
  141. constexpr std::size_t max_size()
  142. {
  143. if constexpr (sizeof...(rest) == 0)
  144. {
  145. return gp::max(sizeof(T),sizeof(U));
  146. }
  147. else
  148. {
  149. return max_size<
  150. typename either<
  151. ( sizeof(T) > sizeof(U) ),
  152. T,
  153. U
  154. >::type,
  155. rest...>();
  156. }
  157. }
  158. /**
  159. * @brief remove reference state from the provided type
  160. */
  161. template<typename T>
  162. struct remove_reference
  163. {
  164. using type = T;
  165. };
  166. template<typename T>
  167. struct remove_reference<T&>
  168. {
  169. using type = T;
  170. };
  171. template<typename T>
  172. struct remove_reference<T&&>
  173. {
  174. using type = T;
  175. };
  176. /**
  177. * @brief Has a value of true if the provided type has a size() function member
  178. */
  179. template<typename T>
  180. struct has_size_interface
  181. {
  182. private:
  183. typedef std::true_type yes;
  184. typedef std::false_type no;
  185. template<typename U, size_t (U::*f)() const> struct SFINAE{};
  186. template<class C> static yes test(SFINAE<C,&C::size>*);
  187. template<class C> static no test(...);
  188. public:
  189. static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
  190. };
  191. /**
  192. * @brief Has a value of true if the provided type has a begin() function member
  193. */
  194. template<typename T>
  195. struct has_begin_interface
  196. {
  197. private:
  198. typedef std::true_type yes;
  199. typedef std::false_type no;
  200. template<typename U, auto (U::*f)() const> struct SFINAE{};
  201. template<class C> static yes test(SFINAE<C,&C::begin>*);
  202. template<class C> static no test(...);
  203. public:
  204. static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
  205. };
  206. /**
  207. * @brief Has a value of true if the provided type has a end() function member
  208. */
  209. template<typename T>
  210. struct has_end_interface
  211. {
  212. private:
  213. typedef std::true_type yes;
  214. typedef std::false_type no;
  215. template<typename U, auto (U::*f)() const> struct SFINAE{};
  216. template<class C> static yes test(SFINAE<C,&C::end>*);
  217. template<class C> static no test(...);
  218. public:
  219. static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
  220. };
  221. // TODO: Replace those with concepts
  222. template<typename T>
  223. using has_range_interface = constexpr_all_of<has_begin_interface<T>::value,has_end_interface<T>::value>;
  224. template<typename T>
  225. using has_measurable_range_interface = constexpr_all_of<has_range_interface<T>::value,has_size_interface<T>::value>;
  226. template<typename T>
  227. struct has_allocate_interface
  228. {
  229. private:
  230. typedef std::true_type yes;
  231. typedef std::false_type no;
  232. template<typename U, void* (U::*f)(size_t)> struct SFINAE{};
  233. template<class C> static yes test(SFINAE<C,&C::allocate>*);
  234. template<class C> static no test(...);
  235. public:
  236. static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
  237. };
  238. template<typename T>
  239. struct has_deallocate_interface
  240. {
  241. private:
  242. typedef std::true_type yes;
  243. typedef std::false_type no;
  244. template<typename U, bool (U::*f)(void*)> struct SFINAE{};
  245. template<class C> static yes test(SFINAE<C,&C::deallocate>*);
  246. template<class C> static no test(...);
  247. public:
  248. static constexpr bool value = std::is_same<yes,decltype(test<T>(nullptr))>::value;
  249. };
  250. template<typename T>
  251. using has_allocator_interface = constexpr_all_of<has_allocate_interface<T>::value,has_deallocate_interface<T>::value>;
  252. }