test/zserio/ArrayViewTest.cpp
Line | Count | Source |
1 | | #include <algorithm> |
2 | | |
3 | | #include "gtest/gtest.h" |
4 | | #include "zserio/ArrayView.h" |
5 | | #include "zserio/Types.h" |
6 | | |
7 | | namespace zserio |
8 | | { |
9 | | |
10 | | namespace |
11 | | { |
12 | | |
13 | | struct TestObject |
14 | | { |
15 | | UInt32 field; |
16 | | |
17 | | constexpr bool operator==(const TestObject& other) const |
18 | 15 | { |
19 | 15 | return field == other.field; |
20 | 15 | } |
21 | | |
22 | | constexpr bool operator<(const TestObject& other) const |
23 | 3 | { |
24 | 3 | return field < other.field; |
25 | 3 | } |
26 | | }; |
27 | | |
28 | | struct VarDynInt16Owner |
29 | | { |
30 | | uint8_t numBits = 10; |
31 | | }; |
32 | | |
33 | | } // namespace |
34 | | |
35 | | template <> |
36 | | class View<TestObject> |
37 | | { |
38 | | public: |
39 | | explicit View(const TestObject& data) : |
40 | 60 | m_data(data) |
41 | 60 | {} |
42 | | |
43 | | UInt32 field() const |
44 | 35 | { |
45 | 35 | return m_data.field; |
46 | 35 | } |
47 | | |
48 | | constexpr bool operator==(const View& other) const |
49 | 8 | { |
50 | 8 | return m_data == other.m_data; |
51 | 8 | } |
52 | | |
53 | | constexpr bool operator!=(const View& other) const |
54 | 4 | { |
55 | 4 | return !operator==(other); |
56 | 4 | } |
57 | | |
58 | | constexpr bool operator<(const View& other) const |
59 | 3 | { |
60 | 3 | return m_data < other.m_data; |
61 | 3 | } |
62 | | |
63 | | private: |
64 | | const TestObject& m_data; |
65 | | }; |
66 | | |
67 | | namespace detail |
68 | | { |
69 | | |
70 | | template <> |
71 | | struct ObjectTraits<TestObject> |
72 | | { |
73 | | struct PackingContext |
74 | | { |
75 | | DeltaContext field; |
76 | | }; |
77 | | |
78 | | static BitSize bitSizeOf(const View<TestObject>& view, BitSize bitPosition) |
79 | 2 | { |
80 | 2 | BitSize endBitPosition = bitPosition; |
81 | 2 | endBitPosition += detail::bitSizeOf(view.field(), endBitPosition); |
82 | 2 | return endBitPosition - bitPosition; |
83 | 2 | } |
84 | | |
85 | | static void write(BitStreamWriter& writer, const View<TestObject>& view) |
86 | 2 | { |
87 | 2 | detail::write(writer, view.field()); |
88 | 2 | } |
89 | | |
90 | | static View<TestObject> read(BitStreamReader& reader, TestObject& data) |
91 | 4 | { |
92 | 4 | View<TestObject> view(data); |
93 | 4 | detail::read(reader, data.field); |
94 | 4 | return view; |
95 | 4 | } |
96 | | |
97 | | static void initContext(PackingContext& packingContext, const View<TestObject>& view) |
98 | 10 | { |
99 | 10 | detail::initContext(packingContext.field, view.field()); |
100 | 10 | } |
101 | | |
102 | | static BitSize bitSizeOf(PackingContext& packingContext, const View<TestObject>& view, BitSize bitPosition) |
103 | 5 | { |
104 | 5 | BitSize endBitPosition = bitPosition; |
105 | 5 | endBitPosition += detail::bitSizeOf(packingContext.field, view.field(), endBitPosition); |
106 | 5 | return endBitPosition - bitPosition; |
107 | 5 | } |
108 | | |
109 | | static void write(PackingContext& packingContext, BitStreamWriter& writer, const View<TestObject>& view) |
110 | 5 | { |
111 | 5 | detail::write(packingContext.field, writer, view.field()); |
112 | 5 | } |
113 | | |
114 | | static void read(PackingContext& packingContext, BitStreamReader& reader, TestObject& data) |
115 | 11 | { |
116 | | |
117 | 11 | detail::read(packingContext.field, reader, data.field); |
118 | 11 | } |
119 | | }; |
120 | | |
121 | | } // namespace detail |
122 | | |
123 | | struct VarDynInt16ArrayTraits |
124 | | { |
125 | | using OwnerType = VarDynInt16Owner; |
126 | | |
127 | | static View<DynInt16> at(const VarDynInt16Owner& owner, const DynInt16& element, size_t) |
128 | 48 | { |
129 | 48 | return View<DynInt16>(element, owner.numBits); |
130 | 48 | } |
131 | | |
132 | | static void read(BitStreamReader& reader, const VarDynInt16Owner& owner, DynInt16& element, size_t) |
133 | 11 | { |
134 | 11 | detail::read(reader, element, owner.numBits); |
135 | 11 | } |
136 | | |
137 | | static void read(detail::DeltaContext& context, BitStreamReader& reader, const VarDynInt16Owner& owner, |
138 | | DynInt16& element, size_t) |
139 | 7 | { |
140 | 7 | detail::read(context, reader, element, owner.numBits); |
141 | 7 | } |
142 | | }; |
143 | | |
144 | | TEST(ArrayViewTest, boolArray) |
145 | 1 | { |
146 | 1 | Vector<Bool> rawArray1{true, false}; |
147 | 1 | Vector<Bool> rawArray2{true, true}; |
148 | | |
149 | 1 | ArrayView<const Bool> array1(rawArray1); |
150 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0)); |
151 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1)); |
152 | | |
153 | 1 | ArrayView<const Bool> array2(rawArray2); |
154 | 1 | ASSERT_FALSE(array1 == array2); |
155 | 1 | ASSERT_TRUE(array1 != array2); |
156 | 1 | ASSERT_LT(array1, array2); |
157 | | |
158 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
159 | 1 | BitBuffer buffer(bitSize); |
160 | 1 | BitStreamWriter writer(buffer); |
161 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
162 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
163 | | |
164 | 1 | BitStreamReader reader(buffer); |
165 | 1 | Vector<Bool> readRawArray; |
166 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray); |
167 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
168 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
169 | | |
170 | 1 | const std::array<uint8_t, 10> buffer2{ |
171 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
172 | 1 | }; |
173 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
174 | 1 | ASSERT_THROW(detail::read<detail::ArrayType::AUTO>(reader2, readRawArray), CppRuntimeException); |
175 | 1 | } |
176 | | |
177 | | TEST(ArrayViewTest, boolPackedArray) |
178 | 1 | { |
179 | 1 | Vector<Bool> rawArray{true, false, true, false, true}; |
180 | 1 | ArrayView<const Bool> array(rawArray); |
181 | | |
182 | 1 | const BitSize packedBitSize = detail::bitSizeOfPacked<detail::ArrayType::AUTO>(array); |
183 | 1 | BitBuffer buffer(packedBitSize); |
184 | 1 | BitStreamWriter writer(buffer); |
185 | 1 | detail::writePacked<detail::ArrayType::AUTO>(writer, array); |
186 | 1 | ASSERT_EQ(packedBitSize, writer.getBitPosition()); |
187 | | |
188 | 1 | BitStreamReader reader(buffer); |
189 | 1 | Vector<Bool> readRawArray; |
190 | 1 | detail::readPacked<detail::ArrayType::AUTO>(reader, readRawArray, rawArray.size()); |
191 | 1 | ASSERT_EQ(packedBitSize, reader.getBitPosition()); |
192 | 1 | ASSERT_EQ(rawArray, readRawArray); |
193 | | |
194 | 1 | const std::array<uint8_t, 10> buffer2{ |
195 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
196 | 1 | }; |
197 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
198 | 1 | ASSERT_THROW(detail::readPacked<detail::ArrayType::AUTO>(reader2, readRawArray), CppRuntimeException); |
199 | 1 | } |
200 | | |
201 | | TEST(ArrayViewTest, int8Array) |
202 | 1 | { |
203 | 1 | Vector<Int8> rawArray1{0, 13}; |
204 | 1 | Vector<Int8> rawArray2{0, 42}; |
205 | | |
206 | 1 | ArrayView<const Int8> array1(rawArray1); |
207 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0)); |
208 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1)); |
209 | | |
210 | 1 | ArrayView<const Int8> array2(rawArray2); |
211 | 1 | ASSERT_FALSE(array1 == array2); |
212 | 1 | ASSERT_TRUE(array1 != array2); |
213 | 1 | ASSERT_LT(array1, array2); |
214 | | |
215 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
216 | 1 | BitBuffer buffer(bitSize); |
217 | 1 | BitStreamWriter writer(buffer); |
218 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
219 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
220 | | |
221 | 1 | BitStreamReader reader(buffer); |
222 | 1 | Vector<Int8> readRawArray; |
223 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray); |
224 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
225 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
226 | | |
227 | 1 | const std::array<uint8_t, 10> buffer2{ |
228 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
229 | 1 | }; |
230 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
231 | 1 | ASSERT_THROW(detail::read<detail::ArrayType::AUTO>(reader2, readRawArray), CppRuntimeException); |
232 | 1 | } |
233 | | |
234 | | TEST(ArrayViewTest, int8PackedArray) |
235 | 1 | { |
236 | 1 | Vector<Int8> rawArray = {-4, -3, -1, 0, 2, 4, 6, 8, 10, 10, 11}; |
237 | 1 | ArrayView<const Int8> array(rawArray); |
238 | | |
239 | 1 | static_assert(detail::is_packable_v<Int8>, "shall be packable"); |
240 | 1 | static_assert(detail::is_packable_v<const Int8>, "shall be packable"); |
241 | | |
242 | | // maxBitNumber == 2 |
243 | | // packingDescriptor 7 + firstElement 8 + 10 * (maxBitNumber 2 + 1) |
244 | 1 | static constexpr BitSize packedBitSize = 45; |
245 | 1 | ASSERT_EQ(packedBitSize, detail::bitSizeOfPacked<detail::ArrayType::NORMAL>(array)); |
246 | | |
247 | 1 | BitBuffer buffer(packedBitSize); |
248 | 1 | BitStreamWriter writer(buffer); |
249 | 1 | detail::writePacked<detail::ArrayType::NORMAL>(writer, array); |
250 | 1 | ASSERT_EQ(packedBitSize, writer.getBitPosition()); |
251 | | |
252 | 1 | BitStreamReader reader(buffer); |
253 | 1 | Vector<Int8> readRawArray; |
254 | | |
255 | 1 | ASSERT_THROW( |
256 | 1 | detail::readPacked<detail::ArrayType::NORMAL>(reader, readRawArray, 9999), CppRuntimeException); |
257 | | |
258 | 1 | reader.setBitPosition(0); |
259 | 1 | detail::readPacked<detail::ArrayType::NORMAL>(reader, readRawArray, rawArray.size()); |
260 | 1 | ASSERT_EQ(rawArray, readRawArray); |
261 | | |
262 | 1 | ASSERT_EQ(rawArray.size(), array.size()); |
263 | 1 | ASSERT_FALSE(array.empty()); |
264 | | |
265 | 1 | Vector<Int8> emptyRawArray; |
266 | 1 | ArrayView<const Int8> emptyArray(emptyRawArray); |
267 | 1 | ASSERT_TRUE(emptyArray.empty()); |
268 | | |
269 | 1 | ASSERT_THROW(emptyArray.front(), CppRuntimeException); |
270 | | |
271 | 1 | ASSERT_EQ(rawArray.front(), array.front()); |
272 | 1 | ASSERT_EQ(rawArray.back(), array.back()); |
273 | | |
274 | 1 | auto it = array.begin(); |
275 | 1 | ASSERT_EQ(-4, *it); |
276 | 1 | ASSERT_EQ(-1, it[2]); |
277 | 1 | it += 2; |
278 | 1 | ASSERT_EQ(-1, *it); |
279 | 1 | ASSERT_EQ(-3, it[-1]); |
280 | 1 | it -= 1; |
281 | 1 | ASSERT_EQ(-3, *it); |
282 | 1 | auto otherIt = it + 2; |
283 | 1 | ASSERT_EQ(0, *otherIt); |
284 | 1 | ASSERT_EQ(2, *(++otherIt)); |
285 | 1 | ASSERT_EQ(2, *(otherIt++)); |
286 | 1 | ASSERT_EQ(4, *otherIt); |
287 | 1 | ASSERT_EQ(2, *(--otherIt)); |
288 | 1 | ASSERT_EQ(2, *(otherIt--)); |
289 | 1 | ASSERT_EQ(0, *otherIt); |
290 | 1 | otherIt = 2 + it; |
291 | 1 | ASSERT_EQ(0, *otherIt); |
292 | 1 | otherIt = it - 1; |
293 | 1 | ASSERT_EQ(-4, *otherIt); |
294 | 1 | ASSERT_EQ(1, it - otherIt); |
295 | 1 | ASSERT_EQ(-1, otherIt - it); |
296 | 1 | ASSERT_EQ(array.size(), array.end() - array.begin()); |
297 | | |
298 | 1 | ASSERT_TRUE(otherIt == array.begin()); |
299 | 1 | ASSERT_FALSE(otherIt == array.end()); |
300 | | |
301 | 1 | ASSERT_TRUE(otherIt != array.end()); |
302 | 1 | ASSERT_FALSE(otherIt != array.begin()); |
303 | | |
304 | 1 | ASSERT_TRUE(otherIt < array.end()); |
305 | 1 | ASSERT_FALSE(array.end() < otherIt); |
306 | | |
307 | 1 | ASSERT_TRUE(array.end() > array.begin()); |
308 | 1 | ASSERT_FALSE(array.begin() > array.end()); |
309 | | |
310 | 1 | ASSERT_TRUE(array.begin() <= array.end()); |
311 | 1 | ASSERT_TRUE(array.begin() <= array.begin()); |
312 | 1 | ASSERT_FALSE(array.end() <= array.begin()); |
313 | | |
314 | 1 | ASSERT_TRUE(array.end() >= array.begin()); |
315 | 1 | ASSERT_TRUE(array.end() >= array.end()); |
316 | 1 | ASSERT_FALSE(array.begin() >= array.end()); |
317 | | |
318 | 1 | size_t i = 0; |
319 | 1 | for (auto element : array) |
320 | 11 | { |
321 | 11 | ASSERT_EQ(rawArray[i++], element); |
322 | 11 | } |
323 | | |
324 | 1 | i = array.size() - 1; |
325 | 12 | for (auto rit = array.rbegin(); rit < array.rend(); ++rit11 ) |
326 | 11 | { |
327 | 11 | ASSERT_EQ(rawArray[i--], *rit); |
328 | 11 | } |
329 | | |
330 | 5 | auto foundIt = std::find_if(array.begin(), array.end(), [](auto value) 1 { |
331 | 5 | return value > 0; |
332 | 5 | }); |
333 | 1 | ASSERT_NE(array.end(), foundIt); |
334 | 1 | ASSERT_EQ(2, *foundIt); |
335 | 1 | } |
336 | | |
337 | | TEST(ArrayViewTest, fixedDynInt16Array) |
338 | 1 | { |
339 | 1 | Vector<Int<9>> rawArray1{-2, 13}; |
340 | 1 | Vector<Int<9>> rawArray2{-2, 42}; |
341 | | |
342 | 1 | ArrayView<const Int<9>> array1(rawArray1); |
343 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0)); |
344 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1)); |
345 | | |
346 | 1 | ArrayView<const Int<9>> array2(rawArray2); |
347 | 1 | ASSERT_FALSE(array1 == array2); |
348 | 1 | ASSERT_TRUE(array1 != array2); |
349 | 1 | ASSERT_LT(array1, array2); |
350 | | |
351 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
352 | 1 | BitBuffer buffer(bitSize); |
353 | 1 | BitStreamWriter writer(buffer); |
354 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
355 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
356 | | |
357 | 1 | BitStreamReader reader(buffer); |
358 | 1 | Vector<Int<9>> readRawArray; |
359 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray, rawArray1.size()); |
360 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
361 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
362 | | |
363 | 1 | const std::array<uint8_t, 10> buffer2{ |
364 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
365 | 1 | }; |
366 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
367 | 1 | ASSERT_THROW(detail::read<detail::ArrayType::AUTO>(reader2, readRawArray), CppRuntimeException); |
368 | 1 | } |
369 | | |
370 | | TEST(ArrayViewTest, variableDynInt16Array) |
371 | 1 | { |
372 | 1 | Vector<DynInt16> rawArray1{-2, 13}; |
373 | 1 | Vector<DynInt16> rawArray2{-2, 42}; |
374 | | |
375 | 1 | VarDynInt16Owner owner; |
376 | | |
377 | 1 | ArrayView<const DynInt16, VarDynInt16ArrayTraits> array1(rawArray1, owner); |
378 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0).value()); |
379 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1).value()); |
380 | | |
381 | 1 | ArrayView<const DynInt16, VarDynInt16ArrayTraits> array2(rawArray2, owner); |
382 | 1 | ASSERT_FALSE(array1 == array2); |
383 | 1 | ASSERT_TRUE(array1 != array2); |
384 | 1 | ASSERT_LT(array1, array2); |
385 | | |
386 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
387 | 1 | BitBuffer buffer(bitSize); |
388 | 1 | BitStreamWriter writer(buffer); |
389 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
390 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
391 | | |
392 | 1 | BitStreamReader reader(buffer); |
393 | 1 | Vector<DynInt16> readRawArray; |
394 | 1 | detail::readWithTraits<detail::ArrayType::AUTO, VarDynInt16ArrayTraits>( |
395 | 1 | reader, readRawArray, owner, rawArray1.size()); |
396 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
397 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
398 | | |
399 | 1 | const std::array<uint8_t, 10> buffer2{ |
400 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
401 | 1 | }; |
402 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
403 | 1 | ASSERT_THROW((detail::readWithTraits<detail::ArrayType::AUTO, VarDynInt16ArrayTraits>( |
404 | 1 | reader2, readRawArray, owner)), |
405 | 1 | CppRuntimeException); |
406 | 1 | } |
407 | | |
408 | | TEST(ArrayViewTest, variableDynInt16PackedArray) |
409 | 1 | { |
410 | 1 | Vector<DynInt16> rawArray{-2, 0, 2, 4, 6, 8, 10}; |
411 | | |
412 | 1 | VarDynInt16Owner owner; |
413 | 1 | ArrayView<const DynInt16, VarDynInt16ArrayTraits> array(rawArray, owner); |
414 | | |
415 | | // maxBitNumber == 2 |
416 | | // packingDescriptor 7 + firstElement 10 + 6 * (maxBitNumber 2 + 1) |
417 | 1 | const BitSize packedBitSize = 35; |
418 | 1 | ASSERT_EQ(packedBitSize, detail::bitSizeOfPacked<detail::ArrayType::NORMAL>(array)); |
419 | | |
420 | 1 | BitBuffer buffer(packedBitSize); |
421 | 1 | BitStreamWriter writer(buffer); |
422 | 1 | detail::writePacked<detail::ArrayType::NORMAL>(writer, array); |
423 | 1 | ASSERT_EQ(packedBitSize, writer.getBitPosition()); |
424 | | |
425 | 1 | BitStreamReader reader(buffer); |
426 | 1 | Vector<DynInt16> readRawArray; |
427 | 1 | detail::readPackedWithTraits<detail::ArrayType::NORMAL, VarDynInt16ArrayTraits>( |
428 | 1 | reader, readRawArray, owner, rawArray.size()); |
429 | 1 | ASSERT_EQ(packedBitSize, reader.getBitPosition()); |
430 | 1 | ASSERT_EQ(rawArray, readRawArray); |
431 | | |
432 | 1 | reader.setBitPosition(0); |
433 | 1 | ASSERT_THROW((detail::readWithTraits<detail::ArrayType::NORMAL, VarDynInt16ArrayTraits>( |
434 | 1 | reader, readRawArray, owner, 9999)), |
435 | 1 | CppRuntimeException); |
436 | 1 | } |
437 | | |
438 | | TEST(ArrayViewTest, varUInt16Array) |
439 | 1 | { |
440 | 1 | Vector<VarUInt16> rawArray1{0, 13}; |
441 | 1 | Vector<VarUInt16> rawArray2{0, 42}; |
442 | | |
443 | 1 | ArrayView<const VarUInt16> array1(rawArray1); |
444 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0)); |
445 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1)); |
446 | | |
447 | 1 | ArrayView<const VarUInt16> array2(rawArray2); |
448 | 1 | ASSERT_FALSE(array1 == array2); |
449 | 1 | ASSERT_TRUE(array1 != array2); |
450 | 1 | ASSERT_LT(array1, array2); |
451 | | |
452 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
453 | 1 | BitBuffer buffer(bitSize); |
454 | 1 | BitStreamWriter writer(buffer); |
455 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
456 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
457 | | |
458 | 1 | BitStreamReader reader(buffer); |
459 | 1 | Vector<VarUInt16> readRawArray; |
460 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray, rawArray1.size()); |
461 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
462 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
463 | | |
464 | 1 | const std::array<uint8_t, 10> buffer2{ |
465 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
466 | 1 | }; |
467 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
468 | 1 | ASSERT_THROW((detail::read<detail::ArrayType::AUTO>(reader2, readRawArray)), CppRuntimeException); |
469 | 1 | } |
470 | | |
471 | | TEST(ArrayViewTest, varUInt16PackedArray) |
472 | 1 | { |
473 | 1 | Vector<VarUInt16> rawArray{0, 2, 4, 6, 8, 10, 12}; |
474 | 1 | ArrayView<const VarUInt16> array(rawArray); |
475 | | |
476 | 1 | const BitSize packedBitSize = detail::bitSizeOfPacked<detail::ArrayType::AUTO>(array); |
477 | 1 | BitBuffer buffer(packedBitSize); |
478 | 1 | BitStreamWriter writer(buffer); |
479 | 1 | detail::writePacked<detail::ArrayType::AUTO>(writer, array); |
480 | 1 | ASSERT_EQ(packedBitSize, writer.getBitPosition()); |
481 | | |
482 | 1 | BitStreamReader reader(buffer); |
483 | 1 | Vector<VarUInt16> readRawArray; |
484 | 1 | detail::readPacked<detail::ArrayType::AUTO>(reader, readRawArray, rawArray.size()); |
485 | 1 | ASSERT_EQ(packedBitSize, reader.getBitPosition()); |
486 | 1 | ASSERT_EQ(rawArray, readRawArray); |
487 | | |
488 | 1 | const std::array<uint8_t, 10> buffer2{ |
489 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
490 | 1 | }; |
491 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
492 | 1 | ASSERT_THROW((detail::readPacked<detail::ArrayType::AUTO>(reader2, readRawArray)), CppRuntimeException); |
493 | 1 | } |
494 | | |
495 | | TEST(ArrayViewTest, float16Array) |
496 | 1 | { |
497 | 1 | Vector<Float16> rawArray1{-9.0F, 0.0F, 10.0F}; |
498 | 1 | Vector<Float16> rawArray2{-9.0F, 0.0F, 10.1F}; |
499 | | |
500 | 1 | ArrayView<const Float16> array1(rawArray1); |
501 | 1 | ArrayView<const Float16> array2(rawArray2); |
502 | | |
503 | 1 | ASSERT_EQ(16, ArrayTraits<Float16>::bitSizeOf()); |
504 | | |
505 | 1 | ASSERT_LT(array1, array2); |
506 | 1 | ASSERT_GT(array2, array1); |
507 | | |
508 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
509 | 1 | BitBuffer buffer(bitSize); |
510 | 1 | BitStreamWriter writer(buffer); |
511 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
512 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
513 | | |
514 | 1 | BitStreamReader reader(buffer); |
515 | 1 | Vector<Float16> readRawArray; |
516 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray, rawArray1.size()); |
517 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
518 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
519 | | |
520 | 1 | const std::array<uint8_t, 10> buffer2{ |
521 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
522 | 1 | }; |
523 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
524 | 1 | ASSERT_THROW((detail::read<detail::ArrayType::AUTO>(reader2, readRawArray)), CppRuntimeException); |
525 | 1 | } |
526 | | |
527 | | TEST(ArrayViewTest, bytesArray) |
528 | 1 | { |
529 | 1 | Vector<Bytes> rawArray1{{{{1, 255}}, {{127, 128}}}}; |
530 | 1 | Vector<Bytes> rawArray2{{{{1, 255}}, {{127, 129}}}}; |
531 | | |
532 | 1 | ArrayView<const Bytes> array1(rawArray1); |
533 | 1 | ArrayView<const Bytes> array2(rawArray2); |
534 | | |
535 | 1 | ASSERT_TRUE(std::equal( |
536 | 1 | rawArray1.begin(), rawArray1.end(), array1.zserioData().begin(), array1.zserioData().end())); |
537 | | |
538 | 1 | constexpr bool isSpan = std::is_same_v<Span<const uint8_t>, decltype(array1.at(0))>; |
539 | 1 | ASSERT_TRUE(isSpan); |
540 | | |
541 | 1 | ASSERT_TRUE(std::equal( |
542 | 1 | rawArray1.at(0).begin(), rawArray1.at(0).end(), array1.at(0).begin(), array1.at(0).end())); |
543 | 1 | ASSERT_TRUE(std::equal( |
544 | 1 | rawArray1.at(1).begin(), rawArray1.at(1).end(), array1.at(1).begin(), array1.at(1).end())); |
545 | | |
546 | 1 | ASSERT_NE(array1, array2); |
547 | 1 | ASSERT_LT(array1, array2); |
548 | | |
549 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
550 | 1 | BitBuffer buffer(bitSize); |
551 | 1 | BitStreamWriter writer(buffer); |
552 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
553 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
554 | | |
555 | 1 | BitStreamReader reader(buffer); |
556 | 1 | Vector<Bytes> readRawArray; |
557 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray, rawArray1.size()); |
558 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
559 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
560 | | |
561 | 1 | const std::array<uint8_t, 10> buffer2{ |
562 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
563 | 1 | }; |
564 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
565 | 1 | ASSERT_THROW((detail::read<detail::ArrayType::AUTO>(reader2, readRawArray)), CppRuntimeException); |
566 | 1 | } |
567 | | |
568 | | TEST(ArrayViewTest, stringArray) |
569 | 1 | { |
570 | 1 | Vector<std::string> rawArray1 = {"String0", "String1", "String2"}; |
571 | 1 | Vector<std::string> rawArray2 = {"String0", "String1", "String3"}; |
572 | | |
573 | 1 | ArrayView<const std::string> array1(rawArray1); |
574 | 1 | ArrayView<const std::string> array2(rawArray2); |
575 | | |
576 | 1 | constexpr bool isStringView = std::is_same_v<std::string_view, decltype(array1.at(0))>; |
577 | 1 | ASSERT_TRUE(isStringView); |
578 | | |
579 | 1 | ASSERT_EQ(rawArray1.at(0), array1.at(0)); |
580 | 1 | ASSERT_EQ(rawArray1.at(1), array1.at(1)); |
581 | 1 | ASSERT_EQ(rawArray1.at(2), array1.at(2)); |
582 | | |
583 | 1 | ASSERT_NE(array1, array2); |
584 | 1 | ASSERT_LT(array1, array2); |
585 | | |
586 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
587 | 1 | BitBuffer buffer(bitSize); |
588 | 1 | BitStreamWriter writer(buffer); |
589 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
590 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
591 | | |
592 | 1 | BitStreamReader reader(buffer); |
593 | 1 | Vector<std::string> readRawArray; |
594 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray, rawArray1.size()); |
595 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
596 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
597 | | |
598 | 1 | const std::array<uint8_t, 10> buffer2{ |
599 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
600 | 1 | }; |
601 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
602 | 1 | ASSERT_THROW((detail::read<detail::ArrayType::AUTO>(reader2, readRawArray)), CppRuntimeException); |
603 | 1 | } |
604 | | |
605 | | TEST(ArrayViewTest, testObjectArray) |
606 | 1 | { |
607 | 1 | Vector<TestObject> rawArray1{TestObject{0}, TestObject{13}}; |
608 | 1 | Vector<TestObject> rawArray2{TestObject{0}, TestObject{42}}; |
609 | | |
610 | 1 | ArrayView<const TestObject> array1(rawArray1); |
611 | 1 | ASSERT_EQ(rawArray1.at(0).field, array1.at(0).field()); |
612 | 1 | ASSERT_EQ(rawArray1.at(1).field, array1.at(1).field()); |
613 | | |
614 | 1 | ArrayView<const TestObject> array2(rawArray2); |
615 | | |
616 | 1 | ASSERT_FALSE(array1 == array2); |
617 | 1 | ASSERT_TRUE(array1 != array2); |
618 | 1 | ASSERT_LT(array1, array2); |
619 | | |
620 | 1 | const std::array<uint8_t, 10> buffer2{ |
621 | 1 | 0xFF, 0xFF, 0xFF, 0x3F, // big array size |
622 | 1 | }; |
623 | 1 | Vector<TestObject> readRawArray2; |
624 | 1 | BitStreamReader reader2(buffer2.data(), buffer2.size()); |
625 | 1 | ASSERT_THROW((detail::read<detail::ArrayType::AUTO>(reader2, readRawArray2)), CppRuntimeException); |
626 | | |
627 | 1 | const BitSize bitSize = detail::bitSizeOf<detail::ArrayType::AUTO>(array1); |
628 | 1 | BitBuffer buffer(bitSize); |
629 | 1 | BitStreamWriter writer(buffer); |
630 | 1 | detail::write<detail::ArrayType::AUTO>(writer, array1); |
631 | 1 | ASSERT_EQ(bitSize, writer.getBitPosition()); |
632 | | |
633 | 1 | BitStreamReader reader(buffer); |
634 | 1 | Vector<TestObject> readRawArray; |
635 | 1 | detail::read<detail::ArrayType::AUTO>(reader, readRawArray); |
636 | 1 | ASSERT_EQ(bitSize, reader.getBitPosition()); |
637 | 1 | ASSERT_EQ(rawArray1, readRawArray); |
638 | | |
639 | 1 | ASSERT_FALSE(array1.empty()); |
640 | 1 | ASSERT_EQ(0, array1.front().field()); |
641 | 1 | ASSERT_EQ(13, array1.back().field()); |
642 | | |
643 | 1 | size_t i = 0; |
644 | 1 | for (auto object : array1) |
645 | 2 | { |
646 | 2 | ASSERT_EQ(i++ == 0 ? 0 : 13, object.field()); |
647 | 2 | } |
648 | | |
649 | 1 | TestObject object{13}; |
650 | 1 | zserio::View view(object); |
651 | 1 | ASSERT_EQ(view, *(array1.begin() + 1)); |
652 | 1 | ASSERT_EQ(0, array1.begin()->field()); |
653 | 1 | ASSERT_EQ(view, array1.begin()[1]); |
654 | 1 | ASSERT_EQ(array1.begin(), array1.end() - 2); |
655 | 1 | ASSERT_EQ(*array1.begin(), *(array1.end() - 2)); |
656 | 1 | ASSERT_EQ(array1.size(), array1.end() - array1.begin()); |
657 | | |
658 | 2 | auto foundIt = std::find_if(array1.begin(), array1.end(), [](const zserio::View<TestObject>& element) 1 { |
659 | 2 | return element.field() != 0; |
660 | 2 | }); |
661 | 1 | ASSERT_NE(array1.end(), foundIt); |
662 | 1 | ASSERT_EQ(array1.at(1), *foundIt); |
663 | | |
664 | 2 | auto notFoundIt = std::find_if(array1.begin(), array1.end(), [](const zserio::View<TestObject>& element) 1 { |
665 | 2 | return element.field() > 13; |
666 | 2 | }); |
667 | 1 | ASSERT_EQ(array1.end(), notFoundIt); |
668 | 1 | } |
669 | | |
670 | | TEST(ArrayViewTest, testObjectPackedArray) |
671 | 1 | { |
672 | 1 | Vector<TestObject> rawArray{TestObject{0}, TestObject{2}, TestObject{4}, TestObject{6}, TestObject{8}}; |
673 | 1 | ArrayView<const TestObject> array(rawArray); |
674 | | |
675 | 1 | static_assert(detail::is_packable_v<TestObject>, "shall be packable"); |
676 | 1 | static_assert(detail::is_packable_v<const TestObject>, "shall be packable"); |
677 | | |
678 | | // maxBitNumber == 2 |
679 | | // packingDescriptor 7 + firstElement 32 + 4 * (maxBitNumber 2 + 1) |
680 | 1 | const BitSize packedBitSize = 51; |
681 | 1 | ASSERT_EQ(packedBitSize, detail::bitSizeOfPacked<detail::ArrayType::NORMAL>(array)); |
682 | | |
683 | 1 | BitBuffer buffer(packedBitSize); |
684 | 1 | BitStreamWriter writer(buffer); |
685 | 1 | detail::writePacked<detail::ArrayType::NORMAL>(writer, array); |
686 | 1 | ASSERT_EQ(packedBitSize, writer.getBitPosition()); |
687 | | |
688 | 1 | BitStreamReader reader(buffer); |
689 | 1 | Vector<TestObject> readRawArray; |
690 | 1 | detail::readPacked<detail::ArrayType::NORMAL>(reader, readRawArray, rawArray.size()); |
691 | 1 | ASSERT_EQ(packedBitSize, reader.getBitPosition()); |
692 | 1 | ASSERT_EQ(rawArray, readRawArray); |
693 | | |
694 | 1 | reader.setBitPosition(0); |
695 | 1 | ASSERT_THROW( |
696 | 1 | (detail::readPacked<detail::ArrayType::NORMAL>(reader, readRawArray, 9999)), CppRuntimeException); |
697 | 1 | } |
698 | | |
699 | | } // namespace zserio |