diff --git a/include/etl/byte_stream.h b/include/etl/byte_stream.h index 9f6d75e5..164c70b4 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,22 @@ 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_) + { + } + + //*************************************************************************** + /// 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_) { } @@ -376,17 +408,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,11 +429,9 @@ 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, etl::optional > >::type read(etl::span range) { - etl::optional > result; - // Do we have enough room? if (available() >= range.size()) { @@ -412,14 +442,16 @@ namespace etl *destination++ = from_bytes(); } - result = range; + 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) @@ -438,6 +470,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 +556,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 +584,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/include/etl/span.h b/include/etl/span.h index 12587528..d78a9460 100644 --- a/include/etl/span.h +++ b/include/etl/span.h @@ -41,9 +41,12 @@ SOFTWARE. #include "array.h" ///\defgroup span span -/// A wrapper for arrays ///\ingroup containers +#if ETL_CPP11_SUPPORTED && ETL_USING_STL + #include +#endif + namespace etl { static ETL_CONSTANT size_t dynamic_extent = etl::integral_limits::max; @@ -80,22 +83,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_CPP11_SUPPORTED && 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 bbe40c77..d840d089 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()); + 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]); @@ -1071,5 +1071,35 @@ namespace // Skip five int16_t (too many) CHECK(!reader.skip(5U)); } + + //************************************************************************* + TEST(read_span_int32_t) + { + 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::span input(put_data.begin(), put_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]); + } }; }