Initial bit_stream_writer code

This commit is contained in:
John Wellbelove 2022-05-29 14:04:26 +01:00
parent 2695cd8fb8
commit cace71c3f7
5 changed files with 1363 additions and 62 deletions

View File

@ -38,6 +38,9 @@ SOFTWARE.
#include "algorithm.h"
#include "iterator.h"
#include "memory.h"
#include "delegate.h"
#include "span.h"
#include "endianness.h"
#include "private/minmax_push.h"
@ -58,7 +61,7 @@ namespace etl
//***************************************************************************
bit_stream()
: pdata(ETL_NULLPTR),
length(0U)
length_chars(0U)
{
restart();
}
@ -68,7 +71,7 @@ namespace etl
//***************************************************************************
bit_stream(void* begin_, void* end_)
: pdata(reinterpret_cast<unsigned char*>(begin_)),
length(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
length_chars(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
{
restart();
}
@ -78,7 +81,7 @@ namespace etl
//***************************************************************************
bit_stream(void* begin_, size_t length_)
: pdata(reinterpret_cast<unsigned char*>(begin_)),
length(length_)
length_chars(length_)
{
restart();
}
@ -89,7 +92,7 @@ namespace etl
void set_stream(void* begin_, size_t length_)
{
pdata = reinterpret_cast<unsigned char*>(begin_);
length = length_;
length_chars = length_;
restart();
}
@ -106,9 +109,9 @@ namespace etl
//***************************************************************************
void restart()
{
bits_in_byte = 8;
byte_index = 0U;
bits_remaining = CHAR_BIT * length;
bits_available_in_char = 8;
char_index = 0U;
bits_remaining = CHAR_BIT * length_chars;
}
//***************************************************************************
@ -120,7 +123,7 @@ namespace etl
}
//***************************************************************************
/// Puts a boolean to the stream
/// Writes a boolean to the stream
//***************************************************************************
bool put(bool value)
{
@ -144,26 +147,26 @@ namespace etl
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type
put(T value, uint_least8_t width = CHAR_BIT * sizeof(T))
put(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
return put_integral(static_cast<uint32_t>(value), width);
return put_integral(static_cast<uint32_t>(value), nbits);
}
#if ETL_USING_64BIT_TYPES
//***************************************************************************
/// For 64bit integral types
//***************************************************************************
bool put(int64_t value, uint_least8_t width = CHAR_BIT * sizeof(int64_t))
bool put(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
{
return put_integral(uint64_t(value), width);
return put_integral(uint64_t(value), nbits);
}
//***************************************************************************
/// For 64bit integral types
//***************************************************************************
bool put(uint64_t value, uint_least8_t width = CHAR_BIT * sizeof(uint64_t))
bool put(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
{
return put_integral(value, width);
return put_integral(value, nbits);
}
#endif
@ -215,28 +218,28 @@ namespace etl
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type
get(T& value, uint_least8_t width = CHAR_BIT * sizeof(T))
get(T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
bool success = false;
uint_least8_t bits = width;
uint_least8_t bits = nbits;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_remaining >= width)
if (bits_remaining >= nbits)
{
value = 0;
// Get the bits from the stream.
while (width != 0)
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(width, bits_in_byte));
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);
width -= mask_width;
value |= static_cast<T>(chunk << width);
nbits -= mask_width;
value |= static_cast<T>(chunk << nbits);
}
success = true;
@ -264,10 +267,10 @@ namespace etl
if (pdata != ETL_NULLPTR)
{
uint_least8_t width = CHAR_BIT * sizeof(T);
uint_least8_t nbits = CHAR_BIT * sizeof(T);
// Do we have enough bits?
if (bits_remaining >= width)
if (bits_remaining >= nbits)
{
// Temporary storage.
etl::uninitialized_buffer_of<T, 1U> data;
@ -291,10 +294,10 @@ namespace etl
//***************************************************************************
size_t size() const
{
size_t s = byte_index;
size_t s = char_index;
// Current byte is used?
if (bits_in_byte != CHAR_BIT)
if (bits_available_in_char != CHAR_BIT)
{
++s;
}
@ -307,7 +310,7 @@ namespace etl
//***************************************************************************
size_t bits() const
{
return (length * CHAR_BIT) - bits_remaining;
return (length_chars * CHAR_BIT) - bits_remaining;
}
//***************************************************************************
@ -331,25 +334,25 @@ namespace etl
//***************************************************************************
/// For unsigned integral types
//***************************************************************************
bool put_integral(uint32_t value, uint_least8_t width)
bool put_integral(uint32_t value, uint_least8_t nbits)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_remaining >= width)
if (bits_remaining >= nbits)
{
// Send the bits to the stream.
while (width != 0)
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(width, bits_in_byte));
width -= mask_width;
uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << width;
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << nbits;
// Move chunk to lowest char bits.
// Chunks are never larger than one char.
uint32_t chunk = ((value & mask) >> width) << (bits_in_byte - mask_width);
uint32_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
put_chunk(static_cast<unsigned char>(chunk), mask_width);
}
@ -365,25 +368,25 @@ namespace etl
//***************************************************************************
/// For unsigned integral types. 64bit
//***************************************************************************
bool put_integral(uint64_t value, uint_least8_t width)
bool put_integral(uint64_t value, uint_least8_t nbits)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_remaining >= width)
if (bits_remaining >= nbits)
{
// Send the bits to the stream.
while (width != 0)
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(width, bits_in_byte));
width -= mask_width;
uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << width;
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << nbits;
// Move chunk to lowest char bits.
// Chunks are never larger than one char.
uint64_t chunk = ((value & mask) >> width) << (bits_in_byte - mask_width);
uint64_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
put_chunk(static_cast<unsigned char>(chunk), mask_width);
}
@ -399,41 +402,41 @@ namespace etl
//***************************************************************************
/// Put a data chunk to the stream
//***************************************************************************
void put_chunk(unsigned char chunk, unsigned char width)
void put_chunk(unsigned char chunk, unsigned char nbits)
{
// Clear if new byte.
if (bits_in_byte == 8)
if (bits_available_in_char == 8U)
{
pdata[byte_index] = 0U;
pdata[char_index] = 0U;
}
pdata[byte_index] |= chunk;
step(width);
pdata[char_index] |= chunk;
step(nbits);
}
//***************************************************************************
/// Get a data chunk from the stream
//***************************************************************************
unsigned char get_chunk(unsigned char width)
unsigned char get_chunk(unsigned char nbits)
{
unsigned char value = pdata[byte_index];
unsigned char value = pdata[char_index];
value >>= (bits_in_byte - width);
value >>= (bits_available_in_char - nbits);
unsigned char mask;
if (width == CHAR_BIT)
if (nbits == CHAR_BIT)
{
mask = etl::integral_limits<unsigned char>::max;
}
else
{
mask = (1U << width) - 1;
mask = (1U << nbits) - 1;
}
value &= mask;
step(width);
step(nbits);
return value;
}
@ -443,7 +446,7 @@ namespace etl
//***************************************************************************
bool get_bit()
{
bool result = (pdata[byte_index] & (1U << (bits_in_byte - 1U))) != 0U;
bool result = (pdata[char_index] & (1U << (bits_available_in_char - 1U))) != 0U;
step(1U);
@ -492,27 +495,547 @@ namespace etl
//***************************************************************************
/// Step the specified number of bits along the stream.
/// The width will never be larger than 'bits_in_byte'.
/// The nbits will never be larger than 'bits_available_in_char'.
//***************************************************************************
void step(unsigned char width)
void step(unsigned char nbits)
{
bits_in_byte -= width;
bits_available_in_char -= nbits;
if (bits_in_byte == 0)
if (bits_available_in_char == 0)
{
++byte_index;
bits_in_byte = 8;
++char_index;
bits_available_in_char = 8;
}
bits_remaining -= width;
bits_remaining -= nbits;
}
unsigned char *pdata; ///< The start of the bitstream buffer.
size_t length; ///< The length, in unsigned char, of the bitstream buffer.
unsigned char bits_in_byte; ///< The number of available bits in the current char.
size_t byte_index; ///< The index of the char in 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.
};
//***************************************************************************
/// Writes bits streams.
//***************************************************************************
class bit_stream_writer
{
public:
typedef const unsigned char* const_iterator;
typedef char callback_parameter_type;
typedef etl::delegate<void(char)> callback_type;
//***************************************************************************
/// Construct from span.
//***************************************************************************
bit_stream_writer(etl::span<char> span_, callback_type callback_ = callback_type())
: pdata(reinterpret_cast<unsigned char*>(span_.begin()))
, length_chars(span_.size_bytes())
, callback(callback_)
{
restart();
}
//***************************************************************************
/// Construct from span.
//***************************************************************************
bit_stream_writer(etl::span<unsigned char> span_, callback_type callback_ = callback_type())
: pdata(span_.begin())
, length_chars(span_.size_bytes())
, callback(callback_)
{
restart();
}
//***************************************************************************
/// Construct from range.
//***************************************************************************
bit_stream_writer(void* begin_, void* end_, callback_type callback_ = callback_type())
: pdata(reinterpret_cast<unsigned char*>(begin_))
, length_chars(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_)))
, callback(callback_)
{
restart();
}
//***************************************************************************
/// 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_))
, length_chars(length_chars_)
, callback(callback_)
{
restart();
}
//***************************************************************************
/// Sets the indexes back to the beginning of the stream.
//***************************************************************************
void restart()
{
bits_available_in_char = 8;
char_index = 0U;
bits_remaining = CHAR_BIT * length_chars;
}
//***************************************************************************
/// Returns the maximum capacity in bits.
//***************************************************************************
size_t capacity_bytes() const
{
return length_chars;
}
//***************************************************************************
size_t capacity_bits() const
{
return length_chars * CHAR_BIT;
}
//***************************************************************************
/// Returns <b>true</b> if the bitsteam indexes have been reset.
//***************************************************************************
bool empty() const
{
return (bits_remaining == length_chars);
}
//***************************************************************************
/// Returns <b>true</b> if the bitsteam indexes have reached the end.
//***************************************************************************
bool full() const
{
return (bits_remaining == 0U);
}
//***************************************************************************
/// Writes a boolean to the stream
//***************************************************************************
void write_unchecked(bool value)
{
unsigned char chunk = value ? 1 : 0;
write_integral(uint32_t(chunk), 1);
}
//***************************************************************************
/// Writes a boolean to the stream
//***************************************************************************
bool write(bool value)
{
bool success = false;
if (available<1U>() > 0U)
{
write_unchecked(value);
success = true;
}
return success;
}
//***************************************************************************
/// For integral types
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, void>::type
write_unchecked(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
write_integral(static_cast<uint32_t>(value), nbits);
}
//***************************************************************************
/// For integral types
//***************************************************************************
template <typename T>
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;
if (available(nbits) > 0U)
{
write_unchecked(value, nbits);
success = true;
}
return success;
}
#if ETL_USING_64BIT_TYPES
//***************************************************************************
/// For signed 64bit integral types
//***************************************************************************
void write_unchecked(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
{
write_integral(uint64_t(value), nbits);
}
//***************************************************************************
/// For signed 64bit integral types
//***************************************************************************
bool write(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
{
bool success = false;
if (available(nbits) > 0U)
{
write_unchecked(value, nbits);
success = true;
}
return success;
}
//***************************************************************************
/// For unsigned 64bit integral types
//***************************************************************************
void write_unchecked(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
{
write_integral(uint64_t(value), nbits);
}
//***************************************************************************
/// For unsigned 64bit integral types
//***************************************************************************
bool write(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
{
bool success = false;
if (available(nbits) > 0U)
{
write_unchecked(value, nbits);
success = true;
}
return success;
}
#endif
//***************************************************************************
/// For floating point types
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_floating_point<T>::value, void>::type
write_unchecked(T value)
{
unsigned char data[sizeof(T)];
to_bytes(value, data);
for (size_t i = 0UL; i < sizeof(T); ++i)
{
write_integral(uint32_t(data[i]), CHAR_BIT);
}
}
//***************************************************************************
/// For floating point types
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type
write(T value)
{
bool success = false;
if (available<T>())
{
write_unchecked(value);
success = true;
}
return success;
}
//***************************************************************************
/// Skip n bits, up to the maximum space available.
/// Returns <b>true</b> if the skip was possible.
/// Returns <b>false</b> if the full skip size was not possible.
//***************************************************************************
bool skip(size_t nbits)
{
bool success = true;
if (nbits > available_bits())
{
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(unsigned char(nbits));
}
return success;
}
//***************************************************************************
/// Returns the number of bytes used in the stream.
//***************************************************************************
size_t size_bytes() const
{
size_t s = char_index;
// Is the current byte 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 capacity_bits() - available_bits();
}
//***************************************************************************
/// The number of 'bit nbits' available in the stream.
/// Compile time.
//***************************************************************************
template <size_t Nbits>
size_t available() const
{
return bits_remaining / Nbits;
}
//***************************************************************************
/// The number of T available in the stream.
/// Compile time.
//***************************************************************************
template <typename T>
size_t available() const
{
return available<CHAR_BIT * sizeof(T)>();
}
//***************************************************************************
/// The number of 'bit width' available in the stream.
/// Run time.
//***************************************************************************
size_t available(size_t nbits) const
{
return bits_remaining / nbits;
}
//***************************************************************************
/// The number of bits left in the stream.
//***************************************************************************
size_t available_bits() const
{
return bits_remaining;
}
//***************************************************************************
/// Returns start of the stream.
//***************************************************************************
const_iterator begin() const
{
return pdata;
}
//***************************************************************************
/// Returns start of the stream.
//***************************************************************************
const_iterator cbegin() const
{
return pdata;
}
//***************************************************************************
/// Returns end of the stream.
//***************************************************************************
const_iterator end() const
{
return pdata + size_bytes();
}
//***************************************************************************
/// Returns end of the stream.
//***************************************************************************
const_iterator cend() const
{
return pdata + size_bytes();
}
//***************************************************************************
/// Returns a span of the used portion of the stream.
//***************************************************************************
etl::span<char> used_data() const
{
return etl::span<char>(reinterpret_cast<char*>(pdata), reinterpret_cast<char*>(pdata) + size_bytes());
}
//***************************************************************************
/// Returns a span of whole the stream.
//***************************************************************************
etl::span<char> data() const
{
return etl::span<char>(reinterpret_cast<char*>(pdata), reinterpret_cast<char*>(pdata) + length_chars);
}
//***************************************************************************
/// Finalizes the stream and calls the callback, if set.
//***************************************************************************
void finalize()
{
if (bits_remaining != 0U)
{
callback.call_if(pdata[char_index]);
}
}
//***************************************************************************
/// Sets the function to call afer every write.
//***************************************************************************
void set_callback(callback_type callback_)
{
callback = callback_;
}
//***************************************************************************
/// Gets the function to call afer every write.
//***************************************************************************
callback_type get_callback() const
{
return callback;
}
private:
//***************************************************************************
/// For unsigned integral types
//***************************************************************************
void write_integral(uint32_t value, uint_least8_t nbits)
{
// Send the bits to the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << nbits;
// Move chunk to lowest char bits.
// 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);
}
}
#if ETL_USING_64BIT_TYPES
//***************************************************************************
/// For unsigned integral types. 64bit
//***************************************************************************
void write_integral(uint64_t value, uint_least8_t nbits)
{
// Send the bits to the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << nbits;
// Move chunk to lowest char bits.
// 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);
}
}
#endif
//***************************************************************************
/// Write a data chunk to the stream
//***************************************************************************
void write_chunk(unsigned char chunk, unsigned char nbits)
{
// Clear if new byte.
if (bits_available_in_char == CHAR_BIT)
{
pdata[char_index] = 0U;
}
pdata[char_index] |= chunk;
step(nbits);
}
//***************************************************************************
/// Convert to bytes.
//***************************************************************************
template <typename T>
void to_bytes(T value, unsigned char* data)
{
unsigned char* pf = reinterpret_cast<unsigned char*>(&value);
// Host to network.
if (etl::endianness::value() == etl::endian::little)
{
etl::reverse_copy(pf, pf + sizeof(T), data);
}
else
{
etl::copy(pf, pf + sizeof(T), data);
}
}
//***************************************************************************
/// Step the specified number of bits along the stream.
/// The width 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 = CHAR_BIT;
}
bits_remaining -= 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.
};
//***************************************************************************
/// Default implementation of the write function.
/// For integral and floating point types only.
/// Overload this to support custom types.
//***************************************************************************
template <typename T>
void write_unchecked(etl::bit_stream_writer& stream, const T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
stream.write_unchecked(value, nbits);
}
//***************************************************************************
/// Implementation of the write function.
//***************************************************************************
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);
}
}
#include "private/minmax_pop.h"

