1 | #pragma once |
2 | |
3 | #include <mbgl/util/type_list.hpp> |
4 | #include <mbgl/util/tuple.hpp> |
5 | |
6 | #include <type_traits> |
7 | |
8 | namespace mbgl { |
9 | |
10 | template <class T, class... Ts> |
11 | struct TypeIndex; |
12 | |
13 | template <class T, class... Ts> |
14 | struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {}; |
15 | |
16 | template <class T, class U, class... Ts> |
17 | struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {}; |
18 | |
19 | template <class...> class IndexedTuple; |
20 | |
21 | // A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is. |
22 | // |
23 | // See https://github.com/mapbox/cpp/blob/master/C%2B%2B%20Structural%20Metaprogramming.md |
24 | // for motivation. |
25 | // |
26 | template <class... Is, class... Ts> |
27 | class IndexedTuple<TypeList<Is...>, TypeList<Ts...>> : public tuple_polyfill<Ts...> { |
28 | public: |
29 | static_assert(sizeof...(Is) == sizeof...(Ts), "IndexedTuple size mismatch" ); |
30 | |
31 | using tuple_polyfill<Ts...>::tuple; |
32 | |
33 | template <class I> |
34 | auto& get() { |
35 | return get_polyfill<TypeIndex<I, Is...>::value>(*this); |
36 | } |
37 | |
38 | template <class I> |
39 | const auto& get() const { |
40 | return get_polyfill<TypeIndex<I, Is...>::value>(*this); |
41 | } |
42 | |
43 | template <class... Js, class... Us> |
44 | IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> |
45 | concat(const IndexedTuple<TypeList<Js...>, TypeList<Us...>>& other) const { |
46 | return IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> { |
47 | get<Is>()..., |
48 | other.template get<Js>()... |
49 | }; |
50 | } |
51 | }; |
52 | |
53 | } // namespace mbgl |
54 | |