Added callback functionality to bit_stream_writer

This commit is contained in:
John Wellbelove 2022-06-06 11:01:36 +01:00
parent be9d64f5fc
commit 0ae71fb797
3 changed files with 126 additions and 14 deletions

View File

@ -510,11 +510,11 @@ namespace etl
bits_remaining -= 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.
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.
};
//***************************************************************************
@ -525,8 +525,9 @@ namespace etl
public:
typedef const unsigned char* const_iterator;
typedef char callback_parameter_type;
typedef etl::delegate<void(char)> callback_type;
typedef etl::span<char> callback_parameter_type;
typedef etl::delegate<void(callback_parameter_type)> callback_type;
//***************************************************************************
/// Construct from span.
@ -785,7 +786,7 @@ namespace etl
{
size_t s = char_index;
// Is the current byte used?
// Is the current byte partially used?
if (bits_available_in_char != CHAR_BIT)
{
++s;
@ -888,13 +889,19 @@ namespace etl
}
//***************************************************************************
/// Finalizes the stream and calls the callback, if set.
/// Flush the last byte, if partially filled, to the callback, if valid.
//***************************************************************************
void finalize()
void flush()
{
if (bits_remaining != 0U)
if (callback.is_valid())
{
callback.call_if(pdata[char_index]);
if (bits_available_in_char != 0U)
{
char_index = 1U;
flush_full_bytes();
char_index = 0U;
bits_available_in_char = CHAR_BIT;
}
}
}
@ -934,6 +941,11 @@ namespace etl
write_chunk(static_cast<unsigned char>(chunk), mask_width);
}
if (callback.is_valid())
{
flush_full_bytes();
}
}
#if ETL_USING_64BIT_TYPES
@ -955,6 +967,13 @@ namespace etl
write_chunk(static_cast<unsigned char>(chunk), mask_width);
}
size_t end_index = char_index;
if (callback.is_valid())
{
flush_full_bytes();
}
}
#endif
@ -973,6 +992,27 @@ namespace etl
step(nbits);
}
//***************************************************************************
/// Flush full bytes to the callback, if valid.
/// Resets the
//***************************************************************************
void flush_full_bytes()
{
// Is the first byte fully filled?
if (char_index > 0U)
{
callback(callback_parameter_type((char*)pdata, (char*)pdata + char_index));
if (bits_available_in_char != 0U)
{
// Move a partially filled last byte to the start of the buffer.
pdata[0] = pdata[char_index];
}
char_index = 0U;
}
}
//***************************************************************************
/// Convert to bytes.
//***************************************************************************

View File

@ -58,7 +58,7 @@ namespace etl
typedef const char* const_iterator;
typedef etl::span<char> callback_parameter_type;
typedef etl::delegate<void(etl::span<char>)> callback_type;
typedef etl::delegate<void(callback_parameter_type)> callback_type;
//***************************************************************************
/// Construct from span.

View File

@ -31,6 +31,7 @@ SOFTWARE.
#include "etl/bit_stream.h"
#include <array>
#include <vector>
#include <numeric>
namespace
@ -85,6 +86,30 @@ namespace etl
namespace
{
class Accumulator
{
public:
void Add(etl::bit_stream_writer::callback_parameter_type s)
{
data.insert(data.end(), s.begin(), s.end());
}
void Clear()
{
data.clear();
}
const std::vector<char>& GetData() const
{
return data;
}
private:
std::vector<char> data;
};
SUITE(test_bit_stream)
{
//*************************************************************************
@ -648,7 +673,7 @@ namespace
CHECK_EQUAL((int)expected_data[13], (int)storage[13]);
}
////*************************************************************************
//*************************************************************************
TEST(test_write_multiple_variable_size)
{
char c1 = 90; // 0x5A 6 bits
@ -692,6 +717,53 @@ namespace
CHECK_EQUAL((int)expected_data[10], (int)storage[10]);
}
//*************************************************************************
TEST(test_write_multiple_variable_size_with_callback)
{
Accumulator accumulator;
char c1 = 90; // 0x5A 6 bits
char c2 = -91; // 0xA5 7 bits
unsigned short s1 = 4660U; // 0x1234 13 bits
unsigned short s2 = 22136U; // 0x5678 11 bits
int32_t i1 = 2309737967L; // 0x89ABCDEF 23 bits
int32_t i2 = 4275878552L; // 0xFEDCBA98 25 bits
std::array<char, 14> storage;
storage.fill(0);
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) };
auto callback = etl::bit_stream_writer::callback_type::create<Accumulator, &Accumulator::Add>(accumulator);
etl::bit_stream_writer bit_stream(storage.data(), storage.size(), callback);
// Insert into the stream.
bit_stream.write(c1, 6);
bit_stream.write(s1, 13);
bit_stream.write(i1, 23);
bit_stream.write(i2, 25);
bit_stream.write(s2, 11);
bit_stream.write(c2, 7);
bit_stream.flush();
CHECK_EQUAL(11U, accumulator.GetData().size());
CHECK_EQUAL((int)expected_data[0], (int)accumulator.GetData()[0]);
CHECK_EQUAL((int)expected_data[1], (int)accumulator.GetData()[1]);
CHECK_EQUAL((int)expected_data[2], (int)accumulator.GetData()[2]);
CHECK_EQUAL((int)expected_data[3], (int)accumulator.GetData()[3]);
CHECK_EQUAL((int)expected_data[4], (int)accumulator.GetData()[4]);
CHECK_EQUAL((int)expected_data[5], (int)accumulator.GetData()[5]);
CHECK_EQUAL((int)expected_data[6], (int)accumulator.GetData()[6]);
CHECK_EQUAL((int)expected_data[7], (int)accumulator.GetData()[7]);
CHECK_EQUAL((int)expected_data[8], (int)accumulator.GetData()[8]);
CHECK_EQUAL((int)expected_data[9], (int)accumulator.GetData()[9]);
CHECK_EQUAL((int)expected_data[10], (int)accumulator.GetData()[10]);
}
////*************************************************************************
//TEST(put_get_object_global)
//{