View File

@ -72,6 +72,18 @@ namespace etl
{
}
//***************************************************************************
/// Construct from span.
//***************************************************************************
byte_stream_writer(etl::span<unsigned char> span_, etl::endian buffer_endianness_, callback_type callback_ = callback_type())
: pdata(reinterpret_cast<char*>(span_.begin()))
, pcurrent(reinterpret_cast<char*>(span_.begin()))
, length(span_.size_bytes())
, buffer_endianness(buffer_endianness_)
, callback(callback_)
{
}
//***************************************************************************
/// Construct from range.
//***************************************************************************
@ -370,6 +382,22 @@ namespace etl
callback = callback_;
}
//***************************************************************************
/// Gets the function to call afer every write.
//***************************************************************************
callback_type get_callback() const
{
return callback;
}
//***************************************************************************
/// Gets the endianness of the stream.
//***************************************************************************
etl::endian get_endianness() const
{
return buffer_endianness;
}
private:
//***************************************************************************

View File

@ -0,0 +1,746 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2022 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 write(etl::bit_stream_writer& stream, const Object& object)
{
bool success = true;
if (!stream.write(object.i, 14))
{
success = false;
}
if (!stream.write(object.d))
{
success = false;
}
if (!stream.write(object.c))
{
success = false;
}
return success;
}
}
namespace
{
SUITE(test_bit_stream)
{
//*************************************************************************
TEST(test_bit_stream_writer_construction)
{
std::array<char, 256> storage;
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK_EQUAL(storage.size(), bit_stream.available(CHAR_BIT));
CHECK_EQUAL(storage.size(), bit_stream.available<CHAR_BIT>());
CHECK_EQUAL(storage.size(), bit_stream.available<unsigned char>());
CHECK_EQUAL(storage.size() * CHAR_BIT, bit_stream.available_bits());
CHECK_EQUAL(0U, bit_stream.size_bits());
CHECK_EQUAL(0U, bit_stream.size_bytes());
CHECK_EQUAL(storage.size(), bit_stream.data().size());
CHECK_EQUAL(0U, bit_stream.used_data().size());
}
//*************************************************************************
TEST(test_write_bool)
{
unsigned char storage = 0;
unsigned char expected_data = 0x5AU;
etl::bit_stream_writer bit_stream(&storage, 1U);
CHECK(bit_stream.write(false));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(true));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(false));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(true));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(true));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(false));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(true));
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK(bit_stream.write(false));
CHECK_EQUAL(1U, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(true));
CHECK_EQUAL(1U, bit_stream.data().size());
CHECK_EQUAL(1U, bit_stream.used_data().size());
CHECK_EQUAL(int(expected_data), int(storage));
}
//*************************************************************************
TEST(test_write_int8_t)
{
std::array<char, 256U> storage;
std::array<char, 256U> expected_data;
std::iota(expected_data.begin(), expected_data.end(), 0);
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
for (size_t i = 0UL; i < 256UL; ++i)
{
CHECK(bit_stream.write(int8_t(i)));
CHECK_EQUAL(i + 1U, bit_stream.used_data().size());
}
// One too many.
CHECK(!bit_stream.write(int8_t(0)));
CHECK_EQUAL(256U, bit_stream.data().size());
CHECK_EQUAL(256U, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_uint8_t)
{
std::array<char, 256> storage;
std::array<char, 256> expected_data;
std::iota(expected_data.begin(), expected_data.end(), 0);
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
for (size_t i = 0UL; i < 256UL; ++i)
{
CHECK(bit_stream.write(uint8_t(i)));
CHECK_EQUAL(i + 1U, bit_stream.used_data().size());
}
// One too many.
CHECK(!bit_stream.write(int8_t(0)));
CHECK_EQUAL(256U, bit_stream.data().size());
CHECK_EQUAL(256U, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_int16_t)
{
// Tests assume big endian.
std::array<char, sizeof(int16_t) * 4> storage;
std::array<char, sizeof(int16_t) * 4> expected_data = { char(0x00), char(0x01),
char(0x5A), char(0xA5),
char(0xA5), char(0x5A),
char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(int16_t(0x0001)));
CHECK_EQUAL(sizeof(int16_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(int16_t(0x5AA5)));
CHECK_EQUAL(sizeof(int16_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(int16_t(0xA55A)));
CHECK_EQUAL(sizeof(int16_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(int16_t(0xFFFF)));
CHECK_EQUAL(sizeof(int16_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(int16_t(0)));
CHECK_EQUAL(sizeof(int16_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(int16_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_uint16_t)
{
// Tests assume big endian.
std::array<char, sizeof(uint16_t) * 4> storage;
std::array<char, sizeof(uint16_t) * 4> expected_data = { char(0x00), char(0x01),
char(0x5A), char(0xA5),
char(0xA5), char(0x5A),
char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(uint16_t(0x0001)));
CHECK_EQUAL(sizeof(uint16_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(uint16_t(0x5AA5)));
CHECK_EQUAL(sizeof(uint16_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(uint16_t(0xA55A)));
CHECK_EQUAL(sizeof(uint16_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(uint16_t(0xFFFF)));
CHECK_EQUAL(sizeof(uint16_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(uint16_t(0)));
CHECK_EQUAL(sizeof(uint16_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(uint16_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_int32_t)
{
// Tests assume big endian.
std::array<char, sizeof(int32_t) * 4> storage;
std::array<char, sizeof(int32_t) * 4> expected_data = { char(0x00), char(0x00), char(0x00), char(0x01),
char(0x5A), char(0xA5), char(0xA5), char(0x5A),
char(0xA5), char(0x5A), char(0x5A), char(0xA5),
char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(int32_t(0x00000001)));
CHECK_EQUAL(sizeof(int32_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(int32_t(0x5AA5A55A)));
CHECK_EQUAL(sizeof(int32_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(int32_t(0xA55A5AA5)));
CHECK_EQUAL(sizeof(int32_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(int32_t(0xFFFFFFFF)));
CHECK_EQUAL(sizeof(int32_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(int32_t(0)));
CHECK_EQUAL(sizeof(int32_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(int32_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_uint32_t)
{
// Tests assume big endian.
std::array<char, sizeof(uint32_t) * 4> storage;
std::array<char, sizeof(uint32_t) * 4> expected_data = { char(0x00), char(0x00), char(0x00), char(0x01),
char(0x5A), char(0xA5), char(0xA5), char(0x5A),
char(0xA5), char(0x5A), char(0x5A), char(0xA5),
char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(uint32_t(0x00000001)));
CHECK_EQUAL(sizeof(uint32_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(uint32_t(0x5AA5A55A)));
CHECK_EQUAL(sizeof(uint32_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(uint32_t(0xA55A5AA5)));
CHECK_EQUAL(sizeof(uint32_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(uint32_t(0xFFFFFFFF)));
CHECK_EQUAL(sizeof(uint32_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(uint32_t(0)));
CHECK_EQUAL(sizeof(uint32_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(uint32_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_int64_t)
{
// Tests assume big endian.
std::array<char, sizeof(int64_t) * 4> storage;
std::array<char, sizeof(int64_t) * 4> expected_data = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x01),
char(0x5A), char(0xA5), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0x5A), char(0xA5),
char(0xA5), char(0x5A), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0xA5), char(0x5A),
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(int64_t(0x0000000000000001LL)));
CHECK_EQUAL(sizeof(int64_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(int64_t(0x5AA5A55AA55A5AA5LL)));
CHECK_EQUAL(sizeof(int64_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(int64_t(0xA55A5AA55AA5A55ALL)));
CHECK_EQUAL(sizeof(int64_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(int64_t(0xFFFFFFFFFFFFFFFFLL)));
CHECK_EQUAL(sizeof(int64_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(int64_t(0)));
CHECK_EQUAL(sizeof(int64_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(int64_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_uint64_t)
{
// Tests assume big endian.
std::array<char, sizeof(uint64_t) * 4> storage;
std::array<char, sizeof(uint64_t) * 4> expected_data = { char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x00), char(0x01),
char(0x5A), char(0xA5), char(0xA5), char(0x5A), char(0xA5), char(0x5A), char(0x5A), char(0xA5),
char(0xA5), char(0x5A), char(0x5A), char(0xA5), char(0x5A), char(0xA5), char(0xA5), char(0x5A),
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF) };
CHECK(expected_data.size() == storage.size());
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
CHECK(bit_stream.write(uint64_t(0x0000000000000001LL)));
CHECK_EQUAL(sizeof(uint64_t) * 1, bit_stream.used_data().size());
CHECK(bit_stream.write(uint64_t(0x5AA5A55AA55A5AA5LL)));
CHECK_EQUAL(sizeof(uint64_t) * 2, bit_stream.used_data().size());
CHECK(bit_stream.write(uint64_t(0xA55A5AA55AA5A55ALL)));
CHECK_EQUAL(sizeof(uint64_t) * 3, bit_stream.used_data().size());
CHECK(bit_stream.write(uint64_t(0xFFFFFFFFFFFFFFFFLL)));
CHECK_EQUAL(sizeof(uint64_t) * 4, bit_stream.used_data().size());
// One too many.
CHECK(!bit_stream.write(uint64_t(0)));
CHECK_EQUAL(sizeof(uint64_t) * 4, bit_stream.data().size());
CHECK_EQUAL(sizeof(uint64_t) * 4, bit_stream.used_data().size());
for (size_t i = 0UL; i < storage.size(); ++i)
{
CHECK_EQUAL(int(expected_data[i]), int(storage[i]));
}
}
//*************************************************************************
TEST(test_write_int8_t_5bits)
{
std::array<char, 4 * sizeof(char)> storage;
std::array<int8_t, 4> write_data = { int8_t(0x01), int8_t(0xF5), int8_t(0x05), int8_t(0xFF) }; // 1, -11, 10, -1
std::array<char, 4> expected_data = { char(0x0D), char(0x4B), char(0xF0), char(0x00) }; // 1, -11, 10, -1
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
// Insert into the stream
CHECK(bit_stream.write(write_data[0], 5));
CHECK_EQUAL(1, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[1], 5));
CHECK_EQUAL(2, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[2], 5));
CHECK_EQUAL(2, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[3], 5));
CHECK_EQUAL(3, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
// 4th byte not used.
}
//*************************************************************************
TEST(test_write_int16_t_10bits)
{
std::array<char, 4 * sizeof(int16_t)> storage;
std::array<int16_t, 4> write_data = { int16_t(0x0001), int16_t(0xA55A), int16_t(0x5AA5), int16_t(0xFFFF) };
std::array<char, 4 * sizeof(int16_t)> expected_data = { char(0x00), char(0x55), char(0xAA), char(0x97),
char(0xFF), char(0x00), char(0x00), char(0x00) };
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
// Insert into the stream
CHECK(bit_stream.write(write_data[0], 10));
CHECK_EQUAL(2, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[1], 10));
CHECK_EQUAL(3, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[2], 10));
CHECK_EQUAL(4, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[3], 10));
CHECK_EQUAL(5, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
// 6th to 8th bytes not used.
}
//*************************************************************************
TEST(test_write_uint32_t_22bits)
{
std::array<char, 4 * sizeof(uint32_t)> storage;
std::array<uint32_t, 4> write_data = { uint32_t(0x00000001UL), uint32_t(0xA55AA55AUL), uint32_t(0x5AA55AA5UL), uint32_t(0xFFFFFFFFUL) };
std::array<char, 4 * sizeof(uint32_t)> expected_data = { char(0x00), char(0x00), char(0x05), char(0xAA),
char(0x55), char(0xA9), char(0x56), char(0xA9),
char(0x7F), char(0xFF), char(0xFF), char(0x00),
char(0x00), char(0x00), char(0x00), char(0x00) };
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
// Insert into the stream
CHECK(bit_stream.write(write_data[0], 22));
CHECK_EQUAL(3, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[1], 22));
CHECK_EQUAL(6, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[2], 22));
CHECK_EQUAL(9, bit_stream.used_data().size());
CHECK(bit_stream.write(write_data[3], 22));
CHECK_EQUAL(11, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
CHECK_EQUAL((int)expected_data[5], (int)storage[5]);
CHECK_EQUAL((int)expected_data[6], (int)storage[6]);
CHECK_EQUAL((int)expected_data[7], (int)storage[7]);
CHECK_EQUAL((int)expected_data[8], (int)storage[8]);
CHECK_EQUAL((int)expected_data[9], (int)storage[9]);
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
// 12th to 16th to bytes not used.
}
//*************************************************************************
TEST(test_write_int64_t_47bits)
{
std::array<char, 4 * sizeof(int64_t)> storage;
std::array<int64_t, 4> write_data = { int64_t(0x0000000000000001LL), int64_t(0xA55AA55AA55AA55ALL), int64_t(0x5AA55AA55AA55AA5LL), int64_t(0xFFFFFFFFFFFFFFFFLL) };
std::array<char, 4 * sizeof(int64_t)> expected_data = { 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) };
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
// Insert into the stream
bit_stream.write(write_data[0], 47);
CHECK_EQUAL(6, bit_stream.used_data().size());
bit_stream.write(write_data[1], 47);
CHECK_EQUAL(12, bit_stream.used_data().size());
bit_stream.write(write_data[2], 47);
CHECK_EQUAL(18, bit_stream.used_data().size());
bit_stream.write(write_data[3], 47);
CHECK_EQUAL(24, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
CHECK_EQUAL((int)expected_data[5], (int)storage[5]);
CHECK_EQUAL((int)expected_data[6], (int)storage[6]);
CHECK_EQUAL((int)expected_data[7], (int)storage[7]);
CHECK_EQUAL((int)expected_data[8], (int)storage[8]);
CHECK_EQUAL((int)expected_data[9], (int)storage[9]);
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
CHECK_EQUAL((int)expected_data[11], (int)storage[11]);
CHECK_EQUAL((int)expected_data[12], (int)storage[12]);
CHECK_EQUAL((int)expected_data[13], (int)storage[13]);
CHECK_EQUAL((int)expected_data[14], (int)storage[14]);
CHECK_EQUAL((int)expected_data[15], (int)storage[15]);
CHECK_EQUAL((int)expected_data[16], (int)storage[16]);
CHECK_EQUAL((int)expected_data[17], (int)storage[17]);
CHECK_EQUAL((int)expected_data[18], (int)storage[18]);
CHECK_EQUAL((int)expected_data[19], (int)storage[19]);
CHECK_EQUAL((int)expected_data[20], (int)storage[20]);
CHECK_EQUAL((int)expected_data[21], (int)storage[21]);
CHECK_EQUAL((int)expected_data[22], (int)storage[22]);
CHECK_EQUAL((int)expected_data[23], (int)storage[23]);
// 25th to 32nd bytes not used.
}
//*************************************************************************
TEST(test_write_uint64_t_47bits)
{
std::array<char, 4 * sizeof(uint64_t)> storage;
std::array<uint64_t, 4> write_data = { uint64_t(0x0000000000000001ULL), uint64_t(0xA55AA55AA55AA55AULL), uint64_t(0x5AA55AA55AA55AA5ULL), uint64_t(0xFFFFFFFFFFFFFFFFULL) };
std::array<char, 4 * sizeof(uint64_t)> expected_data = { 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) };
etl::bit_stream_writer bit_stream(storage.data(), storage.size());
// Insert into the stream
bit_stream.write(write_data[0], 47);
CHECK_EQUAL(6, bit_stream.used_data().size());
bit_stream.write(write_data[1], 47);
CHECK_EQUAL(12, bit_stream.used_data().size());
bit_stream.write(write_data[2], 47);
CHECK_EQUAL(18, bit_stream.used_data().size());
bit_stream.write(write_data[3], 47);
CHECK_EQUAL(24, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
CHECK_EQUAL((int)expected_data[5], (int)storage[5]);
CHECK_EQUAL((int)expected_data[6], (int)storage[6]);
CHECK_EQUAL((int)expected_data[7], (int)storage[7]);
CHECK_EQUAL((int)expected_data[8], (int)storage[8]);
CHECK_EQUAL((int)expected_data[9], (int)storage[9]);
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
CHECK_EQUAL((int)expected_data[11], (int)storage[11]);
CHECK_EQUAL((int)expected_data[12], (int)storage[12]);
CHECK_EQUAL((int)expected_data[13], (int)storage[13]);
CHECK_EQUAL((int)expected_data[14], (int)storage[14]);
CHECK_EQUAL((int)expected_data[15], (int)storage[15]);
CHECK_EQUAL((int)expected_data[16], (int)storage[16]);
CHECK_EQUAL((int)expected_data[17], (int)storage[17]);
CHECK_EQUAL((int)expected_data[18], (int)storage[18]);
CHECK_EQUAL((int)expected_data[19], (int)storage[19]);
CHECK_EQUAL((int)expected_data[20], (int)storage[20]);
CHECK_EQUAL((int)expected_data[21], (int)storage[21]);
CHECK_EQUAL((int)expected_data[22], (int)storage[22]);
CHECK_EQUAL((int)expected_data[23], (int)storage[23]);
// 25th to 32nd bytes not used.
}
//*************************************************************************
TEST(test_write_multiple_full_size)
{
char c1 = 90; // 0x5A
char c2 = -91; // 0xA5
unsigned short s1 = 4660; // 0x1234
unsigned short s2 = 22136; // 0x5678
int32_t i1 = 2309737967L; // 0x89ABCDEF
int32_t i2 = 4275878552L; // 0xFEDCBA98
std::array<char, 14> storage;
std::array<char, 14> expected_data = { 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_writer bit_stream(storage.data(), storage.size());
// Insert into the stream.
bit_stream.write(c1);
CHECK_EQUAL(1, bit_stream.used_data().size());
bit_stream.write(s1);
CHECK_EQUAL(3, bit_stream.used_data().size());
bit_stream.write(i1);
CHECK_EQUAL(7, bit_stream.used_data().size());
bit_stream.write(i2);
CHECK_EQUAL(11, bit_stream.used_data().size());
bit_stream.write(s2);
CHECK_EQUAL(13, bit_stream.used_data().size());
bit_stream.write(c2);
CHECK_EQUAL(14, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
CHECK_EQUAL((int)expected_data[5], (int)storage[5]);
CHECK_EQUAL((int)expected_data[6], (int)storage[6]);
CHECK_EQUAL((int)expected_data[7], (int)storage[7]);
CHECK_EQUAL((int)expected_data[8], (int)storage[8]);
CHECK_EQUAL((int)expected_data[9], (int)storage[9]);
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
CHECK_EQUAL((int)expected_data[11], (int)storage[11]);
CHECK_EQUAL((int)expected_data[12], (int)storage[12]);
CHECK_EQUAL((int)expected_data[13], (int)storage[13]);
}
////*************************************************************************
TEST(test_write_multiple_variable_size)
{
char c1 = 90; // 0x5A 6 bits
char c2 = -91; // 0xA5 7 bits
unsigned short s1 = 4660; // 0x1234 13 bits
unsigned short s2 = 22136; // 0x5678 11 bits
int32_t i1 = 2309737967L; // 0x89ABCDEF 23 bits
int32_t i2 = 4275878552L; // 0xFEDCBA98 25 bits
std::array<char, 14> storage;
std::array<char, 14> expected_data = { 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_writer bit_stream(storage.data(), storage.size());
// Insert into the stream.
bit_stream.write(c1, 6);
CHECK_EQUAL(1, bit_stream.used_data().size());
bit_stream.write(s1, 13);
CHECK_EQUAL(3, bit_stream.used_data().size());
bit_stream.write(i1, 23);
CHECK_EQUAL(6, bit_stream.used_data().size());
bit_stream.write(i2, 25);
CHECK_EQUAL(9, bit_stream.used_data().size());
bit_stream.write(s2, 11);
CHECK_EQUAL(10, bit_stream.used_data().size());
bit_stream.write(c2, 7);
CHECK_EQUAL(11, bit_stream.used_data().size());
CHECK_EQUAL((int)expected_data[0], (int)storage[0]);
CHECK_EQUAL((int)expected_data[1], (int)storage[1]);
CHECK_EQUAL((int)expected_data[2], (int)storage[2]);
CHECK_EQUAL((int)expected_data[3], (int)storage[3]);
CHECK_EQUAL((int)expected_data[4], (int)storage[4]);
CHECK_EQUAL((int)expected_data[5], (int)storage[5]);
CHECK_EQUAL((int)expected_data[6], (int)storage[6]);
CHECK_EQUAL((int)expected_data[7], (int)storage[7]);
CHECK_EQUAL((int)expected_data[8], (int)storage[8]);
CHECK_EQUAL((int)expected_data[9], (int)storage[9]);
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
}
////*************************************************************************
//TEST(put_get_object_global)
//{
// std::array<char, 2 * sizeof(Object)> storage;
// etl::bit_stream bit_stream(storage.data(), storage.size());
// Object object1 = { -1234, 2.71578369, 250 };
// Object object2 = { 5678, 5.24685744, 126 };
// CHECK(etl::bit_stream_put(bit_stream, object1));
// CHECK(etl::bit_stream_put(bit_stream, object2));
// Object object1a;
// Object object2a;
// bit_stream.restart();
// CHECK(etl::bit_stream_get(bit_stream, object1a));
// CHECK(etl::bit_stream_get(bit_stream, object2a));
// CHECK_EQUAL(object1, object1a);
// CHECK_EQUAL(object2, object2a);
//}
////*************************************************************************
//TEST(put_get_multiple_float)
//{
// float f = 3.1415927f;
// double d = 3.1415927;
// std::array<char, 12> storage;
// etl::bit_stream bit_stream(storage.data(), storage.size());
// bit_stream.put(f);
// bit_stream.put(d);
// bit_stream.restart();
// float rf;
// double rd;
// CHECK(bit_stream.get(rf));
// CHECK_CLOSE(f, rf, 0.1f);
// CHECK(bit_stream.get(rd));
// CHECK_CLOSE(f, rd, 0.1f);
//}
};
}

View File

@ -10912,6 +10912,7 @@
<ClCompile Include="..\test_atomic_clang_sync.cpp" />
<ClCompile Include="..\test_atomic_gcc_sync.cpp" />
<ClCompile Include="..\test_bit.cpp" />
<ClCompile Include="..\test_bit_stream_writer.cpp" />
<ClCompile Include="..\test_bresenham_line.cpp" />
<ClCompile Include="..\test_buffer_descriptors.cpp" />
<ClCompile Include="..\test_byte.cpp" />

View File

@ -3254,6 +3254,9 @@
<ClCompile Include="..\sanity-check\delegate_cpp03.h.t.cpp">
<Filter>Tests\Sanity Checks\Source</Filter>
</ClCompile>
<ClCompile Include="..\test_bit_stream_writer.cpp">
<Filter>Tests\Binary</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">