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.
 
 
 
 

247 lines
7.8 KiB

  1. /*!
  2. * \file utility.h
  3. * \brief Template meta-programming utilities
  4. *
  5. * Copyright (C) 2018 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #ifndef __utl_meta_utility_h__
  21. #define __utl_meta_utility_h__
  22. #include <utl/core/impl.h>
  23. #include <utl/meta/integral.h>
  24. #include <utl/meta/void.h>
  25. #include <utl/meta/selection.h>
  26. /*!
  27. * \ingroup meta
  28. * \defgroup utility
  29. *
  30. */
  31. //! @{
  32. namespace utl {
  33. namespace meta{
  34. /*!
  35. *
  36. * \name invoke
  37. * All Metafunction classes shall contain apply, which is Metafunction
  38. *
  39. * Metafunction:
  40. * A metafunction is a class or a class template that represents a function invocable at compile-time.
  41. * An non-nullary metafunction is invoked by instantiating the class template with particular template
  42. * parameters (metafunction arguments). The result of the metafunction application is accessible
  43. * through the instantiation's nested type typedef.
  44. * All metafunction's arguments must be types (i.e. only type template parameters are allowed).
  45. * A metafunction can have a variable number of parameters.
  46. * A nullary metafunction is represented as a (template) class with a nested type typename member.
  47. *
  48. * Metafunction Class:
  49. * A metafunction class is a certain form of metafunction representation that enables higher-order
  50. * metaprogramming. More precisely, it's a class with a publicly-accessible nested Metafunction called
  51. * apply. Correspondingly, a metafunction class invocation is defined as invocation of its nested apply
  52. * metafunction.
  53. *
  54. * Concept here is `Invokable` (contains apply metafunction)
  55. */
  56. //! @{
  57. /*!
  58. * *invocable* identity, identity_t.
  59. */
  60. //! @{
  61. template <typename _Tp>
  62. struct identity {
  63. #if defined (UTL_WORKAROUND_CWG_1558)
  64. // decltype via use_() using Ts... to set the apply type
  65. template <typename... Ts>
  66. using _dummy = void_t<Ts...>;
  67. using apply = _Tp; //!< identity is invokable, must also have apply
  68. #else
  69. template <typename...>
  70. using apply = _Tp; //!< identity is invokable, must also have apply
  71. #endif
  72. using type = _Tp; //!< identity
  73. };
  74. //! identity type alias
  75. template <typename _Tp>
  76. using identity_t = type_<identity<_Tp>>;
  77. //! @}
  78. //! Is evaluable trait
  79. //! @{
  80. namespace detail {
  81. // we check for template \p F to be a metafunction with parameters \p T
  82. template<template<typename...> class F, typename... T>
  83. struct is_evaluable_ {
  84. template<template<typename...> class G, typename = G<T...>>
  85. static true_ check (int);
  86. template<template<typename...> class>
  87. static false_ check (...);
  88. using type = decltype(check<F>(0));
  89. };
  90. // we check for template \p F with integral constant parameters \p Is of type \p T
  91. // template<typename T, template <T...> class F, T... Is>
  92. // struct is_evaluable_i_ {
  93. // template<typename TT, template <TT...> class G, class = G<Is...>>
  94. // static true_ check (int);
  95. // template<typename, template<typename...> class>
  96. // static false_ check (...);
  97. //
  98. // using type = decltype(check<T, F>(0));
  99. // };
  100. }
  101. template<template<typename...> class F, typename... T>
  102. using is_evaluable = type_<
  103. detail::is_evaluable_<F, T...>
  104. >;
  105. // template <typename T, template<T...> class F, T... Is>
  106. // using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>;
  107. //! @}
  108. //! defer
  109. //! @{
  110. namespace detail {
  111. //! @{
  112. template<template<typename...> class F, typename... Ts>
  113. struct defer_ {
  114. using type = F<Ts...>;
  115. };
  116. // template<typename T, template<T...> class F, T... Is>
  117. // struct defer_i_ {
  118. // using type = F<Is...>;
  119. // };
  120. //!
  121. //! We use struct instead of:
  122. //! template<template<typename...> class F, typename... Ts>
  123. //! using defer_ = F<Ts...>;
  124. //!
  125. //! The use of struct here is due to Core issue 1430 [1] and is used
  126. //! as suggested by Roy Crihfield in [2].
  127. //! In short, this is due to language's inability to expand Ts... into
  128. //! a fixed parameter list of an alias template.
  129. //!
  130. //! [1]: https://wg21.link/cwg1430
  131. //! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
  132. //! @}
  133. }
  134. //! defer alias template for F<Ts...>
  135. template<template<class...> class F, class... Ts>
  136. using defer = if_<
  137. is_evaluable<F, Ts...>,
  138. detail::defer_<F, Ts...>,
  139. nil_
  140. >;
  141. //! defer_i alias template for F<T, Is...>
  142. // template <typename T, template<T...> class F, T... Is>
  143. // using defer_i = if_ <
  144. // is_evaluable_i<T, F<Is...>>,
  145. // detail::defer_i_<F, Is...>,
  146. // nil_
  147. // >;
  148. //! @}
  149. /*!
  150. * quote is a higher-order primitive that wraps an n-ary Metafunction
  151. * to create a corresponding Metafunction Class (Invocable).
  152. */
  153. template <template <typename...> class F>
  154. struct quote {
  155. template <typename... Args>
  156. using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430
  157. };
  158. //! Wrap a template \p F taking literals of type \p T into an Invokable
  159. // template <typename T, template <T...> class F>
  160. // struct quote_i {
  161. // // requires meta::Integral
  162. // template <typename... Is>
  163. // using apply = type_<
  164. // defer_i<T, F, Is...> //!< defer here to avoid DR1430
  165. // >;
  166. // };
  167. /*!
  168. * Invoke the nested apply metafunction from \c Fn
  169. * with the arguments \c Args.
  170. * requires Invocable(Fn)
  171. */
  172. template <typename Fn, typename... Args>
  173. using invoke = typename Fn::template apply<Args...>;
  174. //! compose
  175. //! @{
  176. namespace detail {
  177. template<typename ...Fns> struct compose_ { };
  178. // recursive call to all invokes
  179. template<typename Fn0, typename ...Fns>
  180. struct compose_<Fn0, Fns...> {
  181. template <typename ...Args>
  182. using apply = invoke<
  183. Fn0,
  184. invoke<compose_<Fns...>, Args...>
  185. >;
  186. };
  187. // Termination specialization, finally pass the arguments
  188. template<typename Fn0>
  189. struct compose_<Fn0> {
  190. template <typename... Args>
  191. using apply = invoke<Fn0, Args...>;
  192. };
  193. }
  194. /*!
  195. * Create an invokable from other invokables by composition
  196. * ex:
  197. * compose<Fns...> will result to something like F0<F1<F2<F3<...>>>>
  198. */
  199. template <typename... Fns>
  200. using compose = detail::compose_<Fns...>;
  201. //! @}
  202. //! Applies the Invocable \p Fn by binding the arguments \p Ts
  203. //! to the \e front of \p Fn.
  204. template<typename Fn, typename... Ts>
  205. struct bind_front {
  206. template<typename... Us>
  207. using apply = invoke<Fn, Ts..., Us...>;
  208. };
  209. //! Applies the Invocable \p Fn by binding the arguments \p Ts
  210. //! to the \e back of \p Fn.
  211. template<typename Fn, typename... Ts>
  212. struct bind_back {
  213. template<typename... Us>
  214. using apply = invoke<Fn, Us..., Ts...>;
  215. };
  216. //! @}
  217. }}
  218. //! @}
  219. #endif /* __utl_meta_utility_h__ */