From 0ae71fb7975de5f2b6d2951996e92abf4aed48b8 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 6 Jun 2022 11:01:36 +0100 Subject: [PATCH] Added callback functionality to bit_stream_writer --- include/etl/bit_stream.h | 64 ++++++++++++++++++++++------ include/etl/byte_stream.h | 2 +- test/test_bit_stream_writer.cpp | 74 ++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/include/etl/bit_stream.h b/include/etl/bit_stream.h index 4f715a5d..1cba277f 100644 --- a/include/etl/bit_stream.h +++ b/include/etl/bit_stream.h @@ -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 callback_type; + + typedef etl::span callback_parameter_type; + typedef etl::delegate 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(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(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. //*************************************************************************** diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 2b6592c0..c9c417f2 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -58,7 +58,7 @@ namespace etl typedef const char* const_iterator; typedef etl::span callback_parameter_type; - typedef etl::delegate)> callback_type; + typedef etl::delegate callback_type; //*************************************************************************** /// Construct from span. diff --git a/test/test_bit_stream_writer.cpp b/test/test_bit_stream_writer.cpp index bff30452..a2d666d8 100644 --- a/test/test_bit_stream_writer.cpp +++ b/test/test_bit_stream_writer.cpp @@ -31,6 +31,7 @@ SOFTWARE. #include "etl/bit_stream.h" #include +#include #include 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& GetData() const + { + return data; + } + + private: + + std::vector 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 storage; + storage.fill(0); + std::array 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); + + 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) //{