Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

421 lignes
13 KiB

  1. /*!
  2. * \file typelist.h
  3. * \brief A template parameter "container"
  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_pack_h__
  21. #define __utl_meta_pack_h__
  22. #include <utl/core/impl.h>
  23. #include <utl/meta/integral.h>
  24. #include <utl/meta/idx_sequence.h>
  25. #include <utl/meta/void.h>
  26. #include <utl/meta/invoke.h>
  27. #include <utl/meta/sfinae.h>
  28. /*!
  29. * \ingroup meta
  30. * \defgroup typelist
  31. */
  32. //! @{
  33. namespace utl {
  34. namespace meta {
  35. /*!
  36. * A class template that just holds a parameter pack.
  37. * The idea came from MPL's sequence concept[1] and from N4115[2].
  38. * In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
  39. * This way the name gives the feeling of a container and smells like Python.
  40. *
  41. * In addition to tuple we lack members, so typelist could serve as an empty base class,
  42. * and an object of the ultimate type could always be instantiated
  43. * (even if the parameter typelist contains void or some type that lacks
  44. * a default constructor).
  45. * ex:
  46. * using l1 = typelist<int, void*, double>;
  47. *
  48. * boost::hana[3] suggest a more powerful scheme were type invariant structures can be used
  49. * for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
  50. * responsibility that comse along). So a simple python-like list with some extra vector-like
  51. * element access functionalities and no iterators is good enough(for now).
  52. *
  53. * [1]: https://www.boost.org/doc/
  54. * [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
  55. * [3]: https://github.com/boostorg/hana
  56. */
  57. template <typename... Ts>
  58. struct typelist {
  59. using type = typelist; //!< act as identity
  60. //! \return sizeof...(Ts)
  61. static constexpr size_t size() noexcept {
  62. return sizeof...(Ts);
  63. }
  64. //! \return true if empty
  65. static constexpr bool empty() noexcept {
  66. return (sizeof...(Ts) == 0);
  67. }
  68. };
  69. /*!
  70. * An integral constant wrapper that is the size of the \c meta::typelist
  71. * Complexity \f$ O(1) \f$.
  72. * \param List A typelist
  73. * \return The size of the typelist
  74. */
  75. template <typename List>
  76. using size = size_t_<List::size()>;
  77. /*!
  78. * An Boolean constant wrapper that returns if the typelist is empty
  79. * Complexity \f$ O(1) \f$.
  80. * \param List A typelist
  81. * \return Empty or not
  82. */
  83. template <typename List>
  84. using empty = bool_<List::empty()>;
  85. //! pair
  86. //! A special typelist with only 2 Types
  87. //! @{
  88. template <typename T1, typename T2>
  89. using pair = typelist<T1, T2>;
  90. //! @}
  91. //! apply
  92. //! like:
  93. //! template <class F, class Tuple>
  94. //! constexpr decltype(auto) apply(F&& f, Tuple&& t);
  95. namespace detail {
  96. template <typename Fn, typename Param>
  97. struct apply_ { };
  98. // apply Param =Ret(Args...)
  99. template <typename Fn, typename Ret, typename... Args>
  100. struct apply_<Fn, Ret(Args...)>
  101. : invoke<Fn, Ret, Args...> { };
  102. // apply Param = F<Args...>
  103. template <typename Fn, template <typename...> class F, typename... Args>
  104. struct apply_<Fn, F<Args...>>
  105. : invoke<Fn, Args...> { };
  106. // apply Param = integer_sequence<T, Is...>
  107. template <typename Fn, typename T, T... Is>
  108. struct apply_<Fn, integer_sequence<T, Is...>>
  109. : invoke<Fn, integral_constant<T, Is>...> { };
  110. }
  111. //! Apply the Invocable \p Fn using the types in the type \p Param as arguments.
  112. template <typename Fn, typename Param>
  113. using apply = detail::apply_<Fn, Param>;
  114. //! @}
  115. /*
  116. * ========= typelist operations =========
  117. */
  118. //! fold<List, V, Fn>, rev_fold<List, V, Fn>
  119. //! @{
  120. namespace detail {
  121. // fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
  122. template<typename, typename, typename>
  123. struct fold_ { }; // ill formed
  124. // recursive call
  125. template<typename Head, typename... Tail,
  126. typename V,
  127. typename Fn>
  128. struct fold_<typelist<Head, Tail...>, V, Fn> {
  129. using type = type_<
  130. fold_<
  131. typelist<Tail...>,
  132. invoke<Fn, V, Head>,
  133. Fn
  134. >
  135. >;
  136. };
  137. // termination call
  138. template<typename V0, typename Fn>
  139. struct fold_<typelist<>, V0, Fn> {
  140. using type = V0;
  141. };
  142. // rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
  143. template<typename, typename, typename>
  144. struct rev_fold_ { }; // ill formed
  145. // recursive call
  146. template<typename Head, typename... Tail,
  147. typename V,
  148. typename Fn>
  149. struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
  150. using type = invoke <
  151. Fn, Head, type_<
  152. rev_fold_ <
  153. typelist<Tail...>,
  154. V,
  155. Fn
  156. >
  157. >
  158. >;
  159. };
  160. // termination call
  161. template<typename Tail, typename V, typename Fn>
  162. struct rev_fold_ <typelist<Tail>, V, Fn> {
  163. using type = invoke<Fn, Tail, V>;
  164. };
  165. // termination call
  166. template<typename V, typename Fn>
  167. struct rev_fold_ <typelist<>, V, Fn> {
  168. using type = invoke<Fn, V>;
  169. };
  170. }
  171. /*!
  172. * transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
  173. * and initial value \p V
  174. * Complexity \f$ O(N) \f$
  175. * \param List The list to fold
  176. * \param V The initial item feeded to Fn
  177. * \param Fn The binary Invocable
  178. */
  179. template <typename List, typename V, typename Fn>
  180. using fold = type_<detail::fold_<List, V, Fn>>;
  181. //! accumulate is an stl name for fold
  182. template <typename List, typename V, typename Fn>
  183. using accumulate = fold<List, V, Fn>;
  184. /*!
  185. * transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
  186. * and initial value \p V
  187. * Complexity \f$ O(N) \f$
  188. * \param List The list to fold
  189. * \param V The initial item feeded to Fn
  190. * \param Fn The binary Invocable
  191. */
  192. template <typename List, typename V, typename Fn>
  193. using rev_fold = type_<detail::rev_fold_<List, V, Fn>>;
  194. //! @}
  195. //! Concatenation
  196. //! @{
  197. namespace detail {
  198. template <typename... Lists>
  199. struct concat_ { };
  200. template <>
  201. struct concat_<> {
  202. using type = typelist<>;
  203. };
  204. template <typename... L1>
  205. struct concat_<typelist<L1...>> {
  206. using type = typelist<L1...>;
  207. };
  208. template <typename... L1, typename... L2>
  209. struct concat_<typelist<L1...>, typelist<L2...>> {
  210. using type = typelist<L1..., L2...>;
  211. };
  212. template <typename... L1, typename... L2, typename... L3>
  213. struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>> {
  214. using type = typelist<L1..., L2..., L3...>;
  215. };
  216. template <typename... L1, typename... L2, typename... L3, typename... Rest>
  217. struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, Rest...>
  218. : concat_<typelist<L1..., L2..., L3...>, Rest...> { };
  219. template <typename... L1, typename... L2,
  220. typename... L3, typename... L4,
  221. typename... Rest>
  222. struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, typelist<L4...>, Rest...>
  223. : concat_<typelist<L1..., L2..., L3..., L4...>, Rest...> { };
  224. }
  225. /*!
  226. * Transformation that concatenates several lists into a single typelist.
  227. * The parameters must all be instantiations of \c meta::typelist.
  228. * Complexity: \f$ O(L) \f$
  229. * where \f$ L \f$ is the number of lists in the typelist of lists.
  230. */
  231. template <typename... Lists>
  232. using concat = type_<detail::concat_<Lists...>>;
  233. //! @}
  234. //! Transform
  235. //! @{
  236. namespace detail {
  237. template <typename, typename = void>
  238. struct transform_ { };
  239. template <typename... Ts, typename Fn>
  240. struct transform_<typelist<typelist<Ts...>, Fn>, void_<invoke<Fn, Ts>...>> {
  241. using type = typelist<invoke<Fn, Ts>...>;
  242. };
  243. template <typename... Ts0, typename... Ts1, typename Fn>
  244. struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
  245. void_<invoke<Fn, Ts0, Ts1>...>> {
  246. using type = typelist<invoke<Fn, Ts0, Ts1>...>;
  247. };
  248. } // namespace detail
  249. /*!
  250. * Transform One or two lists with invocable \c Fn and return a new typelist
  251. * Syntax:
  252. * 1) transform<List..., Fn> Unary invocable
  253. * 2) transform<List1, List2, Fn> Binary invocable
  254. * Complexity \f$ O(N) \f$.
  255. */
  256. template <typename... Args>
  257. using transform = type_<detail::transform_<typelist<Args...>>>;
  258. //! @}
  259. //! repeat_n
  260. //! @{
  261. namespace detail {
  262. template <typename T, size_t>
  263. using first_ = T;
  264. template <typename T, typename Ints>
  265. struct repeat_n_c_ { };
  266. template <typename T, size_t... Is>
  267. struct repeat_n_c_<T, index_sequence<Is...>> {
  268. using type = typelist<first_<T, Is>...>;
  269. };
  270. }
  271. /*!
  272. * Generate typelist<T,T,T...T> of size \c N arguments.
  273. * Complexity \f$ O(log N) \f$.
  274. */
  275. template <index_t N, typename T = void>
  276. using repeat_n_c = type_<detail::repeat_n_c_<T, make_index_sequence<N>>>;
  277. /*!
  278. * Generate typelist<T,T,T...T> of size \c N::type::value arguments.
  279. * Complexity \f$ O(log N) \f$.
  280. */
  281. template <typename N, typename T = void>
  282. using repeat_n = repeat_n_c<N::type::value, T>;
  283. //! @}
  284. //! at
  285. //! @{
  286. namespace detail {
  287. template <typename VoidPtrs>
  288. struct at_impl_;
  289. template <typename... VoidPtrs>
  290. struct at_impl_<typelist<VoidPtrs...>> {
  291. static nil_ eval(...);
  292. template <typename T, typename... Us>
  293. static T eval(VoidPtrs..., T *, Us *...);
  294. };
  295. template <typename L, index_t N>
  296. struct at_ { };
  297. template <typename... Ts, index_t N>
  298. struct at_<typelist<Ts...>, N>
  299. : decltype(
  300. at_impl_<repeat_n_c<N, void *>>::eval(static_cast<identity<Ts> *>(nullptr)...)
  301. ) { };
  302. } // namespace detail
  303. /// Return the \p N th element in the \c meta::typelist \p L.
  304. /// Complexity \f$ O(1) \f$.
  305. template <typename L, index_t N>
  306. using at_c = type_<detail::at_<L, N>>;
  307. //! Return the \p N th element in the \c meta::typelist \p L.
  308. //! Complexity \f$ O(1) \f$.
  309. template <typename L, typename N>
  310. using at = at_c<L, N::type::value>;
  311. //!@}
  312. //! front
  313. //! @{
  314. namespace detail {
  315. template <typename L>
  316. struct front_ { };
  317. template <typename Head, typename... Tail>
  318. struct front_<typelist<Head, Tail...>> {
  319. using type = Head;
  320. };
  321. }
  322. //! Return the first element in \c meta::typelist \p L.
  323. //! Complexity \f$ O(1) \f$.
  324. template <typename L>
  325. using front = type_<detail::front_<L>>;
  326. //! @}
  327. //! back
  328. //! @{
  329. namespace detail {
  330. template <typename L>
  331. struct back_ { };
  332. template <typename Head, typename... Tail>
  333. struct back_<typelist<Head, Tail...>> {
  334. using type = at_c<typelist<Head, Tail...>, sizeof...(Tail)>;
  335. };
  336. }
  337. //! Return the last element in \c meta::typelist \p L.
  338. //! Complexity \f$ O(1) \f$.
  339. template <typename L>
  340. using back = type_<detail::back_<L>>;
  341. //! @}
  342. //! pop_front
  343. //! @{
  344. namespace detail {
  345. template <typename L>
  346. struct pop_front_ { };
  347. template <typename Head, typename... L>
  348. struct pop_front_<typelist<Head, L...>> {
  349. using type = typelist<L...>;
  350. };
  351. }
  352. /*!
  353. * Return a new \c meta::typelist by removing the first element from the
  354. * front of \p L.
  355. * Complexity \f$ O(1) \f$.
  356. */
  357. template <typename L>
  358. using pop_front = type_<detail::pop_front_<L>>;
  359. //! @}
  360. }}
  361. //! @}
  362. #endif /* __utl_meta_pack_h__ */