Micro template library A library for building device drivers
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.
 
 
 
 

416 lines
12 KiB

  1. /*!
  2. * \file utl/meta/basic.h
  3. * \brief Template meta-programming basic definitions
  4. */
  5. #ifndef __utl_meta_basic_h__
  6. #define __utl_meta_basic_h__
  7. #include <utl/core/impl.h>
  8. #include <type_traits>
  9. #include <utility>
  10. /*!
  11. * \ingroup meta
  12. * \defgroup basic Basic
  13. * Basic definitions
  14. */
  15. //! @{
  16. /*!
  17. * \ingroup basic
  18. * \defgroup meta_core Core
  19. * Core definitions
  20. */
  21. //! @{
  22. namespace utl {
  23. namespace meta {
  24. /*!
  25. * \brief meta's empty type
  26. *
  27. * utl::meta's nil type is not pure nil. It's a recursive "de-referencable nil.
  28. * Each time someone applies \c \::type to it, he gets back nil_. This way we can prevent
  29. * a lot of compilation errors in a wrong meta:: handling.
  30. */
  31. struct nil_ {
  32. using type = nil_;
  33. };
  34. //! Type alias for \c Tp::type.
  35. //! Is used to evaluate/extract return type of metafunctions
  36. //! \tparam Tp The metafunction to evaluate
  37. //! \return The inner \::type
  38. template <typename Tp>
  39. using eval = typename Tp::type;
  40. //! Type alias for \c Tp::type::value.
  41. //! Is used to evaluate/extract return value of metafunctions
  42. //! \tparam Tp The metafunction to evaluate
  43. //! \return The inner \::type::value
  44. template <typename Tp>
  45. using eval_v = typename eval<Tp>::value;
  46. //!
  47. //! integral_ is a holder class for a compile-time value of an integral type.
  48. //!
  49. //! Every Integral Constant is also a null-ary Metafunction, returning itself.\n
  50. //! An integral constant object is implicitly convertible to the corresponding
  51. //! run-time value of the wrapped integral type
  52. template <typename Tp, Tp v>
  53. using integral_ = std::integral_constant<Tp, v>;
  54. //! \name Wrappers for basic types
  55. //! @{
  56. //! bool_ type: integral constant wrapper for bool
  57. template<bool v>
  58. using bool_ = integral_<bool, v>;
  59. using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value.
  60. using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value.
  61. //! int8_ type: integral constant wrapper for \c int8_t
  62. template<int8_t v>
  63. using int8_ = integral_<int8_t, v>;
  64. //! uint8_ type: integral constant wrapper for \c uint8_t
  65. template<uint8_t v>
  66. using uint8_ = integral_<uint8_t, v>;
  67. //! int16_ type: integral constant wrapper for \c int16_t
  68. template<int16_t v>
  69. using int16_ = integral_<int16_t, v>;
  70. //! uint16_ type: integral constant wrapper for \c uint16_t
  71. template<uint16_t v>
  72. using uint16_ = integral_<uint16_t, v>;
  73. //! int32_ type: integral constant wrapper for \c int32_t
  74. template<int32_t v>
  75. using int32_ = integral_<int32_t, v>;
  76. //! uint32_ type: integral constant wrapper for \c uint32_t
  77. template<uint32_t v>
  78. using uint32_ = integral_<uint32_t, v>;
  79. //! char_ type: integral constant wrapper for \c char
  80. template<char v>
  81. using char_ = integral_<char, v>;
  82. //! int_ type: integral constant wrapper for \c int
  83. template<int v>
  84. using int_ = integral_<int, v>;
  85. //! long_ type: integral constant wrapper for \c long
  86. template<long v>
  87. using long_ = integral_<long, v>;
  88. //! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t
  89. template<index_t v>
  90. using index_ = integral_<index_t, v>;
  91. //! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t
  92. template<size_t v>
  93. using size_ = integral_<size_t, v>;
  94. //! The last position we can express for indexing
  95. using Npos = size_<index_t(-1)>;
  96. //! @}
  97. //! \name unevaluated expressions
  98. //! @{
  99. //! Computes the size of the type \p Tp.
  100. //! Complexity \f$ O(1) \f$.
  101. template <typename Tp>
  102. using sizeof_ = size_<sizeof(Tp)>;
  103. //! Computes the alignment required for any instance of the type \p Tp.
  104. //! Complexity \f$ O(1) \f$.
  105. template <typename Tp>
  106. using alignof_ = size_<alignof(Tp)>;
  107. //! @}
  108. //! \name integer sequence
  109. //! @{
  110. template< class Tp, Tp... Ints >
  111. using integer_sequence = std::integer_sequence<Tp, Ints...>;
  112. template<typename Tp, Tp Num>
  113. using make_integer_sequence = std::make_integer_sequence<Tp, Num>;
  114. //! Alias template index_sequence
  115. template<index_t... Idx>
  116. using index_sequence = integer_sequence<index_t, Idx...>;
  117. //! Alias template make_index_sequence
  118. template<index_t Num>
  119. using make_index_sequence = make_integer_sequence <index_t, Num>;
  120. //! Alias template index_sequence_for
  121. template<typename... Types>
  122. using index_sequence_for = make_index_sequence<sizeof...(Types)>;
  123. //! @}
  124. }}
  125. //!@}
  126. /*!
  127. * \ingroup basic
  128. * \defgroup selection Selection
  129. * Type selection support header
  130. */
  131. //! @{
  132. namespace utl {
  133. namespace meta{
  134. //! \name if implementation
  135. //! @{
  136. namespace details {
  137. template <bool If, typename...>
  138. struct if_c_ {
  139. using type = nil_; //< avoid ill formed result
  140. };
  141. template<typename Then>
  142. struct if_c_<true, Then> {
  143. using type = Then;
  144. };
  145. template<typename Then, typename Else>
  146. struct if_c_<true, Then, Else> {
  147. using type = Then;
  148. };
  149. template<typename Then, typename Else>
  150. struct if_c_<false, Then, Else> {
  151. using type = Else;
  152. };
  153. }
  154. //! Select one type or another depending on a compile-time Boolean.
  155. template <bool B, typename... Args>
  156. using if_c = eval<details::if_c_<B, Args...>>;
  157. //! Select one type or another depending on a compile-time Boolean type
  158. template <typename If, typename... Args>
  159. using if_ = if_c<If::type::value, Args...>;
  160. //! @}
  161. /*!
  162. * \name Named type selectors
  163. */
  164. //! @{
  165. //! Select the first type of a type sequence
  166. template <typename T1, typename ...> using first_of = T1;
  167. //! Select the second type of a type sequence
  168. template <typename T1, typename T2, typename ...> using second_of = T2;
  169. //! @}
  170. }}
  171. //! @}
  172. /*!
  173. * \ingroup basic
  174. * \defgroup logic_operations Logic Operations
  175. * logic operators and type relations support
  176. */
  177. //! @{
  178. namespace utl {
  179. namespace meta{
  180. /*!
  181. * \name Logical relation for types
  182. */
  183. //! @{
  184. //! Negate the *bool* constant parameter and return bool_
  185. template <bool B>
  186. using not_c = bool_<!B>;
  187. //! negate the bool_ parameter and return bool_
  188. template<typename Tp>
  189. using not_ = not_c<Tp::type::value>;
  190. //! \name OR implementation
  191. //! @{
  192. namespace details {
  193. template<typename...> struct _or_;
  194. template<>
  195. struct _or_<> : false_ { };
  196. template<typename T1>
  197. struct _or_<T1> : T1 { };
  198. template<typename T1, typename T2>
  199. struct _or_ <T1, T2>
  200. : if_<T1, T1, T2> { };
  201. template<typename T1, typename T2, typename T3, typename... Tn>
  202. struct _or_<T1, T2, T3, Tn...>
  203. : if_<T1, T1, _or_<T2, T3, Tn...>> { };
  204. }
  205. //! Operator or for bool_ types
  206. //! \tparam Ts Variadic args of type bool_
  207. //! \return Logical or as bool_
  208. template <typename... Ts>
  209. using or_ = eval<details::_or_<Ts...>>;
  210. //! @}
  211. //! \name AND implementation
  212. //! @{
  213. namespace details {
  214. template<typename...> struct _and_;
  215. template<>
  216. struct _and_<>
  217. : true_ { };
  218. template<typename T1>
  219. struct _and_ <T1>
  220. : T1 { };
  221. template<typename T1, typename T2>
  222. struct _and_<T1, T2>
  223. : if_<T1, T2, T1> { };
  224. template<typename T1, typename T2, typename T3, typename... Tn>
  225. struct _and_<T1, T2, T3, Tn...>
  226. : if_<T1, _and_<T2, T3, Tn...>, T1> { };
  227. }
  228. //! Operator and for bool_ types
  229. //! \tparam Ts Variadic args of type bool_
  230. //! \return Logical and as bool_
  231. template <typename... Ts>
  232. using and_ = eval<details::_and_<Ts...>>;
  233. //! @}
  234. //! \name same
  235. //! @{
  236. template<typename T1, typename T2>
  237. struct same_ : false_ { };
  238. template<typename Tp>
  239. struct same_ <Tp, Tp> : true_ { };
  240. template<typename T1, typename T2>
  241. using not_same_ = not_<eval<same_<T1, T2>>>;
  242. //! @}
  243. //! @}
  244. }}
  245. //! @}
  246. /*!
  247. * \ingroup basic
  248. * \defgroup integral_operators integral operators
  249. * Type arithmetic and operations
  250. */
  251. //! @{
  252. namespace utl {
  253. namespace meta {
  254. /*!
  255. * \name Math operations
  256. */
  257. //! @{
  258. //! Negation
  259. template <typename Tp>
  260. using negate = integral_<decltype(-Tp()), -Tp()>;
  261. //! Addition
  262. template <typename Tp1, typename Tp2>
  263. using add = integral_<
  264. decltype(Tp1() + Tp2()),
  265. Tp1() + Tp2()
  266. >;
  267. //! Multiplication
  268. template <typename Tp1, typename Tp2>
  269. using mult = integral_<
  270. decltype(Tp2() * Tp2()),
  271. Tp1() * Tp2()
  272. >;
  273. //! Division
  274. template <typename Tp1, typename Tp2>
  275. using divide = integral_<
  276. decltype(Tp2() / Tp2()),
  277. Tp1() / Tp2()
  278. >;
  279. //! Modulo
  280. template <typename Tp1, typename Tp2>
  281. using modulo = integral_<
  282. decltype(Tp1() % Tp2()),
  283. Tp1() % Tp2()
  284. >;
  285. //! Substruction
  286. template <typename Tp1, typename Tp2>
  287. using sub = add<Tp1, negate<Tp2>>;
  288. //! Increase
  289. template <typename Tp>
  290. using inc = add<Tp, int_<1>>;
  291. //! decrease
  292. template <typename Tp>
  293. using dec = add<Tp, int_<-1>>;
  294. //! @}
  295. /*!
  296. * \name Comparison operations
  297. */
  298. //! @{
  299. //! \return a true-valued Integral Constant if Tp1 and Tp2 are equal.
  300. template <typename Tp1, typename Tp2> using comp_eq = bool_<Tp1() == Tp2()>;
  301. //! \return a true-valued Integral Constant if Tp1 is less than Tp2.
  302. template <typename Tp1, typename Tp2> using comp_lt = bool_<(Tp1() < Tp2())>;
  303. //! Not equal
  304. template <typename Tp1, typename Tp2> using comp_ne = not_<comp_eq<Tp1, Tp2>>;
  305. //! Greater than
  306. template <typename Tp1, typename Tp2> using comp_gt = comp_lt <Tp2, Tp1>;
  307. //! Less or equal
  308. template <typename Tp1, typename Tp2> using comp_le = not_<comp_lt<Tp2, Tp1>>;
  309. //! Greater or equal
  310. template <typename Tp1, typename Tp2> using comp_ge = not_<comp_lt<Tp1, Tp2>>;
  311. //! @}
  312. /*!
  313. * \name Bitwise operations
  314. */
  315. //! @{
  316. //! \return bitwise not (~) operation of its argument.
  317. template <typename T> using bitnot_ = integral_<typename T::value_type, (typename T::value_type)(~T())>;
  318. //! \return bitwise and (&) operation of its arguments
  319. template <typename Tp1, typename Tp2>
  320. using bitand_ = integral_<decltype(Tp1() & Tp2()), Tp1() & Tp2()>;
  321. //! \return bitwise or (|) operation of its arguments.
  322. template <typename Tp1, typename Tp2>
  323. using bitor_ = integral_<decltype(Tp1() | Tp2()), Tp1() | Tp2()>;
  324. //! \return bitwise xor (^) operation of its arguments.
  325. template <typename Tp1, typename Tp2>
  326. using bitxor_ = integral_<decltype(Tp1() ^ Tp2()), Tp1() ^ Tp2()>;
  327. //! \return the result of bitwise shift left (<<) operation on Tp.
  328. template <typename Tp, typename shift>
  329. using shift_left = integral_<typename Tp::value_type, (typename Tp::value_type)(Tp() << shift())>;
  330. //! \return the result of bitwise shift right (>>) operation on Tp.
  331. template <typename Tp, typename shift>
  332. using shift_right = integral_<typename Tp::value_type, (typename Tp::value_type)(Tp() >> shift())>;
  333. //! @}
  334. }}
  335. //! @}
  336. //! @}
  337. #endif /* __utl_meta_basic_h__ */