125 lines
4.1 KiB
C
125 lines
4.1 KiB
C
|
/*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <limits>
|
||
|
#include <tuple>
|
||
|
#include <type_traits>
|
||
|
|
||
|
// tupleRange<start, n>(tuple): select n elements starting at index start
|
||
|
// in the given tuple
|
||
|
// tupleRange<start>(tuple): select all elements starting at index start
|
||
|
// until the end of the given tuple
|
||
|
// tuplePrepend(x, tuple): return a tuple obtained by prepending x to the
|
||
|
// given tuple.
|
||
|
//
|
||
|
// In Lisp lingo, std::get<0> is car, tupleRange<1> is cdr, and tuplePrepend
|
||
|
// is cons.
|
||
|
|
||
|
namespace folly {
|
||
|
|
||
|
// TemplateSeq<T, ...> is a type parametrized by sizeof...(Xs) values of type
|
||
|
// T. Used to destructure the values into a template parameter pack;
|
||
|
// see the example in TupleSelect, below.
|
||
|
template <class T, T... xs>
|
||
|
struct TemplateSeq {
|
||
|
template <T x>
|
||
|
using Prepend = TemplateSeq<T, x, xs...>;
|
||
|
};
|
||
|
|
||
|
// TemplateRange<T, start, n>::type is
|
||
|
// TemplateSeq<T, start+1, start+2, ..., start+n-1>
|
||
|
template <class T, T start, T n, class Enable = void>
|
||
|
struct TemplateRange;
|
||
|
|
||
|
template <class T, T start, T n>
|
||
|
struct TemplateRange<T, start, n, typename std::enable_if<(n > 0)>::type> {
|
||
|
using type =
|
||
|
typename TemplateRange<T, start + 1, n - 1>::type::template Prepend<
|
||
|
start>;
|
||
|
};
|
||
|
|
||
|
template <class T, T start, T n>
|
||
|
struct TemplateRange<T, start, n, typename std::enable_if<(n <= 0)>::type> {
|
||
|
using type = TemplateSeq<T>;
|
||
|
};
|
||
|
|
||
|
// Similar to TemplateRange, given a tuple T,
|
||
|
// TemplateTupleRange<T, start, n>::type is
|
||
|
// TemplateSeq<size_t, start, start+1, ..., start+k-1>
|
||
|
// where k = min(tuple_size<T>::value - start, n)
|
||
|
// (that is, it's a TemplateSeq of at most n elements, but won't extend
|
||
|
// past the end of the given tuple)
|
||
|
template <
|
||
|
class T,
|
||
|
std::size_t start = 0,
|
||
|
std::size_t n = std::numeric_limits<std::size_t>::max(),
|
||
|
std::size_t size =
|
||
|
std::tuple_size<typename std::remove_reference<T>::type>::value,
|
||
|
class Enable = typename std::enable_if<(start <= size)>::type>
|
||
|
struct TemplateTupleRange {
|
||
|
using type = typename TemplateRange<
|
||
|
std::size_t,
|
||
|
start,
|
||
|
(n <= size - start ? n : size - start)>::type;
|
||
|
};
|
||
|
|
||
|
namespace detail {
|
||
|
|
||
|
// Helper class to select a subset of a tuple
|
||
|
template <class S>
|
||
|
struct TupleSelect;
|
||
|
template <std::size_t... Ns>
|
||
|
struct TupleSelect<TemplateSeq<std::size_t, Ns...>> {
|
||
|
template <class T>
|
||
|
static auto select(T&& v)
|
||
|
-> decltype(std::make_tuple(std::get<Ns>(std::forward<T>(v))...)) {
|
||
|
return std::make_tuple(std::get<Ns>(std::forward<T>(v))...);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace detail
|
||
|
|
||
|
// Return a tuple consisting of the elements at a range of indices.
|
||
|
//
|
||
|
// Use as tupleRange<start, n>(t) to return a tuple of (at most) n
|
||
|
// elements starting at index start in tuple t.
|
||
|
// If only start is specified (tupleRange<start>(t)), returns all elements
|
||
|
// starting at index start until the end of the tuple t.
|
||
|
// Won't compile if start > size of t.
|
||
|
// Will return fewer elements (size - start) if start + n > size of t.
|
||
|
template <
|
||
|
std::size_t start = 0,
|
||
|
std::size_t n = std::numeric_limits<std::size_t>::max(),
|
||
|
class T,
|
||
|
class Seq = typename TemplateTupleRange<T, start, n>::type>
|
||
|
auto tupleRange(T&& v)
|
||
|
-> decltype(detail::TupleSelect<Seq>::select(std::forward<T>(v))) {
|
||
|
return detail::TupleSelect<Seq>::select(std::forward<T>(v));
|
||
|
}
|
||
|
|
||
|
// Return a tuple obtained by prepending car to the tuple cdr.
|
||
|
template <class T, class U>
|
||
|
auto tuplePrepend(T&& car, U&& cdr) -> decltype(std::tuple_cat(
|
||
|
std::make_tuple(std::forward<T>(car)),
|
||
|
std::forward<U>(cdr))) {
|
||
|
return std::tuple_cat(
|
||
|
std::make_tuple(std::forward<T>(car)), std::forward<U>(cdr));
|
||
|
}
|
||
|
|
||
|
} // namespace folly
|