// 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 #include #include #include #include #include namespace v8 { namespace base { namespace detail { template constexpr inline auto make_array_helper(Function f, std::index_sequence) -> std::array { return {{f(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 arr = base::make_array<3>( // [](std::size_t i) { return static_cast(2 * i); }); // The resulting array will be constexpr if the passed function is constexpr. template constexpr auto make_array(Function f) { return detail::make_array_helper(f, std::make_index_sequence{}); } // 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 struct pass_value_or_ref { using noref_t = typename std::remove_reference::type; using decay_t = typename std::conditional< std::is_array::value && !remove_array_extend, noref_t, typename std::decay::type>::type; using type = typename std::conditional::value || std::is_array::value, decay_t, const decay_t&>::type; }; // Uses expression SFINAE to detect whether using operator<< would work. template struct has_output_operator : std::false_type {}; template struct has_output_operator< T, TStream, decltype(void(std::declval() << std::declval()))> : std::true_type {}; // Turn std::tuple into std::tuple. template using append_tuple_type = decltype(std::tuple_cat( std::declval(), std::declval>())); // Turn std::tuple into std::tuple. template using prepend_tuple_type = decltype(std::tuple_cat( std::declval>(), std::declval())); namespace detail { template constexpr bool NIsNotGreaterThanTupleSize = N <= std::tuple_size_v>; template constexpr auto tuple_slice_impl(const T& tpl, std::index_sequence) { return std::tuple{std::get(tpl)...}; } template constexpr auto tuple_for_each_impl(const Tuple& tpl, Function&& function, std::index_sequence) { (function(std::get(tpl)), ...); } template constexpr auto tuple_for_each_with_index_impl(const Tuple& tpl, Function&& function, std::index_sequence) { (function(std::get(tpl), std::integral_constant()), ...); } } // namespace detail // Get the first N elements from a tuple. template constexpr auto tuple_head(Tuple&& tpl) { constexpr size_t total_size = std::tuple_size_v>; static_assert(N <= total_size); return detail::tuple_slice_impl<0>(std::forward(tpl), std::make_index_sequence()); } // 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>> constexpr auto tuple_drop(Tuple&& tpl) { constexpr size_t total_size = std::tuple_size_v>; static_assert(N <= total_size); return detail::tuple_slice_impl( std::forward(tpl), std::make_index_sequence()); } // Calls `function(v)` for each `v` in the tuple. template constexpr void tuple_for_each(Tuple&& tpl, Function&& function) { detail::tuple_for_each_impl( std::forward(tpl), function, std::make_index_sequence>>()); } // Calls `function(v, i)` for each `v` in the tuple, with index `i`. The index // `i` is passed as an std::integral_constant, rather than a raw size_t, // to allow it to be used template constexpr void tuple_for_each_with_index(Tuple&& tpl, Function&& function) { detail::tuple_for_each_with_index_impl( std::forward(tpl), function, std::make_index_sequence>>()); } #ifdef __clang__ template using nth_type = __type_pack_element; #else template struct nth_type; template struct nth_type<0, T, Ts...> { using type = T; }; template struct nth_type : public nth_type {}; #endif template using nth_type_t = typename nth_type::type; // Find SearchT in Ts. SearchT must be present at most once in Ts, and returns // sizeof...(Ts) if not found. template struct index_of_type; // Not found / empty list. template struct index_of_type : public std::integral_constant {}; // SearchT found at head of list. template struct index_of_type : public std::integral_constant { // SearchT is not allowed to be anywhere else in the list. static_assert(index_of_type::value == sizeof...(Ts)); }; // Recursion, SearchT not found at head of list. template struct index_of_type : public std::integral_constant::value> { }; template constexpr size_t index_of_type_v = index_of_type::value; } // namespace base } // namespace v8 #endif // V8_BASE_TEMPLATE_UTILS_H_