chromium/v8/src/base/template-utils.h

// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_BASE_TEMPLATE_UTILS_H_
#define V8_BASE_TEMPLATE_UTILS_H_

#include <array>
#include <functional>
#include <iosfwd>
#include <tuple>
#include <type_traits>
#include <utility>

namespace v8 {
namespace base {

namespace detail {

template <typename Function, std::size_t... Indexes>
constexpr inline auto make_array_helper(Function f,
                                        std::index_sequence<Indexes...>)
    -> std::array<decltype(f(0)), sizeof...(Indexes)> {}

}  // namespace detail

// base::make_array: Create an array of fixed length, initialized by a function.
// The content of the array is created by calling the function with 0 .. Size-1.
// Example usage to create the array {0, 2, 4}:
//   std::array<int, 3> arr = base::make_array<3>(
//       [](std::size_t i) { return static_cast<int>(2 * i); });
// The resulting array will be constexpr if the passed function is constexpr.
template <std::size_t Size, class Function>
constexpr auto make_array(Function f) {}

// Helper to determine how to pass values: Pass scalars and arrays by value,
// others by const reference (even if it was a non-const ref before; this is
// disallowed by the style guide anyway).
// The default is to also remove array extends (int[5] -> int*), but this can be
// disabled by setting {remove_array_extend} to false.
template <typename T, bool remove_array_extend = true>
struct pass_value_or_ref {};

// Uses expression SFINAE to detect whether using operator<< would work.
template <typename T, typename TStream = std::ostream, typename = void>
struct has_output_operator : std::false_type {};
has_output_operator<T, TStream, decltype(void(std::declval<TStream &>() << std::declval<T>()))>;

// Turn std::tuple<A...> into std::tuple<A..., T>.
append_tuple_type;

// Turn std::tuple<A...> into std::tuple<T, A...>.
prepend_tuple_type;

namespace detail {

NIsNotGreaterThanTupleSize;

template <size_t N, typename T, size_t... Ints>
constexpr auto tuple_slice_impl(const T& tpl, std::index_sequence<Ints...>) {}

template <typename Tuple, typename Function, size_t... Index>
constexpr auto tuple_for_each_impl(const Tuple& tpl, Function&& function,
                                   std::index_sequence<Index...>) {}

template <typename Tuple, typename Function, size_t... Index>
constexpr auto tuple_for_each_with_index_impl(const Tuple& tpl,
                                              Function&& function,
                                              std::index_sequence<Index...>) {}

template <typename Tuple, typename Function, size_t... Index>
constexpr auto tuple_map_impl(Tuple&& tpl, const Function& function,
                              std::index_sequence<Index...>) {}

template <typename TupleV, typename TupleU, typename Function, size_t... Index>
constexpr auto tuple_map2_impl(TupleV&& tplv, TupleU&& tplu,
                               const Function& function,
                               std::index_sequence<Index...>) {}

template <size_t I, typename T, typename Tuple, typename Function>
constexpr auto tuple_fold_impl(T&& initial, Tuple&& tpl, Function&& function) {}

}  // namespace detail

// Get the first N elements from a tuple.
template <size_t N, typename Tuple>
constexpr auto tuple_head(Tuple&& tpl) {}

// Drop the first N elements from a tuple.
template <
    size_t N, typename Tuple,
    // If the user accidentally passes in an N that is larger than the tuple
    // size, the unsigned subtraction will create a giant index sequence and
    // crash the compiler. To avoid this and fail early, disable this function
    // for invalid N.
    typename = std::enable_if_t<detail::NIsNotGreaterThanTupleSize<N, Tuple>>>
constexpr auto tuple_drop(Tuple&& tpl) {}

// Calls `function(v)` for each `v` in the tuple.
template <typename Tuple, typename Function>
constexpr void tuple_for_each(Tuple&& tpl, Function&& function) {}

// Calls `function(v, i)` for each `v` in the tuple, with index `i`. The index
// `i` is passed as an std::integral_constant<size_t>, rather than a raw size_t,
// to allow it to be used
template <typename Tuple, typename Function>
constexpr void tuple_for_each_with_index(Tuple&& tpl, Function&& function) {}

// Calls `function(v)` for each `v` in the tuple and returns a new tuple with
// all the results.
template <typename Tuple, typename Function>
constexpr auto tuple_map(Tuple&& tpl, Function&& function) {}

// Calls `function(v, u)` for pairs `v<I>, u<I>` in the
// tuples and returns a new tuple with all the results.
template <typename TupleV, typename TupleU, typename Function>
constexpr auto tuple_map2(TupleV&& tplv, TupleU&& tplu, Function&& function) {}

// Left fold (reduce) the tuple starting with an initial value by applying
// function(...function(initial, tpl<0>)..., tpl<size-1>)
template <typename T, typename Tuple, typename Function>
constexpr auto tuple_fold(T&& initial, Tuple&& tpl, Function&& function) {}

#ifdef __clang__

nth_type_t;

#else

namespace detail {
template <size_t N, typename... Ts>
struct nth_type;

template <typename T, typename... Ts>
struct nth_type<0, T, Ts...> {
  using type = T;
};

template <size_t N, typename T, typename... Ts>
struct nth_type<N, T, Ts...> : public nth_type<N - 1, Ts...> {};
}  // namespace detail

template <size_t N, typename... T>
using nth_type_t = typename detail::nth_type<N, T...>::type;

#endif

// Find SearchT in Ts. SearchT must be present at most once in Ts, and returns
// sizeof...(Ts) if not found.
template <typename SearchT, typename... Ts>
struct index_of_type;

index_of_type_v;
has_type_v;

// Not found / empty list.
index_of_type<SearchT>;

// SearchT found at head of list.
index_of_type<SearchT, SearchT, Ts...>;

// Recursion, SearchT not found at head of list.
index_of_type<SearchT, T, Ts...>;

}  // namespace base
}  // namespace v8

#endif  // V8_BASE_TEMPLATE_UTILS_H_