1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include <array>
16 #include <cstddef>
17 #include <span>
18 #include <string_view>
19 #include <vector>
20
21 #include "gtest/gtest.h"
22 #include "pw_kvs/internal/span_traits.h"
23
24 namespace pw::kvs {
25 namespace {
26
27 using internal::make_span;
28 using std::byte;
29 using std::dynamic_extent;
30 using std::span;
31
32 // Test that the ConvertsToSpan trait correctly idenitifies types that convert
33 // to std::span.
34
35 // Basic types should not convert to span.
36 struct Foo {};
37
38 static_assert(!ConvertsToSpan<Foo>());
39 static_assert(!ConvertsToSpan<int>());
40 static_assert(!ConvertsToSpan<void>());
41 static_assert(!ConvertsToSpan<byte>());
42 static_assert(!ConvertsToSpan<byte*>());
43
44 // Arrays without an extent are just pointers -- these should not convert.
45 static_assert(!ConvertsToSpan<bool[]>());
46 static_assert(!ConvertsToSpan<const int[]>());
47 static_assert(!ConvertsToSpan<bool (&)[]>());
48 static_assert(!ConvertsToSpan<const int (&)[]>());
49 static_assert(!ConvertsToSpan<bool(&&)[]>());
50 static_assert(!ConvertsToSpan<const int(&&)[]>());
51
52 // C arrays convert to span.
53 static_assert(ConvertsToSpan<std::array<int, 5>>());
54 static_assert(ConvertsToSpan<decltype("Hello!")>());
55
56 static_assert(ConvertsToSpan<bool[1]>());
57 static_assert(ConvertsToSpan<char[35]>());
58 static_assert(ConvertsToSpan<const int[35]>());
59
60 static_assert(ConvertsToSpan<bool (&)[1]>());
61 static_assert(ConvertsToSpan<char (&)[35]>());
62 static_assert(ConvertsToSpan<const int (&)[35]>());
63
64 static_assert(ConvertsToSpan<bool(&&)[1]>());
65 static_assert(ConvertsToSpan<bool(&&)[1]>());
66 static_assert(ConvertsToSpan<char(&&)[35]>());
67 static_assert(ConvertsToSpan<const int(&&)[35]>());
68
69 // Container types convert to span.
70 struct FakeContainer {
datapw::kvs::__anon965cffe80111::FakeContainer71 const char* data() const { return nullptr; }
sizepw::kvs::__anon965cffe80111::FakeContainer72 size_t size() const { return 0; }
73 };
74
75 static_assert(ConvertsToSpan<FakeContainer>());
76 static_assert(ConvertsToSpan<FakeContainer&>());
77 static_assert(ConvertsToSpan<FakeContainer&&>());
78 static_assert(ConvertsToSpan<const FakeContainer>());
79 static_assert(ConvertsToSpan<const FakeContainer&>());
80 static_assert(ConvertsToSpan<const FakeContainer&&>());
81
82 static_assert(ConvertsToSpan<std::string_view>());
83 static_assert(ConvertsToSpan<std::string_view&>());
84 static_assert(ConvertsToSpan<std::string_view&&>());
85
86 static_assert(ConvertsToSpan<const std::string_view>());
87 static_assert(ConvertsToSpan<const std::string_view&>());
88 static_assert(ConvertsToSpan<const std::string_view&&>());
89
90 // Spans should also convert to span.
91 static_assert(ConvertsToSpan<std::span<int>>());
92 static_assert(ConvertsToSpan<std::span<byte>>());
93 static_assert(ConvertsToSpan<std::span<const int*>>());
94 static_assert(ConvertsToSpan<std::span<bool>&&>());
95 static_assert(ConvertsToSpan<const std::span<bool>&>());
96 static_assert(ConvertsToSpan<std::span<bool>&&>());
97
98 // These tests for the make_span function were copied from Chromium:
99 // https://chromium.googlesource.com/chromium/src/+/master/base/containers/span_unittest.cc
100
TEST(SpanTest,MakeSpanFromDataAndSize)101 TEST(SpanTest, MakeSpanFromDataAndSize) {
102 int* nullint = nullptr;
103 auto empty_span = make_span(nullint, 0);
104 EXPECT_TRUE(empty_span.empty());
105 EXPECT_EQ(nullptr, empty_span.data());
106 std::vector<int> vector = {1, 1, 2, 3, 5, 8};
107 span<int> expected_span(vector.data(), vector.size());
108 auto made_span = make_span(vector.data(), vector.size());
109 EXPECT_EQ(expected_span.data(), made_span.data());
110 EXPECT_EQ(expected_span.size(), made_span.size());
111 static_assert(decltype(made_span)::extent == dynamic_extent, "");
112 static_assert(
113 std::is_same<decltype(expected_span), decltype(made_span)>::value,
114 "the type of made_span differs from expected_span!");
115 }
116
TEST(SpanTest,MakeSpanFromPointerPair)117 TEST(SpanTest, MakeSpanFromPointerPair) {
118 int* nullint = nullptr;
119 auto empty_span = make_span(nullint, nullint);
120 EXPECT_TRUE(empty_span.empty());
121 EXPECT_EQ(nullptr, empty_span.data());
122 std::vector<int> vector = {1, 1, 2, 3, 5, 8};
123 span<int> expected_span(vector.data(), vector.size());
124 auto made_span = make_span(vector.data(), vector.data() + vector.size());
125 EXPECT_EQ(expected_span.data(), made_span.data());
126 EXPECT_EQ(expected_span.size(), made_span.size());
127 static_assert(decltype(made_span)::extent == dynamic_extent, "");
128 static_assert(
129 std::is_same<decltype(expected_span), decltype(made_span)>::value,
130 "the type of made_span differs from expected_span!");
131 }
132
TEST(SpanTest,MakeSpanFromConstexprArray)133 TEST(SpanTest, MakeSpanFromConstexprArray) {
134 static constexpr int kArray[] = {1, 2, 3, 4, 5};
135 constexpr span<const int, 5> expected_span(kArray);
136 constexpr auto made_span = make_span(kArray);
137 EXPECT_EQ(expected_span.data(), made_span.data());
138 EXPECT_EQ(expected_span.size(), made_span.size());
139 static_assert(decltype(made_span)::extent == 5, "");
140 static_assert(
141 std::is_same<decltype(expected_span), decltype(made_span)>::value,
142 "the type of made_span differs from expected_span!");
143 }
144
TEST(SpanTest,MakeSpanFromStdArray)145 TEST(SpanTest, MakeSpanFromStdArray) {
146 const std::array<int, 5> kArray = {{1, 2, 3, 4, 5}};
147 span<const int, 5> expected_span(kArray);
148 auto made_span = make_span(kArray);
149 EXPECT_EQ(expected_span.data(), made_span.data());
150 EXPECT_EQ(expected_span.size(), made_span.size());
151 static_assert(decltype(made_span)::extent == 5, "");
152 static_assert(
153 std::is_same<decltype(expected_span), decltype(made_span)>::value,
154 "the type of made_span differs from expected_span!");
155 }
156
TEST(SpanTest,MakeSpanFromConstContainer)157 TEST(SpanTest, MakeSpanFromConstContainer) {
158 const std::vector<int> vector = {-1, -2, -3, -4, -5};
159 span<const int> expected_span(vector);
160 auto made_span = make_span(vector);
161 EXPECT_EQ(expected_span.data(), made_span.data());
162 EXPECT_EQ(expected_span.size(), made_span.size());
163 static_assert(decltype(made_span)::extent == dynamic_extent, "");
164 static_assert(
165 std::is_same<decltype(expected_span), decltype(made_span)>::value,
166 "the type of made_span differs from expected_span!");
167 }
168
169 #if 0 // Not currently working with fixed extent spans.
170
171 TEST(SpanTest, MakeStaticSpanFromConstContainer) {
172 const std::vector<int> vector = {-1, -2, -3, -4, -5};
173 span<const int, 5> expected_span(vector.data(), vector.size());
174 auto made_span = make_span<5>(vector);
175 EXPECT_EQ(expected_span.data(), made_span.data());
176 EXPECT_EQ(expected_span.size(), made_span.size());
177 static_assert(decltype(made_span)::extent == 5, "");
178 static_assert(
179 std::is_same<decltype(expected_span), decltype(made_span)>::value,
180 "the type of made_span differs from expected_span!");
181 }
182
183 #endif // 0
184
TEST(SpanTest,MakeSpanFromContainer)185 TEST(SpanTest, MakeSpanFromContainer) {
186 std::vector<int> vector = {-1, -2, -3, -4, -5};
187 span<int> expected_span(vector);
188 auto made_span = make_span(vector);
189 EXPECT_EQ(expected_span.data(), made_span.data());
190 EXPECT_EQ(expected_span.size(), made_span.size());
191 static_assert(decltype(made_span)::extent == dynamic_extent, "");
192 static_assert(
193 std::is_same<decltype(expected_span), decltype(made_span)>::value,
194 "the type of made_span differs from expected_span!");
195 }
196
197 #if 0 // Not currently working with fixed extent spans.
198
199 TEST(SpanTest, MakeStaticSpanFromContainer) {
200 std::vector<int> vector = {-1, -2, -3, -4, -5};
201 span<int, 5> expected_span(vector.data(), vector.size());
202 auto made_span = make_span<5>(vector);
203 EXPECT_EQ(expected_span.data(), make_span<5>(vector).data());
204 EXPECT_EQ(expected_span.size(), make_span<5>(vector).size());
205 static_assert(decltype(make_span<5>(vector))::extent == 5, "");
206 static_assert(
207 std::is_same<decltype(expected_span), decltype(made_span)>::value,
208 "the type of made_span differs from expected_span!");
209 }
210
211 TEST(SpanTest, MakeStaticSpanFromConstexprContainer) {
212 constexpr StringPiece str = "Hello, World";
213 constexpr auto made_span = make_span<12>(str);
214 static_assert(str.data() == made_span.data(), "Error: data() does not match");
215 static_assert(str.size() == made_span.size(), "Error: size() does not match");
216 static_assert(std::is_same<decltype(str)::value_type,
217 decltype(made_span)::value_type>::value,
218 "Error: value_type does not match");
219 static_assert(str.size() == decltype(made_span)::extent,
220 "Error: extent does not match");
221 }
222
223 #endif // 0
224
TEST(SpanTest,MakeSpanFromRValueContainer)225 TEST(SpanTest, MakeSpanFromRValueContainer) {
226 std::vector<int> vector = {-1, -2, -3, -4, -5};
227 span<const int> expected_span(vector);
228 // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
229 // std::move(foo), make_span does not actually take ownership of the passed in
230 // container. Writing it this way makes it more obvious that we simply care
231 // about the right behavour when passing rvalues.
232 auto made_span = make_span(static_cast<std::vector<int>&&>(vector));
233 EXPECT_EQ(expected_span.data(), made_span.data());
234 EXPECT_EQ(expected_span.size(), made_span.size());
235 static_assert(decltype(made_span)::extent == dynamic_extent, "");
236 static_assert(
237 std::is_same<decltype(expected_span), decltype(made_span)>::value,
238 "the type of made_span differs from expected_span!");
239 }
240
241 #if 0 // Not currently working with fixed extent spans.
242
243 TEST(SpanTest, MakeStaticSpanFromRValueContainer) {
244 std::vector<int> vector = {-1, -2, -3, -4, -5};
245 span<const int, 5> expected_span(vector.data(), vector.size());
246 // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
247 // std::move(foo), make_span does not actually take ownership of the passed in
248 // container. Writing it this way makes it more obvious that we simply care
249 // about the right behavour when passing rvalues.
250 auto made_span = make_span<5>(static_cast<std::vector<int>&&>(vector));
251 EXPECT_EQ(expected_span.data(), made_span.data());
252 EXPECT_EQ(expected_span.size(), made_span.size());
253 static_assert(decltype(made_span)::extent == 5, "");
254 static_assert(
255 std::is_same<decltype(expected_span), decltype(made_span)>::value,
256 "the type of made_span differs from expected_span!");
257 }
258
259 #endif // 0
260
TEST(SpanTest,MakeSpanFromDynamicSpan)261 TEST(SpanTest, MakeSpanFromDynamicSpan) {
262 static constexpr int kArray[] = {1, 2, 3, 4, 5};
263 constexpr span<const int> expected_span(kArray);
264 constexpr auto made_span = make_span(expected_span);
265 static_assert(std::is_same<decltype(expected_span)::element_type,
266 decltype(made_span)::element_type>::value,
267 "make_span(span) should have the same element_type as span");
268 static_assert(expected_span.data() == made_span.data(),
269 "make_span(span) should have the same data() as span");
270 static_assert(expected_span.size() == made_span.size(),
271 "make_span(span) should have the same size() as span");
272 static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
273 "make_span(span) should have the same extent as span");
274 static_assert(
275 std::is_same<decltype(expected_span), decltype(made_span)>::value,
276 "the type of made_span differs from expected_span!");
277 }
278
TEST(SpanTest,MakeSpanFromStaticSpan)279 TEST(SpanTest, MakeSpanFromStaticSpan) {
280 static constexpr int kArray[] = {1, 2, 3, 4, 5};
281 constexpr span<const int, 5> expected_span(kArray);
282 constexpr auto made_span = make_span(expected_span);
283 static_assert(std::is_same<decltype(expected_span)::element_type,
284 decltype(made_span)::element_type>::value,
285 "make_span(span) should have the same element_type as span");
286 static_assert(expected_span.data() == made_span.data(),
287 "make_span(span) should have the same data() as span");
288 static_assert(expected_span.size() == made_span.size(),
289 "make_span(span) should have the same size() as span");
290 static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
291 "make_span(span) should have the same extent as span");
292 static_assert(
293 std::is_same<decltype(expected_span), decltype(made_span)>::value,
294 "the type of made_span differs from expected_span!");
295 }
296
297 } // namespace
298 } // namespace pw::kvs
299