folly: replace old-style header guards with "pragma once"
[folly.git] / folly / experimental / TupleOps.h
1 /*
2  * Copyright 2016 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> struct TemplateRange;
47
48 template <class T, T start, T n>
49 struct TemplateRange<
50   T, start, n,
51   typename std::enable_if<(n > 0)>::type> {
52   using type =
53     typename TemplateRange<T, start+1, n-1>::type::template Prepend<start>;
54 };
55
56 template <class T, T start, T n>
57 struct TemplateRange<
58   T, start, n,
59   typename std::enable_if<(n <= 0)>::type> {
60   using type = TemplateSeq<T>;
61 };
62
63 // Similar to TemplateRange, given a tuple T,
64 // TemplateTupleRange<T, start, n>::type is
65 // TemplateSeq<size_t, start, start+1, ..., start+k-1>
66 // where k = min(tuple_size<T>::value - start, n)
67 // (that is, it's a TemplateSeq of at most n elements, but won't extend
68 // past the end of the given tuple)
69 template <class T,
70           std::size_t start = 0,
71           std::size_t n = std::numeric_limits<std::size_t>::max(),
72           std::size_t size =
73             std::tuple_size<typename std::remove_reference<T>::type>::value,
74           class Enable = typename std::enable_if<(start <= size)>::type>
75 struct TemplateTupleRange {
76   using type = typename TemplateRange<
77       std::size_t,
78       start,
79       (n <= size - start ? n : size - start)>::type;
80 };
81
82 namespace detail {
83
84 // Helper class to select a subset of a tuple
85 template <class S> 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)
118 -> decltype(std::tuple_cat(std::make_tuple(std::forward<T>(car)),
119                            std::forward<U>(cdr))) {
120   return std::tuple_cat(std::make_tuple(std::forward<T>(car)),
121                         std::forward<U>(cdr));
122 }
123
124 }  // namespaces