tuple-list.H 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file tuple-list.H
  3. /// @brief Using tuples as compile time lists.
  4. // (c) Daniel Llorens - 2005-2013, 2016, 2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU Lesser General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. /// The convention here is that the alias xxx<...> is user facing and xxx_<...>::type is
  10. /// implementation. Ideally we have only the alias.
  11. #pragma once
  12. #include "ra/macros.H"
  13. #include <tuple>
  14. #include <limits>
  15. namespace mp {
  16. template <int V> using int_t = std::integral_constant<int, V>;
  17. template <bool V> using bool_t = std::integral_constant<bool, V>;
  18. using std::tuple;
  19. using nil = tuple<>;
  20. template <class T> constexpr bool nilp = std::is_same_v<nil, T>;
  21. template <class A> constexpr int len = std::tuple_size_v<A>;
  22. template <int ... I> using int_list = tuple<int_t<I> ...>; // shortcut for std::integer_sequence<int, I ...>
  23. template <class T> struct is_tuple { constexpr static bool value = false; };
  24. template <class ... A> struct is_tuple<tuple<A ...>> { constexpr static bool value = true; };
  25. template <class T> constexpr bool is_tuple_v = is_tuple<T>::value;
  26. template <class A, class B> struct cons_ { static_assert(is_tuple_v<B>); };
  27. template <class A0, class ... A> struct cons_<A0, tuple<A ...>> { using type = tuple<A0, A ...>; };
  28. template <class A, class B> using cons = typename cons_<A, B>::type;
  29. template <class A, class B> struct append_ { static_assert(is_tuple_v<A> && is_tuple_v<B>); };
  30. template <class ... A, class ... B> struct append_<tuple<A ...>, tuple<B ...>> { using type = tuple<A ..., B ...>; };
  31. template <class A, class B> using append = typename append_<A, B>::type;
  32. template <class A, class B> struct zip_ { static_assert(is_tuple_v<A> && is_tuple_v<B>); };
  33. template <class ... A, class ... B> struct zip_<tuple<A ...>, tuple<B ...>> { using type = tuple<tuple<A, B> ...>; };
  34. template <class A, class B> using zip = typename zip_<A, B>::type;
  35. template <int n, int o=0, int s=1> struct iota_ { static_assert(n>0); using type = cons<int_t<o>, typename iota_<n-1, o+s, s>::type>; };
  36. template <int o, int s> struct iota_<0, o, s> { using type = nil; };
  37. template <int n, int o=0, int s=1> using iota = typename iota_<n, o, s>::type;
  38. template <int n, class T> struct makelist_ { static_assert(n>0); using type = cons<T, typename makelist_<n-1, T>::type>; };
  39. template <class T> struct makelist_<0, T> { using type = nil; };
  40. template <int n, class T> using makelist = typename makelist_<n, T>::type;
  41. // A is a nested list, I the indices at each level.
  42. template <class A, int ... I> struct ref_ { using type = A; };
  43. template <class A, int ... I> using ref = typename ref_<A, I ...>::type;
  44. template <class A, int I0, int ... I> struct ref_<A, I0, I ...> { using type = ref<std::tuple_element_t<I0, A>, I ...>; };
  45. template <class A> using first = ref<A, 0>;
  46. template <class A> using last = ref<A, (len<A> - 1)>;
  47. template <bool a> using when = bool_t<a>;
  48. template <bool a> using unless = bool_t<(!a)>;
  49. // Return the index of a type in a type list, or -1 if not found.
  50. template <class A, class T, int i=0> struct index_ { using type = int_t<-1>; };
  51. template <class A, class T, int i=0> using index = typename index_<A, T, i>::type;
  52. template <class ... A, class T, int i> struct index_<tuple<T, A ...>, T, i> { using type = int_t<i>; };
  53. template <class A0, class ... A, class T, int i> struct index_<tuple<A0, A ...>, T, i> { using type = index<tuple<A ...>, T, i+1>; };
  54. // Index (& type) of the 1st item for which Pred<> is true, or -1 (& nil).
  55. template <class A, template <class> class Pred, int i=0, class Enable=void>
  56. struct IndexIf
  57. {
  58. constexpr static int value = -1;
  59. using type = nil;
  60. };
  61. template <class A0, class ... A, template <class> class Pred, int i>
  62. struct IndexIf<tuple<A0, A ...>, Pred, i, std::enable_if_t<Pred<A0>::value>>
  63. {
  64. using type = A0;
  65. constexpr static int value = i;
  66. };
  67. template <class A0, class ... A, template <class> class Pred, int i>
  68. struct IndexIf<tuple<A0, A ...>, Pred, i, std::enable_if_t<!(Pred<A0>::value)>>
  69. {
  70. using next = IndexIf<tuple<A ...>, Pred, i+1>;
  71. using type = typename next::type;
  72. constexpr static int value = next::value;
  73. };
  74. // Index (& type) of pairwise winner. A variant of fold.
  75. template <template <class A, class B> class pick_i, class T, int k=1, int sel=0>
  76. struct IndexOf;
  77. template <template <class A, class B> class pick_i, class T0, int k, int sel>
  78. struct IndexOf<pick_i, tuple<T0>, k, sel>
  79. {
  80. constexpr static int value = sel;
  81. using type = T0;
  82. };
  83. template <template <class A, class B> class pick_i, class T0, class T1, class ... Ti, int k, int sel>
  84. struct IndexOf<pick_i, tuple<T0, T1, Ti ...>, k, sel>
  85. {
  86. constexpr static int i = pick_i<std::decay_t<T0>, std::decay_t<T1>>::value;
  87. using next = IndexOf<pick_i, tuple<std::conditional_t<i==0, T0, T1>, Ti ...>, k+1, i==0 ? sel : k>;
  88. using type = typename next::type;
  89. constexpr static int value = next::value;
  90. };
  91. // Return the first tail of A headed by Val, like find-tail.
  92. template <class A, class Val> struct findtail_;
  93. template <class A, class Val> using findtail = typename findtail_<A, Val>::type;
  94. template <class Val> struct findtail_<nil, Val> { using type = nil; };
  95. template <class ... A, class Val> struct findtail_<tuple<Val, A ...>, Val> { using type = tuple<Val, A ...>; };
  96. template <class A0, class ... A, class Val> struct findtail_<tuple<A0, A ...>, Val> { using type = findtail<tuple<A ...>, Val>; };
  97. // Reverse list. See TSPL^3, p. 137.
  98. template <class A, class B=nil> struct reverse_ { using type = B; };
  99. template <class A, class B=nil> using reverse = typename reverse_<A, B>::type;
  100. template <class A0, class ... A, class B> struct reverse_<tuple<A0, A ...>, B> { using type = reverse<tuple<A ...>, cons<A0, B>>; };
  101. // drop1 is needed to avoid ambiguity in the declarations of drop, take.
  102. template <class A> struct drop1_;
  103. template <class A0, class ... A> struct drop1_<tuple<A0, A ...>> { using type = tuple<A ...>; };
  104. template <class A> using drop1 = typename drop1_<A>::type;
  105. template <class A, int n> struct drop_ { static_assert(n>0); using type = typename drop_<drop1<A>, n-1>::type; };
  106. template <class A> struct drop_<A, 0> { using type = A; };
  107. template <class A, int n> using drop = typename drop_<A, n>::type;
  108. template <class A, int n> struct take_ { static_assert(n>0); using type = cons<first<A>, typename take_<drop1<A>, n-1>::type>; };
  109. template <class A> struct take_<A, 0> { using type = nil; };
  110. template <class A, int n> using take = typename take_<A, n>::type;
  111. template <template <class ... A> class F, class L> struct apply_;
  112. template <template <class ... A> class F, class ... L> struct apply_<F, tuple<L ...>> { using type = F<L ...>; };
  113. template <template <class ... A> class F, class L> using apply = typename apply_<F, L>::type;
  114. // As map.
  115. template <template <class ... A> class F, class ... L>
  116. struct map_ { using type = cons<F<first<L> ...>, typename map_<F, drop1<L> ...>::type>; };
  117. template <template <class ... A> class F, class ... L>
  118. struct map_<F, nil, L ...> { using type = nil; };
  119. template <template <class ... A> class F>
  120. struct map_<F> { using type = nil; };
  121. template <template <class ... A> class F, class ... L> using map = typename map_<F, L ...>::type;
  122. template <class A, class B> struct Filter
  123. {
  124. using type = mp::append<std::conditional_t<mp::first<A>::value, mp::take<B, 1>, mp::nil>,
  125. typename Filter<mp::drop1<A>, mp::drop1<B>>::type>;
  126. };
  127. template <class B> struct Filter<mp::nil, B> { using type = B; };
  128. template <class A, class B> using Filter_ = typename Filter<A, B>::type;
  129. // As SRFI-1 fold (= fold-left).
  130. template <template <class ... A> class F, class Def, class ... L>
  131. struct fold_
  132. {
  133. using def = std::conditional_t<std::is_same_v<void, Def>, F<>, Def>;
  134. using type = typename fold_<F, F<def, first<L> ...>, drop1<L> ...>::type;
  135. };
  136. template <template <class ... A> class F, class Def, class ... L>
  137. struct fold_<F, Def, nil, L ...>
  138. {
  139. using type = std::conditional_t<std::is_same_v<void, Def>, F<>, Def>;
  140. };
  141. template <template <class ... A> class F, class Def>
  142. struct fold_<F, Def>
  143. {
  144. using type = std::conditional_t<std::is_same_v<void, Def>, F<>, Def>;
  145. };
  146. template <template <class ... A> class F, class Def, class ... L>
  147. using fold = typename fold_<F, Def, L ...>::type;
  148. template <class ... A> struct max_ { using type = int_t<std::numeric_limits<int>::min()>; };
  149. template <class ... A> using max = typename max_<A ...>::type;
  150. template <class A0, class ... A> struct max_<A0, A ...> { using type = int_t<std::max(A0::value, max<A ...>::value)>; };
  151. template <class ... A> struct min_ { using type = int_t<std::numeric_limits<int>::max()>; };
  152. template <class ... A> using min = typename min_<A ...>::type;
  153. template <class A0, class ... A> struct min_<A0, A ...> { using type = int_t<std::min(A0::value, min<A ...>::value)>; };
  154. // Operations on int_t arguments.
  155. template <class ... A> using sum = int_t<(A::value + ... + 0)>;
  156. template <class ... A> using prod = int_t<(A::value * ... * 1)>;
  157. template <class ... A> using andb = bool_t<(A::value && ... && true)>;
  158. template <class ... A> using orb = bool_t<(A::value || ... || false)>;
  159. // Remove from the second list the elements of the first list. None may have repeated elements, but they may be unsorted.
  160. template <class S, class T, class SS=S> struct complement_list_;
  161. template <class S, class T, class SS=S> using complement_list = typename complement_list_<S, T, SS>::type;
  162. // end of T.
  163. template <class S, class SS>
  164. struct complement_list_<S, nil, SS>
  165. {
  166. using type = nil;
  167. };
  168. // end search on S, did not find.
  169. template <class T0, class ... T, class SS>
  170. struct complement_list_<nil, tuple<T0, T ...>, SS>
  171. {
  172. using type = cons<T0, complement_list<SS, tuple<T ...>>>;
  173. };
  174. // end search on S, found.
  175. template <class F, class ... S, class ... T, class SS>
  176. struct complement_list_<tuple<F, S ...>, tuple<F, T ...>, SS>
  177. {
  178. using type = complement_list<SS, tuple<T ...>>;
  179. };
  180. // keep searching on S.
  181. template <class S0, class ... S, class T0, class ... T, class SS>
  182. struct complement_list_<tuple<S0, S ...>, tuple<T0, T ...>, SS>
  183. {
  184. using type = complement_list<tuple<S ...>, tuple<T0, T ...>, SS>;
  185. };
  186. // Like complement_list, but assume that both lists are sorted.
  187. template <class S, class T> struct complement_sorted_list_ { using type = nil; };
  188. template <class S, class T> using complement_sorted_list = typename complement_sorted_list_<S, T>::type;
  189. template <class T>
  190. struct complement_sorted_list_<nil, T>
  191. {
  192. using type = T;
  193. };
  194. template <class F, class ... S, class ... T>
  195. struct complement_sorted_list_<tuple<F, S ...>, tuple<F, T ...>>
  196. {
  197. using type = complement_sorted_list<tuple<S ...>, tuple<T ...>>;
  198. };
  199. template <class S0, class ... S, class T0, class ... T>
  200. struct complement_sorted_list_<tuple<S0, S ...>, tuple<T0, T ...>>
  201. {
  202. static_assert(T0::value<=S0::value, "bad lists for complement_sorted_list<>");
  203. using type = cons<T0, complement_sorted_list<tuple<S0, S ...>, tuple<T ...>>>;
  204. };
  205. // Variant of complement_list where the second argument is [0 .. end-1].
  206. template <class S, int end> using complement = complement_sorted_list<S, iota<end>>;
  207. // Prepend an element to each of a list of lists.
  208. template <class c, class A> struct MapCons;
  209. template <class c, class A> using MapCons_ = typename MapCons<c, A>::type;
  210. template <class c, class ... A> struct MapCons<c, tuple<A ...>> { using type = tuple<cons<c, A> ...>; };
  211. // Prepend a list to each list in a list of lists.
  212. template <class c, class A> struct MapPrepend;
  213. template <class c, class A> using MapPrepend_ = typename MapPrepend<c, A>::type;
  214. template <class c, class ... A> struct MapPrepend<c, tuple<A ...>> { using type = tuple<append<c, A> ...>; };
  215. // Form all possible lists by prepending an element of A to an element of B.
  216. template <class A, class B> struct ProductAppend { using type = nil; };
  217. template <class A, class B> using ProductAppend_ = typename ProductAppend<A, B>::type;
  218. template <class A0, class ... A, class B> struct ProductAppend<tuple<A0, A ...>, B> { using type = append<MapPrepend_<A0, B>, ProductAppend_<tuple<A ...>, B>>; };
  219. // Compute the K-combinations of the N elements of list A.
  220. template <class A, int K, int N=len<A>> struct combinations_;
  221. template <class A, int k, int N=len<A>> using combinations = typename combinations_<A, k, N>::type;
  222. // In this case, return a list with one element: the empty list.
  223. template <class A, int N> struct combinations_<A, 0, N> { using type = tuple<nil>; };
  224. // In this case, return a list with one element: the whole list.
  225. template <class A, int N> struct combinations_<A, N, N> { using type = tuple<A>; };
  226. // Special case for 0 over 0, to resolve ambiguity of 0/N and N/N when N=0.
  227. template <> struct combinations_<nil, 0> { using type = tuple<nil>; };
  228. template <class A, int K, int N>
  229. struct combinations_
  230. {
  231. static_assert(is_tuple_v<A>);
  232. static_assert(N>=0 && K>=0);
  233. static_assert(K<=N);
  234. using Rest = drop1<A>;
  235. using type = append<MapCons_<first<A>, combinations<Rest, K-1, N-1>>, combinations<Rest, K, N-1>>;
  236. };
  237. // Sign of permutations.
  238. template <class C, class R> struct PermutationSign;
  239. template <int w, class C, class R>
  240. struct PermutationSignIfFound
  241. {
  242. constexpr static int value = ((w & 1) ? -1 : +1) * PermutationSign<append<take<C, w>, drop<C, w+1>>,
  243. drop1<R>>::value;
  244. };
  245. template <class C, class R> struct PermutationSignIfFound<-1, C, R> { constexpr static int value = 0; };
  246. template <> struct PermutationSign<nil, nil> { constexpr static int value = 1; };
  247. template <class C> struct PermutationSign<C, nil> { constexpr static int value = 0; };
  248. template <class R> struct PermutationSign<nil, R> { constexpr static int value = 0; };
  249. template <class C, class Org>
  250. struct PermutationSign
  251. {
  252. constexpr static int value = PermutationSignIfFound<index<C, first<Org>>::value, C, Org>::value;
  253. };
  254. // increment the w-th element of an int_list
  255. template <class L, int w> using inc = append<take<L, w>, cons<int_t<ref<L, w>::value+1>, drop<L, w+1>>>;
  256. template <class A> struct InvertIndex;
  257. template <class ... A> struct InvertIndex<tuple<A ...>>
  258. {
  259. using AT = tuple<A ...>;
  260. template <class T> using IndexA = int_t<index<AT, T>::value>;
  261. constexpr static int N = apply<max, AT>::value;
  262. using type = map<IndexA, iota<(N>=0 ? N+1 : 0)>>;
  263. };
  264. template <class A> using InvertIndex_ = typename InvertIndex<A>::type;
  265. // Used in tests.
  266. template <class A, int ... I> struct check_idx { constexpr static bool value = false; };
  267. template <> struct check_idx<nil> { constexpr static bool value = true; };
  268. template <class A0, int I0, class ... A, int ... I>
  269. struct check_idx<tuple<A0, A ...>, I0, I ...>
  270. {
  271. constexpr static bool value = (A0::value==I0) && check_idx<tuple<A ...>, I ...>::value;
  272. };
  273. } // namespace mp