Fixes to byte_stream_reader for const data

This commit is contained in:
John Wellbelove 2021-09-23 11:49:16 +01:00
parent 0754b3380e
commit 49c9393537
2 changed files with 241 additions and 126 deletions

View File

@ -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<char*>(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<char> used_data() const
{
return etl::span<char>(pdata, pcurrent);
}
//***************************************************************************
/// Returns a span of the free portion of the stream.
//***************************************************************************
etl::span<char> free_data() const
{
return etl::span<char>(pcurrent, pdata + length);
}
//***************************************************************************
/// Returns a span of whole the stream.
//***************************************************************************
etl::span<char> data() const
{
return etl::span<char>(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<char> 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 <typename T, size_t Size>
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<char*>(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<char> used_data() const
{
return etl::span<char>(pdata, pcurrent);
}
//***************************************************************************
/// Returns a span of the free portion of the stream.
//***************************************************************************
etl::span<char> free_data() const
{
return etl::span<char>(pcurrent, pdata + length);
}
//***************************************************************************
/// Returns a span of whole the stream.
//***************************************************************************
etl::span<char> data() const
{
return etl::span<char>(pdata, pdata + length);
}
//***************************************************************************
/// Returns <b>true</b> 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<char> 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<const char> 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 <typename T, size_t Size>
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 T>
typename etl::enable_if<sizeof(T) == 1U, etl::optional<etl::span<T> > >::type
typename etl::enable_if<sizeof(T) == 1U, etl::optional<etl::span<const T> > >::type
read(size_t n)
{
etl::optional<etl::span<T> > result;
etl::optional<etl::span<const T> > result;
// Do we have enough room?
if (available<T>() >= n)
{
char* pend = pcurrent + (n * sizeof(T));
const char* pend = pcurrent + (n * sizeof(T));
result = etl::span<T>(reinterpret_cast<T*>(pcurrent), reinterpret_cast<T*>(pend));
result = etl::span<const T>(reinterpret_cast<const T*>(pcurrent), reinterpret_cast<const T*>(pend));
pcurrent = pend;
}
@ -397,10 +417,10 @@ namespace etl
/// Read a range of T from the stream.
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value || etl::is_floating_point<T>::value, etl::optional<etl::span<T> > >::type
typename etl::enable_if<etl::is_integral<T>::value || etl::is_floating_point<T>::value, bool>::type
read(etl::span<T> range)
{
etl::optional<etl::span<T> > result;
bool result = false;
// Do we have enough room?
if (available<T>() >= range.size())
@ -412,7 +432,7 @@ namespace etl
*destination++ = from_bytes<T>();
}
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<const char> used_data() const
{
return etl::span<const char>(pdata, pcurrent);
}
//***************************************************************************
/// Returns a span of the free portion of the stream.
//***************************************************************************
etl::span<const char> free_data() const
{
return etl::span<const char>(pcurrent, pdata + length);
}
//***************************************************************************
/// Returns a span of whole the stream.
//***************************************************************************
etl::span<const char> data() const
{
return etl::span<const char>(pdata, pdata + length);
}
//***************************************************************************
/// Returns <b>true</b> if the byte stream is empty.
//***************************************************************************
@ -460,7 +544,7 @@ namespace etl
template <typename T>
size_t available() const
{
return (length - etl::distance(pdata, reinterpret_cast<char* const>(pcurrent))) / sizeof(T);
return (length - etl::distance(pdata, reinterpret_cast<const char* const>(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.
};
//***************************************************************************

View File

@ -881,7 +881,7 @@ namespace
etl::byte_stream_reader reader(storage.data(), writer.size_bytes());
etl::optional<etl::span<char>> output = reader.read<char>(4U);
etl::optional<etl::span<const char>> output = reader.read<char>(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<int32_t> output(get_data.begin(), get_data.end());
etl::optional<etl::span<int32_t>> result = reader.read<int32_t>(output);
CHECK_EQUAL(4U, result.value().size());
bool result = reader.read<int32_t>(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<int16_t>(5U));
}
//*************************************************************************
TEST(read_span_int32_t)
{
std::array<const int32_t, 4> storage = { int32_t(0x00000001), int32_t(0xA55AA55A), int32_t(0x5AA55AA5), int32_t(0xFFFFFFFF) };
std::array<int32_t, 4> get_data = { int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000), int32_t(0x00000000) };
etl::byte_stream_reader reader(reinterpret_cast<const char*>(storage.data()), storage.size() * sizeof(int32_t));
bool result = reader.read(etl::span<int32_t>(get_data.begin(), get_data.end()));
}
};
}