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
33namespace 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.
38template <class T, T... xs>
39struct 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>
46template <class T, T start, T n, class Enable = void>
47struct TemplateRange;
48
49template <class T, T start, T n>
50struct 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
56template <class T, T start, T n>
57struct 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)
67template <
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>
74struct TemplateTupleRange {
75 using type = typename TemplateRange<
76 std::size_t,
77 start,
78 (n <= size - start ? n : size - start)>::type;
79};
80
81namespace detail {
82
83// Helper class to select a subset of a tuple
84template <class S>
85struct TupleSelect;
86template <std::size_t... Ns>
87struct 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.
105template <
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>
110auto 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.
116template <class T, class U>
117auto 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