1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_BASE_TEMPLATE_UTILS_H_
6 #define V8_BASE_TEMPLATE_UTILS_H_
7
8 #include <array>
9 #include <functional>
10 #include <iosfwd>
11 #include <type_traits>
12 #include <utility>
13
14 namespace v8 {
15 namespace base {
16
17 namespace detail {
18
19 template <typename Function, std::size_t... Indexes>
20 constexpr inline auto make_array_helper(Function f,
21 std::index_sequence<Indexes...>)
22 -> std::array<decltype(f(0)), sizeof...(Indexes)> {
23 return {{f(Indexes)...}};
24 }
25
26 } // namespace detail
27
28 // base::make_array: Create an array of fixed length, initialized by a function.
29 // The content of the array is created by calling the function with 0 .. Size-1.
30 // Example usage to create the array {0, 2, 4}:
31 // std::array<int, 3> arr = base::make_array<3>(
32 // [](std::size_t i) { return static_cast<int>(2 * i); });
33 // The resulting array will be constexpr if the passed function is constexpr.
34 template <std::size_t Size, class Function>
make_array(Function f)35 constexpr auto make_array(Function f) {
36 return detail::make_array_helper(f, std::make_index_sequence<Size>{});
37 }
38
39 // Helper to determine how to pass values: Pass scalars and arrays by value,
40 // others by const reference (even if it was a non-const ref before; this is
41 // disallowed by the style guide anyway).
42 // The default is to also remove array extends (int[5] -> int*), but this can be
43 // disabled by setting {remove_array_extend} to false.
44 template <typename T, bool remove_array_extend = true>
45 struct pass_value_or_ref {
46 using noref_t = typename std::remove_reference<T>::type;
47 using decay_t = typename std::conditional<
48 std::is_array<noref_t>::value && !remove_array_extend, noref_t,
49 typename std::decay<noref_t>::type>::type;
50 using type = typename std::conditional<std::is_scalar<decay_t>::value ||
51 std::is_array<decay_t>::value,
52 decay_t, const decay_t&>::type;
53 };
54
55 // Uses expression SFINAE to detect whether using operator<< would work.
56 template <typename T, typename = void>
57 struct has_output_operator : std::false_type {};
58 template <typename T>
59 struct has_output_operator<T, decltype(void(std::declval<std::ostream&>()
60 << std::declval<T>()))>
61 : std::true_type {};
62
63 // Fold all arguments from left to right with a given function.
64 template <typename Func, typename T>
65 constexpr auto fold(Func func, T&& t) {
66 return std::forward<T>(t);
67 }
68
69 template <typename Func, typename T1, typename T2, typename... Ts>
70 constexpr auto fold(Func func, T1&& first, T2&& second, Ts&&... more) {
71 auto&& folded = func(std::forward<T1>(first), std::forward<T2>(second));
72 return fold(std::move(func), std::forward<decltype(folded)>(folded),
73 std::forward<Ts>(more)...);
74 }
75
76 // {is_same<Ts...>::value} is true if all Ts are the same, false otherwise.
77 template <typename... Ts>
78 struct is_same : public std::false_type {};
79 template <>
80 struct is_same<> : public std::true_type {};
81 template <typename T>
82 struct is_same<T> : public std::true_type {};
83 template <typename T, typename... Ts>
84 struct is_same<T, T, Ts...> : public is_same<T, Ts...> {};
85
86 // Returns true, iff all values (implicitly converted to bool) are trueish.
87 template <typename... Args>
88 constexpr bool all(Args... rest) {
89 return fold(std::logical_and<>{}, true, rest...);
90 }
91
92 template <class... Ts>
93 struct make_void {
94 using type = void;
95 };
96 // Corresponds to C++17's std::void_t.
97 // Used for SFINAE based on type errors.
98 template <class... Ts>
99 using void_t = typename make_void<Ts...>::type;
100
101 } // namespace base
102 } // namespace v8
103
104 #endif // V8_BASE_TEMPLATE_UTILS_H_
105