From 49c93935371b12dc979a115d24a1a3585c447f2f Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Thu, 23 Sep 2021 11:49:16 +0100 Subject: [PATCH 1/3] Fixes to byte_stream_reader for const data --- include/etl/byte_stream.h | 350 ++++++++++++++++++++++++-------------- test/test_byte_stream.cpp | 17 +- 2 files changed, 241 insertions(+), 126 deletions(-) diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 9f6d75e5..f97a6090 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -48,121 +48,23 @@ SOFTWARE. namespace etl { - namespace private_byte_stream - { - class byte_stream_common - { - public: - - typedef const char* const_iterator; - - //*************************************************************************** - /// Sets the index back to the position in the stream. Default = 0. - //*************************************************************************** - void restart(size_t n = 0U) - { - pcurrent = const_cast(pdata + n); - } - - //*************************************************************************** - /// Returns start of the stream. - //*************************************************************************** - const_iterator begin() const - { - return pdata; - } - - //*************************************************************************** - /// Returns end of the stream. - //*************************************************************************** - const_iterator end() const - { - return pcurrent; - } - - //*************************************************************************** - /// Returns start of the stream. - //*************************************************************************** - const_iterator cbegin() const - { - return pdata; - } - - //*************************************************************************** - /// Returns end of the stream. - //*************************************************************************** - const_iterator cend() const - { - return pcurrent; - } - - //*************************************************************************** - /// Returns a span of the used portion of the stream. - //*************************************************************************** - etl::span used_data() const - { - return etl::span(pdata, pcurrent); - } - - //*************************************************************************** - /// Returns a span of the free portion of the stream. - //*************************************************************************** - etl::span free_data() const - { - return etl::span(pcurrent, pdata + length); - } - - //*************************************************************************** - /// Returns a span of whole the stream. - //*************************************************************************** - etl::span data() const - { - return etl::span(pdata, pdata + length); - } - - protected: - - byte_stream_common(char* pdata_, size_t length_, etl::endian buffer_endianness_) - : pdata(pdata_) - , pcurrent(pdata_) - , length(length_) - , buffer_endianness(buffer_endianness_) - { - } - - void copy_value(const char* source, char* destination, size_t length) const - { - const etl::endian platform_endianness = etl::endianness::value(); - - if (buffer_endianness == platform_endianness) - { - etl::copy(source, source + length, destination); - } - else - { - etl::reverse_copy(source, source + length, destination); - } - } - - char* const pdata; ///< The start of the byte stream buffer. - char* pcurrent; ///< The current position in the byte stream buffer. - const size_t length; ///< The length of the byte stream buffer. - const etl::endian buffer_endianness; ///< The endianness of the buffer data. - }; - } - //*************************************************************************** /// Encodes a byte stream. //*************************************************************************** - class byte_stream_writer : public private_byte_stream::byte_stream_common + class byte_stream_writer { public: + typedef const char* const_iterator; + //*************************************************************************** /// Construct from span. //*************************************************************************** byte_stream_writer(etl::span span_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(span_.begin(), span_.size_bytes(), buffer_endianness_) + : pdata(span_.begin()) + , pcurrent(span_.begin()) + , length(span_.size_bytes()) + , buffer_endianness(buffer_endianness_) { } @@ -170,7 +72,10 @@ namespace etl /// Construct from range. //*************************************************************************** byte_stream_writer(char* begin_, char* end_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, etl::distance(begin_, end_), buffer_endianness_) + : pdata(begin_) + , pcurrent(begin_) + , length(etl::distance(begin_, end_)) + , buffer_endianness(buffer_endianness_) { } @@ -178,7 +83,10 @@ namespace etl /// Construct from begin and length. //*************************************************************************** byte_stream_writer(char* begin_, size_t length_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, length_, buffer_endianness_) + : pdata(begin_) + , pcurrent(begin_) + , length(length_) + , buffer_endianness(buffer_endianness_) { } @@ -187,7 +95,10 @@ namespace etl //*************************************************************************** template byte_stream_writer(T(&begin_)[Size], etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, begin_ + (Size * sizeof(T)), buffer_endianness_) + : pdata(begin_) + , pcurrent(begin_) + , length(begin_ + (Size * sizeof(T))) + , buffer_endianness(buffer_endianness_) { } @@ -249,6 +160,70 @@ namespace etl return success; } + //*************************************************************************** + /// Sets the index back to the position in the stream. Default = 0. + //*************************************************************************** + void restart(size_t n = 0U) + { + pcurrent = const_cast(pdata + n); + } + + //*************************************************************************** + /// Returns start of the stream. + //*************************************************************************** + const_iterator begin() const + { + return pdata; + } + + //*************************************************************************** + /// Returns end of the stream. + //*************************************************************************** + const_iterator end() const + { + return pcurrent; + } + + //*************************************************************************** + /// Returns start of the stream. + //*************************************************************************** + const_iterator cbegin() const + { + return pdata; + } + + //*************************************************************************** + /// Returns end of the stream. + //*************************************************************************** + const_iterator cend() const + { + return pcurrent; + } + + //*************************************************************************** + /// Returns a span of the used portion of the stream. + //*************************************************************************** + etl::span used_data() const + { + return etl::span(pdata, pcurrent); + } + + //*************************************************************************** + /// Returns a span of the free portion of the stream. + //*************************************************************************** + etl::span free_data() const + { + return etl::span(pcurrent, pdata + length); + } + + //*************************************************************************** + /// Returns a span of whole the stream. + //*************************************************************************** + etl::span data() const + { + return etl::span(pdata, pdata + length); + } + //*************************************************************************** /// Returns true if the byte stream index has reached the end. //*************************************************************************** @@ -311,37 +286,79 @@ namespace etl copy_value(pv, pcurrent, sizeof(T)); pcurrent += sizeof(T); } + + //********************************* + void copy_value(const char* source, char* destination, size_t length) const + { + const etl::endian platform_endianness = etl::endianness::value(); + + if (buffer_endianness == platform_endianness) + { + etl::copy(source, source + length, destination); + } + else + { + etl::reverse_copy(source, source + length, destination); + } + } + + char* const pdata; ///< The start of the byte stream buffer. + char* pcurrent; ///< The current position in the byte stream buffer. + const size_t length; ///< The length of the byte stream buffer. + const etl::endian buffer_endianness; ///< The endianness of the buffer data. }; //*************************************************************************** /// Decodes byte streams. /// Data must be stored in the stream in network order. //*************************************************************************** - class byte_stream_reader : public private_byte_stream::byte_stream_common + class byte_stream_reader { public: + typedef const char* const_iterator; + //*************************************************************************** /// Construct from span. //*************************************************************************** byte_stream_reader(etl::span span_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(span_.begin(), span_.size_bytes(), buffer_endianness_) + : pdata(span_.begin()) + , pcurrent(span_.begin()) + , length(span_.size_bytes()) + , buffer_endianness(buffer_endianness_) + { + } + + //*************************************************************************** + /// Construct from span. + //*************************************************************************** + byte_stream_reader(etl::span span_, etl::endian buffer_endianness_ = etl::endian::big) + : pdata(span_.begin()) + , pcurrent(span_.begin()) + , length(span_.size_bytes()) + , buffer_endianness(buffer_endianness_) { } //*************************************************************************** /// Construct from range. //*************************************************************************** - byte_stream_reader(char* begin_, char* end_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, etl::distance(begin_, end_), buffer_endianness_) + byte_stream_reader(const char* begin_, const char* end_, etl::endian buffer_endianness_ = etl::endian::big) + : pdata(begin_) + , pcurrent(begin_) + , length(etl::distance(begin_, end_)) + , buffer_endianness(buffer_endianness_) { } //*************************************************************************** /// Construct from begin and length. //*************************************************************************** - byte_stream_reader(char* begin_, size_t length_, etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, length_, buffer_endianness_) + byte_stream_reader(const char* begin_, size_t length_, etl::endian buffer_endianness_ = etl::endian::big) + : pdata(begin_) + , pcurrent(begin_) + , length(length_) + , buffer_endianness(buffer_endianness_) { } @@ -350,7 +367,10 @@ namespace etl //*************************************************************************** template byte_stream_reader(T(&begin_)[Size], etl::endian buffer_endianness_ = etl::endian::big) - : byte_stream_common(begin_, begin_ + (Size * sizeof(T)), buffer_endianness_) + : pdata(begin_) + , pcurrent(begin_) + , length(begin_ + (Size * sizeof(T))) + , buffer_endianness(buffer_endianness_) { } @@ -376,17 +396,17 @@ namespace etl /// Read a byte range from the stream. //*************************************************************************** template - typename etl::enable_if > >::type + typename etl::enable_if > >::type read(size_t n) { - etl::optional > result; + etl::optional > result; // Do we have enough room? if (available() >= n) { - char* pend = pcurrent + (n * sizeof(T)); + const char* pend = pcurrent + (n * sizeof(T)); - result = etl::span(reinterpret_cast(pcurrent), reinterpret_cast(pend)); + result = etl::span(reinterpret_cast(pcurrent), reinterpret_cast(pend)); pcurrent = pend; } @@ -397,10 +417,10 @@ namespace etl /// Read a range of T from the stream. //*************************************************************************** template - typename etl::enable_if::value || etl::is_floating_point::value, etl::optional > >::type + typename etl::enable_if::value || etl::is_floating_point::value, bool>::type read(etl::span range) { - etl::optional > result; + bool result = false; // Do we have enough room? if (available() >= range.size()) @@ -412,7 +432,7 @@ namespace etl *destination++ = from_bytes(); } - result = range; + result = true; } return result; @@ -438,6 +458,70 @@ namespace etl } } + //*************************************************************************** + /// Sets the index back to the position in the stream. Default = 0. + //*************************************************************************** + void restart(size_t n = 0U) + { + pcurrent = pdata + n; + } + + //*************************************************************************** + /// Returns start of the stream. + //*************************************************************************** + const_iterator begin() const + { + return pdata; + } + + //*************************************************************************** + /// Returns end of the stream. + //*************************************************************************** + const_iterator end() const + { + return pcurrent; + } + + //*************************************************************************** + /// Returns start of the stream. + //*************************************************************************** + const_iterator cbegin() const + { + return pdata; + } + + //*************************************************************************** + /// Returns end of the stream. + //*************************************************************************** + const_iterator cend() const + { + return pcurrent; + } + + //*************************************************************************** + /// Returns a span of the used portion of the stream. + //*************************************************************************** + etl::span used_data() const + { + return etl::span(pdata, pcurrent); + } + + //*************************************************************************** + /// Returns a span of the free portion of the stream. + //*************************************************************************** + etl::span free_data() const + { + return etl::span(pcurrent, pdata + length); + } + + //*************************************************************************** + /// Returns a span of whole the stream. + //*************************************************************************** + etl::span data() const + { + return etl::span(pdata, pdata + length); + } + //*************************************************************************** /// Returns true if the byte stream is empty. //*************************************************************************** @@ -460,7 +544,7 @@ namespace etl template size_t available() const { - return (length - etl::distance(pdata, reinterpret_cast(pcurrent))) / sizeof(T); + return (length - etl::distance(pdata, reinterpret_cast(pcurrent))) / sizeof(T); } private: @@ -488,6 +572,26 @@ namespace etl return value; } + + //********************************* + void copy_value(const char* source, char* destination, size_t length) const + { + const etl::endian platform_endianness = etl::endianness::value(); + + if (buffer_endianness == platform_endianness) + { + etl::copy(source, source + length, destination); + } + else + { + etl::reverse_copy(source, source + length, destination); + } + } + + const char* const pdata; ///< The start of the byte stream buffer. + const char* pcurrent; ///< The current position in the byte stream buffer. + const size_t length; ///< The length of the byte stream buffer. + const etl::endian buffer_endianness; ///< The endianness of the buffer data. }; //*************************************************************************** diff --git a/test/test_byte_stream.cpp b/test/test_byte_stream.cpp index bbe40c77..b2045624 100644 --- a/test/test_byte_stream.cpp +++ b/test/test_byte_stream.cpp @@ -881,7 +881,7 @@ namespace etl::byte_stream_reader reader(storage.data(), writer.size_bytes()); - etl::optional> output = reader.read(4U); + etl::optional> output = reader.read(4U); CHECK_EQUAL(4U, output.value().size()); CHECK_EQUAL(int(put_data[0]), int(output.value()[0])); CHECK_EQUAL(int(put_data[1]), int(output.value()[1])); @@ -909,8 +909,8 @@ namespace etl::span output(get_data.begin(), get_data.end()); - etl::optional> result = reader.read(output); - CHECK_EQUAL(4U, result.value().size()); + bool result = reader.read(output); + CHECK(result); CHECK_EQUAL(put_data[0], get_data[0]); CHECK_EQUAL(put_data[1], get_data[1]); CHECK_EQUAL(put_data[2], get_data[2]); @@ -1071,5 +1071,16 @@ namespace // Skip five int16_t (too many) CHECK(!reader.skip(5U)); } + + //************************************************************************* + TEST(read_span_int32_t) + { + std::array storage = { int32_t(0x00000001), int32_t(0xA55AA55A), int32_t(0x5AA55AA5), int32_t(0xFFFFFFFF) }; + std::array get_data = { int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000) }; + + etl::byte_stream_reader reader(reinterpret_cast(storage.data()), storage.size() * sizeof(int32_t)); + + bool result = reader.read(etl::span(get_data.begin(), get_data.end())); + } }; } From 9f976d98b9d706e0f8b77e052271db24ae1428d4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 24 Sep 2021 09:44:49 +0100 Subject: [PATCH 2/3] #428 byte_stream_reader can't be used to read a span of const data --- include/etl/byte_stream.h | 10 +++++----- include/etl/span.h | 38 ++++++++++++++++++++++++++++++++------ test/test_byte_stream.cpp | 31 +++++++++++++++++++++++++------ 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index f97a6090..45fd3718 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -417,11 +417,9 @@ namespace etl /// Read a range of T from the stream. //*************************************************************************** template - typename etl::enable_if::value || etl::is_floating_point::value, bool>::type + typename etl::enable_if::value || etl::is_floating_point::value, etl::optional > >::type read(etl::span range) { - bool result = false; - // Do we have enough room? if (available() >= range.size()) { @@ -432,14 +430,16 @@ namespace etl *destination++ = from_bytes(); } - result = true; + return etl::optional >(etl::span(range.begin(), range.end())); } - return result; + return etl::optional >(); } //*************************************************************************** /// Skip n items of T, up to the maximum space available. + /// Returns true if the skip was possible. + /// Returns false if the full skip size was not possible. //*************************************************************************** template bool skip(size_t n) diff --git a/include/etl/span.h b/include/etl/span.h index 12587528..127e0415 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -44,6 +44,10 @@ SOFTWARE. /// A wrapper for arrays ///\ingroup containers +#if ETL_USING_STL + #include +#endif + namespace etl { static ETL_CONSTANT size_t dynamic_extent = etl::integral_limits::max; @@ -80,22 +84,44 @@ namespace etl } //************************************************************************* - /// Construct from std::array or etl::array or other type that supports + /// Construct from etl::array. + //************************************************************************* + template + ETL_CONSTEXPR span(const etl::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } + +#if ETL_USING_STL + //************************************************************************* + /// Construct from std::array. + //************************************************************************* + template + ETL_CONSTEXPR span(const std::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#endif + + //************************************************************************* + /// Construct from a container or other type that supports /// data() and size() member functions. //************************************************************************* - template - ETL_CONSTEXPR span(TSpan& a) ETL_NOEXCEPT + template + ETL_CONSTEXPR span(TContainer& a) ETL_NOEXCEPT : mbegin(a.data()) , mend(a.data() + a.size()) { } //************************************************************************* - /// Construct from std::array or etl::array or other type that supports + /// Construct from a container or other type that supports /// data() and size() member functions. //************************************************************************* - template - ETL_CONSTEXPR span(const TSpan& a) ETL_NOEXCEPT + template + ETL_CONSTEXPR span(const TContainer& a) ETL_NOEXCEPT : mbegin(a.data()) , mend(a.data() + a.size()) { diff --git a/test/test_byte_stream.cpp b/test/test_byte_stream.cpp index b2045624..d840d089 100644 --- a/test/test_byte_stream.cpp +++ b/test/test_byte_stream.cpp @@ -909,8 +909,8 @@ namespace etl::span output(get_data.begin(), get_data.end()); - bool result = reader.read(output); - CHECK(result); + etl::optional > result = reader.read(output); + CHECK(result.has_value()); CHECK_EQUAL(put_data[0], get_data[0]); CHECK_EQUAL(put_data[1], get_data[1]); CHECK_EQUAL(put_data[2], get_data[2]); @@ -1075,12 +1075,31 @@ namespace //************************************************************************* TEST(read_span_int32_t) { - std::array storage = { int32_t(0x00000001), int32_t(0xA55AA55A), int32_t(0x5AA55AA5), int32_t(0xFFFFFFFF) }; - std::array get_data = { int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000) }; + std::array storage; + std::array put_data = { int32_t(0x00000001), int32_t(0xA55AA55A), int32_t(0x5AA55AA5), int32_t(0xFFFFFFFF) }; + std::array get_data = { int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000) }; - etl::byte_stream_reader reader(reinterpret_cast(storage.data()), storage.size() * sizeof(int32_t)); + etl::span input(put_data.begin(), put_data.end()); - bool result = reader.read(etl::span(get_data.begin(), get_data.end())); + etl::byte_stream_writer writer(storage.data(), storage.size()); + writer.write(input); + + const char* read_only_storage = reinterpret_cast(storage.data()); + etl::byte_stream_reader reader(read_only_storage, storage.size() * sizeof(int32_t)); + + etl::optional > result = reader.read(etl::span(get_data.begin(), get_data.end())); + + CHECK(result.has_value()); + + CHECK_EQUAL(int32_t(0x00000001), result.value()[0]); + CHECK_EQUAL(int32_t(0xA55AA55A), result.value()[1]); + CHECK_EQUAL(int32_t(0x5AA55AA5), result.value()[2]); + CHECK_EQUAL(int32_t(0xFFFFFFFF), result.value()[3]); + + CHECK_EQUAL(int32_t(0x00000001), get_data[0]); + CHECK_EQUAL(int32_t(0xA55AA55A), get_data[1]); + CHECK_EQUAL(int32_t(0x5AA55AA5), get_data[2]); + CHECK_EQUAL(int32_t(0xFFFFFFFF), get_data[3]); } }; } From 2fd15f9f687b2c3d41df5f9441aff124eeb18ac4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 29 Sep 2021 18:49:27 +0100 Subject: [PATCH 3/3] Fixes to byte_stream_reader for const data --- include/etl/byte_stream.h | 12 ++++++++++++ include/etl/span.h | 5 ++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 45fd3718..164c70b4 100644 --- a/include/etl/byte_stream.h +++ b/include/etl/byte_stream.h @@ -374,6 +374,18 @@ namespace etl { } + //*************************************************************************** + /// Construct from const array. + //*************************************************************************** + template + byte_stream_reader(const T(&begin_)[Size], etl::endian buffer_endianness_ = etl::endian::big) + : pdata(begin_) + , pcurrent(begin_) + , length(begin_ + (Size * sizeof(T))) + , buffer_endianness(buffer_endianness_) + { + } + //*************************************************************************** /// Read a value from the stream. //*************************************************************************** diff --git a/include/etl/span.h b/include/etl/span.h index 127e0415..d78a9460 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -41,10 +41,9 @@ SOFTWARE. #include "array.h" ///\defgroup span span -/// A wrapper for arrays ///\ingroup containers -#if ETL_USING_STL +#if ETL_CPP11_SUPPORTED && ETL_USING_STL #include #endif @@ -93,7 +92,7 @@ namespace etl { } -#if ETL_USING_STL +#if ETL_CPP11_SUPPORTED && ETL_USING_STL //************************************************************************* /// Construct from std::array. //*************************************************************************