xref: /aosp_15_r20/external/emboss/runtime/cpp/test/emboss_memory_util_test.cc (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of 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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <array>
16 #include <string>
17 #if __cplusplus >= 201703L
18 #include <cstddef>  // std::byte
19 #include <string_view>
20 #endif  // __cplusplus >= 201703L
21 #include <vector>
22 
23 #include "gtest/gtest.h"
24 #include "runtime/cpp/emboss_memory_util.h"
25 #include "runtime/cpp/emboss_prelude.h"
26 
27 namespace emboss {
28 namespace support {
29 namespace test {
30 
31 using ::emboss::prelude::IntView;
32 using ::emboss::prelude::UIntView;
33 
34 template </**/ ::std::size_t kBits>
35 using BigEndianBitBlockN =
36     BitBlock<BigEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
37 
38 template </**/ ::std::size_t kBits>
39 using LittleEndianBitBlockN =
40     BitBlock<LittleEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
41 
42 template <typename T, typename... Args>
init_array(Args &&...args)43 std::array<T, sizeof...(Args)> constexpr init_array(Args &&...args) {
44   return {T(std::forward<Args>(args))...};
45 }
46 
47 template <typename Container, typename... Args>
init_container(Args &&...args)48 auto constexpr init_container(Args &&...args) -> Container {
49   using CharType =
50       typename ::std::remove_reference<decltype(*Container().data())>::type;
51   return {CharType(std::forward<Args>(args))...};
52 }
53 
TEST(GreatestCommonDivisor,GreatestCommonDivisor)54 TEST(GreatestCommonDivisor, GreatestCommonDivisor) {
55   EXPECT_EQ(4U, GreatestCommonDivisor(12, 20));
56   EXPECT_EQ(4U, GreatestCommonDivisor(20, 12));
57   EXPECT_EQ(4U, GreatestCommonDivisor(20, 4));
58   EXPECT_EQ(6U, GreatestCommonDivisor(12, 78));
59   EXPECT_EQ(6U, GreatestCommonDivisor(6, 0));
60   EXPECT_EQ(6U, GreatestCommonDivisor(0, 6));
61   EXPECT_EQ(3U, GreatestCommonDivisor(9, 6));
62   EXPECT_EQ(0U, GreatestCommonDivisor(0, 0));
63 }
64 
65 // Because MemoryAccessor's parameters are template parameters, it is not
66 // possible to loop through them directly.  Instead, TestMemoryAccessor tests
67 // a particular MemoryAccessor's methods, then calls the next template to test
68 // the next set of template parameters to MemoryAccessor.
69 template <typename CharT, ::std::size_t kAlignment, ::std::size_t kOffset,
70           ::std::size_t kBits>
TestMemoryAccessor()71 void TestMemoryAccessor() {
72   alignas(kAlignment) auto bytes =
73       init_array<CharT>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
74   EXPECT_EQ(
75       0x0807060504030201UL & (~0x0UL >> (64 - kBits)),
76       (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadLittleEndianUInt(
77           bytes.data())))
78       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
79       << "; kBits = " << kBits;
80   EXPECT_EQ(
81       0x0102030405060708UL >> (64 - kBits),
82       (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadBigEndianUInt(
83           bytes.data())))
84       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
85       << "; kBits = " << kBits;
86 
87   MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteLittleEndianUInt(
88       bytes.data(), 0x7172737475767778UL & (~0x0UL >> (64 - kBits)));
89   auto expected_vector_after_write = init_container<std::vector<CharT>>(
90       0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71);
91   for (int i = kBits / 8; i < 8; ++i) {
92     expected_vector_after_write[i] = CharT(i + 1);
93   }
94   EXPECT_EQ(expected_vector_after_write,
95             ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
96       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
97       << "; kBits = " << kBits;
98 
99   MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteBigEndianUInt(
100       bytes.data(), 0x7172737475767778UL >> (64 - kBits));
101   expected_vector_after_write = init_container<std::vector<CharT>>(
102       0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78);
103   for (int i = kBits / 8; i < 8; ++i) {
104     expected_vector_after_write[i] = CharT(i + 1);
105   }
106   EXPECT_EQ(expected_vector_after_write,
107             ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
108       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
109       << "; kBits = " << kBits;
110 
111   // Recursively iterate the template:
112   //
113   // For every kAlignment/kOffset pair, check kBits from 64 to 8 in increments
114   // of 8.
115   //
116   // If kBits is 8, reset kBits to 64 and go to the next kAlignment/kOffset
117   // pair.
118   //
119   // For each kAlignment, try all kOffsets from 0 to kAlignment - 1.
120   //
121   // If kBits is 8 and kOffset is kAlignment - 1, reset kBits to 64, kOffset to
122   // 0, and halve kAlignment.
123   //
124   // Base cases below handle kAlignment == 0, terminating the recursion.
125   TestMemoryAccessor<
126       CharT,
127       kBits == 8 && kAlignment == kOffset + 1 ? kAlignment / 2 : kAlignment,
128       kBits == 8 ? kAlignment == kOffset + 1 ? 0 : kOffset + 1 : kOffset,
129       kBits == 8 ? 64 : kBits - 8>();
130 }
131 
132 template <>
TestMemoryAccessor()133 void TestMemoryAccessor<char, 0, 0, 64>() {}
134 
135 #if __cplusplus >= 201703L
136 template <>
TestMemoryAccessor()137 void TestMemoryAccessor<std::byte, 0, 0, 64>() {}
138 #endif
139 
140 template <>
TestMemoryAccessor()141 void TestMemoryAccessor<unsigned char, 0, 0, 64>() {}
142 
TEST(MemoryAccessor,LittleEndianReads)143 TEST(MemoryAccessor, LittleEndianReads) {
144   TestMemoryAccessor<char, 8, 0, 64>();
145 #if __cplusplus >= 201703L
146   TestMemoryAccessor<std::byte, 8, 0, 64>();
147 #endif
148   TestMemoryAccessor<unsigned char, 8, 0, 64>();
149 }
150 
TEST(ContiguousBuffer,OffsetStorageType)151 TEST(ContiguousBuffer, OffsetStorageType) {
152   EXPECT_TRUE((::std::is_same<
153                ContiguousBuffer<char, 2, 0>,
154                ContiguousBuffer<char, 2, 0>::OffsetStorageType<2, 0>>::value));
155   EXPECT_TRUE((::std::is_same<
156                ContiguousBuffer<char, 2, 0>,
157                ContiguousBuffer<char, 2, 0>::OffsetStorageType<0, 0>>::value));
158   EXPECT_TRUE((::std::is_same<
159                ContiguousBuffer<char, 2, 0>,
160                ContiguousBuffer<char, 2, 0>::OffsetStorageType<4, 0>>::value));
161   EXPECT_TRUE((::std::is_same<
162                ContiguousBuffer<char, 2, 0>,
163                ContiguousBuffer<char, 4, 0>::OffsetStorageType<2, 0>>::value));
164   EXPECT_TRUE((::std::is_same<
165                ContiguousBuffer<char, 2, 0>,
166                ContiguousBuffer<char, 4, 2>::OffsetStorageType<2, 0>>::value));
167   EXPECT_TRUE((::std::is_same<
168                ContiguousBuffer<char, 2, 0>,
169                ContiguousBuffer<char, 4, 1>::OffsetStorageType<2, 1>>::value));
170   EXPECT_TRUE((::std::is_same<
171                ContiguousBuffer<char, 4, 2>,
172                ContiguousBuffer<char, 4, 1>::OffsetStorageType<4, 1>>::value));
173   EXPECT_TRUE((::std::is_same<
174                ContiguousBuffer<char, 4, 1>,
175                ContiguousBuffer<char, 4, 3>::OffsetStorageType<0, 2>>::value));
176   EXPECT_TRUE((::std::is_same<
177                ContiguousBuffer<char, 4, 1>,
178                ContiguousBuffer<char, 4, 3>::OffsetStorageType<4, 2>>::value));
179   EXPECT_TRUE((::std::is_same<
180                ContiguousBuffer<char, 4, 1>,
181                ContiguousBuffer<char, 4, 3>::OffsetStorageType<8, 6>>::value));
182   EXPECT_TRUE((::std::is_same<
183                ContiguousBuffer<char, 4, 1>,
184                ContiguousBuffer<char, 4, 3>::OffsetStorageType<12, 6>>::value));
185   EXPECT_TRUE((::std::is_same<
186                ContiguousBuffer<char, 1, 0>,
187                ContiguousBuffer<char, 4, 1>::OffsetStorageType<3, 1>>::value));
188 }
189 
190 // Minimal class that forwards to std::allocator.  Used to test that
191 // ReadOnlyContiguousBuffer can be constructed from std::vector<> and
192 // std::basic_string<> with non-default trailing template parameters.
193 template <class T>
194 struct NonstandardAllocator {
195   using value_type =
196       typename ::std::allocator_traits<::std::allocator<T>>::value_type;
197   using pointer =
198       typename ::std::allocator_traits<::std::allocator<T>>::pointer;
199   using const_pointer =
200       typename ::std::allocator_traits<::std::allocator<T>>::const_pointer;
201   using reference = typename ::std::allocator<T>::value_type &;
202   using const_reference =
203       const typename ::std::allocator_traits<::std::allocator<T>>::value_type &;
204   using size_type =
205       typename ::std::allocator_traits<::std::allocator<T>>::size_type;
206   using difference_type =
207       typename ::std::allocator_traits<::std::allocator<T>>::difference_type;
208 
209   template <class U>
210   struct rebind {
211     using other = NonstandardAllocator<U>;
212   };
213 
214   NonstandardAllocator() = default;
215   // This constructor is *not* explicit in order to conform to the requirements
216   // for an allocator.
217   template <class U>
NonstandardAllocatoremboss::support::test::NonstandardAllocator218   NonstandardAllocator(const NonstandardAllocator<U> &) {}  // NOLINT
219 
allocateemboss::support::test::NonstandardAllocator220   T *allocate(::std::size_t n) { return ::std::allocator<T>().allocate(n); }
deallocateemboss::support::test::NonstandardAllocator221   void deallocate(T *p, ::std::size_t n) {
222     ::std::allocator<T>().deallocate(p, n);
223   }
224 
max_sizeemboss::support::test::NonstandardAllocator225   static size_type max_size() {
226     return ::std::numeric_limits<size_type>::max() / sizeof(value_type);
227   }
228 };
229 
230 template <class T, class U>
operator ==(const NonstandardAllocator<T> &,const NonstandardAllocator<U> &)231 bool operator==(const NonstandardAllocator<T> &,
232                 const NonstandardAllocator<U> &) {
233   return true;
234 }
235 
236 template <class T, class U>
operator !=(const NonstandardAllocator<T> &,const NonstandardAllocator<U> &)237 bool operator!=(const NonstandardAllocator<T> &,
238                 const NonstandardAllocator<U> &) {
239   return false;
240 }
241 
242 // ContiguousBuffer tests for std::vector, std::array, and std::string types.
243 template <typename T>
244 class ReadOnlyContiguousBufferTest : public ::testing::Test {};
245 typedef ::testing::Types<
246     /**/ ::std::vector<char>, ::std::array<char, 8>,
247     ::std::vector<unsigned char>,
248 #if __cplusplus >= 201703L
249     ::std::vector<std::byte>,
250 #endif
251     ::std::string, ::std::basic_string<char>,
252     ::std::vector<unsigned char, NonstandardAllocator<unsigned char>>,
253     ::std::basic_string<char, ::std::char_traits<char>,
254                         NonstandardAllocator<char>>>
255     ReadOnlyContiguousContainerTypes;
256 TYPED_TEST_SUITE(ReadOnlyContiguousBufferTest,
257                  ReadOnlyContiguousContainerTypes);
258 
TYPED_TEST(ReadOnlyContiguousBufferTest,ConstructionFromContainers)259 TYPED_TEST(ReadOnlyContiguousBufferTest, ConstructionFromContainers) {
260   const TypeParam bytes =
261       init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
262   using CharType =
263       typename ::std::remove_reference<decltype(*bytes.data())>::type;
264   const auto buffer = ContiguousBuffer<const CharType, 1, 0>{&bytes};
265   EXPECT_EQ(bytes.size(), buffer.SizeInBytes());
266   EXPECT_TRUE(buffer.Ok());
267   EXPECT_EQ(0x0807060504030201UL, buffer.template ReadBigEndianUInt<64>());
268 
269   const auto offset_buffer = buffer.template GetOffsetStorage<1, 0>(4, 4);
270   EXPECT_EQ(4U, offset_buffer.SizeInBytes());
271   EXPECT_EQ(0x04030201U, offset_buffer.template ReadBigEndianUInt<32>());
272 
273   // The size of the resulting buffer should be the minimum of the available
274   // size and the requested size.
275   EXPECT_EQ(bytes.size() - 4,
276             (buffer.template GetOffsetStorage<1, 0>(2, bytes.size() - 4)
277                  .SizeInBytes()));
278   EXPECT_EQ(
279       0U,
280       (buffer.template GetOffsetStorage<1, 0>(bytes.size(), 4).SizeInBytes()));
281 }
282 
283 // ContiguousBuffer tests for std::vector and std::array types.
284 template <typename T>
285 class ReadWriteContiguousBufferTest : public ::testing::Test {};
286 typedef ::testing::Types</**/ ::std::vector<char>, ::std::array<char, 8>,
287 #if __cplusplus >= 201703L
288                          ::std::vector<std::byte>,
289 #endif
290                          ::std::vector<unsigned char>>
291     ReadWriteContiguousContainerTypes;
292 TYPED_TEST_SUITE(ReadWriteContiguousBufferTest,
293                  ReadWriteContiguousContainerTypes);
294 
TYPED_TEST(ReadWriteContiguousBufferTest,ConstructionFromContainers)295 TYPED_TEST(ReadWriteContiguousBufferTest, ConstructionFromContainers) {
296   TypeParam bytes =
297       init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
298   using CharType =
299       typename ::std::remove_reference<decltype(*bytes.data())>::type;
300   const auto buffer = ContiguousBuffer<CharType, 1, 0>{&bytes};
301 
302   // Read and Ok methods should work just as in ReadOnlyContiguousBuffer.
303   EXPECT_EQ(bytes.size(), buffer.SizeInBytes());
304   EXPECT_TRUE(buffer.Ok());
305   EXPECT_EQ(0x0807060504030201UL, buffer.template ReadBigEndianUInt<64>());
306 
307   buffer.template WriteBigEndianUInt<64>(0x0102030405060708UL);
308   EXPECT_EQ((init_container<TypeParam>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
309                                        0x08)),
310             bytes);
311 
312   bytes[4] = static_cast<CharType>(255);
313   EXPECT_EQ(0x1020304ff060708UL, buffer.template ReadBigEndianUInt<64>());
314 }
315 
TEST(ContiguousBuffer,ReturnTypeOfReadUInt)316 TEST(ContiguousBuffer, ReturnTypeOfReadUInt) {
317   const auto buffer = ContiguousBuffer<char, 1, 0>();
318 
319   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<64>()),
320                               ::std::uint64_t>::value));
321   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<48>()),
322                               ::std::uint64_t>::value));
323   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<32>()),
324                               ::std::uint32_t>::value));
325   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<16>()),
326                               ::std::uint16_t>::value));
327   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadBigEndianUInt<8>()),
328                               ::std::uint8_t>::value));
329 
330   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<64>()),
331                               ::std::uint64_t>::value));
332   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<48>()),
333                               ::std::uint64_t>::value));
334   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<32>()),
335                               ::std::uint32_t>::value));
336   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<16>()),
337                               ::std::uint16_t>::value));
338   EXPECT_TRUE((::std::is_same<decltype(buffer.ReadLittleEndianUInt<8>()),
339                               ::std::uint8_t>::value));
340 
341   EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<64>()),
342                               ::std::uint64_t>::value));
343   EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<48>()),
344                               ::std::uint64_t>::value));
345   EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<32>()),
346                               ::std::uint32_t>::value));
347   EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<16>()),
348                               ::std::uint16_t>::value));
349   EXPECT_TRUE((::std::is_same<decltype(buffer.UncheckedReadBigEndianUInt<8>()),
350                               ::std::uint8_t>::value));
351 
352   EXPECT_TRUE(
353       (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<64>()),
354                       ::std::uint64_t>::value));
355   EXPECT_TRUE(
356       (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<48>()),
357                       ::std::uint64_t>::value));
358   EXPECT_TRUE(
359       (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<32>()),
360                       ::std::uint32_t>::value));
361   EXPECT_TRUE(
362       (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<16>()),
363                       ::std::uint16_t>::value));
364   EXPECT_TRUE(
365       (::std::is_same<decltype(buffer.UncheckedReadLittleEndianUInt<8>()),
366                       ::std::uint8_t>::value));
367 }
368 
TEST(ReadOnlyContiguousBuffer,Methods)369 TEST(ReadOnlyContiguousBuffer, Methods) {
370   const ::std::vector</**/ ::std::uint8_t> bytes = {
371       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05,
372        0x04, 0x03, 0x02, 0x01}};
373   const auto buffer = ReadOnlyContiguousBuffer{bytes.data(), bytes.size() - 4};
374 #if EMBOSS_CHECK_ABORTS
375   EXPECT_DEATH(buffer.ReadBigEndianUInt<64>(), "");
376 #endif  // EMBOSS_CHECK_ABORTS
377   EXPECT_TRUE(buffer.Ok());
378   EXPECT_EQ(bytes.size() - 4, buffer.SizeInBytes());
379   EXPECT_EQ(0x100f0e0d0c0b0a09UL, buffer.UncheckedReadBigEndianUInt<64>());
380   EXPECT_EQ(0x090a0b0c0d0e0f10UL, buffer.UncheckedReadLittleEndianUInt<64>());
381 
382   const auto offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 4);
383   EXPECT_EQ(0x0c0b0a09U, offset_buffer.ReadBigEndianUInt<32>());
384   EXPECT_EQ(0x090a0b0cU, offset_buffer.ReadLittleEndianUInt<32>());
385   EXPECT_EQ(0x0c0b0a0908070605UL,
386             offset_buffer.UncheckedReadBigEndianUInt<64>());
387   EXPECT_EQ(4U, offset_buffer.SizeInBytes());
388   EXPECT_TRUE(offset_buffer.Ok());
389 
390   const auto small_offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 1);
391   EXPECT_EQ(0x0cU, small_offset_buffer.ReadBigEndianUInt<8>());
392   EXPECT_EQ(0x0cU, small_offset_buffer.ReadLittleEndianUInt<8>());
393   EXPECT_EQ(1U, small_offset_buffer.SizeInBytes());
394   EXPECT_TRUE(small_offset_buffer.Ok());
395 
396   EXPECT_FALSE(ReadOnlyContiguousBuffer().Ok());
397   EXPECT_FALSE(
398       (ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 12}.Ok()));
399 #if EMBOSS_CHECK_ABORTS
400   EXPECT_DEATH((ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 4}
401                     .ReadBigEndianUInt<32>()),
402                "");
403 #endif  // EMBOSS_CHECK_ABORTS
404   EXPECT_EQ(0U, ReadOnlyContiguousBuffer().SizeInBytes());
405   EXPECT_EQ(0U, (ReadOnlyContiguousBuffer{static_cast<char *>(nullptr), 12}
406                      .SizeInBytes()));
407 #if EMBOSS_CHECK_ABORTS
408   EXPECT_DEATH(
409       (ReadOnlyContiguousBuffer{bytes.data(), 0}.ReadBigEndianUInt<8>()), "");
410 #endif  // EMBOSS_CHECK_ABORTS
411 
412   // The size of the resulting buffer should be the minimum of the available
413   // size and the requested size.
414   EXPECT_EQ(bytes.size() - 8,
415             (buffer.GetOffsetStorage<1, 0>(4, bytes.size() - 4).SizeInBytes()));
416   EXPECT_EQ(4U, (buffer.GetOffsetStorage<1, 0>(0, 4).SizeInBytes()));
417   EXPECT_EQ(0U, (buffer.GetOffsetStorage<1, 0>(bytes.size(), 4).SizeInBytes()));
418   EXPECT_FALSE((ReadOnlyContiguousBuffer().GetOffsetStorage<1, 0>(0, 0).Ok()));
419 }
420 
TEST(ReadWriteContiguousBuffer,Methods)421 TEST(ReadWriteContiguousBuffer, Methods) {
422   ::std::vector</**/ ::std::uint8_t> bytes = {
423       {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}};
424   const auto buffer = ReadWriteContiguousBuffer{bytes.data(), bytes.size() - 4};
425   // Read and Ok methods should work just as in ReadOnlyContiguousBuffer.
426   EXPECT_TRUE(buffer.Ok());
427   EXPECT_EQ(bytes.size() - 4U, buffer.SizeInBytes());
428   EXPECT_EQ(0x0c0b0a0908070605UL, buffer.ReadBigEndianUInt<64>());
429 
430   buffer.WriteBigEndianUInt<64>(0x05060708090a0b0c);
431   EXPECT_EQ(
432       (::std::vector</**/ ::std::uint8_t>{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
433                                           0x0b, 0x0c, 0x04, 0x03, 0x02, 0x01}),
434       bytes);
435   buffer.WriteLittleEndianUInt<64>(0x05060708090a0b0c);
436   EXPECT_EQ(
437       (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
438                                           0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
439       bytes);
440 
441   const auto offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 4);
442   offset_buffer.WriteBigEndianUInt<32>(0x05060708);
443   EXPECT_EQ(
444       (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x05, 0x06,
445                                           0x07, 0x08, 0x04, 0x03, 0x02, 0x01}),
446       bytes);
447   offset_buffer.WriteLittleEndianUInt<32>(0x05060708);
448   EXPECT_EQ(
449       (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
450                                           0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
451       bytes);
452 
453   const auto small_offset_buffer = buffer.GetOffsetStorage<1, 0>(4, 1);
454   small_offset_buffer.WriteBigEndianUInt<8>(0x80);
455   EXPECT_EQ(
456       (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x80, 0x07,
457                                           0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
458       bytes);
459   small_offset_buffer.WriteLittleEndianUInt<8>(0x08);
460   EXPECT_EQ(
461       (::std::vector</**/ ::std::uint8_t>{0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
462                                           0x06, 0x05, 0x04, 0x03, 0x02, 0x01}),
463       bytes);
464 
465 #if EMBOSS_CHECK_ABORTS
466   EXPECT_DEATH(ReadWriteContiguousBuffer().ReadLittleEndianUInt<8>(), "");
467   EXPECT_DEATH(
468       (ReadWriteContiguousBuffer{static_cast<unsigned char *>(nullptr), 1}
469            .ReadLittleEndianUInt<8>()),
470       "");
471   EXPECT_DEATH(
472       (ReadWriteContiguousBuffer{static_cast<unsigned char *>(nullptr), 1}
473            .WriteLittleEndianUInt<8>(0xff)),
474       "");
475 #endif  // EMBOSS_CHECK_ABORTS
476 }
477 
TEST(ContiguousBuffer,AssignmentFromCompatibleContiguousBuffers)478 TEST(ContiguousBuffer, AssignmentFromCompatibleContiguousBuffers) {
479   alignas(4) char data[8];
480   ContiguousBuffer<const unsigned char, 1, 0> buffer;
481   buffer = ContiguousBuffer<char, 4, 1>(data + 1, sizeof data - 1);
482   EXPECT_TRUE(buffer.Ok());
483   EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
484 
485   ContiguousBuffer<const unsigned char, 2, 1> aligned_buffer;
486   aligned_buffer =
487       ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3);
488   EXPECT_TRUE(aligned_buffer.Ok());
489   EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<unsigned char *>(data + 3));
490 }
491 
TEST(ContiguousBuffer,ConstructionFromCompatibleContiguousBuffers)492 TEST(ContiguousBuffer, ConstructionFromCompatibleContiguousBuffers) {
493   alignas(4) char data[8];
494   ContiguousBuffer<const unsigned char, 1, 0> buffer{
495       ContiguousBuffer<char, 4, 1>(data + 1, sizeof data - 1)};
496   EXPECT_TRUE(buffer.Ok());
497   EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
498 
499   ContiguousBuffer<const char, 2, 1> aligned_buffer{
500       ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3)};
501   EXPECT_TRUE(aligned_buffer.Ok());
502   EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<char *>(data + 3));
503 }
504 
TEST(ContiguousBuffer,ToString)505 TEST(ContiguousBuffer, ToString) {
506   const ::std::vector</**/ ::std::uint8_t> bytes = {
507       {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
508   const auto buffer = ReadOnlyContiguousBuffer{bytes.data(), bytes.size() - 4};
509   auto str = buffer.ToString</**/ ::std::string>();
510   EXPECT_TRUE((::std::is_same</**/ ::std::string, decltype(str)>::value));
511   EXPECT_EQ(str, "abcd");
512 #if __cplusplus >= 201703L
513   auto str_view = buffer.ToString</**/ ::std::string_view>();
514   EXPECT_TRUE(
515       (::std::is_same</**/ ::std::string_view, decltype(str_view)>::value));
516   EXPECT_EQ(str_view, "abcd");
517 #endif  // __cplusplus >= 201703L
518 }
519 
TEST(LittleEndianByteOrderer,Methods)520 TEST(LittleEndianByteOrderer, Methods) {
521   ::std::vector</**/ ::std::uint8_t> bytes = {
522       {21, 22, 1, 2, 3, 4, 5, 6, 7, 8, 23, 24}};
523   const int buffer_start = 2;
524   const auto buffer = LittleEndianByteOrderer<ReadWriteContiguousBuffer>{
525       ReadWriteContiguousBuffer{bytes.data() + buffer_start, 8}};
526   EXPECT_EQ(8U, buffer.SizeInBytes());
527   EXPECT_TRUE(buffer.Ok());
528   EXPECT_EQ(0x0807060504030201UL, buffer.ReadUInt<64>());
529   EXPECT_EQ(0x0807060504030201UL, buffer.UncheckedReadUInt<64>());
530 #if EMBOSS_CHECK_ABORTS
531   EXPECT_DEATH(buffer.ReadUInt<56>(), "");
532 #endif  // EMBOSS_CHECK_ABORTS
533   EXPECT_EQ(0x07060504030201UL, buffer.UncheckedReadUInt<56>());
534   buffer.WriteUInt<64>(0x0102030405060708);
535   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 8, 7, 6, 5, 4, 3, 2, 1,
536                                                 23, 24}),
537             bytes);
538   buffer.UncheckedWriteUInt<64>(0x0807060504030201);
539   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 1, 2, 3, 4, 5, 6, 7, 8,
540                                                 23, 24}),
541             bytes);
542 #if EMBOSS_CHECK_ABORTS
543   EXPECT_DEATH(buffer.WriteUInt<56>(0x77777777777777), "");
544 #endif  // EMBOSS_CHECK_ABORTS
545 
546   EXPECT_FALSE(LittleEndianByteOrderer<ReadOnlyContiguousBuffer>().Ok());
547   EXPECT_EQ(0U,
548             LittleEndianByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
549   EXPECT_EQ(bytes[1], (LittleEndianByteOrderer<ReadOnlyContiguousBuffer>{
550                           ReadOnlyContiguousBuffer{bytes.data() + 1, 0}}
551                            .UncheckedReadUInt<8>()));
552   EXPECT_TRUE((LittleEndianByteOrderer<ReadOnlyContiguousBuffer>{
553       ReadOnlyContiguousBuffer{bytes.data(), 0}}
554                    .Ok()));
555 }
556 
TEST(BigEndianByteOrderer,Methods)557 TEST(BigEndianByteOrderer, Methods) {
558   ::std::vector</**/ ::std::uint8_t> bytes = {
559       {21, 22, 1, 2, 3, 4, 5, 6, 7, 8, 23, 24}};
560   const int buffer_start = 2;
561   const auto buffer = BigEndianByteOrderer<ReadWriteContiguousBuffer>{
562       ReadWriteContiguousBuffer{bytes.data() + buffer_start, 8}};
563   EXPECT_EQ(8U, buffer.SizeInBytes());
564   EXPECT_TRUE(buffer.Ok());
565   EXPECT_EQ(0x0102030405060708UL, buffer.ReadUInt<64>());
566   EXPECT_EQ(0x0102030405060708UL, buffer.UncheckedReadUInt<64>());
567 #if EMBOSS_CHECK_ABORTS
568   EXPECT_DEATH(buffer.ReadUInt<56>(), "");
569 #endif  // EMBOSS_CHECK_ABORTS
570   EXPECT_EQ(0x01020304050607UL, buffer.UncheckedReadUInt<56>());
571   buffer.WriteUInt<64>(0x0807060504030201);
572   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 8, 7, 6, 5, 4, 3, 2, 1,
573                                                 23, 24}),
574             bytes);
575   buffer.UncheckedWriteUInt<64>(0x0102030405060708);
576   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{21, 22, 1, 2, 3, 4, 5, 6, 7, 8,
577                                                 23, 24}),
578             bytes);
579 #if EMBOSS_CHECK_ABORTS
580   EXPECT_DEATH(buffer.WriteUInt<56>(0x77777777777777), "");
581 #endif  // EMBOSS_CHECK_ABORTS
582 
583   EXPECT_FALSE(BigEndianByteOrderer<ReadOnlyContiguousBuffer>().Ok());
584   EXPECT_EQ(0U, BigEndianByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
585   EXPECT_EQ(bytes[1], (BigEndianByteOrderer<ReadOnlyContiguousBuffer>{
586                           ReadOnlyContiguousBuffer{bytes.data() + 1, 0}}
587                            .UncheckedReadUInt<8>()));
588   EXPECT_TRUE((BigEndianByteOrderer<ReadOnlyContiguousBuffer>{
589       ReadOnlyContiguousBuffer{bytes.data(), 0}}
590                    .Ok()));
591 }
592 
TEST(NullByteOrderer,Methods)593 TEST(NullByteOrderer, Methods) {
594   ::std::uint8_t bytes[] = {0xdb, 0x0f, 0x0e, 0x0d};
595   const auto buffer = NullByteOrderer<ReadWriteContiguousBuffer>{
596       ReadWriteContiguousBuffer{bytes, 1}};
597   EXPECT_EQ(bytes[0], buffer.ReadUInt<8>());
598   EXPECT_EQ(bytes[0], buffer.UncheckedReadUInt<8>());
599   // NullByteOrderer::UncheckedRead ignores its argument.
600   EXPECT_EQ(bytes[0], buffer.UncheckedReadUInt<8>());
601   buffer.WriteUInt<8>(0x24);
602   EXPECT_EQ(0x24U, bytes[0]);
603   buffer.UncheckedWriteUInt<8>(0x25);
604   EXPECT_EQ(0x25U, bytes[0]);
605   EXPECT_EQ(1U, buffer.SizeInBytes());
606   EXPECT_TRUE(buffer.Ok());
607 
608   EXPECT_FALSE(NullByteOrderer<ReadOnlyContiguousBuffer>().Ok());
609   EXPECT_EQ(0U, NullByteOrderer<ReadOnlyContiguousBuffer>().SizeInBytes());
610 #if EMBOSS_CHECK_ABORTS
611   EXPECT_DEATH((NullByteOrderer<ReadOnlyContiguousBuffer>{
612                    ReadOnlyContiguousBuffer{bytes, 0}}
613                     .ReadUInt<8>()),
614                "");
615   EXPECT_DEATH((NullByteOrderer<ReadOnlyContiguousBuffer>{
616                    ReadOnlyContiguousBuffer{bytes, 2}}
617                     .ReadUInt<8>()),
618                "");
619 #endif  // EMBOSS_CHECK_ABORTS
620   EXPECT_EQ(bytes[0], (NullByteOrderer<ReadOnlyContiguousBuffer>{
621                           ReadOnlyContiguousBuffer{bytes, 0}}
622                            .UncheckedReadUInt<8>()));
623   EXPECT_TRUE((NullByteOrderer<ReadOnlyContiguousBuffer>{
624       ReadOnlyContiguousBuffer{bytes, 0}}
625                    .Ok()));
626 }
627 
TEST(BitBlock,BigEndianMethods)628 TEST(BitBlock, BigEndianMethods) {
629   ::std::uint8_t bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
630                             0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
631   const auto big_endian =
632       BigEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes + 4, 8}};
633   EXPECT_EQ(64U, big_endian.SizeInBits());
634   EXPECT_TRUE(big_endian.Ok());
635   EXPECT_EQ(0x05060708090a0b0cUL, big_endian.ReadUInt());
636   EXPECT_EQ(0x05060708090a0b0cUL, big_endian.UncheckedReadUInt());
637   EXPECT_FALSE(BigEndianBitBlockN<64>().Ok());
638   EXPECT_EQ(64U, BigEndianBitBlockN<64>().SizeInBits());
639   EXPECT_FALSE(
640       (BigEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 0}}.Ok()));
641 }
642 
TEST(BitBlock,LittleEndianMethods)643 TEST(BitBlock, LittleEndianMethods) {
644   ::std::uint8_t bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
645                             0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
646   const auto little_endian =
647       LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes + 4, 8}};
648   EXPECT_EQ(64U, little_endian.SizeInBits());
649   EXPECT_TRUE(little_endian.Ok());
650   EXPECT_EQ(0x0c0b0a0908070605UL, little_endian.ReadUInt());
651   EXPECT_EQ(0x0c0b0a0908070605UL, little_endian.UncheckedReadUInt());
652   EXPECT_FALSE(LittleEndianBitBlockN<64>().Ok());
653   EXPECT_EQ(64U, LittleEndianBitBlockN<64>().SizeInBits());
654   EXPECT_FALSE(
655       (LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 0}}.Ok()));
656 }
657 
TEST(BitBlock,GetOffsetStorage)658 TEST(BitBlock, GetOffsetStorage) {
659   ::std::uint8_t bytes[] = {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09,
660                             0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
661   const auto bit_block =
662       LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{bytes, 8}};
663   const OffsetBitBlock<LittleEndianBitBlockN<64>> offset_block =
664       bit_block.GetOffsetStorage<1, 0>(4, 8);
665   EXPECT_EQ(8U, offset_block.SizeInBits());
666   EXPECT_EQ(0xf1U, offset_block.ReadUInt());
667   EXPECT_EQ(bit_block.SizeInBits(),
668             (bit_block.GetOffsetStorage<1, 0>(8, bit_block.SizeInBits())
669                  .SizeInBits()));
670   EXPECT_FALSE(
671       (bit_block.GetOffsetStorage<1, 0>(8, bit_block.SizeInBits()).Ok()));
672   EXPECT_EQ(10U, (bit_block.GetOffsetStorage<1, 0>(bit_block.SizeInBits(), 10)
673                       .SizeInBits()));
674 }
675 
TEST(OffsetBitBlock,Methods)676 TEST(OffsetBitBlock, Methods) {
677   ::std::vector</**/ ::std::uint8_t> bytes = {
678       {0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09}};
679   const auto bit_block =
680       LittleEndianBitBlockN<64>{ReadWriteContiguousBuffer{&bytes}};
681   EXPECT_FALSE((bit_block.GetOffsetStorage<1, 0>(0, 96).Ok()));
682   EXPECT_TRUE((bit_block.GetOffsetStorage<1, 0>(0, 64).Ok()));
683 
684   const auto offset_block = bit_block.GetOffsetStorage<1, 0>(8, 48);
685   EXPECT_FALSE((offset_block.GetOffsetStorage<1, 0>(40, 16).Ok()));
686   EXPECT_EQ(0x0a0b0c0d0e0fUL, offset_block.ReadUInt());
687   EXPECT_EQ(0x0a0b0c0d0e0fUL, offset_block.UncheckedReadUInt());
688   offset_block.WriteUInt(0x0f0e0d0c0b0a);
689   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
690                                                 0x0e, 0x0f, 0x09}),
691             bytes);
692   offset_block.UncheckedWriteUInt(0x0a0b0c0d0e0f);
693   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0f, 0x0e, 0x0d, 0x0c,
694                                                 0x0b, 0x0a, 0x09}),
695             bytes);
696 #if EMBOSS_CHECK_ABORTS
697   EXPECT_DEATH(offset_block.WriteUInt(0x10f0e0d0c0b0a), "");
698 #endif  // EMBOSS_CHECK_ABORTS
699   offset_block.UncheckedWriteUInt(0x10f0e0d0c0b0a);
700   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
701                                                 0x0e, 0x0f, 0x09}),
702             bytes);
703 
704   const auto offset_offset_block = offset_block.GetOffsetStorage<1, 0>(16, 16);
705   EXPECT_FALSE((offset_offset_block.GetOffsetStorage<1, 0>(8, 16).Ok()));
706   EXPECT_EQ(0x0d0cU, offset_offset_block.ReadUInt());
707   EXPECT_EQ(0x0d0cU, offset_offset_block.UncheckedReadUInt());
708   offset_offset_block.WriteUInt(0x0c0d);
709   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0d, 0x0c,
710                                                 0x0e, 0x0f, 0x09}),
711             bytes);
712   offset_offset_block.UncheckedWriteUInt(0x0d0c);
713   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0c, 0x0d,
714                                                 0x0e, 0x0f, 0x09}),
715             bytes);
716 #if EMBOSS_CHECK_ABORTS
717   EXPECT_DEATH(offset_offset_block.WriteUInt(0x10c0d), "");
718 #endif  // EMBOSS_CHECK_ABORTS
719   offset_offset_block.UncheckedWriteUInt(0x20c0d);
720   EXPECT_EQ((::std::vector</**/ ::std::uint8_t>{0x10, 0x0a, 0x0b, 0x0d, 0x0c,
721                                                 0x0e, 0x0f, 0x09}),
722             bytes);
723 
724   const auto null_offset_block = OffsetBitBlock<BigEndianBitBlockN<32>>();
725   EXPECT_FALSE(null_offset_block.Ok());
726   EXPECT_EQ(0U, null_offset_block.SizeInBits());
727 }
728 
729 }  // namespace test
730 }  // namespace support
731 }  // namespace emboss
732