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