Line data Source code
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 : #include "src/base/template-utils.h"
6 :
7 : #include "test/unittests/test-utils.h"
8 :
9 : namespace v8 {
10 : namespace base {
11 : namespace template_utils_unittest {
12 :
13 : ////////////////////////////
14 : // Test make_array.
15 : ////////////////////////////
16 :
17 : namespace {
18 : template <typename T, size_t Size>
19 2 : void CheckArrayEquals(const std::array<T, Size>& arr1,
20 : const std::array<T, Size>& arr2) {
21 14 : for (size_t i = 0; i < Size; ++i) {
22 6 : CHECK_EQ(arr1[i], arr2[i]);
23 : }
24 2 : }
25 : } // namespace
26 :
27 15443 : TEST(TemplateUtilsTest, MakeArraySimple) {
28 1 : auto computed_array = base::make_array<3>([](int i) { return 1 + (i * 3); });
29 1 : std::array<int, 3> expected{{1, 4, 7}};
30 1 : CheckArrayEquals(computed_array, expected);
31 1 : }
32 :
33 : namespace {
34 : constexpr int doubleIntValue(int i) { return i * 2; }
35 : } // namespace
36 :
37 15443 : TEST(TemplateUtilsTest, MakeArrayConstexpr) {
38 1 : constexpr auto computed_array = base::make_array<3>(doubleIntValue);
39 1 : constexpr std::array<int, 3> expected{{0, 2, 4}};
40 1 : CheckArrayEquals(computed_array, expected);
41 1 : }
42 :
43 : ////////////////////////////
44 : // Test pass_value_or_ref.
45 : ////////////////////////////
46 :
47 : // Wrap into this helper struct, such that the type is printed on errors.
48 : template <typename T1, typename T2>
49 : struct CheckIsSame {
50 : static_assert(std::is_same<T1, T2>::value, "test failure");
51 : };
52 :
53 : #define TEST_PASS_VALUE_OR_REF0(remove_extend, expected, given) \
54 : static_assert( \
55 : sizeof(CheckIsSame<expected, \
56 : pass_value_or_ref<given, remove_extend>::type>) > 0, \
57 : "check")
58 :
59 : #define TEST_PASS_VALUE_OR_REF(expected, given) \
60 : static_assert( \
61 : sizeof(CheckIsSame<expected, pass_value_or_ref<given>::type>) > 0, \
62 : "check")
63 :
64 : TEST_PASS_VALUE_OR_REF(int, int&);
65 : TEST_PASS_VALUE_OR_REF(int, int&&);
66 : TEST_PASS_VALUE_OR_REF(const char*, const char[14]);
67 : TEST_PASS_VALUE_OR_REF(const char*, const char*&&);
68 : TEST_PASS_VALUE_OR_REF(const char*, const char (&)[14]);
69 : TEST_PASS_VALUE_OR_REF(const std::string&, std::string);
70 : TEST_PASS_VALUE_OR_REF(const std::string&, std::string&);
71 : TEST_PASS_VALUE_OR_REF(const std::string&, const std::string&);
72 : TEST_PASS_VALUE_OR_REF(int, const int);
73 : TEST_PASS_VALUE_OR_REF(int, const int&);
74 : TEST_PASS_VALUE_OR_REF(const int*, const int*);
75 : TEST_PASS_VALUE_OR_REF(const int*, const int* const);
76 : TEST_PASS_VALUE_OR_REF0(false, const char[14], const char[14]);
77 : TEST_PASS_VALUE_OR_REF0(false, const char[14], const char (&)[14]);
78 : TEST_PASS_VALUE_OR_REF0(false, const std::string&, std::string);
79 : TEST_PASS_VALUE_OR_REF0(false, const std::string&, std::string&);
80 : TEST_PASS_VALUE_OR_REF0(false, const std::string&, const std::string&);
81 : TEST_PASS_VALUE_OR_REF0(false, int, const int);
82 : TEST_PASS_VALUE_OR_REF0(false, int, const int&);
83 :
84 : //////////////////////////////
85 : // Test has_output_operator.
86 : //////////////////////////////
87 :
88 : // Intrinsic types:
89 : static_assert(has_output_operator<int>::value, "int can be output");
90 : static_assert(has_output_operator<void*>::value, "void* can be output");
91 : static_assert(has_output_operator<uint64_t>::value, "int can be output");
92 :
93 : // Classes:
94 : class TestClass1 {};
95 : class TestClass2 {};
96 : extern std::ostream& operator<<(std::ostream& str, const TestClass2&);
97 : class TestClass3 {};
98 : extern std::ostream& operator<<(std::ostream& str, TestClass3);
99 : static_assert(!has_output_operator<TestClass1>::value,
100 : "TestClass1 can not be output");
101 : static_assert(has_output_operator<TestClass2>::value,
102 : "non-const TestClass2 can be output");
103 : static_assert(has_output_operator<const TestClass2>::value,
104 : "const TestClass2 can be output");
105 : static_assert(has_output_operator<TestClass3>::value,
106 : "non-const TestClass3 can be output");
107 : static_assert(has_output_operator<const TestClass3>::value,
108 : "const TestClass3 can be output");
109 :
110 : //////////////////////////////
111 : // Test fold.
112 : //////////////////////////////
113 :
114 : struct FoldAllSameType {
115 : constexpr uint32_t operator()(uint32_t a, uint32_t b) const { return a | b; }
116 : };
117 : static_assert(base::fold(FoldAllSameType{}, 3, 6) == 7, "check fold");
118 : // Test that it works if implicit conversion is needed for one of the
119 : // parameters.
120 : static_assert(base::fold(FoldAllSameType{}, uint8_t{1}, 256) == 257,
121 : "check correct type inference");
122 : // Test a single parameter.
123 : static_assert(base::fold(FoldAllSameType{}, 25) == 25,
124 : "check folding a single argument");
125 :
126 15443 : TEST(TemplateUtilsTest, FoldDifferentType) {
127 : auto fn = [](std::string str, char c) {
128 3 : str.push_back(c);
129 : return str;
130 : };
131 3 : CHECK_EQ(base::fold(fn, std::string("foo"), 'b', 'a', 'r'), "foobar");
132 1 : }
133 :
134 15443 : TEST(TemplateUtilsTest, FoldMoveOnlyType) {
135 : auto fn = [](std::unique_ptr<std::string> str, char c) {
136 1 : str->push_back(c);
137 : return str;
138 : };
139 : std::unique_ptr<std::string> str = base::make_unique<std::string>("foo");
140 : std::unique_ptr<std::string> folded =
141 2 : base::fold(fn, std::move(str), 'b', 'a', 'r');
142 1 : CHECK_NULL(str);
143 1 : CHECK_NOT_NULL(folded);
144 1 : CHECK_EQ(*folded, "foobar");
145 1 : }
146 :
147 : struct TemplatizedFoldFunctor {
148 : template <typename T, typename... Tup>
149 1 : std::tuple<Tup..., typename std::decay<T>::type> operator()(
150 : std::tuple<Tup...> tup, T&& val) {
151 : return std::tuple_cat(std::move(tup),
152 1 : std::make_tuple(std::forward<T>(val)));
153 : }
154 : };
155 15443 : TEST(TemplateUtilsTest, FoldToTuple) {
156 : auto input = std::make_tuple(char{'x'}, int{4}, double{3.2},
157 2 : std::unique_ptr<uint8_t>{}, std::string{"foo"});
158 : auto result =
159 : base::fold(TemplatizedFoldFunctor{}, std::make_tuple(),
160 : std::get<0>(input), std::get<1>(input), std::get<2>(input),
161 1 : std::unique_ptr<uint8_t>{}, std::get<4>(input));
162 : static_assert(std::is_same<decltype(result), decltype(input)>::value,
163 : "the resulting tuple should have the same type as the input");
164 : DCHECK_EQ(input, result);
165 1 : }
166 :
167 : } // namespace template_utils_unittest
168 : } // namespace base
169 9264 : } // namespace v8
|