1 | /* |
2 | * Copyright 2015-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <limits> |
20 | #include <tuple> |
21 | #include <type_traits> |
22 | |
23 | // tupleRange<start, n>(tuple): select n elements starting at index start |
24 | // in the given tuple |
25 | // tupleRange<start>(tuple): select all elements starting at index start |
26 | // until the end of the given tuple |
27 | // tuplePrepend(x, tuple): return a tuple obtained by prepending x to the |
28 | // given tuple. |
29 | // |
30 | // In Lisp lingo, std::get<0> is car, tupleRange<1> is cdr, and tuplePrepend |
31 | // is cons. |
32 | |
33 | namespace folly { |
34 | |
35 | // TemplateSeq<T, ...> is a type parametrized by sizeof...(Xs) values of type |
36 | // T. Used to destructure the values into a template parameter pack; |
37 | // see the example in TupleSelect, below. |
38 | template <class T, T... xs> |
39 | struct TemplateSeq { |
40 | template <T x> |
41 | using Prepend = TemplateSeq<T, x, xs...>; |
42 | }; |
43 | |
44 | // TemplateRange<T, start, n>::type is |
45 | // TemplateSeq<T, start+1, start+2, ..., start+n-1> |
46 | template <class T, T start, T n, class Enable = void> |
47 | struct TemplateRange; |
48 | |
49 | template <class T, T start, T n> |
50 | struct TemplateRange<T, start, n, typename std::enable_if<(n > 0)>::type> { |
51 | using type = |
52 | typename TemplateRange<T, start + 1, n - 1>::type::template Prepend< |
53 | start>; |
54 | }; |
55 | |
56 | template <class T, T start, T n> |
57 | struct TemplateRange<T, start, n, typename std::enable_if<(n <= 0)>::type> { |
58 | using type = TemplateSeq<T>; |
59 | }; |
60 | |
61 | // Similar to TemplateRange, given a tuple T, |
62 | // TemplateTupleRange<T, start, n>::type is |
63 | // TemplateSeq<size_t, start, start+1, ..., start+k-1> |
64 | // where k = min(tuple_size<T>::value - start, n) |
65 | // (that is, it's a TemplateSeq of at most n elements, but won't extend |
66 | // past the end of the given tuple) |
67 | template < |
68 | class T, |
69 | std::size_t start = 0, |
70 | std::size_t n = std::numeric_limits<std::size_t>::max(), |
71 | std::size_t size = |
72 | std::tuple_size<typename std::remove_reference<T>::type>::value, |
73 | class Enable = typename std::enable_if<(start <= size)>::type> |
74 | struct TemplateTupleRange { |
75 | using type = typename TemplateRange< |
76 | std::size_t, |
77 | start, |
78 | (n <= size - start ? n : size - start)>::type; |
79 | }; |
80 | |
81 | namespace detail { |
82 | |
83 | // Helper class to select a subset of a tuple |
84 | template <class S> |
85 | struct TupleSelect; |
86 | template <std::size_t... Ns> |
87 | struct TupleSelect<TemplateSeq<std::size_t, Ns...>> { |
88 | template <class T> |
89 | static auto select(T&& v) |
90 | -> decltype(std::make_tuple(std::get<Ns>(std::forward<T>(v))...)) { |
91 | return std::make_tuple(std::get<Ns>(std::forward<T>(v))...); |
92 | } |
93 | }; |
94 | |
95 | } // namespace detail |
96 | |
97 | // Return a tuple consisting of the elements at a range of indices. |
98 | // |
99 | // Use as tupleRange<start, n>(t) to return a tuple of (at most) n |
100 | // elements starting at index start in tuple t. |
101 | // If only start is specified (tupleRange<start>(t)), returns all elements |
102 | // starting at index start until the end of the tuple t. |
103 | // Won't compile if start > size of t. |
104 | // Will return fewer elements (size - start) if start + n > size of t. |
105 | template < |
106 | std::size_t start = 0, |
107 | std::size_t n = std::numeric_limits<std::size_t>::max(), |
108 | class T, |
109 | class Seq = typename TemplateTupleRange<T, start, n>::type> |
110 | auto tupleRange(T&& v) |
111 | -> decltype(detail::TupleSelect<Seq>::select(std::forward<T>(v))) { |
112 | return detail::TupleSelect<Seq>::select(std::forward<T>(v)); |
113 | } |
114 | |
115 | // Return a tuple obtained by prepending car to the tuple cdr. |
116 | template <class T, class U> |
117 | auto tuplePrepend(T&& car, U&& cdr) -> decltype(std::tuple_cat( |
118 | std::make_tuple(std::forward<T>(car)), |
119 | std::forward<U>(cdr))) { |
120 | return std::tuple_cat( |
121 | std::make_tuple(std::forward<T>(car)), std::forward<U>(cdr)); |
122 | } |
123 | |
124 | } // namespace folly |
125 | |