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/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__ */