123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- // (c) Daniel Llorens - 2005-2013, 2016
- // This library is free software; you can redistribute it and/or modify it under
- // the terms of the GNU Lesser General Public License as published by the Free
- // Software Foundation; either version 3 of the License, or (at your option) any
- // later version.
- /// @file tuple-list.H
- /// @brief Using tuples as compile time lists.
- #pragma once
- #include "ra/int_t.H"
- #include <tuple>
- #include <limits>
- namespace mp {
- using std::tuple;
- using nil = tuple<>;
- template <class T> constexpr bool nilp = std::is_same<nil, T>::value;
- template <class A> constexpr int len = std::tuple_size<A>::value;
- template <class A, class B> struct Cons;
- template <class A0, class ... A>
- struct Cons<A0, tuple<A ...>>
- {
- using type = tuple<A0, A ...>;
- };
- template <class A, class B>
- using Cons_ = typename Cons<A, B>::type;
- template <class A, class B> struct Append;
- template <class ... A, class ... B>
- struct Append<tuple<A ...>, tuple<B ...>>
- {
- using type = tuple<A ..., B ...>;
- };
- template <class A, class B>
- using Append_ = typename Append<A, B>::type;
- template <class A, class B> struct Zip;
- template <class ... A, class ... B>
- struct Zip<tuple<A ...>, tuple<B ...>>
- {
- using type = tuple<tuple<A, B> ...>;
- };
- template <class A, class B> using Zip_ = typename Zip<A, B>::type;
- // The list is [a .. a+n).
- template <int n, int a=0, int step=1>
- struct Iota
- {
- static_assert(n>=0, "bad size for Iota");
- using type = typename Cons<int_t<a>, typename Iota<n-1, a+step, step>::type>::type;
- };
- template <int a, int step>
- struct Iota<0, a, step>
- {
- using type = nil;
- };
- template <int n, int a=0, int step=1>
- using Iota_ = typename Iota<n, a, step>::type;
- template <int n, class T>
- struct MakeList
- {
- static_assert(n>=0, "bad size for MakeList");
- using type = typename Cons<T, typename MakeList<n-1, T>::type>::type;
- };
- template <class T>
- struct MakeList<0, T>
- {
- using type = nil;
- };
- template <int n, class T>
- using MakeList_ = typename MakeList<n, T>::type;
- // Subscript a list (of lists (of lists ...)).
- // @param A a list (of lists (of lists ...)).
- // @param I... the indices.
- template <class A, int ... I>
- struct Ref
- {
- using type = A;
- };
- template <class A, int I0, int ... I>
- struct Ref<A, I0, I ...>
- {
- static_assert(I0>=0, "bad index for Ref");
- using type = typename Ref<typename std::tuple_element<I0, A>::type, I ...>::type;
- };
- template <class A, int ... I> using Ref_ = typename Ref<A, I ...>::type;
- template <class A> struct First { using type = Ref_<A, 0>; };
- template <class A> using First_ = typename First<A>::type;
- template <class A> struct Last { using type = Ref_<A, len<A>-1>; };
- template <class A> using Last_ = typename Last<A>::type;
- template <bool c, class A, class B> using If = std::conditional<c, A, B>;
- template <bool c, class A, class B> using If_ = typename If<c, A, B>::type;
- template <bool a>
- struct When
- {
- constexpr static bool value = a;
- using type = int_t<value>;
- };
- template <bool a>
- struct Unless
- {
- constexpr static bool value = !a;
- using type = int_t<value>;
- };
- // Return the index of a type in a type list, or -1 if not found.
- template <class A, class Val, int i=0>
- struct Index
- {
- constexpr static int value = -1;
- };
- template <class ... A, class Val, int i>
- struct Index<tuple<Val, A ...>, Val, i>
- {
- constexpr static int value = i;
- };
- template <class A0, class ... A, class Val, int i>
- struct Index<tuple<A0, A ...>, Val, i>
- {
- constexpr static int value = Index<tuple<A ...>, Val, i+1>::value;
- };
- // Index (& type) of the 1st item for which Pred<> is true, or -1 (& nil).
- template <class A, template <class> class Pred, int i=0, class Enable=void>
- struct IndexIf
- {
- constexpr static int value = -1;
- using type = nil;
- };
- template <class A0, class ... A, template <class> class Pred, int i>
- struct IndexIf<tuple<A0, A ...>, Pred, i, std::enable_if_t<Pred<A0>::value>>
- {
- using type = A0;
- constexpr static int value = i;
- };
- template <class A0, class ... A, template <class> class Pred, int i>
- struct IndexIf<tuple<A0, A ...>, Pred, i, std::enable_if_t<!(Pred<A0>::value)>>
- {
- using next = IndexIf<tuple<A ...>, Pred, i+1>;
- using type = typename next::type;
- constexpr static int value = next::value;
- };
- // Index (& type) of pairwise winner. A variant of Fold.
- template <template <class A, class B> class pick_i, class T, int k=1, int sel=0>
- struct IndexOf;
- template <template <class A, class B> class pick_i, class T0, int k, int sel>
- struct IndexOf<pick_i, tuple<T0>, k, sel>
- {
- constexpr static int value = sel;
- using type = T0;
- };
- template <template <class A, class B> class pick_i, class T0, class T1, class ... Ti, int k, int sel>
- struct IndexOf<pick_i, tuple<T0, T1, Ti ...>, k, sel>
- {
- constexpr static int i = pick_i<std::decay_t<T0>, std::decay_t<T1>>::value;
- using next = IndexOf<pick_i, tuple<mp::If_<i==0, T0, T1>, Ti ...>, k+1, i==0 ? sel : k>;
- using type = typename next::type;
- constexpr static int value = next::value;
- };
- // Return the first tail of A headed by Val, like find-tail.
- template <class A, class Val> struct FindTail;
- template <class Val>
- struct FindTail<nil, Val>
- {
- using type = nil;
- };
- template <class ... A, class Val>
- struct FindTail<tuple<Val, A ...>, Val>
- {
- using type = tuple<Val, A ...>;
- };
- template <class A0, class ... A, class Val>
- struct FindTail<tuple<A0, A ...>, Val>
- {
- using type = typename FindTail<tuple<A ...>, Val>::type;
- };
- // Reverse list. See TSPL^3, p. 137.
- template <class A, class New=nil>
- struct Reverse
- {
- using type = New;
- };
- template <class A0, class ... A, class New>
- struct Reverse<tuple<A0, A ...>, New>
- {
- using type = typename Reverse<tuple<A ...>, typename Cons<A0, New>::type>::type;
- };
- template <class A, class New=nil>
- using Reverse_ = typename Reverse<A, New>::type;
- // Drop1 is needed to avoid ambiguity in the declarations of Drop, Take.
- template <class A> struct Drop1;
- template <class A0, class ... A>
- struct Drop1<tuple<A0, A ...>>
- {
- using type = tuple<A ...>;
- };
- template <class A>
- using Drop1_ = typename Drop1<A>::type;
- template <class A, int n>
- struct Drop
- {
- static_assert(n>=0, "bad drop size");
- using type = typename Drop<typename Drop1<A>::type, n-1>::type;
- };
- template <class A>
- struct Drop<A, 0>
- {
- using type = A;
- };
- template <class A, int n>
- using Drop_ = typename Drop<A, n>::type;
- template <class A, int n>
- struct Take
- {
- static_assert(n>=0, "bad take size");
- using type = typename Cons<First_<A>,
- typename Take<typename Drop1<A>::type, n-1>::type>::type;
- };
- template <class A>
- struct Take<A, 0>
- {
- using type = nil;
- };
- template <class A, int n>
- using Take_ = typename Take<A, n>::type;
- // As apply, or as ApplyV<Valuer<>>
- template <template <class ... A> class F, class L>
- struct Apply
- {
- static_assert(len<L> >= 0, "arg must be a tuple");
- };
- template <template <class ... A> class F, class ... L>
- struct Apply<F, tuple<L ...>>
- {
- using type = typename F<L ...>::type;
- };
- template <template <class ... A> class F, class L>
- using Apply_ = typename Apply<F, L>::type;
- // As apply, or as Apply<Typer<>>
- template <template <class ... A> class F, class L>
- struct ApplyV
- {
- static_assert(len<L> >= 0, "arg must be a tuple"); // ??
- };
- template <template <class ... A> class F, class ... L>
- struct ApplyV<F, tuple<L ...>>
- {
- static int const value = F<L ...>::value;
- };
- // As map.
- template <template <class ... A> class F, class ... L>
- struct Map
- {
- using type = typename Cons<typename F<First_<L> ...>::type,
- typename Map<F, typename Drop1<L>::type ...>::type>::type;
- };
- template <template <class ... A> class F, class ... L>
- struct Map<F, nil, L ...>
- {
- using type = nil;
- };
- template <template <class ... A> class F>
- struct Map<F>
- {
- using type = nil;
- };
- template <template <class ... A> class F, class ... L>
- using Map_ = typename Map<F, L ...>::type;
- template <class A, class B> struct Filter
- {
- using type = mp::Append_<mp::If_<mp::First_<A>::value, mp::Take_<B, 1>, mp::nil>,
- typename Filter<mp::Drop1_<A>, mp::Drop1_<B>>::type>;
- };
- template <class B> struct Filter<mp::nil, B>
- {
- using type = B;
- };
- template <class A, class B>
- using Filter_ = typename Filter<A, B>::type;
- // As SRFI-1 fold (= fold-left).
- template <template <class ... A> class F, class Def, class ... L>
- struct Fold
- {
- using def = If_<std::is_same<void, Def>::value, F<>, Def>;
- using type = typename Fold<F,
- typename F<def, First_<L> ...>::type,
- typename Drop1<L>::type ...>::type;
- };
- template <template <class ... A> class F, class Def, class ... L>
- struct Fold<F, Def, nil, L ...>
- {
- using type = If_<std::is_same<void, Def>::value, F<>, Def>;
- };
- template <template <class ... A> class F, class Def>
- struct Fold<F, Def>
- {
- using type = If_<std::is_same<void, Def>::value, F<>, Def>;
- };
- template <template <class ... A> class F, class Def, class ... L>
- using Fold_ = typename Fold<F, Def, L ...>::type;
- // Pass F(A) to templates expecting F(A ...). todo Wait for C++ to be fixed.
- template <template <class A> class F>
- struct Coerce1
- {
- template <class ... B> struct type_; // bug ---breaks composability
- template <class B0, class ... B>
- struct type_<B0, B ...>
- {
- using type = typename F<B0>::type;
- };
- };
- // Pass F(A, B) to templates expecting F(A ...). todo Wait for C++ to be fixed.
- template <template <class A, class B> class F>
- struct Coerce2
- {
- template <class ... B> struct type_; // bug ---breaks composability
- template <class B0, class B1, class ... B>
- struct type_<B0, B1, B ...>
- {
- using type = typename F<B0, B1>::type;
- };
- };
- // Pass F(A ...) -> type to/from templates expecting F(A ...) -> value.
- template <template <class ... A> class F>
- struct Valuer
- {
- template <class ... B>
- struct type
- {
- constexpr static int value = F<B ...>::type::value;
- };
- };
- template <template <class ... A> class F>
- struct Typer
- {
- template <class ... B>
- struct type_ // bug ---breaks composability
- {
- using type = int_t<F<B ...>::value>;
- };
- };
- // Operations on int_t arguments.
- template <class ... A> struct Sum
- {
- constexpr static int value = (A::value + ... + 0);
- using type = int_t<value>;
- };
- template <class ... A> struct Max
- {
- constexpr static int value = std::numeric_limits<int>::min();
- using type = int_t<value>;
- };
- template <class A0, class ... A>
- struct Max<A0, A ...>
- {
- constexpr static int value = std::max(A0::value, Max<A ...>::type::value);
- using type = int_t<value>;
- };
- template <class ... A> struct Min
- {
- constexpr static int value = std::numeric_limits<int>::max();
- using type = int_t<value>;
- };
- template <class A0, class ... A>
- struct Min<A0, A ...>
- {
- constexpr static int value = std::min(A0::value, Min<A ...>::type::value);
- using type = int_t<value>;
- };
- template <class ... A> struct Prod
- {
- constexpr static int value = (A::value * ... * 1);
- using type = int_t<value>;
- };
- template <class ... A> struct And
- {
- constexpr static bool value = (A::value && ...);
- using type = bool_t<value>;
- };
- template <class ... A> struct Or
- {
- constexpr static bool value = (A::value || ...);
- using type = bool_t<value>;
- };
- // Remove from the second list the elements of the first list. None may have repeated elements, but they may be unsorted.
- template <class S, class T, class SS=S>
- struct ComplementList;
- // end of T.
- template <class S, class SS>
- struct ComplementList<S, nil, SS>
- {
- using type = nil;
- };
- // end search on S, did not find.
- template <class T0, class ... T, class SS>
- struct ComplementList<nil, tuple<T0, T ...>, SS>
- {
- using type = typename Cons<T0, typename ComplementList<SS, tuple<T ...>>::type>::type;
- };
- // end search on S, found.
- template <class F, class ... S, class ... T, class SS>
- struct ComplementList<tuple<F, S ...>, tuple<F, T ...>, SS>
- {
- using type = typename ComplementList<SS, tuple<T ...>>::type;
- };
- // keep searching on S.
- template <class S0, class ... S, class T0, class ... T, class SS>
- struct ComplementList<tuple<S0, S ...>, tuple<T0, T ...>, SS>
- {
- using type = typename ComplementList<tuple<S ...>, tuple<T0, T ...>, SS>::type;
- };
- template <class S, class T, class SS=S>
- using ComplementList_ = typename ComplementList<S, T, SS>::type;
- // Like ComplementList, but assume that both lists are sorted.
- template <class S, class T>
- struct ComplementSList
- {
- using type = nil;
- };
- template <class T>
- struct ComplementSList<nil, T>
- {
- using type = T;
- };
- template <class F, class ... S, class ... T>
- struct ComplementSList<tuple<F, S ...>, tuple<F, T ...>>
- {
- using type = typename ComplementSList<tuple<S ...>, tuple<T ...>>::type;
- };
- template <class S0, class ... S, class T0, class ... T>
- struct ComplementSList<tuple<S0, S ...>, tuple<T0, T ...>>
- {
- static_assert(T0::value<=S0::value, "bad lists for ComplementSList<>");
- using type = typename Cons<T0, typename ComplementSList<tuple<S0, S ...>, tuple<T ...>>::type>::type;
- };
- // Variant of ComplementList where the second argument is [0 .. end-1].
- template <class S, int end>
- struct Complement
- {
- using type = typename ComplementSList<S, typename Iota<end>::type>::type;
- };
- template <class S, int end>
- using Complement_ = typename Complement<S, end>::type;
- // Prepend an element to each of a list of lists.
- template <class c, class A> struct MapCons;
- template <class c, class ... A>
- struct MapCons<c, tuple<A ...>>
- {
- using type = tuple<typename Cons<c, A>::type ...>;
- };
- // Prepend a list to each list in a list of lists.
- template <class c, class A> struct MapPrepend;
- template <class c, class ... A>
- struct MapPrepend<c, tuple<A ...>>
- {
- using type = tuple<typename Append<c, A>::type ...>;
- };
- // Form all possible lists by prepending an element of A to an element of B.
- template <class A, class B> struct ProductAppend
- {
- using type = nil;
- };
- template <class A0, class ... A, class B>
- struct ProductAppend<tuple<A0, A ...>, B>
- {
- using type = typename Append<typename MapPrepend<A0, B>::type,
- typename ProductAppend<tuple<A ...>, B>::type
- >::type;
- };
- // Compute the K-combinations of the N elements of A.
- //
- // @param A type list.
- // @param K take combinations of length K.
- template <class A, int K, int N=len<A>>
- struct Combinations
- {
- static_assert(N>=0 && K>=0, "N and K must be positive in Combinations");
- static_assert(K<=N, "K cannot be > N in Combinations of N elements by K");
- using Rest = typename Drop1<A>::type;
- using type = typename Append
- // with the first element and the (N-1 K-1) combinations on the rest.
- <typename MapCons<First_<A>,
- typename Combinations<Rest, K-1, N-1>::type>::type,
- // combinations on the rest, which are another (N-1 K).
- typename Combinations<Rest, K, N-1>::type
- >::type;
- };
- // In this case, return a list with one element: the null list.
- template <class A, int N>
- struct Combinations<A, 0, N>
- {
- using type = tuple<nil>;
- };
- // In this case, return a list with one element: the whole list.
- template <class A, int N>
- struct Combinations<A, N, N>
- {
- using type = tuple<A>;
- };
- // Special case for 0 over 0, to resolve ambiguity of 0/N and N/N when N=0.
- template <>
- struct Combinations<nil, 0>
- {
- using type = tuple<nil>;
- };
- template <class A, int k, int N=len<A>>
- using Combinations_ = typename Combinations<A, k, N>::type;
- // Sign of permutations.
- template <class C, class R> struct PermutationSign;
- template <int w, class C, class R>
- struct PermutationSignIfFound
- {
- constexpr static int value
- = ((w & 1) ? -1 : +1)
- * PermutationSign<typename Append<typename Take<C, w>::type,
- typename Drop<C, w+1>::type>::type,
- typename Drop1<R>::type>::value;
- };
- template <class C, class R>
- struct PermutationSignIfFound<-1, C, R>
- {
- constexpr static int value = 0;
- };
- template <>
- struct PermutationSign<nil, nil>
- {
- constexpr static int value = 1;
- };
- template <class C>
- struct PermutationSign<C, nil>
- {
- constexpr static int value = 0;
- };
- template <class R>
- struct PermutationSign<nil, R>
- {
- constexpr static int value = 0;
- };
- template <class C, class Org>
- struct PermutationSign
- {
- constexpr static int value
- = PermutationSignIfFound<Index<C, First_<Org>>::value,
- C, Org>::value;
- };
- template <int ... I> using int_list = tuple<int_t<I> ...>;
- // increment the w-th element of an int_t<> list.
- template <class L, int w>
- struct Inc
- {
- using type = typename
- Append<typename Take<L, w>::type,
- typename Cons<int_t<Ref_<L, w>::value+1>,
- typename Drop<L, w+1>::type>::type>::type;
- };
- template <class A> struct InvertIndex;
- template <class ... A> struct InvertIndex<std::tuple<A ...>>
- {
- using AT = std::tuple<A ...>;
- template <class T> struct IndexA
- {
- using type = int_t<Index<AT, T>::value>;
- };
- constexpr static int N = Apply_<Max, AT>::value;
- using type = Map_<IndexA, Iota_<(N>=0 ? N+1 : 0)>>;
- };
- template <class A> using InvertIndex_ = typename InvertIndex<A>::type;
- // Used in tests.
- template <class A, int ... I>
- struct check_idx
- {
- constexpr static bool value = false;
- };
- template <>
- struct check_idx<nil>
- {
- constexpr static bool value = true;
- };
- template <class A0, int I0, class ... A, int ... I>
- struct check_idx<std::tuple<A0, A ...>, I0, I ...>
- {
- constexpr static bool value = (A0::value==I0)
- && check_idx<std::tuple<A ...>, I ...>::value;
- };
- } // namespace mp
|