mirror of
https://github.com/ETLCPP/etl.git
synced 2026-11-09 14:49:53 +08:00
Latest updates to bit_stream_reader
This commit is contained in:
parent
11b97359fb
commit
f88999bb12
@ -40,12 +40,41 @@ SOFTWARE.
|
||||
#include "memory.h"
|
||||
#include "delegate.h"
|
||||
#include "span.h"
|
||||
#include "endianness.h"
|
||||
#include "optional.h"
|
||||
#include "exception.h"
|
||||
#include "error_handler.h"
|
||||
|
||||
#include "private/minmax_push.h"
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***************************************************************************
|
||||
/// Exception base for bit streams
|
||||
//***************************************************************************
|
||||
class bit_stream_exception : public etl::exception
|
||||
{
|
||||
public:
|
||||
|
||||
bit_stream_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
|
||||
: exception(reason_, file_name_, line_number_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
///\ingroup string
|
||||
/// String empty exception.
|
||||
//***************************************************************************
|
||||
class bit_stream_overflow : public etl::bit_stream_exception
|
||||
{
|
||||
public:
|
||||
|
||||
bit_stream_overflow(string_type file_name_, numeric_type line_number_)
|
||||
: bit_stream_exception(ETL_ERROR_TEXT("bit_stream:overflow", ETL_BIT_STREAM_FILE_ID"A"), file_name_, line_number_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Encodes and decodes bitstreams.
|
||||
/// Data must be stored in the stream in network order.
|
||||
@ -109,9 +138,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
void restart()
|
||||
{
|
||||
bits_available_in_char = 8;
|
||||
bits_available_in_char = CHAR_BIT;
|
||||
char_index = 0U;
|
||||
bits_remaining = CHAR_BIT * length_chars;
|
||||
bits_available = CHAR_BIT * length_chars;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -119,7 +148,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool at_end() const
|
||||
{
|
||||
return (bits_remaining == 0U);
|
||||
return (bits_available == 0U);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -131,7 +160,7 @@ namespace etl
|
||||
|
||||
if (pdata != ETL_NULLPTR)
|
||||
{
|
||||
if (bits_remaining > 0)
|
||||
if (bits_available > 0)
|
||||
{
|
||||
unsigned char chunk = value ? 1 : 0;
|
||||
put_integral(uint32_t(chunk), 1);
|
||||
@ -203,7 +232,7 @@ namespace etl
|
||||
if (pdata != ETL_NULLPTR)
|
||||
{
|
||||
// Do we have enough bits?
|
||||
if (bits_remaining > 0)
|
||||
if (bits_available > 0U)
|
||||
{
|
||||
value = get_bit();
|
||||
success = true;
|
||||
@ -226,7 +255,7 @@ namespace etl
|
||||
if (pdata != ETL_NULLPTR)
|
||||
{
|
||||
// Do we have enough bits?
|
||||
if (bits_remaining >= nbits)
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
value = 0;
|
||||
|
||||
@ -270,7 +299,7 @@ namespace etl
|
||||
uint_least8_t nbits = CHAR_BIT * sizeof(T);
|
||||
|
||||
// Do we have enough bits?
|
||||
if (bits_remaining >= nbits)
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
// Temporary storage.
|
||||
etl::uninitialized_buffer_of<T, 1U> data;
|
||||
@ -310,7 +339,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
size_t bits() const
|
||||
{
|
||||
return (length_chars * CHAR_BIT) - bits_remaining;
|
||||
return (length_chars * CHAR_BIT) - bits_available;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -341,7 +370,7 @@ namespace etl
|
||||
if (pdata != ETL_NULLPTR)
|
||||
{
|
||||
// Do we have enough bits?
|
||||
if (bits_remaining >= nbits)
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
// Send the bits to the stream.
|
||||
while (nbits != 0)
|
||||
@ -375,7 +404,7 @@ namespace etl
|
||||
if (pdata != ETL_NULLPTR)
|
||||
{
|
||||
// Do we have enough bits?
|
||||
if (bits_remaining >= nbits)
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
// Send the bits to the stream.
|
||||
while (nbits != 0)
|
||||
@ -507,14 +536,14 @@ namespace etl
|
||||
bits_available_in_char = 8;
|
||||
}
|
||||
|
||||
bits_remaining -= nbits;
|
||||
bits_available -= nbits;
|
||||
}
|
||||
|
||||
unsigned char *pdata; ///< The start of the bitstream buffer.
|
||||
size_t length_chars; ///< The length, in char, of the bitstream buffer.
|
||||
unsigned char bits_available_in_char; ///< The number of available bits in the current char.
|
||||
size_t char_index; ///< The index of the char in the bitstream buffer.
|
||||
size_t bits_remaining; ///< The number of bits still available in the bitstream buffer.
|
||||
size_t bits_available; ///< The number of bits still available in the bitstream buffer.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
@ -524,16 +553,16 @@ namespace etl
|
||||
{
|
||||
public:
|
||||
|
||||
typedef const unsigned char* const_iterator;
|
||||
|
||||
typedef etl::span<char> callback_parameter_type;
|
||||
typedef char value_type;
|
||||
typedef const value_type* const_iterator;
|
||||
typedef etl::span<value_type> callback_parameter_type;
|
||||
typedef etl::delegate<void(callback_parameter_type)> callback_type;
|
||||
|
||||
//***************************************************************************
|
||||
/// Construct from span.
|
||||
//***************************************************************************
|
||||
bit_stream_writer(etl::span<char> span_, callback_type callback_ = callback_type())
|
||||
: pdata(reinterpret_cast<unsigned char*>(span_.begin()))
|
||||
: pdata(span_.begin())
|
||||
, length_chars(span_.size_bytes())
|
||||
, callback(callback_)
|
||||
{
|
||||
@ -544,7 +573,7 @@ namespace etl
|
||||
/// Construct from span.
|
||||
//***************************************************************************
|
||||
bit_stream_writer(etl::span<unsigned char> span_, callback_type callback_ = callback_type())
|
||||
: pdata(span_.begin())
|
||||
: pdata(reinterpret_cast<char*>(span_.begin()))
|
||||
, length_chars(span_.size_bytes())
|
||||
, callback(callback_)
|
||||
{
|
||||
@ -555,7 +584,7 @@ namespace etl
|
||||
/// Construct from range.
|
||||
//***************************************************************************
|
||||
bit_stream_writer(void* begin_, void* end_, callback_type callback_ = callback_type())
|
||||
: pdata(reinterpret_cast<unsigned char*>(begin_))
|
||||
: pdata(reinterpret_cast<char*>(begin_))
|
||||
, length_chars(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
|
||||
, callback(callback_)
|
||||
{
|
||||
@ -566,7 +595,7 @@ namespace etl
|
||||
/// Construct from begin and length.
|
||||
//***************************************************************************
|
||||
bit_stream_writer(void* begin_, size_t length_chars_, callback_type callback_ = callback_type())
|
||||
: pdata(reinterpret_cast<unsigned char*>(begin_))
|
||||
: pdata(reinterpret_cast<char*>(begin_))
|
||||
, length_chars(length_chars_)
|
||||
, callback(callback_)
|
||||
{
|
||||
@ -578,9 +607,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
void restart()
|
||||
{
|
||||
bits_available_in_char = 8;
|
||||
bits_available_in_char = CHAR_BIT;
|
||||
char_index = 0U;
|
||||
bits_remaining = CHAR_BIT * length_chars;
|
||||
bits_available = CHAR_BIT * length_chars;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -602,7 +631,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool empty() const
|
||||
{
|
||||
return (bits_remaining == length_chars);
|
||||
return (bits_available == length_chars);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -610,7 +639,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool full() const
|
||||
{
|
||||
return (bits_remaining == 0U);
|
||||
return (bits_available == 0U);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -627,12 +656,15 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool write(bool value)
|
||||
{
|
||||
bool success = false;
|
||||
bool success = (available<1U>() > 0U);
|
||||
|
||||
if (available<1U>() > 0U)
|
||||
if (success)
|
||||
{
|
||||
write_unchecked(value);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -655,12 +687,15 @@ namespace etl
|
||||
typename etl::enable_if<etl::is_integral<T>::value, bool>::type
|
||||
write(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
|
||||
{
|
||||
bool success = false;
|
||||
bool success = (available(nbits) > 0U);
|
||||
|
||||
if (available(nbits) > 0U)
|
||||
if (success)
|
||||
{
|
||||
write_unchecked(value, nbits);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -680,12 +715,15 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool write(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
|
||||
{
|
||||
bool success = false;
|
||||
bool success = (available(nbits) > 0U);
|
||||
|
||||
if (available(nbits) > 0U)
|
||||
if (success)
|
||||
{
|
||||
write_unchecked(value, nbits);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -704,12 +742,15 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool write(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
|
||||
{
|
||||
bool success = false;
|
||||
bool success = (available(nbits) > 0U);
|
||||
|
||||
if (available(nbits) > 0U)
|
||||
if (success)
|
||||
{
|
||||
write_unchecked(value, nbits);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -739,12 +780,15 @@ namespace etl
|
||||
typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type
|
||||
write(T value)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
if (available<T>())
|
||||
bool success = available<T>();
|
||||
|
||||
if (success)
|
||||
{
|
||||
write_unchecked(value);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -757,23 +801,24 @@ namespace etl
|
||||
//***************************************************************************
|
||||
bool skip(size_t nbits)
|
||||
{
|
||||
bool success = true;
|
||||
bool success = (nbits <= available_bits());
|
||||
|
||||
if (nbits > available_bits())
|
||||
if (success)
|
||||
{
|
||||
nbits = available_bits();
|
||||
success = false;
|
||||
while (nbits > bits_available_in_char)
|
||||
{
|
||||
step(bits_available_in_char);
|
||||
nbits -= bits_available_in_char;
|
||||
}
|
||||
|
||||
if (nbits != 0U)
|
||||
{
|
||||
step(static_cast<unsigned char>(nbits));
|
||||
}
|
||||
}
|
||||
|
||||
while (nbits > bits_available_in_char)
|
||||
else
|
||||
{
|
||||
step(bits_available_in_char);
|
||||
nbits -= bits_available_in_char;
|
||||
}
|
||||
|
||||
if (nbits != 0U)
|
||||
{
|
||||
step(static_cast<unsigned char>(nbits));
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -804,13 +849,13 @@ namespace etl
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// The number of 'bit nbits' available in the stream.
|
||||
/// The number of multiples of 'Nbits' available in the stream.
|
||||
/// Compile time.
|
||||
//***************************************************************************
|
||||
template <size_t Nbits>
|
||||
size_t available() const
|
||||
{
|
||||
return bits_remaining / Nbits;
|
||||
return bits_available / Nbits;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -829,7 +874,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
size_t available(size_t nbits) const
|
||||
{
|
||||
return bits_remaining / nbits;
|
||||
return bits_available / nbits;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -837,7 +882,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
size_t available_bits() const
|
||||
{
|
||||
return bits_remaining;
|
||||
return bits_available;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -877,7 +922,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
etl::span<char> used_data() const
|
||||
{
|
||||
return etl::span<char>(reinterpret_cast<char*>(pdata), reinterpret_cast<char*>(pdata) + size_bytes());
|
||||
return etl::span<char>(pdata, pdata + size_bytes());
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -885,7 +930,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
etl::span<char> data() const
|
||||
{
|
||||
return etl::span<char>(reinterpret_cast<char*>(pdata), reinterpret_cast<char*>(pdata) + length_chars);
|
||||
return etl::span<char>(pdata, pdata + length_chars);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
@ -897,11 +942,11 @@ namespace etl
|
||||
{
|
||||
if (bits_available_in_char != 0U)
|
||||
{
|
||||
char_index = 1U;
|
||||
char_index = 1U; // Indicate that the first char is actually 'full'.
|
||||
flush_full_bytes();
|
||||
char_index = 0U;
|
||||
bits_available_in_char = CHAR_BIT;
|
||||
}
|
||||
|
||||
restart();
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,7 +984,7 @@ namespace etl
|
||||
// Chunks are never larger than one char.
|
||||
uint32_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
|
||||
|
||||
write_chunk(static_cast<unsigned char>(chunk), mask_width);
|
||||
write_chunk(static_cast<char>(chunk), mask_width);
|
||||
}
|
||||
|
||||
if (callback.is_valid())
|
||||
@ -965,7 +1010,7 @@ namespace etl
|
||||
// Chunks are never larger than one char.
|
||||
uint64_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
|
||||
|
||||
write_chunk(static_cast<unsigned char>(chunk), mask_width);
|
||||
write_chunk(static_cast<char>(chunk), mask_width);
|
||||
}
|
||||
|
||||
size_t end_index = char_index;
|
||||
@ -980,7 +1025,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
/// Write a data chunk to the stream
|
||||
//***************************************************************************
|
||||
void write_chunk(unsigned char chunk, unsigned char nbits)
|
||||
void write_chunk(char chunk, unsigned char nbits)
|
||||
{
|
||||
// Clear if new byte.
|
||||
if (bits_available_in_char == CHAR_BIT)
|
||||
@ -994,19 +1039,22 @@ namespace etl
|
||||
|
||||
//***************************************************************************
|
||||
/// Flush full bytes to the callback, if valid.
|
||||
/// Resets the
|
||||
/// Resets the stream to empty or the last unfilled byte.
|
||||
//***************************************************************************
|
||||
void flush_full_bytes()
|
||||
{
|
||||
// Is the first byte fully filled?
|
||||
if (char_index > 0U)
|
||||
{
|
||||
callback(callback_parameter_type((char*)pdata, (char*)pdata + char_index));
|
||||
callback(callback_parameter_type(pdata, pdata + char_index));
|
||||
|
||||
bits_available = CHAR_BIT * length_chars;
|
||||
|
||||
if (bits_available_in_char != 0U)
|
||||
{
|
||||
// Move a partially filled last byte to the start of the buffer.
|
||||
pdata[0] = pdata[char_index];
|
||||
bits_available -= (CHAR_BIT - bits_available_in_char);
|
||||
}
|
||||
|
||||
char_index = 0U;
|
||||
@ -1046,15 +1094,15 @@ namespace etl
|
||||
bits_available_in_char = CHAR_BIT;
|
||||
}
|
||||
|
||||
bits_remaining -= nbits;
|
||||
bits_available -= nbits;
|
||||
}
|
||||
|
||||
unsigned char* const pdata; ///< The start of the bitstream buffer.
|
||||
const size_t length_chars; ///< The length, in unsigned char, of the bitstream buffer.
|
||||
unsigned char bits_available_in_char; ///< The number of available bits in the current char.
|
||||
size_t char_index; ///< The index of the char in the bitstream buffer.
|
||||
size_t bits_remaining; ///< The number of bits still available in the bitstream buffer.
|
||||
callback_type callback; ///< An optional callback on every filled byte on the write buffer.
|
||||
char* const pdata; ///< The start of the bitstream buffer.
|
||||
const size_t length_chars; ///< The length of the bitstream buffer.
|
||||
unsigned char bits_available_in_char; ///< The number of available bits in the current char.
|
||||
size_t char_index; ///< The index of the current char in the bitstream buffer.
|
||||
size_t bits_available; ///< The number of bits still available in the bitstream buffer.
|
||||
callback_type callback; ///< An optional callback on every filled byte in buffer.
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
@ -1069,13 +1117,331 @@ namespace etl
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Implementation of the write function.
|
||||
/// Default implementation of the write function.
|
||||
/// For integral and floating point types only.
|
||||
/// Overload this to support custom types.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
bool write(etl::bit_stream_writer& stream, const T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
|
||||
{
|
||||
return stream.write(value, nbits);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Reads bit streams
|
||||
//***************************************************************************
|
||||
class bit_stream_reader
|
||||
{
|
||||
public:
|
||||
|
||||
typedef const char* const_iterator;
|
||||
|
||||
//***************************************************************************
|
||||
/// Construct from span.
|
||||
//***************************************************************************
|
||||
bit_stream_reader(etl::span<char> span_)
|
||||
: pdata(span_.begin())
|
||||
, length_chars(span_.size_bytes())
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Construct from span.
|
||||
//***************************************************************************
|
||||
bit_stream_reader(etl::span<unsigned char> span_)
|
||||
: pdata(reinterpret_cast<char*>(span_.begin()))
|
||||
, length_chars(span_.size_bytes())
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Construct from range.
|
||||
//***************************************************************************
|
||||
bit_stream_reader(void* begin_, void* end_)
|
||||
: pdata(reinterpret_cast<char*>(begin_))
|
||||
, length_chars(etl::distance(reinterpret_cast<char*>(begin_), reinterpret_cast<char*>(end_)))
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Construct from begin and length.
|
||||
//***************************************************************************
|
||||
bit_stream_reader(void* begin_, size_t length_)
|
||||
: pdata(reinterpret_cast<char*>(begin_))
|
||||
, length_chars(length_)
|
||||
{
|
||||
restart();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Sets the indexes back to the beginning of the stream.
|
||||
//***************************************************************************
|
||||
void restart()
|
||||
{
|
||||
bits_available_in_char = CHAR_BIT;
|
||||
char_index = 0U;
|
||||
bits_available = CHAR_BIT * length_chars;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For bool types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_same<bool, T>::value, bool>::type
|
||||
read_unchecked()
|
||||
{
|
||||
return get_bit();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For bool types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_same<bool, T>::value, etl::optional<bool>>::type
|
||||
read()
|
||||
{
|
||||
etl::optional<bool> result;
|
||||
|
||||
if (bits_available > 0U)
|
||||
{
|
||||
result = read_unchecked<bool>();
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For integral types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<bool, T>::value, T>::type
|
||||
read_unchecked(uint_least8_t nbits = CHAR_BIT * sizeof(T))
|
||||
{
|
||||
T value = 0;
|
||||
uint_least8_t bits = nbits;
|
||||
|
||||
// Get the bits from the stream.
|
||||
while (nbits != 0)
|
||||
{
|
||||
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
|
||||
|
||||
typedef typename etl::make_unsigned<T>::type chunk_t;
|
||||
chunk_t chunk = get_chunk(mask_width);
|
||||
|
||||
nbits -= mask_width;
|
||||
value |= static_cast<T>(chunk << nbits);
|
||||
}
|
||||
|
||||
// Sign extend if signed type and not already full bit width.
|
||||
if (etl::is_signed<T>::value && (bits != (CHAR_BIT * sizeof(T))))
|
||||
{
|
||||
typedef typename etl::make_signed<T>::type ST;
|
||||
value = etl::sign_extend<ST, ST>(value, bits);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For integral types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<bool, T>::value, etl::optional<T>>::type
|
||||
read(uint_least8_t nbits = CHAR_BIT * sizeof(T))
|
||||
{
|
||||
etl::optional<T> result;
|
||||
|
||||
// Do we have enough bits?
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
result = read_unchecked<T>(nbits);
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For floating point types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_floating_point<T>::value, T>::type
|
||||
read_unchecked()
|
||||
{
|
||||
T value = 0;
|
||||
|
||||
// Temporary storage.
|
||||
etl::uninitialized_buffer_of<T, 1U> data;
|
||||
|
||||
for (size_t i = 0UL; i < sizeof(T); ++i)
|
||||
{
|
||||
get(data.raw[i], CHAR_BIT);
|
||||
}
|
||||
|
||||
from_bytes(reinterpret_cast<const unsigned char*>(data.raw), value);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// For floating point types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
typename etl::enable_if<etl::is_floating_point<T>::value, etl::optional<T>>::type
|
||||
read()
|
||||
{
|
||||
uint_least8_t nbits = CHAR_BIT * sizeof(T);
|
||||
|
||||
etl::optional<T> result;
|
||||
|
||||
// Do we have enough bits?
|
||||
if (bits_available >= nbits)
|
||||
{
|
||||
result = read_unchecked<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
ETL_ASSERT_FAIL(ETL_ERROR(etl::bit_stream_overflow));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Returns the number of bytes used in the stream.
|
||||
//***************************************************************************
|
||||
size_t size_bytes() const
|
||||
{
|
||||
//size_t s = char_index;
|
||||
|
||||
//// Current byte is used?
|
||||
//if (bits_available_in_char != CHAR_BIT)
|
||||
//{
|
||||
// ++s;
|
||||
//}
|
||||
|
||||
//return s;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Returns the number of bits used in the stream.
|
||||
//***************************************************************************
|
||||
size_t size_bits() const
|
||||
{
|
||||
return (length_chars * CHAR_BIT) - bits_available;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Returns start of the stream.
|
||||
//***************************************************************************
|
||||
const_iterator begin() const
|
||||
{
|
||||
return pdata;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Returns end of the stream.
|
||||
//***************************************************************************
|
||||
const_iterator end() const
|
||||
{
|
||||
return pdata + size_bytes();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//***************************************************************************
|
||||
/// Get a data chunk from the stream
|
||||
//***************************************************************************
|
||||
unsigned char get_chunk(unsigned char nbits)
|
||||
{
|
||||
unsigned char value = pdata[char_index];
|
||||
|
||||
value >>= (bits_available_in_char - nbits);
|
||||
|
||||
unsigned char mask;
|
||||
|
||||
if (nbits == CHAR_BIT)
|
||||
{
|
||||
mask = etl::integral_limits<unsigned char>::max;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = (1U << nbits) - 1;
|
||||
}
|
||||
|
||||
value &= mask;
|
||||
|
||||
step(nbits);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Get a bool from the stream
|
||||
//***************************************************************************
|
||||
bool get_bit()
|
||||
{
|
||||
bool result = (pdata[char_index] & (1U << (bits_available_in_char - 1U))) != 0U;
|
||||
|
||||
step(1U);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Helper function for floating point types
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
void from_bytes(const unsigned char* data, T& value)
|
||||
{
|
||||
etl::uninitialized_buffer_of<T, 1U> temp;
|
||||
|
||||
// Network to host.
|
||||
if (etl::endianness::value() == etl::endian::little)
|
||||
{
|
||||
etl::reverse_copy(data, data + sizeof(T), temp.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
etl::copy(data, data + sizeof(T), temp.raw);
|
||||
}
|
||||
|
||||
value = *reinterpret_cast<T*>(temp.raw);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Step the specified number of bits along the stream.
|
||||
/// The nbits will never be larger than 'bits_available_in_char'.
|
||||
//***************************************************************************
|
||||
void step(unsigned char nbits)
|
||||
{
|
||||
bits_available_in_char -= nbits;
|
||||
|
||||
if (bits_available_in_char == 0)
|
||||
{
|
||||
++char_index;
|
||||
bits_available_in_char = 8;
|
||||
}
|
||||
|
||||
bits_available -= nbits;
|
||||
}
|
||||
|
||||
char* pdata; ///< The start of the bitstream buffer.
|
||||
size_t length_chars; ///< The length, in char, of the bitstream buffer.
|
||||
unsigned char bits_available_in_char; ///< The number of available bits in the current char.
|
||||
size_t char_index; ///< The index of the char in the bitstream buffer.
|
||||
size_t bits_available; ///< The number of bits still available in the bitstream buffer.
|
||||
};
|
||||
}
|
||||
|
||||
#include "private/minmax_pop.h"
|
||||
|
||||
@ -95,5 +95,7 @@ SOFTWARE.
|
||||
#define ETL_MEM_CAST_FILE_ID "62"
|
||||
#define ETL_SINGLETON_FILE_ID "63"
|
||||
#define ETL_SUCCESSOR_FILE_ID "64"
|
||||
#define ETL_BIT_STREAM_FILE_ID "65"
|
||||
#define ETL_BYTE_STREAM_FILE_ID "66"
|
||||
|
||||
#endif
|
||||
|
||||
@ -116,10 +116,8 @@ namespace
|
||||
//*************************************************************************
|
||||
TEST(test_atomic_bool_load)
|
||||
{
|
||||
bool i;
|
||||
|
||||
std::atomic<bool> compare(&i);
|
||||
etl::atomic<bool> test(&i);
|
||||
std::atomic<bool> compare(true);
|
||||
etl::atomic<bool> test(true);
|
||||
|
||||
CHECK_EQUAL((bool)compare.load(), (bool)test.load());
|
||||
}
|
||||
|
||||
804
test/test_bit_stream_reader.cpp
Normal file
804
test/test_bit_stream_reader.cpp
Normal file
@ -0,0 +1,804 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2018 jwellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include "etl/bit_stream.h"
|
||||
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
|
||||
namespace
|
||||
{
|
||||
//***********************************
|
||||
struct Object
|
||||
{
|
||||
int16_t i;
|
||||
double d;
|
||||
uint8_t c;
|
||||
};
|
||||
|
||||
bool operator ==(const Object& lhs, const Object& rhs)
|
||||
{
|
||||
return (lhs.i == rhs.i) &&
|
||||
(lhs.d == rhs.d) &&
|
||||
(lhs.c == rhs.c);
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, const Object& object)
|
||||
{
|
||||
os << object.i << "," << object.d << "," << (int)object.c;
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
namespace etl
|
||||
{
|
||||
//***********************************
|
||||
bool read(etl::bit_stream_reader& stream, Object& object)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
//if (!stream.object.i, 14))
|
||||
//{
|
||||
// success = false;
|
||||
//}
|
||||
|
||||
//if (!stream.get(object.d))
|
||||
//{
|
||||
// success = false;
|
||||
//}
|
||||
|
||||
//if (!stream.get(object.c))
|
||||
//{
|
||||
// success = false;
|
||||
//}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_bit_stream_reader)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_read_bool)
|
||||
{
|
||||
char storage = 0x5AU;
|
||||
|
||||
etl::bit_stream_reader bit_stream(&storage, 1);
|
||||
|
||||
etl::optional<bool> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(false, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(true, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(false, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(true, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(true, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(false, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(true, result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<bool>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(false, result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<bool>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int8_t)
|
||||
{
|
||||
std::array storage = { char(0x01), char(0x5A), char(0xA5), char(0xFF) };
|
||||
std::array expected = { int8_t(0x01), int8_t(0x5A), int8_t(0xA5), int8_t(0xFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int8_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[0]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[1]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[2]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[3]), int(result.value()));
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int8_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int8_t_5bits)
|
||||
{
|
||||
std::array storage = { char(0x0E), char(0x8B), char(0xF0) };
|
||||
std::array expected = { int8_t(0x01), int8_t(0xFA), int8_t(0x05), int8_t(0xFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int8_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[0]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[1]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[2]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[3]), int(result.value()));
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int8_t>(5U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint8_t)
|
||||
{
|
||||
std::array storage = { char(0x01), char(0x5A), char(0xA5), char(0xFF) };
|
||||
std::array expected = { uint8_t(0x01), uint8_t(0x5A), uint8_t(0xA5), uint8_t(0xFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint8_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[0]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[1]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[2]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[3]), int(result.value()));
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint8_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint8_t_5bits)
|
||||
{
|
||||
std::array storage = { char(0x0E), char(0x8B), char(0xF0) };
|
||||
std::array expected = { uint8_t(0x01), uint8_t(0x1A), uint8_t(0x05), uint8_t(0x1F) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint8_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[0]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[1]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[2]), int(result.value()));
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint8_t>(5U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(int(expected[3]), int(result.value()));
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint8_t>(5U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int16_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x01), char(0xA5), char(0x5A), char(0x5A), char(0xA5), char(0xFF), char(0xFF) };
|
||||
std::array expected = { int16_t(0x0001), int16_t(0xA55A), int16_t(0x5AA5), int16_t(0xFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int16_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int16_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int16_t_10bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x55), char(0xAA), char(0x97), char(0xFF) };
|
||||
std::array expected = { int16_t(0x0001), int16_t(0x015A), int16_t(0xFEA5), int16_t(0xFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int16_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int16_t>(10U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint16_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x01), char(0xA5), char(0x5A), char(0x5A), char(0xA5), char(0xFF), char(0xFF) };
|
||||
std::array expected = { uint16_t(0x0001), uint16_t(0xA55A), uint16_t(0x5AA5), uint16_t(0xFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint16_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint16_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint16_t_10bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x55), char(0xAA), char(0x97), char(0xFF) };
|
||||
std::array expected = { uint16_t(0x0001), uint16_t(0x015A), uint16_t(0x02A5), uint16_t(0x03FF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint16_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint16_t>(10U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint16_t>(10U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int32_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x01),
|
||||
char(0xA5), char(0x5A), char(0xA5), char(0x5A),
|
||||
char(0x5A), char(0xA5), char(0x5A), char(0xA5),
|
||||
char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
|
||||
std::array expected = { int32_t(0x00000001), int32_t(0xA55AA55A), int32_t(0x5AA55AA5), int32_t(0xFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int32_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int32_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int32_t_22bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x05), char(0xAA),
|
||||
char(0x55), char(0xA9), char(0x56), char(0xA9),
|
||||
char(0x7F), char(0xFF), char(0xFF) };
|
||||
std::array expected = { int32_t(0x00000001), int32_t(0x001AA55A), int32_t(0xFFE55AA5), int32_t(0xFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int32_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int32_t>(22U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint32_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x01),
|
||||
char(0xA5), char(0x5A), char(0xA5), char(0x5A),
|
||||
char(0x5A), char(0xA5), char(0x5A), char(0xA5),
|
||||
char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
|
||||
std::array expected = { uint32_t(0x00000001), uint32_t(0xA55AA55A), uint32_t(0x5AA55AA5), uint32_t(0xFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint32_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint32_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint32_t_22bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x05), char(0xAA),
|
||||
char(0x55), char(0xA9), char(0x56), char(0xA9),
|
||||
char(0x7F), char(0xFF), char(0xFF) };
|
||||
std::array expected = { uint32_t(0x00000001), uint32_t(0x001AA55A), uint32_t(0x00255AA5), uint32_t(0x003FFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint32_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint32_t>(22U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint32_t>(22U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int64_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x01),
|
||||
char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A),
|
||||
char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5),
|
||||
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
|
||||
std::array expected = { int64_t(0x0000000000000001), int64_t(0xA55AA55AA55AA55A), int64_t(0x5AA55AA55AA55AA5), int64_t(0xFFFFFFFFFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int64_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int64_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_int64_t_47bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x02), char(0x95), char(0x6A),
|
||||
char(0x95), char(0x6A), char(0x95), char(0x6A), char(0xD5), char(0x2A), char(0xD5), char(0x2A),
|
||||
char(0xD5), char(0x2F), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xF0) };
|
||||
std::array expected = { int64_t(0x0000000000000001), int64_t(0x0000255AA55AA55A), int64_t(0xFFFFDAA55AA55AA5), int64_t(0xFFFFFFFFFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<int64_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<int64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<int64_t>(47U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint64_t)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x01),
|
||||
char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A),
|
||||
char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0xA5),
|
||||
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
|
||||
std::array expected = { uint64_t(0x0000000000000001), uint64_t(0xA55AA55AA55AA55A), uint64_t(0x5AA55AA55AA55AA5), uint64_t(0xFFFFFFFFFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint64_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>();
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint64_t>(), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_uint64_t_47bits)
|
||||
{
|
||||
std::array storage = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x02), char(0x95), char(0x6A),
|
||||
char(0x95), char(0x6A), char(0x95), char(0x6A), char(0xD5), char(0x2A), char(0xD5), char(0x2A),
|
||||
char(0xD5), char(0x2F), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xF0) };
|
||||
std::array expected = { uint64_t(0x0000000000000001), uint64_t(0x0000255AA55AA55A), uint64_t(0x00005AA55AA55AA5), uint64_t(0x00007FFFFFFFFFFF) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
etl::optional<uint64_t> result;
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[0], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[1], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[2], result.value());
|
||||
|
||||
result.reset();
|
||||
result = bit_stream.read<uint64_t>(47U);
|
||||
CHECK(result.has_value());
|
||||
CHECK_EQUAL(expected[3], result.value());
|
||||
|
||||
// One too many.
|
||||
CHECK_THROW(bit_stream.read<uint64_t>(47U), etl::bit_stream_overflow);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_multiple_full_size)
|
||||
{
|
||||
int8_t c1 = 90; // 0x5A
|
||||
uint16_t s1 = 4660; // 0x1234
|
||||
int32_t i1 = 2309737967L; // 0x89ABCDEF
|
||||
int32_t i2 = 4275878552L; // 0xFEDCBA98
|
||||
uint16_t s2 = 22136; // 0x5678
|
||||
int8_t c2 = -91; // 0xA5
|
||||
|
||||
std::array storage = { char(0x5A),
|
||||
char(0x12), char(0x34),
|
||||
char(0x89), char(0xAB), char(0xCD), char(0xEF),
|
||||
char(0xFE), char(0xDC), char(0xBA), char(0x98),
|
||||
char(0x56), char(0x78),
|
||||
char(0xA5) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
auto result_c1 = bit_stream.read<int8_t>();
|
||||
CHECK(result_c1.has_value());
|
||||
CHECK_EQUAL(int8_t(0x5A), result_c1.value());
|
||||
|
||||
auto result_s1 = bit_stream.read<uint16_t>();
|
||||
CHECK(result_s1.has_value());
|
||||
CHECK_EQUAL(uint16_t(0x1234), result_s1.value());
|
||||
|
||||
auto result_i1 = bit_stream.read<int32_t>();
|
||||
CHECK(result_i1.has_value());
|
||||
CHECK_EQUAL(int32_t(0x89ABCDEF), result_i1.value());
|
||||
|
||||
auto result_i2 = bit_stream.read<int32_t>();
|
||||
CHECK(result_i2.has_value());
|
||||
CHECK_EQUAL(int32_t(0xFEDCBA98), result_i2.value());
|
||||
|
||||
auto result_s2 = bit_stream.read<uint16_t>();
|
||||
CHECK(result_s2.has_value());
|
||||
CHECK_EQUAL(uint16_t(0x5678), result_s2.value());
|
||||
|
||||
auto result_c2 = bit_stream.read<int8_t>();
|
||||
CHECK(result_c2.has_value());
|
||||
CHECK_EQUAL(int8_t(0xA5), result_c2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_multiple_variable_size)
|
||||
{
|
||||
int8_t c1 = 90; // 0x5A 6 bits
|
||||
uint16_t s1 = 4660; // 0x1234 13 bits
|
||||
int32_t i1 = 2309737967L; // 0x89ABCDEF 23 bits
|
||||
int32_t i2 = 4275878552L; // 0xFEDCBA98 25 bits
|
||||
uint16_t s2 = 22136; // 0x5678 11 bits
|
||||
int8_t c2 = -91; // 0xA5 7 bits
|
||||
|
||||
std::array storage = { char(0x6A), char(0x46), char(0x8A), char(0xF3),
|
||||
char(0x7B), char(0xDB), char(0x97), char(0x53),
|
||||
char(0x19), char(0xE1), char(0x28) };
|
||||
|
||||
etl::bit_stream_reader bit_stream(storage.data(), storage.size());
|
||||
|
||||
auto result_c1 = bit_stream.read<int8_t>(6U);
|
||||
CHECK(result_c1.has_value());
|
||||
CHECK_EQUAL(int8_t(0x1A), result_c1.value());
|
||||
|
||||
auto result_s1 = bit_stream.read<uint16_t>(13U);
|
||||
CHECK(result_s1.has_value());
|
||||
CHECK_EQUAL(uint16_t(0x1234), result_s1.value());
|
||||
|
||||
auto result_i1 = bit_stream.read<int32_t>(23U);
|
||||
CHECK(result_i1.has_value());
|
||||
CHECK_EQUAL(int32_t(0x002BCDEF), result_i1.value());
|
||||
|
||||
auto result_i2 = bit_stream.read<int32_t>(25U);
|
||||
CHECK(result_i2.has_value());
|
||||
CHECK_EQUAL(int32_t(0x00DCBA98), result_i2.value());
|
||||
|
||||
auto result_s2 = bit_stream.read<uint16_t>(11U);
|
||||
CHECK(result_s2.has_value());
|
||||
CHECK_EQUAL(uint16_t(0x0678), result_s2.value());
|
||||
|
||||
auto result_c2 = bit_stream.read<int8_t>(7U);
|
||||
CHECK(result_c2.has_value());
|
||||
CHECK_EQUAL(int8_t(0x25), result_c2.value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_object)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_read_multiple_floating_point)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -10911,6 +10911,7 @@
|
||||
<ClCompile Include="..\test_alignment.cpp" />
|
||||
<ClCompile Include="..\test_atomic.cpp" />
|
||||
<ClCompile Include="..\test_bit.cpp" />
|
||||
<ClCompile Include="..\test_bit_stream_reader.cpp" />
|
||||
<ClCompile Include="..\test_bit_stream_writer.cpp" />
|
||||
<ClCompile Include="..\test_bresenham_line.cpp" />
|
||||
<ClCompile Include="..\test_buffer_descriptors.cpp" />
|
||||
|
||||
@ -3251,6 +3251,9 @@
|
||||
<ClCompile Include="..\test_atomic.cpp">
|
||||
<Filter>Tests\Atomic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_bit_stream_reader.cpp">
|
||||
<Filter>Tests\Binary</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\library.properties">
|
||||
@ -3413,4 +3416,4 @@
|
||||
<Filter>Resource Files</Filter>
|
||||
</Natvis>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user