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.
 
 
 
 

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