mirror of
https://github.com/ETLCPP/etl.git
synced 2026-10-28 18:07:10 +08:00
Add be_uint24_t etc. to unaligned_type.h (#1592)
* Add be_uint24_t etc. to unaligned_type.h A typical use case is to endian convert 24, 40, 48 bits etc. This change generalizes the pre-existing types in unaligned_type.h to those odd sizes. * Add documentation for odd sized unaligned_type specializations
This commit is contained in:
parent
3e6b486786
commit
7e328341ae
@ -459,3 +459,317 @@ ETL_CONSTEXPR14 bool operator !=(T lhs, const unaligned_type& rhs)
|
||||
**Description**
|
||||
Inequality operator.
|
||||
Removed: `20.39.3`
|
||||
|
||||
---
|
||||
|
||||
# Arbitrary width integers
|
||||
|
||||
{{< callout type="info">}}
|
||||
From: `20.50.0`
|
||||
{{< /callout >}}
|
||||
|
||||
`etl::unaligned_type` is templated on a fundamental type, so it can only store
|
||||
integers whose width is that of a standard integer type. For protocols that use
|
||||
odd widths, such as 24 or 48 bit integers, the following types are templated on
|
||||
the **number of bytes of storage** instead.
|
||||
|
||||
```cpp
|
||||
template <size_t Size_, int Endian_>
|
||||
class unaligned_uint_type
|
||||
|
||||
template <size_t Size_, int Endian_>
|
||||
class unaligned_int_type
|
||||
```
|
||||
|
||||
Where `Size_` is the number of bytes of storage and `Endian_` is
|
||||
`etl::endian::big` or `etl::endian::little`.
|
||||
|
||||
`unaligned_uint_type` stores an unsigned integer.
|
||||
`unaligned_int_type` stores a signed, two's complement integer, which is sign
|
||||
extended when read.
|
||||
|
||||
The value is interfaced to via `value_type`: the smallest standard integer type
|
||||
that can hold `Size_` bytes. For example, `unaligned_uint_type<3U, ...>` has a
|
||||
`value_type` of `uint32_t`.
|
||||
|
||||
Values that do not fit in `Size_` bytes are truncated, in the same way as a
|
||||
narrowing `static_cast`.
|
||||
|
||||
Marked as `packed` for MSVC, GCC and Clang.
|
||||
|
||||
## Constants
|
||||
`int Endian`
|
||||
 The endianness of the type.
|
||||
`size_t Size`
|
||||
 The size, in bytes, of the type.
|
||||
`value_type Min_Value`
|
||||
 The lowest value that may be stored.
|
||||
`value_type Max_Value`
|
||||
 The highest value that may be stored.
|
||||
|
||||
## Predefined types
|
||||
|
||||
The 40, 48 and 56 bit types are only defined if `ETL_USING_64BIT_TYPES`.
|
||||
The host order types are only defined if `ETL_HAS_CONSTEXPR_ENDIANNESS`.
|
||||
|
||||
### Little Endian
|
||||
```cpp
|
||||
le_uint24_t
|
||||
le_int24_t
|
||||
le_uint40_t ETL_USING_64BIT_TYPES
|
||||
le_int40_t ETL_USING_64BIT_TYPES
|
||||
le_uint48_t ETL_USING_64BIT_TYPES
|
||||
le_int48_t ETL_USING_64BIT_TYPES
|
||||
le_uint56_t ETL_USING_64BIT_TYPES
|
||||
le_int56_t ETL_USING_64BIT_TYPES
|
||||
```
|
||||
|
||||
### Big Endian
|
||||
```cpp
|
||||
be_uint24_t
|
||||
be_int24_t
|
||||
be_uint40_t ETL_USING_64BIT_TYPES
|
||||
be_int40_t ETL_USING_64BIT_TYPES
|
||||
be_uint48_t ETL_USING_64BIT_TYPES
|
||||
be_int48_t ETL_USING_64BIT_TYPES
|
||||
be_uint56_t ETL_USING_64BIT_TYPES
|
||||
be_int56_t ETL_USING_64BIT_TYPES
|
||||
```
|
||||
|
||||
### Network Order
|
||||
Synonyms for Big Endian.
|
||||
```cpp
|
||||
using net_uint24_t = be_uint24_t
|
||||
using net_int24_t = be_int24_t
|
||||
using net_uint40_t = be_uint40_t
|
||||
using net_int40_t = be_int40_t
|
||||
using net_uint48_t = be_uint48_t
|
||||
using net_int48_t = be_int48_t
|
||||
using net_uint56_t = be_uint56_t
|
||||
using net_int56_t = be_int56_t
|
||||
```
|
||||
|
||||
### Host order
|
||||
```cpp
|
||||
host_uint24_t
|
||||
host_int24_t
|
||||
host_uint40_t
|
||||
host_int40_t
|
||||
host_uint48_t
|
||||
host_int48_t
|
||||
host_uint56_t
|
||||
host_int56_t
|
||||
```
|
||||
|
||||
## Constructors
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type()
|
||||
unaligned_int_type()
|
||||
```
|
||||
**Description**
|
||||
Constructs an uninitialised object.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 unaligned_uint_type(value_type value)
|
||||
ETL_CONSTEXPR14 unaligned_int_type(value_type value)
|
||||
```
|
||||
**Description**
|
||||
Constructs with the supplied value.
|
||||
Values that do not fit in `Size` bytes are truncated.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type(const void* address)
|
||||
unaligned_int_type(const void* address)
|
||||
```
|
||||
**Description**
|
||||
Constructs from the `Size` bytes at the address.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type(const void* address, size_t buffer_size)
|
||||
unaligned_int_type(const void* address, size_t buffer_size)
|
||||
```
|
||||
**Description**
|
||||
Constructs from the `Size` bytes at the address.
|
||||
`buffer_size` must be greater than or equal to `Size`. This is a precondition,
|
||||
checked by `ETL_ASSERT`. If checks are disabled then a smaller buffer size
|
||||
results in a read beyond the end of the buffer.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 unaligned_uint_type(const unsigned char* address)
|
||||
ETL_CONSTEXPR14 unaligned_int_type(const unsigned char* address)
|
||||
```
|
||||
**Description**
|
||||
Constructs from the `Size` bytes at the address.
|
||||
Unlike the `const void*` overload, this requires no `reinterpret_cast` and so
|
||||
may be used in a constexpr context.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 unaligned_uint_type(const unsigned char* address, size_t buffer_size)
|
||||
ETL_CONSTEXPR14 unaligned_int_type(const unsigned char* address, size_t buffer_size)
|
||||
```
|
||||
**Description**
|
||||
Constructs from the `Size` bytes at the address.
|
||||
`buffer_size` must be greater than or equal to `Size`. This is a precondition,
|
||||
checked by `ETL_ASSERT`.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
template <int Endian_Other>
|
||||
unaligned_uint_type(const unaligned_uint_type<Size, Endian_Other>& other)
|
||||
```
|
||||
**Description**
|
||||
Constructs from another type of the same size.
|
||||
The endianness is converted, if necessary.
|
||||
|
||||
## Member functions
|
||||
|
||||
The storage interface (`data()`, `size()`, the iterators and `operator[]`) is
|
||||
the same as that of `etl::unaligned_type`.
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 unaligned_uint_type& operator =(value_type value)
|
||||
```
|
||||
**Description**
|
||||
Assignment operator.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 operator value_type() const
|
||||
```
|
||||
**Description**
|
||||
Conversion operator.
|
||||
For `unaligned_int_type` the stored value is sign extended.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
ETL_CONSTEXPR14 value_type value() const
|
||||
```
|
||||
**Description**
|
||||
Gets the value.
|
||||
For `unaligned_int_type` the stored value is sign extended.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
static ETL_CONSTEXPR14 value_type value_from(const_pointer address)
|
||||
```
|
||||
**Description**
|
||||
Gets the value of the `Size` bytes at the address.
|
||||
Unlike construction from an address, the bytes are not copied to storage first.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
template <int Endian_Other>
|
||||
ETL_CONSTEXPR14 unaligned_uint_type& operator =(const unaligned_uint_type<Size, Endian_Other>& other)
|
||||
```
|
||||
**Description**
|
||||
Assignment operator from other endianness.
|
||||
|
||||
---
|
||||
|
||||
# Arbitrary width integers with an external buffer
|
||||
|
||||
{{< callout type="info">}}
|
||||
From: `20.50.0`
|
||||
{{< /callout >}}
|
||||
|
||||
```cpp
|
||||
template <size_t Size_, int Endian_>
|
||||
class unaligned_uint_type_ext
|
||||
|
||||
template <size_t Size_, int Endian_>
|
||||
class unaligned_int_type_ext
|
||||
```
|
||||
|
||||
These are the equivalents of `unaligned_uint_type` and `unaligned_int_type`
|
||||
that do not own their storage, but reference an externally supplied buffer.
|
||||
They have the same `value_type`, constants and value interface.
|
||||
|
||||
The default constructor is deleted: the storage must always be supplied.
|
||||
|
||||
### Predefined types
|
||||
As for the internal storage versions, but with an `_ext_t` suffix.
|
||||
```cpp
|
||||
le_uint24_ext_t be_uint24_ext_t net_uint24_ext_t host_uint24_ext_t
|
||||
le_int24_ext_t be_int24_ext_t net_int24_ext_t host_int24_ext_t
|
||||
le_uint40_ext_t be_uint40_ext_t net_uint40_ext_t host_uint40_ext_t
|
||||
le_int40_ext_t be_int40_ext_t net_int40_ext_t host_int40_ext_t
|
||||
le_uint48_ext_t be_uint48_ext_t net_uint48_ext_t host_uint48_ext_t
|
||||
le_int48_ext_t be_int48_ext_t net_int48_ext_t host_int48_ext_t
|
||||
le_uint56_ext_t be_uint56_ext_t net_uint56_ext_t host_uint56_ext_t
|
||||
le_int56_ext_t be_int56_ext_t net_int56_ext_t host_int56_ext_t
|
||||
```
|
||||
|
||||
## Constructors
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type_ext() ETL_DELETE
|
||||
```
|
||||
**Description**
|
||||
Deleted. The storage must always be supplied.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type_ext(pointer storage)
|
||||
```
|
||||
**Description**
|
||||
Constructs, referencing the supplied storage.
|
||||
The storage is not modified.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
unaligned_uint_type_ext(value_type value, pointer storage)
|
||||
```
|
||||
**Description**
|
||||
Constructs, referencing the supplied storage, and writes the value to it.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
template <int Endian_Other>
|
||||
unaligned_uint_type_ext(const unaligned_uint_type_ext<Size, Endian_Other>& other, pointer storage)
|
||||
```
|
||||
**Description**
|
||||
Constructs, referencing the supplied storage, and copies the value of `other`
|
||||
to it, converting the endianness if necessary.
|
||||
**Note**
|
||||
The storage of `other` must either be the same storage as that supplied, or
|
||||
completely separate. Partially overlapping storage is undefined behaviour.
|
||||
|
||||
## Member functions
|
||||
|
||||
```cpp
|
||||
void set_storage(pointer storage)
|
||||
```
|
||||
**Description**
|
||||
Sets the storage for the type.
|
||||
The storage is not modified.
|
||||
|
||||
---
|
||||
|
||||
```cpp
|
||||
template <int Endian_Other>
|
||||
unaligned_uint_type_ext& operator =(const unaligned_uint_type_ext<Size, Endian_Other>& other)
|
||||
```
|
||||
**Description**
|
||||
Assignment operator from other endianness.
|
||||
**Note**
|
||||
The storage of `other` must either be the same storage as this object's, or
|
||||
completely separate. Partially overlapping storage is undefined behaviour.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -367,6 +367,208 @@ namespace
|
||||
CHECK_EQUAL(f, etl::be_float_t::value_from(be_f.data()));
|
||||
CHECK_EQUAL(d, etl::le_double_t::value_from(le_d.data()));
|
||||
}
|
||||
/// Unsigned integers that have no native equivalent, such as 24 bit.
|
||||
//*************************************************************************
|
||||
TEST(test_uint24)
|
||||
{
|
||||
CHECK_EQUAL(3U, sizeof(etl::le_uint24_t));
|
||||
CHECK_EQUAL(3U, sizeof(etl::be_uint24_t));
|
||||
CHECK_EQUAL(3U, size_t(etl::le_uint24_t::Size));
|
||||
|
||||
CHECK((etl::is_same<uint32_t, etl::le_uint24_t::value_type>::value));
|
||||
CHECK_EQUAL(uint32_t(0x00FFFFFF), etl::le_uint24_t::Max_Value);
|
||||
|
||||
etl::le_uint24_t le_v(0x123456U);
|
||||
etl::be_uint24_t be_v(0x123456U);
|
||||
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v.value());
|
||||
|
||||
// Check the storage byte order.
|
||||
CHECK_EQUAL(0x56, int(le_v.data()[0]));
|
||||
CHECK_EQUAL(0x34, int(le_v.data()[1]));
|
||||
CHECK_EQUAL(0x12, int(le_v.data()[2]));
|
||||
|
||||
CHECK_EQUAL(0x12, int(be_v.data()[0]));
|
||||
CHECK_EQUAL(0x34, int(be_v.data()[1]));
|
||||
CHECK_EQUAL(0x56, int(be_v.data()[2]));
|
||||
|
||||
// Copy construction, including from the other endianness.
|
||||
etl::le_uint24_t le_v2(le_v);
|
||||
etl::be_uint24_t be_v2(be_v);
|
||||
etl::le_uint24_t le_v3(be_v);
|
||||
etl::be_uint24_t be_v3(le_v);
|
||||
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v3.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v3.value());
|
||||
|
||||
// Assignment.
|
||||
le_v2 = 0xFFFFFFU;
|
||||
be_v2 = 0xFFFFFFU;
|
||||
CHECK_EQUAL(uint32_t(0xFFFFFF), le_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0xFFFFFF), be_v2.value());
|
||||
|
||||
// Boundary values.
|
||||
etl::le_uint24_t le_zero(0U);
|
||||
etl::be_uint24_t be_zero(0U);
|
||||
CHECK_EQUAL(uint32_t(0), le_zero.value());
|
||||
CHECK_EQUAL(uint32_t(0), be_zero.value());
|
||||
|
||||
// Values that do not fit are truncated, like a narrowing cast.
|
||||
etl::le_uint24_t le_truncated(0xAB123456U);
|
||||
etl::be_uint24_t be_truncated(0xAB123456U);
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_truncated.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_truncated.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_uint24_decode_buffer)
|
||||
{
|
||||
const std::array<unsigned char, 4> buffer = {0xAA, 0xBB, 0xCC, 0xDD};
|
||||
|
||||
etl::le_uint24_t le_v(buffer.data(), buffer.size());
|
||||
etl::be_uint24_t be_v(buffer.data(), buffer.size());
|
||||
|
||||
CHECK_EQUAL(uint32_t(0xCCBBAA), le_v.value());
|
||||
CHECK_EQUAL(uint32_t(0xAABBCC), be_v.value());
|
||||
|
||||
// One byte short.
|
||||
CHECK_THROW(etl::le_uint24_t le_short(buffer.data(), 2U), etl::unaligned_type_buffer_size);
|
||||
CHECK_THROW(etl::be_uint24_t be_short(buffer.data(), 2U), etl::unaligned_type_buffer_size);
|
||||
}
|
||||
|
||||
#if ETL_USING_64BIT_TYPES
|
||||
//*************************************************************************
|
||||
TEST(test_uint40_uint48_uint56)
|
||||
{
|
||||
CHECK_EQUAL(5U, sizeof(etl::be_uint40_t));
|
||||
CHECK_EQUAL(6U, sizeof(etl::be_uint48_t));
|
||||
CHECK_EQUAL(7U, sizeof(etl::be_uint56_t));
|
||||
|
||||
etl::be_uint48_t be_v(0x0123456789ABULL);
|
||||
etl::le_uint48_t le_v(0x0123456789ABULL);
|
||||
|
||||
CHECK_EQUAL(uint64_t(0x0123456789AB), be_v.value());
|
||||
CHECK_EQUAL(uint64_t(0x0123456789AB), le_v.value());
|
||||
|
||||
CHECK_EQUAL(0x01, int(be_v.data()[0]));
|
||||
CHECK_EQUAL(0xAB, int(le_v.data()[0]));
|
||||
|
||||
CHECK_EQUAL(uint64_t(0x000000FFFFFFFFFF), etl::be_uint40_t::Max_Value);
|
||||
CHECK_EQUAL(uint64_t(0x00FFFFFFFFFFFFFF), etl::be_uint56_t::Max_Value);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
/// Signed integers that have no native equivalent, such as 24 bit.
|
||||
//*************************************************************************
|
||||
TEST(test_int24)
|
||||
{
|
||||
CHECK_EQUAL(3U, sizeof(etl::le_int24_t));
|
||||
CHECK_EQUAL(3U, sizeof(etl::be_int24_t));
|
||||
CHECK_EQUAL(3U, size_t(etl::le_int24_t::Size));
|
||||
|
||||
CHECK((etl::is_same<int32_t, etl::le_int24_t::value_type>::value));
|
||||
CHECK_EQUAL(int32_t(8388607), etl::le_int24_t::Max_Value);
|
||||
CHECK_EQUAL(int32_t(-8388608), etl::le_int24_t::Min_Value);
|
||||
|
||||
etl::le_int24_t le_v(0x123456);
|
||||
etl::be_int24_t be_v(0x123456);
|
||||
|
||||
CHECK_EQUAL(int32_t(0x123456), le_v.value());
|
||||
CHECK_EQUAL(int32_t(0x123456), be_v.value());
|
||||
|
||||
// Check the storage byte order.
|
||||
CHECK_EQUAL(0x56, int(le_v.data()[0]));
|
||||
CHECK_EQUAL(0x12, int(le_v.data()[2]));
|
||||
CHECK_EQUAL(0x12, int(be_v.data()[0]));
|
||||
CHECK_EQUAL(0x56, int(be_v.data()[2]));
|
||||
|
||||
// Negative values are sign extended on reading.
|
||||
etl::le_int24_t le_n(-2);
|
||||
etl::be_int24_t be_n(-2);
|
||||
|
||||
CHECK_EQUAL(int32_t(-2), le_n.value());
|
||||
CHECK_EQUAL(int32_t(-2), be_n.value());
|
||||
|
||||
CHECK_EQUAL(0xFE, int(le_n.data()[0]));
|
||||
CHECK_EQUAL(0xFF, int(le_n.data()[1]));
|
||||
CHECK_EQUAL(0xFF, int(le_n.data()[2]));
|
||||
|
||||
CHECK_EQUAL(0xFF, int(be_n.data()[0]));
|
||||
CHECK_EQUAL(0xFF, int(be_n.data()[1]));
|
||||
CHECK_EQUAL(0xFE, int(be_n.data()[2]));
|
||||
|
||||
// Copy construction, including from the other endianness.
|
||||
etl::le_int24_t le_n2(be_n);
|
||||
etl::be_int24_t be_n2(le_n);
|
||||
|
||||
CHECK_EQUAL(int32_t(-2), le_n2.value());
|
||||
CHECK_EQUAL(int32_t(-2), be_n2.value());
|
||||
|
||||
// Assignment.
|
||||
le_n2 = -1;
|
||||
be_n2 = -1;
|
||||
CHECK_EQUAL(int32_t(-1), le_n2.value());
|
||||
CHECK_EQUAL(int32_t(-1), be_n2.value());
|
||||
|
||||
// Boundary values.
|
||||
etl::le_int24_t le_min(etl::le_int24_t::Min_Value);
|
||||
etl::be_int24_t be_min(etl::be_int24_t::Min_Value);
|
||||
etl::le_int24_t le_max(etl::le_int24_t::Max_Value);
|
||||
etl::be_int24_t be_max(etl::be_int24_t::Max_Value);
|
||||
|
||||
CHECK_EQUAL(int32_t(-8388608), le_min.value());
|
||||
CHECK_EQUAL(int32_t(-8388608), be_min.value());
|
||||
CHECK_EQUAL(int32_t(8388607), le_max.value());
|
||||
CHECK_EQUAL(int32_t(8388607), be_max.value());
|
||||
|
||||
etl::le_int24_t le_zero(0);
|
||||
CHECK_EQUAL(int32_t(0), le_zero.value());
|
||||
|
||||
// Values that do not fit are truncated, like a narrowing cast.
|
||||
etl::be_int24_t be_truncated(0x7F123456);
|
||||
CHECK_EQUAL(int32_t(0x123456), be_truncated.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_int24_decode_buffer)
|
||||
{
|
||||
const std::array<unsigned char, 4> buffer = {0x80, 0x00, 0x00, 0xDD};
|
||||
|
||||
etl::le_int24_t le_v(buffer.data(), buffer.size());
|
||||
etl::be_int24_t be_v(buffer.data(), buffer.size());
|
||||
|
||||
CHECK_EQUAL(int32_t(0x000080), le_v.value());
|
||||
CHECK_EQUAL(int32_t(-8388608), be_v.value());
|
||||
|
||||
// One byte short.
|
||||
CHECK_THROW(etl::le_int24_t le_short(buffer.data(), 2U), etl::unaligned_type_buffer_size);
|
||||
CHECK_THROW(etl::be_int24_t be_short(buffer.data(), 2U), etl::unaligned_type_buffer_size);
|
||||
}
|
||||
|
||||
#if ETL_USING_64BIT_TYPES
|
||||
//*************************************************************************
|
||||
TEST(test_int40_int48_int56)
|
||||
{
|
||||
CHECK_EQUAL(5U, sizeof(etl::be_int40_t));
|
||||
CHECK_EQUAL(6U, sizeof(etl::be_int48_t));
|
||||
CHECK_EQUAL(7U, sizeof(etl::be_int56_t));
|
||||
|
||||
etl::be_int48_t be_v(-1099511627775LL);
|
||||
etl::le_int48_t le_v(-1099511627775LL);
|
||||
|
||||
CHECK_EQUAL(int64_t(-1099511627775LL), be_v.value());
|
||||
CHECK_EQUAL(int64_t(-1099511627775LL), le_v.value());
|
||||
|
||||
CHECK_EQUAL(int64_t(549755813887LL), etl::be_int40_t::Max_Value);
|
||||
CHECK_EQUAL(int64_t(-549755813888LL), etl::be_int40_t::Min_Value);
|
||||
CHECK_EQUAL(int64_t(36028797018963967LL), etl::be_int56_t::Max_Value);
|
||||
CHECK_EQUAL(int64_t(-36028797018963968LL), etl::be_int56_t::Min_Value);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
// The following tests demonstrate the 'decode' direction: given a raw byte
|
||||
|
||||
@ -49,6 +49,8 @@ namespace
|
||||
using storage_i16_t = std::array<unsigned char, sizeof(int16_t)>;
|
||||
using storage_i32_t = std::array<unsigned char, sizeof(int32_t)>;
|
||||
using storage_i64_t = std::array<unsigned char, sizeof(int64_t)>;
|
||||
using storage_24_t = std::array<unsigned char, 3U>;
|
||||
using storage_48_t = std::array<unsigned char, 6U>;
|
||||
|
||||
SUITE(test_unaligned_type_ext)
|
||||
{
|
||||
@ -506,6 +508,148 @@ namespace
|
||||
CHECK_EQUAL(sizeof(uint64_t), etl::net_uint64_ext_t::Size);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Integers that have no native equivalent, such as 24 bit.
|
||||
//*************************************************************************
|
||||
TEST(test_uint24)
|
||||
{
|
||||
storage_24_t store_le1;
|
||||
storage_24_t store_be1;
|
||||
storage_24_t store_le2;
|
||||
storage_24_t store_be2;
|
||||
|
||||
CHECK_EQUAL(3U, size_t(etl::le_uint24_ext_t::Size));
|
||||
CHECK((etl::is_same<uint32_t, etl::le_uint24_ext_t::value_type>::value));
|
||||
CHECK_EQUAL(uint32_t(0x00FFFFFF), etl::le_uint24_ext_t::Max_Value);
|
||||
CHECK_EQUAL(uint32_t(0), etl::le_uint24_ext_t::Min_Value);
|
||||
|
||||
etl::le_uint24_ext_t le_v1(store_le1.data());
|
||||
le_v1 = 0x123456U;
|
||||
etl::be_uint24_ext_t be_v1(0x123456U, store_be1.data());
|
||||
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v1.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v1.value());
|
||||
|
||||
// The external buffers hold the requested byte order.
|
||||
CHECK_EQUAL(0x56, int(store_le1[0]));
|
||||
CHECK_EQUAL(0x12, int(store_le1[2]));
|
||||
CHECK_EQUAL(0x12, int(store_be1[0]));
|
||||
CHECK_EQUAL(0x56, int(store_be1[2]));
|
||||
|
||||
// Copy construct from the other endianness.
|
||||
etl::le_uint24_ext_t le_v2(be_v1, store_le2.data());
|
||||
etl::be_uint24_ext_t be_v2(le_v1, store_be2.data());
|
||||
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v2.value());
|
||||
|
||||
// Assignment.
|
||||
le_v2 = le_v1;
|
||||
be_v2 = le_v1;
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v2.value());
|
||||
|
||||
// Values that do not fit are truncated.
|
||||
be_v2 = 0xABCDEF12U;
|
||||
CHECK_EQUAL(uint32_t(0xCDEF12), be_v2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_construction_uint24)
|
||||
{
|
||||
storage_24_t store_le1;
|
||||
storage_24_t store_be1;
|
||||
|
||||
etl::le_uint24_ext_t le_v1(0x123456U, store_le1.data());
|
||||
etl::be_uint24_ext_t be_v1(0x123456U, store_be1.data());
|
||||
|
||||
etl::le_uint24_ext_t le_v2(etl::move(le_v1));
|
||||
etl::be_uint24_ext_t be_v2(etl::move(be_v1));
|
||||
|
||||
CHECK_TRUE(nullptr == le_v1.data());
|
||||
CHECK_TRUE(nullptr == be_v1.data());
|
||||
CHECK_EQUAL(uint32_t(0x123456), le_v2.value());
|
||||
CHECK_EQUAL(uint32_t(0x123456), be_v2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_int24)
|
||||
{
|
||||
storage_24_t store_le1;
|
||||
storage_24_t store_be1;
|
||||
storage_24_t store_le2;
|
||||
storage_24_t store_be2;
|
||||
|
||||
CHECK_EQUAL(3U, size_t(etl::le_int24_ext_t::Size));
|
||||
CHECK((etl::is_same<int32_t, etl::le_int24_ext_t::value_type>::value));
|
||||
CHECK_EQUAL(int32_t(8388607), etl::le_int24_ext_t::Max_Value);
|
||||
CHECK_EQUAL(int32_t(-8388608), etl::le_int24_ext_t::Min_Value);
|
||||
|
||||
etl::le_int24_ext_t le_v1(store_le1.data());
|
||||
le_v1 = -2;
|
||||
etl::be_int24_ext_t be_v1(-2, store_be1.data());
|
||||
|
||||
// Negative values are sign extended on reading.
|
||||
CHECK_EQUAL(int32_t(-2), le_v1.value());
|
||||
CHECK_EQUAL(int32_t(-2), be_v1.value());
|
||||
|
||||
CHECK_EQUAL(0xFE, int(store_le1[0]));
|
||||
CHECK_EQUAL(0xFF, int(store_le1[2]));
|
||||
CHECK_EQUAL(0xFF, int(store_be1[0]));
|
||||
CHECK_EQUAL(0xFE, int(store_be1[2]));
|
||||
|
||||
// Copy construct from the other endianness.
|
||||
etl::le_int24_ext_t le_v2(be_v1, store_le2.data());
|
||||
etl::be_int24_ext_t be_v2(le_v1, store_be2.data());
|
||||
|
||||
CHECK_EQUAL(int32_t(-2), le_v2.value());
|
||||
CHECK_EQUAL(int32_t(-2), be_v2.value());
|
||||
|
||||
// Boundary values.
|
||||
le_v2 = etl::le_int24_ext_t::Min_Value;
|
||||
be_v2 = etl::be_int24_ext_t::Max_Value;
|
||||
|
||||
CHECK_EQUAL(int32_t(-8388608), le_v2.value());
|
||||
CHECK_EQUAL(int32_t(8388607), be_v2.value());
|
||||
|
||||
le_v2 = 0;
|
||||
CHECK_EQUAL(int32_t(0), le_v2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_construction_int24)
|
||||
{
|
||||
storage_24_t store_le1;
|
||||
storage_24_t store_be1;
|
||||
|
||||
etl::le_int24_ext_t le_v1(-1234567, store_le1.data());
|
||||
etl::be_int24_ext_t be_v1(-1234567, store_be1.data());
|
||||
|
||||
etl::le_int24_ext_t le_v2(etl::move(le_v1));
|
||||
etl::be_int24_ext_t be_v2(etl::move(be_v1));
|
||||
|
||||
CHECK_TRUE(nullptr == le_v1.data());
|
||||
CHECK_TRUE(nullptr == be_v1.data());
|
||||
CHECK_EQUAL(int32_t(-1234567), le_v2.value());
|
||||
CHECK_EQUAL(int32_t(-1234567), be_v2.value());
|
||||
}
|
||||
|
||||
#if ETL_USING_64BIT_TYPES
|
||||
//*************************************************************************
|
||||
TEST(test_uint48_int48)
|
||||
{
|
||||
storage_48_t store_u;
|
||||
storage_48_t store_i;
|
||||
|
||||
etl::be_uint48_ext_t be_u(0x0123456789ABULL, store_u.data());
|
||||
etl::be_int48_ext_t be_i(-1099511627775LL, store_i.data());
|
||||
|
||||
CHECK_EQUAL(6U, size_t(etl::be_uint48_ext_t::Size));
|
||||
CHECK_EQUAL(uint64_t(0x0123456789AB), be_u.value());
|
||||
CHECK_EQUAL(int64_t(-1099511627775LL), be_i.value());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ETL_HAS_CONSTEXPR_ENDIANNESS
|
||||
//*************************************************************************
|
||||
TEST(test_host_sizes)
|
||||
@ -1528,6 +1672,106 @@ namespace
|
||||
CHECK_EQUAL(0x12, bev0);
|
||||
CHECK_EQUAL(0x34, bev1);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_construction_uint24)
|
||||
{
|
||||
storage_24_t store;
|
||||
|
||||
etl::be_uint24_ext_t be_v(0x123456, store.data());
|
||||
|
||||
// Reinterpret the same buffer with the opposite endianness.
|
||||
etl::le_uint24_ext_t le_v(be_v, store.data());
|
||||
|
||||
CHECK_EQUAL(0x56, int(store[0]));
|
||||
CHECK_EQUAL(0x34, int(store[1]));
|
||||
CHECK_EQUAL(0x12, int(store[2]));
|
||||
CHECK_EQUAL(0x123456, le_v.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_construction_int24)
|
||||
{
|
||||
storage_24_t store;
|
||||
|
||||
etl::be_int24_ext_t be_v(-0x123456, store.data());
|
||||
|
||||
etl::le_int24_ext_t le_v(be_v, store.data());
|
||||
|
||||
CHECK_EQUAL(-0x123456, le_v.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_assignment_uint24)
|
||||
{
|
||||
storage_24_t store;
|
||||
|
||||
etl::be_uint24_ext_t be_v(0x123456, store.data());
|
||||
etl::le_uint24_ext_t le_v(store.data());
|
||||
|
||||
le_v = be_v;
|
||||
|
||||
CHECK_EQUAL(0x56, int(store[0]));
|
||||
CHECK_EQUAL(0x34, int(store[1]));
|
||||
CHECK_EQUAL(0x12, int(store[2]));
|
||||
CHECK_EQUAL(0x123456, le_v.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_assignment_int24)
|
||||
{
|
||||
storage_24_t store;
|
||||
|
||||
etl::be_int24_ext_t be_v(-0x123456, store.data());
|
||||
etl::le_int24_ext_t le_v(store.data());
|
||||
|
||||
le_v = be_v;
|
||||
|
||||
CHECK_EQUAL(-0x123456, le_v.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_assignment_uint32)
|
||||
{
|
||||
storage_i32_t store;
|
||||
|
||||
etl::be_uint32_ext_t be_v(0x12345678, store.data());
|
||||
etl::le_uint32_ext_t le_v(store.data());
|
||||
|
||||
le_v = be_v;
|
||||
|
||||
CHECK_EQUAL(0x78, int(store[0]));
|
||||
CHECK_EQUAL(0x56, int(store[1]));
|
||||
CHECK_EQUAL(0x34, int(store[2]));
|
||||
CHECK_EQUAL(0x12, int(store[3]));
|
||||
CHECK_EQUAL(0x12345678, le_v.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_assignment_same_endianness)
|
||||
{
|
||||
storage_i32_t store;
|
||||
|
||||
etl::le_uint32_ext_t le_v1(0x12345678, store.data());
|
||||
etl::le_uint32_ext_t le_v2(store.data());
|
||||
|
||||
le_v2 = le_v1;
|
||||
|
||||
CHECK_EQUAL(0x12345678, le_v2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_shared_storage_copy_assignment_float)
|
||||
{
|
||||
storage_f_t store;
|
||||
|
||||
etl::be_float_ext_t be_v(3.1415927f, store.data());
|
||||
etl::le_float_ext_t le_v(store.data());
|
||||
|
||||
le_v = be_v;
|
||||
|
||||
CHECK_EQUAL(3.1415927f, le_v.value());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user