tuples.hh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra - Basic macros & tuple library.
  3. // (c) Daniel Llorens - 2005-2024
  4. // This library is free software; you can redistribute it and/or modify it under
  5. // the terms of the GNU Lesser General Public License as published by the Free
  6. // Software Foundation; either version 3 of the License, or (at your option) any
  7. // later version.
  8. #pragma once
  9. #include <tuple>
  10. #include <limits>
  11. #include <utility>
  12. #include <algorithm>
  13. #include <type_traits>
  14. #include <functional>
  15. #define STRINGIZE_( x ) #x
  16. #define STRINGIZE( x ) STRINGIZE_( x )
  17. #define JOIN_( x, y ) x##y
  18. #define JOIN( x, y ) JOIN_( x, y )
  19. #define RA_FWD(a) std::forward<decltype(a)>(a)
  20. // see http://stackoverflow.com/a/1872506
  21. #define FOR_EACH_1(what, x, ...) what(x)
  22. #define FOR_EACH_2(what, x, ...) what(x) FOR_EACH_1(what, __VA_ARGS__)
  23. #define FOR_EACH_3(what, x, ...) what(x) FOR_EACH_2(what, __VA_ARGS__)
  24. #define FOR_EACH_4(what, x, ...) what(x) FOR_EACH_3(what, __VA_ARGS__)
  25. #define FOR_EACH_5(what, x, ...) what(x) FOR_EACH_4(what, __VA_ARGS__)
  26. #define FOR_EACH_6(what, x, ...) what(x) FOR_EACH_5(what, __VA_ARGS__)
  27. #define FOR_EACH_7(what, x, ...) what(x) FOR_EACH_6(what, __VA_ARGS__)
  28. #define FOR_EACH_8(what, x, ...) what(x) FOR_EACH_7(what, __VA_ARGS__)
  29. #define FOR_EACH_9(what, x, ...) what(x) FOR_EACH_8(what, __VA_ARGS__)
  30. #define FOR_EACH_10(what, x, ...) what(x) FOR_EACH_9(what, __VA_ARGS__)
  31. #define FOR_EACH_11(what, x, ...) what(x) FOR_EACH_10(what, __VA_ARGS__)
  32. #define FOR_EACH_12(what, x, ...) what(x) FOR_EACH_11(what, __VA_ARGS__)
  33. #define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
  34. #define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
  35. #define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
  36. #define FOR_EACH_RSEQ_N() 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
  37. #define FOR_EACH_(N, what, ...) JOIN(FOR_EACH_, N)(what, __VA_ARGS__)
  38. #define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
  39. namespace ra {
  40. template <class T> constexpr bool is_constant = false;
  41. template <class T, T N> constexpr bool is_constant<std::integral_constant<T, N>> = true;
  42. template <int V> using int_c = std::integral_constant<int, V>;
  43. template <bool V> using bool_c = std::integral_constant<bool, V>;
  44. template <auto V> using ic_t = std::integral_constant<std::remove_const_t<decltype(V)>, V>;
  45. template <auto V> constexpr std::integral_constant<std::remove_const_t<decltype(V)>, V> ic {};
  46. } // namespace ra
  47. namespace ra::mp {
  48. using std::tuple;
  49. using nil = tuple<>;
  50. template <class T> constexpr bool nilp = std::is_same_v<nil, T>;
  51. template <class A> constexpr int len = std::tuple_size_v<A>;
  52. template <int ... I> using int_list = tuple<int_c<I> ...>;
  53. template <class T> constexpr bool is_tuple = false;
  54. template <class ... A> constexpr bool is_tuple<tuple<A ...>> = true;
  55. // A is a nested list, I the indices at each level.
  56. template <class A, int ... I> struct ref_ { using type = A; };
  57. template <class A, int ... I> using ref = typename ref_<A, I ...>::type;
  58. template <class A, int I0, int ... I> struct ref_<A, I0, I ...> { using type = ref<std::tuple_element_t<I0, A>, I ...>; };
  59. template <class A> using first = ref<A, 0>;
  60. template <class A> using last = ref<A, len<A>-1>;
  61. template <class A, class B> struct cons_ { static_assert(is_tuple<B>); };
  62. template <class A0, class ... A> struct cons_<A0, tuple<A ...>> { using type = tuple<A0, A ...>; };
  63. template <class A, class B> using cons = typename cons_<A, B>::type;
  64. template <int n, int o=0, int s=1> struct iota_ { static_assert(n>0); using type = cons<int_c<o>, typename iota_<n-1, o+s, s>::type>; };
  65. template <int o, int s> struct iota_<0, o, s> { using type = nil; };
  66. template <int n, int o=0, int s=1> using iota = typename iota_<n, o, s>::type;
  67. template <class A, class B> struct append_ { static_assert(is_tuple<A> && is_tuple<B>); };
  68. template <class ... A, class ... B> struct append_<tuple<A ...>, tuple<B ...>> { using type = tuple<A ..., B ...>; };
  69. template <class A, class B> using append = typename append_<A, B>::type;
  70. template <class A, class B> struct zip_ { static_assert(is_tuple<A> && is_tuple<B>); };
  71. template <class ... A, class ... B> struct zip_<tuple<A ...>, tuple<B ...>> { using type = tuple<tuple<A, B> ...>; };
  72. template <class A, class B> using zip = typename zip_<A, B>::type;
  73. template <int n, class T> struct makelist_ { static_assert(n>0); using type = cons<T, typename makelist_<n-1, T>::type>; };
  74. template <class T> struct makelist_<0, T> { using type = nil; };
  75. template <int n, class T> using makelist = typename makelist_<n, T>::type;
  76. // Return the index of a type in a type list, or -1 if not found.
  77. template <class A, class T, int i=0> struct index_ { using type = int_c<-1>; };
  78. template <class A, class T, int i=0> using index = typename index_<A, T, i>::type;
  79. template <class ... A, class T, int i> struct index_<tuple<T, A ...>, T, i> { using type = int_c<i>; };
  80. template <class A0, class ... A, class T, int i> struct index_<tuple<A0, A ...>, T, i> { using type = index<tuple<A ...>, T, i+1>; };
  81. // Index (& type) of the 1st item for which Pred<> is true, or -1 (& nil).
  82. template <class A, template <class> class Pred, int i=0>
  83. struct IndexIf
  84. {
  85. constexpr static int value = -1;
  86. using type = nil;
  87. };
  88. template <class A0, class ... A, template <class> class Pred, int i>
  89. requires (Pred<A0>::value)
  90. struct IndexIf<tuple<A0, A ...>, Pred, i>
  91. {
  92. using type = A0;
  93. constexpr static int value = i;
  94. };
  95. template <class A0, class ... A, template <class> class Pred, int i>
  96. requires (!(Pred<A0>::value))
  97. struct IndexIf<tuple<A0, A ...>, Pred, i>
  98. {
  99. using next = IndexIf<tuple<A ...>, Pred, i+1>;
  100. using type = typename next::type;
  101. constexpr static int value = next::value;
  102. };
  103. // index & type of pairwise winner. A variant of fold.
  104. template <template <class A, class B> class pick_i, class T, int k=1, int sel=0> struct indexof_;
  105. template <template <class A, class B> class pick_i, class T0, int k, int sel>
  106. struct indexof_<pick_i, tuple<T0>, k, sel>
  107. {
  108. constexpr static int value = sel;
  109. using type = T0;
  110. };
  111. template <template <class A, class B> class pick_i, class T0, class T1, class ... Ti, int k, int sel>
  112. struct indexof_<pick_i, tuple<T0, T1, Ti ...>, k, sel>
  113. {
  114. constexpr static int i = pick_i<std::decay_t<T0>, std::decay_t<T1>>::value;
  115. using next = indexof_<pick_i, tuple<std::conditional_t<i==0, T0, T1>, Ti ...>, k+1, i==0 ? sel : k>;
  116. using type = typename next::type;
  117. constexpr static int value = next::value;
  118. };
  119. template <template <class A, class B> class pick_i, class T>
  120. constexpr int indexof = indexof_<pick_i, T>::value;
  121. template <class A, class Val> struct findtail_;
  122. template <class A, class Val> using findtail = typename findtail_<A, Val>::type;
  123. template <class Val> struct findtail_<nil, Val> { using type = nil; };
  124. template <class ... A, class Val> struct findtail_<tuple<Val, A ...>, Val> { using type = tuple<Val, A ...>; };
  125. template <class A0, class ... A, class Val> struct findtail_<tuple<A0, A ...>, Val> { using type = findtail<tuple<A ...>, Val>; };
  126. template <class A, class B=nil> struct reverse_ { using type = B; };
  127. template <class A, class B=nil> using reverse = typename reverse_<A, B>::type;
  128. template <class A0, class ... A, class B> struct reverse_<tuple<A0, A ...>, B> { using type = reverse<tuple<A ...>, cons<A0, B>>; };
  129. // drop1 is needed to avoid ambiguity in the declarations of drop, take.
  130. template <class A> struct drop1_;
  131. template <class A0, class ... A> struct drop1_<tuple<A0, A ...>> { using type = tuple<A ...>; };
  132. template <class A> using drop1 = typename drop1_<A>::type;
  133. template <class A, int n> struct drop_ { static_assert(n>0); using type = typename drop_<drop1<A>, n-1>::type; };
  134. template <class A> struct drop_<A, 0> { using type = A; };
  135. template <class A, int n> using drop = typename drop_<A, n>::type;
  136. template <class A, int n> struct take_ { static_assert(n>0); using type = cons<first<A>, typename take_<drop1<A>, n-1>::type>; };
  137. template <class A> struct take_<A, 0> { using type = nil; };
  138. template <class A, int n> using take = typename take_<A, n>::type;
  139. template <template <class ... A> class F, class L> struct apply_;
  140. template <template <class ... A> class F, class ... L> struct apply_<F, tuple<L ...>> { using type = F<L ...>; };
  141. template <template <class ... A> class F, class L> using apply = typename apply_<F, L>::type;
  142. template <template <class ... A> class F, class ... L>
  143. struct map_ { using type = cons<F<first<L> ...>, typename map_<F, drop1<L> ...>::type>; };
  144. template <template <class ... A> class F, class ... L>
  145. struct map_<F, nil, L ...> { using type = nil; };
  146. template <template <class ... A> class F>
  147. struct map_<F> { using type = nil; };
  148. template <template <class ... A> class F, class ... L> using map = typename map_<F, L ...>::type;
  149. template <class A, class B> struct Filter
  150. {
  151. using type = mp::append<std::conditional_t<mp::first<A>::value, mp::take<B, 1>, mp::nil>,
  152. typename Filter<mp::drop1<A>, mp::drop1<B>>::type>;
  153. };
  154. template <class B> struct Filter<mp::nil, B> { using type = B; };
  155. template <class A, class B> using Filter_ = typename Filter<A, B>::type;
  156. // remove from the second list the elements of the first list. None may have repeated elements, but they may be unsorted.
  157. template <class S, class T, class SS=S> struct complement_list_;
  158. template <class S, class T, class SS=S> using complement_list = typename complement_list_<S, T, SS>::type;
  159. // end of T.
  160. template <class S, class SS>
  161. struct complement_list_<S, nil, SS>
  162. {
  163. using type = nil;
  164. };
  165. // end search on S, did not find.
  166. template <class T0, class ... T, class SS>
  167. struct complement_list_<nil, tuple<T0, T ...>, SS>
  168. {
  169. using type = cons<T0, complement_list<SS, tuple<T ...>>>;
  170. };
  171. // end search on S, found.
  172. template <class F, class ... S, class ... T, class SS>
  173. struct complement_list_<tuple<F, S ...>, tuple<F, T ...>, SS>
  174. {
  175. using type = complement_list<SS, tuple<T ...>>;
  176. };
  177. // keep searching on S.
  178. template <class S0, class ... S, class T0, class ... T, class SS>
  179. struct complement_list_<tuple<S0, S ...>, tuple<T0, T ...>, SS>
  180. {
  181. using type = complement_list<tuple<S ...>, tuple<T0, T ...>, SS>;
  182. };
  183. // Like complement_list, but assume that both lists are sorted.
  184. template <class S, class T> struct complement_sorted_list_ { using type = nil; };
  185. template <class S, class T> using complement_sorted_list = typename complement_sorted_list_<S, T>::type;
  186. template <class T>
  187. struct complement_sorted_list_<nil, T>
  188. {
  189. using type = T;
  190. };
  191. template <class F, class ... S, class ... T>
  192. struct complement_sorted_list_<tuple<F, S ...>, tuple<F, T ...>>
  193. {
  194. using type = complement_sorted_list<tuple<S ...>, tuple<T ...>>;
  195. };
  196. template <class S0, class ... S, class T0, class ... T>
  197. struct complement_sorted_list_<tuple<S0, S ...>, tuple<T0, T ...>>
  198. {
  199. static_assert(T0::value<=S0::value, "Bad lists for complement_sorted_list<>.");
  200. using type = cons<T0, complement_sorted_list<tuple<S0, S ...>, tuple<T ...>>>;
  201. };
  202. // Variant of complement_list where the second argument is [0 .. end-1].
  203. template <class S, int end> using complement = complement_sorted_list<S, iota<end>>;
  204. // Prepend an element to each of a list of lists.
  205. template <class c, class A> struct MapCons_;
  206. template <class c, class A> using MapCons = typename MapCons_<c, A>::type;
  207. template <class c, class ... A> struct MapCons_<c, tuple<A ...>> { using type = tuple<cons<c, A> ...>; };
  208. // Prepend a list to each list in a list of lists.
  209. template <class c, class A> struct MapPrepend_;
  210. template <class c, class A> using MapPrepend = typename MapPrepend_<c, A>::type;
  211. template <class c, class ... A> struct MapPrepend_<c, tuple<A ...>> { using type = tuple<append<c, A> ...>; };
  212. // Form all possible lists by prepending an element of A to an element of B.
  213. template <class A, class B> struct ProductAppend_ { using type = nil; };
  214. template <class A, class B> using ProductAppend = typename ProductAppend_<A, B>::type;
  215. template <class A0, class ... A, class B> struct ProductAppend_<tuple<A0, A ...>, B> { using type = append<MapPrepend<A0, B>, ProductAppend<tuple<A ...>, B>>; };
  216. // K-combinations of the N elements of list A.
  217. template <class A, int K, int N=len<A>> struct combinations_;
  218. template <class A, int k, int N=len<A>> using combinations = typename combinations_<A, k, N>::type;
  219. template <class A, int N> struct combinations_<A, 0, N> { using type = tuple<nil>; };
  220. template <class A, int N> struct combinations_<A, N, N> { using type = tuple<A>; };
  221. // Resolve ambiguity of 0/N and N/N when N=0.
  222. template <> struct combinations_<nil, 0> { using type = tuple<nil>; };
  223. template <class A, int K, int N>
  224. struct combinations_
  225. {
  226. static_assert(is_tuple<A>);
  227. static_assert(N>=0 && K>=0 && K<=N);
  228. using Rest = drop1<A>;
  229. using type = append<MapCons<first<A>, combinations<Rest, K-1, N-1>>, combinations<Rest, K, N-1>>;
  230. };
  231. template <class C, class R> struct PermutationSign;
  232. template <int w, class C, class R>
  233. constexpr int PermutationSignIfFound = PermutationSign<append<take<C, w>, drop<C, w+1>>, drop1<R>>::value * ((w & 1) ? -1 : +1);
  234. template <class C, class R>
  235. constexpr int PermutationSignIfFound<-1, C, R> = 0;
  236. template <> struct PermutationSign<nil, nil> { constexpr static int value = 1; };
  237. template <class C> struct PermutationSign<C, nil> { constexpr static int value = 0; };
  238. template <class R> struct PermutationSign<nil, R> { constexpr static int value = 0; };
  239. template <class C, class Org>
  240. struct PermutationSign
  241. {
  242. constexpr static int value = PermutationSignIfFound<index<C, first<Org>>::value, C, Org>;
  243. };
  244. // ---------------------
  245. // tuples in dynamic context
  246. // ---------------------
  247. template <class C, class T, auto f = std::identity {}>
  248. consteval auto
  249. tuple2array()
  250. {
  251. return std::apply([](auto ... t) { return std::array<C, sizeof...(t)> { C(f(t)) ... }; }, T {});
  252. }
  253. template <class T>
  254. constexpr int
  255. int_list_index(int k)
  256. {
  257. return std::apply([&k](auto ... i) { int r=-1; ((k==mp::ref<T, i>::value && (r=i, 1)) || ...); return r; },
  258. iota<len<T>> {});
  259. }
  260. } // namespace ra::mp