Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
endian.hpp
Go to the documentation of this file.
1// parasoft-begin-suppress AUTOSAR-A2_8_1-a-2 "False positive: also defines arene::base::endian"
2
3// Copyright 2024, Toyota Motor Corporation
4//
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ENDIAN_ENDIAN_HPP_
7#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ENDIAN_ENDIAN_HPP_
8
9// IWYU pragma: private, include "arene/base/endian.hpp"
10// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
11
12// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax pmeritted by A7-1-5 Permit #1 v1.0.0"
13
14// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
15
16// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
17#include "arene/base/algorithm/copy.hpp"
18#include "arene/base/byte/byte.hpp"
19#include "arene/base/constraints/constraints.hpp"
20#include "arene/base/span/span.hpp"
21#include "arene/base/stdlib_choice/cstddef.hpp"
22#include "arene/base/stdlib_choice/cstdint.hpp"
23#include "arene/base/stdlib_choice/enable_if.hpp"
24#include "arene/base/stdlib_choice/ignore.hpp"
25#include "arene/base/stdlib_choice/is_arithmetic.hpp"
26#include "arene/base/stdlib_choice/is_enum.hpp"
27#include "arene/base/stdlib_choice/is_floating_point.hpp"
28#include "arene/base/stdlib_choice/is_integral.hpp"
29#include "arene/base/stdlib_choice/is_same.hpp"
30#include "arene/base/stdlib_choice/underlying_type.hpp"
31#include "arene/base/type_traits/type_identity.hpp"
32// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
33
34#if defined(_WIN32)
35#include "arene/base/endian/detail/endian_windows_impl.hpp" // IWYU pragma: export
36#elif defined(__BYTE_ORDER__)
37#include "arene/base/endian/detail/endian_specified_byte_order_impl.hpp" // IWYU pragma: export
38#else
39#include "arene/base/endian/detail/endian_generic_impl.hpp" // IWYU pragma: export
40#endif
41
42namespace arene {
43namespace base {
44
45// parasoft-begin-suppress AUTOSAR-A0_4_2-a-2 "long double named as explicitly not supported"
46
47///////////
48//
49// Utilities for reading/writing binary values in LITTLE-ENDIAN format.
50
51/// @brief Read a value from a serialized binary representation stored in little-endian byte order.
52///
53/// @tparam T The type of the value to read.
54/// @param bytes A view of the bytes to read the data from.
55/// @return The read value
56template <
57 typename T,
59auto read_little_endian(span<byte const, sizeof(T)> bytes) noexcept -> T = delete;
60
61/// @brief Read an integral value from a serialized binary representation stored in little-endian byte order.
62///
63/// @tparam T The type of the value to read.
64/// @param bytes A view of the bytes to read the data from.
65/// @return The read value
66template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>> = nullptr>
67constexpr auto read_little_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
68
69/// @brief Read an enum value from a serialized binary representation stored in little-endian byte order.
70///
71/// @tparam T The type of the value to read.
72/// @param bytes A view of the bytes to read the data from.
73/// @return The read value
74template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>> = nullptr>
75constexpr auto read_little_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
76
77/// @brief Read a floating point value from a serialized binary representation stored in little-endian byte order.
78///
79/// @tparam T The type of the value to read.
80/// @param bytes A view of the bytes to read the data from.
81/// @return The read value
82template <
83 typename T,
86 std::enable_if_t<!std::is_same<T, long double>::value>> = nullptr>
87auto read_little_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
88
89/// @brief Write a value to a buffer in little-endian binary representation.
90///
91/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
92/// @param value The value to write.
93/// @param bytes The buffer to write the little-endian binary representation to.
94template <
95 typename T,
97void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept = delete;
98
99/// @brief Write an integral value to a buffer in little-endian binary representation.
100///
101/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
102/// @param value The value to write.
103/// @param bytes The buffer to write the little-endian binary representation to.
104template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>> = nullptr>
105constexpr void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
106
107/// @brief Write an enum value to a buffer in little-endian binary representation.
108///
109/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
110/// @param value The value to write.
111/// @param bytes The buffer to write the little-endian binary representation to.
112template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>> = nullptr>
113constexpr void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
114
115/// @brief Write a floating point value to a buffer in little-endian binary representation.
116///
117/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
118/// @param value The value to write.
119/// @param bytes The buffer to write the little-endian binary representation to.
120template <
121 typename T,
124 std::enable_if_t<!std::is_same<T, long double>::value>> = nullptr>
125void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
126
127///////////
128//
129// Utilities for reading/writing binary values in BIG-ENDIAN format.
130
131/// @brief Read a value from a serialized binary representation stored in big-endian byte order.
132///
133/// @tparam T The type of the value to read.
134/// @param bytes A view of the bytes to read the data from.
135/// @return The read value
136template <
137 typename T,
139auto read_big_endian(span<byte const, sizeof(T)> bytes) noexcept -> T = delete;
140
141/// @brief Read a value from a serialized binary representation stored in big-endian byte order.
142///
143/// @tparam T The type of the value to read.
144/// @param bytes A view of the bytes to read the data from.
145/// @return The read value
146template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>> = nullptr>
147constexpr auto read_big_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
148
149/// @brief Read a value from a serialized binary representation stored in big-endian byte order.
150///
151/// @tparam T The type of the value to read.
152/// @param bytes A view of the bytes to read the data from.
153/// @return The read value
154template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>> = nullptr>
155constexpr auto read_big_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
156
157/// @brief Read a value from a serialized binary representation stored in big-endian byte order.
158///
159/// @tparam T The type of the value to read.
160/// @param bytes A view of the bytes to read the data from.
161/// @return The read value
162template <
163 typename T,
166 std::enable_if_t<!std::is_same<T, long double>::value>> = nullptr>
167auto read_big_endian(span<byte const, sizeof(T)> bytes) noexcept -> T;
168
169/// @brief Write a value to a buffer in big-endian binary representation.
170///
171/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
172/// @param value The value to write.
173/// @param bytes The buffer to write the big-endian binary representation to.
174template <
175 typename T,
177void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept = delete;
178
179/// @brief Write a value to a buffer in big-endian binary representation.
180///
181/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
182/// @param value The value to write.
183/// @param bytes The buffer to write the big-endian binary representation to.
184template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>> = nullptr>
185constexpr void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
186
187/// @brief Write a value to a buffer in big-endian binary representation.
188///
189/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
190/// @param value The value to write.
191/// @param bytes The buffer to write the big-endian binary representation to.
192template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>> = nullptr>
193constexpr void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
194
195/// @brief Write a value to a buffer in big-endian binary representation.
196///
197/// @tparam T The type of the value to write. This template parameter must be explicitly specified.
198/// @param value The value to write.
199/// @param bytes The buffer to write the big-endian binary representation to.
200template <
201 typename T,
204 std::enable_if_t<!std::is_same<T, long double>::value>> = nullptr>
205void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> bytes) noexcept;
206
207} // namespace base
208} // namespace arene
209
210////////////////////////////////////////////
211// Implementations
212
213namespace arene {
214namespace base {
215
216namespace endian_detail {
217/// @brief constants for bit offsets
218/// @{
219constexpr std::size_t bits_8{8U};
220constexpr std::size_t bits_16{16U};
221constexpr std::size_t bits_24{24U};
222constexpr std::size_t bits_32{32U};
223constexpr std::size_t bits_40{40U};
224constexpr std::size_t bits_48{48U};
225constexpr std::size_t bits_56{56U};
226/// @}
227
228/// @brief indexes for byte words
229/// @{
230constexpr std::size_t byte_0{0U};
231constexpr std::size_t byte_1{1U};
232constexpr std::size_t byte_2{2U};
233constexpr std::size_t byte_3{3U};
234constexpr std::size_t byte_4{4U};
235constexpr std::size_t byte_5{5U};
236constexpr std::size_t byte_6{6U};
237constexpr std::size_t byte_7{7U};
238/// @}
239
240/// @brief Implementation template specialized for each size of type we want to handle
241/// @tparam Size The number of bytes in the representation
242template <std::size_t Size>
243class endian_impl;
244
245/// @brief Implementation template for an 8-bit type
246template <>
247class endian_impl<sizeof(std::uint8_t)> {
248 public:
249 /// @brief The value type
250 using type = std::uint8_t;
251
252 /// @brief Read the value
253 /// @param bytes The source
254 /// @return The read value
255 static constexpr auto read_little_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
256 return ::arene::base::to_integer<type>(bytes[byte_0]);
257 }
258
259 /// @brief Write the value
260 /// @param value The value to write
261 /// @param bytes The target storage
262 static constexpr void write_little_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
263 bytes[byte_0] = to_byte(value);
264 }
265
266 /// @brief Read the value
267 /// @param bytes The source
268 /// @return The read value
269 static constexpr auto read_big_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
270 return ::arene::base::to_integer<type>(bytes[byte_0]);
271 }
272
273 /// @brief Write the value
274 /// @param value The value to write
275 /// @param bytes The target storage
276 static constexpr void write_big_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
277 bytes[byte_0] = to_byte(value);
278 }
279};
280
281/// @brief Implementation template for a 16-bit type
282template <>
283class endian_impl<sizeof(std::uint16_t)> {
284 public:
285 /// @brief The value type
286 using type = std::uint16_t;
287
288 /// @brief Read the value
289 /// @param bytes The source
290 /// @return The read value
291 static constexpr auto read_little_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
292 // Note: GCC/Clang can usually recognise this pattern and compile this down
293 // to a single load, optionally with the target architecture's byte-swap
294 // instruction if byte-swapping is required.
295 // However, when we know for sure that we're not being called as part of
296 // a constant expression we dispatch to a memcpy/byte_swap-based
297 // implementation above which the compiler is generally more reliable at
298 // optimising.
299 return ::arene::base::to_integer<std::uint16_t>(bytes[byte_0]) |
300 static_cast<std::uint16_t>(::arene::base::to_integer<std::uint16_t>(bytes[byte_1]) << bits_8);
301 }
302
303 /// @brief Write the value
304 /// @param value The value to write
305 /// @param bytes The target storage
306 static constexpr void write_little_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
307 // Note: GCC/Clang can usually recognise this pattern and compile this down
308 // to a single store, optionally with the target architecture's byte-swap
309 // instruction if byte-swapping is required.
310 // However, when we know for sure that we're not being called as part of
311 // a constant expression we dispatch to a memcpy/byte_swap-based
312 // implementation above which the compiler is generally more reliable at
313 // optimising.
314
315 bytes[byte_0] = to_byte(value);
316 bytes[byte_1] = to_byte(static_cast<std::uint8_t>(value >> bits_8));
317 }
318
319 /// @brief Read the value
320 /// @param bytes The source
321 /// @return The read value
322 static constexpr auto read_big_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
323 // Note: GCC/Clang can usually recognise this pattern and compile this down
324 // to a single load, optionally with the target architecture's byte-swap
325 // instruction if byte-swapping is required.
326 // However, when we know for sure that we're not being called as part of
327 // a constant expression we dispatch to a memcpy/byte_swap-based
328 // implementation above which the compiler is generally more reliable at
329 // optimising.
330
331 return ::arene::base::to_integer<std::uint16_t>(bytes[byte_1]) |
332 static_cast<std::uint16_t>(::arene::base::to_integer<std::uint16_t>(bytes[byte_0]) << bits_8);
333 }
334
335 /// @brief Write the value
336 /// @param value The value to write
337 /// @param bytes The target storage
338 static constexpr void write_big_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
339 // Note: GCC/Clang can usually recognise this pattern and compile this down
340 // to a single store, optionally with the target architecture's byte-swap
341 // instruction if byte-swapping is required.
342 // However, when we know for sure that we're not being called as part of
343 // a constant expression we dispatch to a memcpy/byte_swap-based
344 // implementation above which the compiler is generally more reliable at
345 // optimising.
346
347 bytes[byte_1] = to_byte(value);
348 bytes[byte_0] = to_byte(static_cast<std::uint8_t>(value >> bits_8));
349 }
350};
351
352/// @brief Implementation template for a 32-bit type
353template <>
354class endian_impl<sizeof(std::uint32_t)> {
355 public:
356 /// @brief The value type
357 using type = std::uint32_t;
358 /// @brief Read the value
359 /// @param bytes The source
360 /// @return The read value
361 static constexpr auto read_little_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
362 // Note: GCC/Clang can usually recognise this pattern and compile this down
363 // to a single load, optionally with the target architecture's byte-swap
364 // instruction if byte-swapping is required.
365 // However, when we know for sure that we're not being called as part of
366 // a constant expression we dispatch to a memcpy/byte_swap-based
367 // implementation above which the compiler is generally more reliable at
368 // optimising.
369
370 return ::arene::base::to_integer<std::uint32_t>(bytes[byte_0]) |
371
372 (::arene::base::to_integer<std::uint32_t>(bytes[byte_1]) << bits_8) |
373
374 (::arene::base::to_integer<std::uint32_t>(bytes[byte_2]) << bits_16) |
375
376 (::arene::base::to_integer<std::uint32_t>(bytes[byte_3]) << bits_24);
377 }
378
379 /// @brief Write the value
380 /// @param value The value to write
381 /// @param bytes The target storage
382 static constexpr void write_little_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
383 // Note: GCC/Clang can usually recognise this pattern and compile this down
384 // to a single store, optionally with the target architecture's byte-swap
385 // instruction if byte-swapping is required.
386 // However, when we know for sure that we're not being called as part of
387 // a constant expression we dispatch to a memcpy/byte_swap-based
388 // implementation above which the compiler is generally more reliable at
389 // optimising.
390 bytes[byte_0] = to_byte(value);
391 bytes[byte_1] = to_byte(value >> bits_8);
392 bytes[byte_2] = to_byte(value >> bits_16);
393 bytes[byte_3] = to_byte(value >> bits_24);
394 }
395
396 /// @brief Read the value
397 /// @param bytes The source
398 /// @return The read value
399 static constexpr auto read_big_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
400 // Note: GCC/Clang can usually recognise this pattern and compile this down
401 // to a single load, optionally with the target architecture's byte-swap
402 // instruction if byte-swapping is required.
403 // However, when we know for sure that we're not being called as part of
404 // a constant expression we dispatch to a memcpy/byte_swap-based
405 // implementation above which the compiler is generally more reliable at
406 // optimising.
407
408 return ::arene::base::to_integer<std::uint32_t>(bytes[byte_3]) |
409 (::arene::base::to_integer<std::uint32_t>(bytes[byte_2]) << bits_8) |
410 (::arene::base::to_integer<std::uint32_t>(bytes[byte_1]) << bits_16) |
411 (::arene::base::to_integer<std::uint32_t>(bytes[byte_0]) << bits_24);
412 }
413
414 /// @brief Write the value
415 /// @param value The value to write
416 /// @param bytes The target storage
417 static constexpr void write_big_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
418 // Note: GCC/Clang can usually recognise this pattern and compile this down
419 // to a single store, optionally with the target architecture's byte-swap
420 // instruction if byte-swapping is required.
421 // However, when we know for sure that we're not being called as part of
422 // a constant expression we dispatch to a memcpy/byte_swap-based
423 // implementation above which the compiler is generally more reliable at
424 // optimising.
425
426 bytes[byte_3] = to_byte(value);
427 bytes[byte_2] = to_byte(value >> bits_8);
428 bytes[byte_1] = to_byte(value >> bits_16);
429 bytes[byte_0] = to_byte(value >> bits_24);
430 }
431};
432
433/// @brief Implementation template for a 64-bit type
434template <>
435class endian_impl<sizeof(std::uint64_t)> {
436 public:
437 /// @brief The value type
438 using type = std::uint64_t;
439 /// @brief Read the value
440 /// @param bytes The source
441 /// @return The read value
442 static constexpr auto read_little_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
443 // Note: GCC/Clang can usually recognise this pattern and compile this down
444 // to a single load, optionally with the target architecture's byte-swap
445 // instruction if byte-swapping is required.
446 // However, when we know for sure that we're not being called as part of
447 // a constant expression we dispatch to a memcpy/byte_swap-based
448 // implementation above which the compiler is generally more reliable at
449 // optimising.
450
451 return ::arene::base::to_integer<std::uint64_t>(bytes[byte_0]) |
452 (::arene::base::to_integer<std::uint64_t>(bytes[byte_1]) << bits_8) |
453 (::arene::base::to_integer<std::uint64_t>(bytes[byte_2]) << bits_16) |
454 (::arene::base::to_integer<std::uint64_t>(bytes[byte_3]) << bits_24) |
455 (::arene::base::to_integer<std::uint64_t>(bytes[byte_4]) << bits_32) |
456 (::arene::base::to_integer<std::uint64_t>(bytes[byte_5]) << bits_40) |
457 (::arene::base::to_integer<std::uint64_t>(bytes[byte_6]) << bits_48) |
458 (::arene::base::to_integer<std::uint64_t>(bytes[byte_7]) << bits_56);
459 }
460
461 /// @brief Write the value
462 /// @param value The value to write
463 /// @param bytes The target storage
464 static constexpr void write_little_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
465 // Note: GCC/Clang can usually recognise this pattern and compile this down
466 // to a single store, optionally with the target architecture's byte-swap
467 // instruction if byte-swapping is required.
468 // However, when we know for sure that we're not being called as part of
469 // a constant expression we dispatch to a memcpy/byte_swap-based
470 // implementation above which the compiler is generally more reliable at
471 // optimising.
472
473 bytes[byte_0] = to_byte(value);
474 bytes[byte_1] = to_byte(value >> bits_8);
475 bytes[byte_2] = to_byte(value >> bits_16);
476 bytes[byte_3] = to_byte(value >> bits_24);
477 bytes[byte_4] = to_byte(value >> bits_32);
478 bytes[byte_5] = to_byte(value >> bits_40);
479 bytes[byte_6] = to_byte(value >> bits_48);
480 bytes[byte_7] = to_byte(value >> bits_56);
481 }
482
483 /// @brief Read the value
484 /// @param bytes The source
485 /// @return The read value
486 static constexpr auto read_big_endian(span<byte const, sizeof(type)> const bytes) noexcept -> type {
487 // Note: GCC/Clang can usually recognise this pattern and compile this down
488 // to a single load, optionally with the target architecture's byte-swap
489 // instruction if byte-swapping is required.
490 // However, when we know for sure that we're not being called as part of
491 // a constant expression we dispatch to a memcpy/byte_swap-based
492 // implementation above which the compiler is generally more reliable at
493 // optimising.
494
495 return ::arene::base::to_integer<std::uint64_t>(bytes[byte_7]) |
496 (::arene::base::to_integer<std::uint64_t>(bytes[byte_6]) << bits_8) |
497 (::arene::base::to_integer<std::uint64_t>(bytes[byte_5]) << bits_16) |
498 (::arene::base::to_integer<std::uint64_t>(bytes[byte_4]) << bits_24) |
499 (::arene::base::to_integer<std::uint64_t>(bytes[byte_3]) << bits_32) |
500 (::arene::base::to_integer<std::uint64_t>(bytes[byte_2]) << bits_40) |
501 (::arene::base::to_integer<std::uint64_t>(bytes[byte_1]) << bits_48) |
502 (::arene::base::to_integer<std::uint64_t>(bytes[byte_0]) << bits_56);
503 }
504
505 /// @brief Write the value
506 /// @param value The value to write
507 /// @param bytes The target storage
508 static constexpr void write_big_endian(type const value, span<byte, sizeof(type)> const bytes) noexcept {
509 // Note: GCC/Clang can usually recognise this pattern and compile this down
510 // to a single store, optionally with the target architecture's byte-swap
511 // instruction if byte-swapping is required.
512 // However, when we know for sure that we're not being called as part of
513 // a constant expression we dispatch to a memcpy/byte_swap-based
514 // implementation above which the compiler is generally more reliable at
515 // optimising.
516
517 bytes[byte_7] = to_byte(value);
518 bytes[byte_6] = to_byte(value >> bits_8);
519 bytes[byte_5] = to_byte(value >> bits_16);
520 bytes[byte_4] = to_byte(value >> bits_24);
521 bytes[byte_3] = to_byte(value >> bits_32);
522 bytes[byte_2] = to_byte(value >> bits_40);
523 bytes[byte_1] = to_byte(value >> bits_48);
524 bytes[byte_0] = to_byte(value >> bits_56);
525 }
526};
527
528} // namespace endian_detail
529
530// parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: Documented on predeclaration"
531// parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: Documented on predeclaration"
532
533template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>>>
534constexpr auto read_little_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
535 return static_cast<T>(endian_detail::endian_impl<sizeof(T)>::read_little_endian(bytes));
536}
537
538// parasoft-begin-suppress AUTOSAR-A7_2_1-a-2 "Value must be checked after reading, this is generic code"
539// parasoft-begin-suppress CERT_CPP-INT50-a-3 "Value must be checked after reading, this is generic code"
540template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>>>
541constexpr auto read_little_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
542 return static_cast<T>(::arene::base::read_little_endian<typename std::underlying_type<T>::type>(bytes));
543}
544// parasoft-end-suppress AUTOSAR-A7_2_1-a-2
545// parasoft-end-suppress CERT_CPP-INT50-a-3
546
547template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>>>
548constexpr void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
550 static_cast<typename endian_detail::endian_impl<sizeof(T)>::type>(value),
551 bytes
552 );
553}
554
555template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>>>
556constexpr void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
558 static_cast<typename std::underlying_type<T>::type>(value),
559 bytes
560 );
561}
562
563template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>>>
564constexpr auto read_big_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
565 return static_cast<T>(endian_detail::endian_impl<sizeof(T)>::read_big_endian(bytes));
566}
567
568// parasoft-begin-suppress AUTOSAR-A7_2_1-a-2 "Value must be checked after reading, this is generic code"
569// parasoft-begin-suppress CERT_CPP-INT50-a-3 "Value must be checked after reading, this is generic code"
570template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>>>
571constexpr auto read_big_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
572 return static_cast<T>(::arene::base::read_big_endian<typename std::underlying_type<T>::type>(bytes));
573}
574// parasoft-end-suppress AUTOSAR-A7_2_1-a-2
575// parasoft-end-suppress CERT_CPP-INT50-a-3
576
577template <typename T, constraints<std::enable_if_t<std::is_integral<T>::value>>>
578constexpr void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
580 static_cast<typename endian_detail::endian_impl<sizeof(T)>::type>(value),
581 bytes
582 );
583}
584
585template <typename T, constraints<std::enable_if_t<std::is_enum<T>::value>>>
586constexpr void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
588 static_cast<typename std::underlying_type<T>::type>(value),
589 bytes
590 );
591}
592
593template <
594 typename T,
597 std::enable_if_t<!std::is_same<T, long double>::value>>>
598void write_big_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
599 static_assert((endian::native == endian::big) || (endian::native == endian::little), "Must have fixed endian");
600 auto const raw_bytes = as_bytes(span<T, 1U>(&value, 1U));
601 switch (endian::native) {
602 case endian::little:
604 break;
605 case endian::big:
607 break;
608 default:
609 break;
610 }
611}
612
613template <
614 typename T,
617 std::enable_if_t<!std::is_same<T, long double>::value>>>
618void write_little_endian(base::type_identity_t<T> value, span<byte, sizeof(T)> const bytes) noexcept {
619 static_assert((endian::native == endian::big) || (endian::native == endian::little), "Must have fixed endian");
620 auto const raw_bytes = ::arene::base::as_bytes(span<T, 1U>(&value, 1U));
621 switch (endian::native) {
622 case endian::little:
624 break;
625 case endian::big:
627 break;
628 default:
629 break;
630 }
631}
632
633template <
634 typename T,
637 std::enable_if_t<!std::is_same<T, long double>::value>>>
638auto read_big_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
639 static_assert((endian::native == endian::big) || (endian::native == endian::little), "Must have fixed endian");
640 T res{};
641 auto raw_bytes = ::arene::base::as_writable_bytes(span<T, 1U>(&res, 1U));
642 switch (endian::native) {
643 case endian::little:
645 break;
646 case endian::big:
648 break;
649 default:
650 break;
651 }
652 return res;
653}
654
655template <
656 typename T,
659 std::enable_if_t<!std::is_same<T, long double>::value>>>
660auto read_little_endian(span<byte const, sizeof(T)> const bytes) noexcept -> T {
661 static_assert((endian::native == endian::big) || (endian::native == endian::little), "Must have fixed endian");
662 T res{};
663 auto raw_bytes = ::arene::base::as_writable_bytes(span<T, 1U>(&res, 1U));
664 switch (endian::native) {
665 case endian::little:
667 break;
668 case endian::big:
670 break;
671 default:
672 break;
673 }
674 return res;
675}
676
677// parasoft-end-suppress AUTOSAR-A0_4_2-a-2
678
679} // namespace base
680} // namespace arene
681
682#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_ENDIAN_ENDIAN_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10