Loading...
Searching...
No Matches
bit_stream.h
Go to the documentation of this file.
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2018 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_BIT_STREAM_INCLUDED
#define ETL_BIT_STREAM_INCLUDED
#include "platform.h"
#include "algorithm.h"
#include "binary.h"
#include "delegate.h"
#include "endianness.h"
#include "enum_type.h"
#include "error_handler.h"
#include "exception.h"
#include "integral_limits.h"
#include "iterator.h"
#include "memory.h"
#include "nullptr.h"
#include "optional.h"
#include "span.h"
#include "type_traits.h"
#include <limits.h>
#include <stdint.h>
#include "private/minmax_push.h"
namespace etl
{
//***************************************************************************
//***************************************************************************
struct bit_order
{
enum enum_type
{
lsb_first,
msb_first
};
ETL_DECLARE_ENUM_TYPE(bit_order, int)
ETL_ENUM_TYPE(lsb_first, "lsb_first")
ETL_ENUM_TYPE(msb_first, "msb_first")
ETL_END_ENUM_TYPE
};
//***************************************************************************
//***************************************************************************
class bit_stream
{
public:
typedef const unsigned char* const_iterator;
//***************************************************************************
//***************************************************************************
bit_stream()
: pdata(ETL_NULLPTR)
, length_chars(0U)
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream(void* begin_, void* end_)
: pdata(reinterpret_cast<unsigned char*>(begin_))
, length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))))
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream(void* begin_, size_t length_)
: pdata(reinterpret_cast<unsigned char*>(begin_))
, length_chars(length_)
{
restart();
}
//***************************************************************************
//***************************************************************************
void set_stream(void* begin_, size_t length_)
{
pdata = reinterpret_cast<unsigned char*>(begin_);
length_chars = length_;
restart();
}
//***************************************************************************
//***************************************************************************
void set_stream(void* begin_, void* end_)
{
set_stream(begin_, static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))));
}
//***************************************************************************
//***************************************************************************
void restart()
{
bits_available_in_char = CHAR_BIT;
char_index = 0U;
bits_available = CHAR_BIT * length_chars;
}
//***************************************************************************
//***************************************************************************
bool at_end() const
{
return (bits_available == 0U);
}
//***************************************************************************
//***************************************************************************
bool put(bool value)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
if (bits_available > 0)
{
unsigned char chunk = value ? 1 : 0;
put_integral(uint32_t(chunk), 1);
success = true;
}
}
return success;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type put(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
return put_integral(static_cast<uint32_t>(value), nbits);
}
#if ETL_USING_64BIT_TYPES
//***************************************************************************
//***************************************************************************
bool put(int64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(int64_t))
{
return put_integral(uint64_t(value), nbits);
}
//***************************************************************************
//***************************************************************************
bool put(uint64_t value, uint_least8_t nbits = CHAR_BIT * sizeof(uint64_t))
{
return put_integral(value, nbits);
}
#endif
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type put(T value)
{
bool success = true;
unsigned char data[sizeof(T)];
to_bytes(value, data);
for (size_t i = 0UL; i < sizeof(T); ++i)
{
if (!put_integral(uint32_t(data[i]), CHAR_BIT))
{
success = false;
}
}
return success;
}
//***************************************************************************
//***************************************************************************
bool get(bool& value)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_available > 0U)
{
value = get_bit();
success = true;
}
}
return success;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type get(T& value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
bool success = false;
uint_least8_t bits = nbits;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_available >= nbits)
{
value = 0;
// Get the bits from the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
typedef typename etl::make_unsigned<T>::type chunk_t;
chunk_t chunk = get_chunk(mask_width);
nbits -= mask_width;
value |= static_cast<T>(chunk << nbits);
}
success = true;
}
}
// Sign extend if signed type and not already full bit width.
if (etl::is_signed<T>::value && (bits != (CHAR_BIT * sizeof(T))))
{
typedef typename etl::make_signed<T>::type ST;
value = static_cast<T>(etl::sign_extend<ST, ST>(static_cast<ST>(value), bits));
}
return success;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_floating_point<T>::value, bool>::type get(T& value)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
uint_least8_t nbits = CHAR_BIT * sizeof(T);
// Do we have enough bits?
if (bits_available >= nbits)
{
// Temporary storage.
etl::uninitialized_buffer_of<T, 1U> data;
for (size_t i = 0UL; i < sizeof(T); ++i)
{
get(data.raw[i], CHAR_BIT);
}
from_bytes(reinterpret_cast<const unsigned char*>(data.raw), value);
success = true;
}
}
return success;
}
//***************************************************************************
//***************************************************************************
size_t size() const
{
size_t s = char_index;
// Current byte is used?
if (bits_available_in_char != CHAR_BIT)
{
++s;
}
return s;
}
//***************************************************************************
//***************************************************************************
size_t bits() const
{
return (length_chars * CHAR_BIT) - bits_available;
}
//***************************************************************************
//***************************************************************************
const_iterator begin() const
{
return pdata;
}
//***************************************************************************
//***************************************************************************
const_iterator end() const
{
return pdata + size();
}
private:
//***************************************************************************
//***************************************************************************
bool put_integral(uint32_t value, uint_least8_t nbits)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_available >= nbits)
{
// Send the bits to the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint32_t mask = ((1U << mask_width) - 1U) << nbits;
// uint32_t mask = ((uint32_t(1U) << mask_width) - 1U) << nbits;
// Normalise the chunk to the low bits (>> nbits), then left-align
// it within the bits still free in the current char.
// Chunks are never larger than one char.
uint32_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
put_chunk(static_cast<unsigned char>(chunk), mask_width);
}
success = true;
}
}
return success;
}
#if ETL_USING_64BIT_TYPES
//***************************************************************************
//***************************************************************************
bool put_integral(uint64_t value, uint_least8_t nbits)
{
bool success = false;
if (pdata != ETL_NULLPTR)
{
// Do we have enough bits?
if (bits_available >= nbits)
{
// Send the bits to the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
uint64_t mask = ((uint64_t(1U) << mask_width) - 1U) << nbits;
// Normalise the chunk to the low bits (>> nbits), then left-align
// it within the bits still free in the current char.
// Chunks are never larger than one char.
uint64_t chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
put_chunk(static_cast<unsigned char>(chunk), mask_width);
}
success = true;
}
}
return success;
}
#endif
//***************************************************************************
//***************************************************************************
void put_chunk(unsigned char chunk, unsigned char nbits)
{
// Clear if new byte.
if (bits_available_in_char == 8U)
{
pdata[char_index] = 0U;
}
pdata[char_index] |= chunk;
step(nbits);
}
//***************************************************************************
//***************************************************************************
unsigned char get_chunk(unsigned char nbits)
{
unsigned char value = static_cast<unsigned char>(pdata[char_index]);
value >>= (bits_available_in_char - nbits);
unsigned char mask;
if (nbits == CHAR_BIT)
{
mask = etl::integral_limits<unsigned char>::max;
}
else
{
mask = static_cast<unsigned char>((1U << nbits) - 1);
}
value &= mask;
step(nbits);
return value;
}
//***************************************************************************
//***************************************************************************
bool get_bit()
{
bool result = (static_cast<unsigned char>(pdata[char_index]) & (1U << (bits_available_in_char - 1U))) != 0U;
step(1U);
return result;
}
//***************************************************************************
//***************************************************************************
template <typename T>
void from_bytes(const unsigned char* data, T& value)
{
etl::uninitialized_buffer_of<T, 1U> temp;
// Network to host.
if (etl::endianness::value() == etl::endian::little)
{
etl::reverse_copy(data, data + sizeof(T), reinterpret_cast<unsigned char*>(temp.raw));
}
else
{
etl::copy(data, data + sizeof(T), reinterpret_cast<unsigned char*>(temp.raw));
}
value = *reinterpret_cast<T*>(temp.raw);
}
//***************************************************************************
//***************************************************************************
template <typename T>
void to_bytes(T value, unsigned char* data)
{
unsigned char* pf = reinterpret_cast<unsigned char*>(&value);
// Host to network.
if (etl::endianness::value() == etl::endian::little)
{
etl::reverse_copy(pf, pf + sizeof(T), data);
}
else
{
etl::copy(pf, pf + sizeof(T), data);
}
}
//***************************************************************************
//***************************************************************************
void step(unsigned char nbits)
{
bits_available_in_char -= nbits;
if (bits_available_in_char == 0)
{
++char_index;
bits_available_in_char = 8;
}
bits_available -= nbits;
}
unsigned char* pdata;
size_t length_chars;
unsigned char bits_available_in_char;
size_t char_index;
size_t bits_available;
};
//***************************************************************************
//***************************************************************************
class bit_stream_writer
{
public:
typedef char value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef etl::span<value_type> callback_parameter_type;
typedef etl::delegate<void(callback_parameter_type)> callback_type;
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_writer(const etl::span<char, Length>& span_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
etl::endian byte_order_ = etl::endian::big)
: pdata(span_.begin())
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
, callback(callback_)
{
restart();
}
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_writer(const etl::span<unsigned char, Length>& span_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<char*>(span_.begin()))
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
, callback(callback_)
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream_writer(void* begin_, void* end_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<char*>(begin_))
, length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<unsigned char*>(begin_), reinterpret_cast<unsigned char*>(end_))))
, bit_order(bit_order_)
, byte_order(byte_order_)
, callback(callback_)
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream_writer(void* begin_, size_t length_chars_, etl::bit_order bit_order_, callback_type callback_ = callback_type(),
etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<char*>(begin_))
, length_chars(length_chars_)
, bit_order(bit_order_)
, byte_order(byte_order_)
, callback(callback_)
{
restart();
}
//***************************************************************************
//***************************************************************************
void restart()
{
bits_available_in_char = CHAR_BIT;
char_index = 0U;
bits_available = capacity_bits();
}
//***************************************************************************
//***************************************************************************
size_t capacity_bytes() const
{
return length_chars;
}
//***************************************************************************
//***************************************************************************
size_t capacity_bits() const
{
return length_chars * CHAR_BIT;
}
//***************************************************************************
//***************************************************************************
bool empty() const
{
return (available_bits() == capacity_bits());
}
//***************************************************************************
//***************************************************************************
bool full() const
{
return (available_bits() == 0U);
}
//***************************************************************************
//***************************************************************************
void write_unchecked(bool value)
{
unsigned char chunk = value ? 1 : 0;
write_data<unsigned char>(chunk, 1);
}
//***************************************************************************
//***************************************************************************
bool write(bool value)
{
bool success = (available<1U>() > 0U);
if (success)
{
write_unchecked(value);
}
return success;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, void>::type write_unchecked(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
typedef typename etl::unsigned_type<T>::type unsigned_t;
write_data<unsigned_t>(static_cast<unsigned_t>(value), nbits);
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type write(T value, uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
bool success = (available(nbits) > 0U);
if (success)
{
write_unchecked(value, nbits);
}
return success;
}
//***************************************************************************
//***************************************************************************
bool skip(size_t nbits)
{
bool success = (nbits <= available_bits());
if (success)
{
while (nbits > bits_available_in_char)
{
step(bits_available_in_char);
nbits -= bits_available_in_char;
}
if (nbits != 0U)
{
step(static_cast<unsigned char>(nbits));
}
}
return success;
}
//***************************************************************************
//***************************************************************************
size_t size_bytes() const
{
size_t s = char_index;
// Is the current byte partially used?
if (bits_available_in_char != CHAR_BIT)
{
++s;
}
return s;
}
//***************************************************************************
//***************************************************************************
size_t size_bits() const
{
return capacity_bits() - available_bits();
}
//***************************************************************************
//***************************************************************************
template <size_t Nbits>
size_t available() const
{
return bits_available / Nbits;
}
//***************************************************************************
//***************************************************************************
template <typename T>
size_t available() const
{
return available<CHAR_BIT * sizeof(T)>();
}
//***************************************************************************
//***************************************************************************
size_t available(size_t nbits) const
{
return bits_available / nbits;
}
//***************************************************************************
//***************************************************************************
size_t available_bits() const
{
return bits_available;
}
//***************************************************************************
//***************************************************************************
iterator begin()
{
return pdata;
}
//***************************************************************************
//***************************************************************************
const_iterator begin() const
{
return pdata;
}
//***************************************************************************
//***************************************************************************
const_iterator cbegin() const
{
return pdata;
}
//***************************************************************************
//***************************************************************************
iterator end()
{
return pdata + size_bytes();
}
//***************************************************************************
//***************************************************************************
const_iterator end() const
{
return pdata + size_bytes();
}
//***************************************************************************
//***************************************************************************
const_iterator cend() const
{
return pdata + size_bytes();
}
//***************************************************************************
//***************************************************************************
etl::span<char> used_data()
{
return etl::span<char>(pdata, pdata + size_bytes());
}
//***************************************************************************
//***************************************************************************
etl::span<const char> used_data() const
{
return etl::span<const char>(pdata, pdata + size_bytes());
}
//***************************************************************************
//***************************************************************************
etl::span<char> data()
{
return etl::span<char>(pdata, pdata + length_chars);
}
//***************************************************************************
//***************************************************************************
etl::span<const char> data() const
{
return etl::span<const char>(pdata, pdata + length_chars);
}
//***************************************************************************
//***************************************************************************
void flush()
{
if (callback.is_valid())
{
if (bits_available_in_char != 0U)
{
char_index = 1U; // Indicate that the first char is actually 'full'.
flush_full_bytes();
}
restart();
}
}
//***************************************************************************
//***************************************************************************
void set_callback(callback_type callback_)
{
callback = callback_;
}
//***************************************************************************
//***************************************************************************
callback_type get_callback() const
{
return callback;
}
private:
//***************************************************************************
//***************************************************************************
template <typename T>
void write_data(T value, uint_least8_t nbits)
{
ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_writer::write_data: nbits too large"));
// Apply the byte order (endianness).
// Only meaningful when writing the full width of the type.
if ((byte_order == etl::endian::little) && (nbits == (CHAR_BIT * sizeof(T))))
{
value = etl::reverse_bytes(value);
}
// Apply the bit order.
if (bit_order == etl::bit_order::lsb_first)
{
value = etl::reverse_bits(value);
value = value >> ((CHAR_BIT * sizeof(T)) - nbits);
}
// Send the bits to the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
nbits -= mask_width;
T mask = ((T(1U) << mask_width) - 1U) << nbits;
// Normalise the chunk to the low bits (>> nbits), then left-align
// it within the bits still free in the current char.
// Chunks are never larger than one char.
T chunk = ((value & mask) >> nbits) << (bits_available_in_char - mask_width);
write_chunk(static_cast<char>(chunk), mask_width);
}
if (callback.is_valid())
{
flush_full_bytes();
}
}
//***************************************************************************
//***************************************************************************
void write_chunk(char chunk, unsigned char nbits)
{
// Clear if new byte.
if (bits_available_in_char == CHAR_BIT)
{
pdata[char_index] = 0U;
}
pdata[char_index] |= chunk;
step(nbits);
}
//***************************************************************************
//***************************************************************************
void flush_full_bytes()
{
// Is the first byte fully filled?
if (char_index > 0U)
{
callback(callback_parameter_type(pdata, pdata + char_index));
bits_available = CHAR_BIT * length_chars;
if (bits_available_in_char != 0U)
{
// Move a partially filled last byte to the start of the buffer.
pdata[0] = pdata[char_index];
bits_available -= (CHAR_BIT - bits_available_in_char);
}
char_index = 0U;
}
}
//***************************************************************************
//***************************************************************************
void step(unsigned char nbits)
{
bits_available_in_char -= nbits;
if (bits_available_in_char == 0)
{
++char_index;
bits_available_in_char = CHAR_BIT;
}
bits_available -= nbits;
}
char* const pdata;
const size_t length_chars;
const etl::bit_order bit_order;
const etl::endian byte_order;
unsigned char bits_available_in_char;
size_t char_index;
size_t bits_available;
callback_type callback;
};
//***************************************************************************
//***************************************************************************
inline void write_unchecked(etl::bit_stream_writer& stream, bool value)
{
stream.write_unchecked(value);
}
//***************************************************************************
//***************************************************************************
inline bool write(etl::bit_stream_writer& stream, bool value)
{
return stream.write(value);
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, void>::type write_unchecked(etl::bit_stream_writer& stream, const T& value,
uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
stream.write_unchecked(value, nbits);
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value, bool>::type write(etl::bit_stream_writer& stream, const T& value,
uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
return stream.write(value, nbits);
}
//***************************************************************************
//***************************************************************************
class bit_stream_reader
{
public:
typedef char value_type;
typedef const char* const_iterator;
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_reader(const etl::span<char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(span_.begin())
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_reader(const etl::span<unsigned char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<const char*>(span_.begin()))
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_reader(const etl::span<const char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(span_.begin())
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
template <size_t Length>
bit_stream_reader(const etl::span<const unsigned char, Length>& span_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<const char*>(span_.begin()))
, length_chars(span_.size_bytes())
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream_reader(const void* begin_, const void* end_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<const char*>(begin_))
, length_chars(static_cast<size_t>(etl::distance(reinterpret_cast<const char*>(begin_), reinterpret_cast<const char*>(end_))))
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
bit_stream_reader(const void* begin_, size_t length_, etl::bit_order bit_order_, etl::endian byte_order_ = etl::endian::big)
: pdata(reinterpret_cast<const char*>(begin_))
, length_chars(length_)
, bit_order(bit_order_)
, byte_order(byte_order_)
{
restart();
}
//***************************************************************************
//***************************************************************************
void restart()
{
bits_available_in_char = CHAR_BIT;
char_index = 0U;
bits_available = CHAR_BIT * length_chars;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_same<bool, T>::value, bool>::type read_unchecked()
{
return get_bit();
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_same<bool, T>::value, etl::optional<bool> >::type read()
{
etl::optional<bool> result;
if (bits_available > 0U)
{
result = read_unchecked<bool>();
}
return result;
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if< etl::is_integral<T>::value && !etl::is_same<bool, T>::value, T>::type read_unchecked(uint_least8_t nbits = CHAR_BIT
* sizeof(T))
{
typedef typename etl::unsigned_type<T>::type unsigned_t;
T value = static_cast<T>(read_value<unsigned_t>(nbits, etl::is_signed<T>::value));
return static_cast<T>(value);
}
//***************************************************************************
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_integral<T>::value && !etl::is_same<bool, T>::value, etl::optional<T> >::type
read(uint_least8_t nbits = CHAR_BIT * sizeof(T))
{
etl::optional<T> result;
// Do we have enough bits?
if (bits_available >= nbits)
{
result = read_unchecked<T>(nbits);
}
return result;
}
//***************************************************************************
//***************************************************************************
size_t size_bytes() const
{
return length_chars;
}
//***************************************************************************
//***************************************************************************
size_t size_bits() const
{
return length_chars * CHAR_BIT;
}
//***************************************************************************
//***************************************************************************
const_iterator begin() const
{
return pdata;
}
//***************************************************************************
//***************************************************************************
const_iterator cbegin() const
{
return pdata;
}
//***************************************************************************
//***************************************************************************
const_iterator end() const
{
return pdata + size_bytes();
}
//***************************************************************************
//***************************************************************************
const_iterator cend() const
{
return pdata + size_bytes();
}
//***************************************************************************
//***************************************************************************
etl::span<const char> data() const
{
return etl::span<const char>(pdata, pdata + length_chars);
}
//***************************************************************************
//***************************************************************************
bool skip(size_t nbits)
{
bool success = (nbits <= bits_available);
if (success)
{
while (nbits > bits_available_in_char)
{
nbits -= bits_available_in_char;
step(bits_available_in_char);
}
if (nbits != 0U)
{
step(static_cast<unsigned char>(nbits));
}
}
return success;
}
private:
//***************************************************************************
//***************************************************************************
template <typename T>
T read_value(uint_least8_t nbits, bool is_signed)
{
ETL_ASSERT(nbits <= (CHAR_BIT * sizeof(T)), ETL_ERROR_GENERIC("bit_stream_reader::read_value: nbits too large"));
T value = 0;
uint_least8_t bits = nbits;
// Get the bits from the stream.
while (nbits != 0)
{
unsigned char mask_width = static_cast<unsigned char>(etl::min(nbits, bits_available_in_char));
T chunk = get_chunk(mask_width);
nbits -= mask_width;
value |= static_cast<T>(chunk << nbits);
}
if (bit_order == etl::bit_order::lsb_first)
{
value = value << ((CHAR_BIT * sizeof(T)) - bits);
value = etl::reverse_bits(value);
}
// Apply the byte order (endianness).
// Only meaningful when reading the full width of the type.
if ((byte_order == etl::endian::little) && (bits == (CHAR_BIT * sizeof(T))))
{
value = etl::reverse_bytes(value);
}
if (is_signed && (bits != (CHAR_BIT * sizeof(T))))
{
value = etl::sign_extend<T, T>(value, bits);
}
return value;
}
//***************************************************************************
//***************************************************************************
unsigned char get_chunk(unsigned char nbits)
{
unsigned char value = static_cast<unsigned char>(pdata[char_index]);
value >>= (bits_available_in_char - nbits);
unsigned char mask;
if (nbits == CHAR_BIT)
{
mask = etl::integral_limits<unsigned char>::max;
}
else
{
mask = static_cast<unsigned char>((1U << nbits) - 1);
}
value &= mask;
step(nbits);
return value;
}
//***************************************************************************
//***************************************************************************
bool get_bit()
{
bool result = (static_cast<unsigned char>(pdata[char_index]) & (1U << (bits_available_in_char - 1U))) != 0U;
step(1U);
return result;
}
//***************************************************************************
//***************************************************************************
void step(unsigned char nbits)
{
bits_available_in_char -= nbits;
if (bits_available_in_char == 0)
{
++char_index;
bits_available_in_char = 8;
}
bits_available -= nbits;
}
const char* pdata;
size_t length_chars;
const etl::bit_order bit_order;
const etl::endian byte_order;
unsigned char bits_available_in_char;
size_t char_index;
size_t bits_available;
};
//***************************************************************************
//***************************************************************************
template <typename T>
T read_unchecked(etl::bit_stream_reader& stream)
{
return stream.read_unchecked<T>();
}
template <typename T>
T read_unchecked(etl::bit_stream_reader& stream, uint_least8_t nbits)
{
return stream.read_unchecked<T>(nbits);
}
//***************************************************************************
//***************************************************************************
template <typename T>
etl::optional<T> read(etl::bit_stream_reader& stream)
{
return stream.read<T>();
}
template <typename T>
etl::optional<T> read(etl::bit_stream_reader& stream, uint_least8_t nbits)
{
return stream.read<T>(nbits);
}
//***************************************************************************
//***************************************************************************
template <>
inline bool read_unchecked<bool>(etl::bit_stream_reader& stream)
{
return stream.read_unchecked<bool>();
}
//***************************************************************************
//***************************************************************************
template <>
inline etl::optional<bool> read<bool>(etl::bit_stream_reader& stream)
{
return stream.read<bool>();
}
} // namespace etl
#include "private/minmax_pop.h"
#endif
algorithm.h
binary.h
etl::bit_stream_reader
Reads bit streams.
Definition bit_stream.h:1068
etl::bit_stream_reader::read
etl::enable_if< etl::is_same< bool, T >::value, etl::optional< bool > >::type read()
For bool types.
Definition bit_stream.h:1173
etl::bit_stream_reader::end
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:1252
etl::bit_stream_reader::cend
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:1260
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const etl::span< char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1078
etl::bit_stream_reader::size_bits
size_t size_bits() const
Returns the number of bits in the stream buffer.
Definition bit_stream.h:1228
etl::bit_stream_reader::read_unchecked
etl::enable_if< etl::is_integral< T >::value &&!etl::is_same< bool, T >::value, T >::type read_unchecked(uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:1189
etl::bit_stream_reader::skip
bool skip(size_t nbits)
Definition bit_stream.h:1278
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const etl::span< const unsigned char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1117
etl::bit_stream_reader::read
etl::enable_if< etl::is_integral< T >::value &&!etl::is_same< bool, T >::value, etl::optional< T > >::type read(uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:1204
etl::bit_stream_reader::restart
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:1153
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const etl::span< const char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1104
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const etl::span< unsigned char, Length > &span_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:1091
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const void *begin_, const void *end_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from range.
Definition bit_stream.h:1129
etl::bit_stream_reader::bit_stream_reader
bit_stream_reader(const void *begin_, size_t length_, etl::bit_order bit_order_, etl::endian byte_order_=etl::endian::big)
Construct from begin and length.
Definition bit_stream.h:1141
etl::bit_stream_reader::cbegin
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:1244
etl::bit_stream_reader::read_unchecked
etl::enable_if< etl::is_same< bool, T >::value, bool >::type read_unchecked()
For bool types.
Definition bit_stream.h:1164
etl::bit_stream_reader::data
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:1268
etl::bit_stream_reader::begin
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:1236
etl::bit_stream_reader::size_bytes
size_t size_bytes() const
Returns the number of bytes in the stream buffer.
Definition bit_stream.h:1220
etl::bit_stream_writer
Writes bits streams.
Definition bit_stream.h:548
etl::bit_stream_writer::write
etl::enable_if< etl::is_integral< T >::value, bool >::type write(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:696
etl::bit_stream_writer::size_bytes
size_t size_bytes() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:737
etl::bit_stream_writer::write_unchecked
etl::enable_if< etl::is_integral< T >::value, void >::type write_unchecked(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:685
etl::bit_stream_writer::used_data
etl::span< const char > used_data() const
Returns a span of the used portion of the stream.
Definition bit_stream.h:854
etl::bit_stream_writer::write
bool write(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:669
etl::bit_stream_writer::size_bits
size_t size_bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:753
etl::bit_stream_writer::available_bits
size_t available_bits() const
The number of bits left in the stream.
Definition bit_stream.h:790
etl::bit_stream_writer::cend
const_iterator cend() const
Returns end of the stream.
Definition bit_stream.h:838
etl::bit_stream_writer::bit_stream_writer
bit_stream_writer(void *begin_, void *end_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from range.
Definition bit_stream.h:590
etl::bit_stream_writer::get_callback
callback_type get_callback() const
Gets the function to call after every write.
Definition bit_stream.h:903
etl::bit_stream_writer::empty
bool empty() const
Returns true if the bitsteam indexes have been reset.
Definition bit_stream.h:644
etl::bit_stream_writer::bit_stream_writer
bit_stream_writer(void *begin_, size_t length_chars_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from begin and length.
Definition bit_stream.h:604
etl::bit_stream_writer::end
iterator end()
Returns end of the stream.
Definition bit_stream.h:822
etl::bit_stream_writer::set_callback
void set_callback(callback_type callback_)
Sets the function to call after every write.
Definition bit_stream.h:895
etl::bit_stream_writer::available
size_t available() const
Definition bit_stream.h:763
etl::bit_stream_writer::data
etl::span< char > data()
Returns a span of whole the stream.
Definition bit_stream.h:862
etl::bit_stream_writer::full
bool full() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:652
etl::bit_stream_writer::skip
bool skip(size_t nbits)
Definition bit_stream.h:713
etl::bit_stream_writer::capacity_bits
size_t capacity_bits() const
Returns the maximum capacity in bits.
Definition bit_stream.h:636
etl::bit_stream_writer::used_data
etl::span< char > used_data()
Returns a span of the used portion of the stream.
Definition bit_stream.h:846
etl::bit_stream_writer::bit_stream_writer
bit_stream_writer(const etl::span< char, Length > &span_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:561
etl::bit_stream_writer::capacity_bytes
size_t capacity_bytes() const
Returns the maximum capacity in bytes.
Definition bit_stream.h:628
etl::bit_stream_writer::data
etl::span< const char > data() const
Returns a span of whole the stream.
Definition bit_stream.h:870
etl::bit_stream_writer::restart
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:618
etl::bit_stream_writer::write_unchecked
void write_unchecked(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:660
etl::bit_stream_writer::flush
void flush()
Flush the last byte, if partially filled, to the callback, if valid.
Definition bit_stream.h:878
etl::bit_stream_writer::cbegin
const_iterator cbegin() const
Returns start of the stream.
Definition bit_stream.h:814
etl::bit_stream_writer::available
size_t available(size_t nbits) const
Definition bit_stream.h:782
etl::bit_stream_writer::end
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:830
etl::bit_stream_writer::begin
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:806
etl::bit_stream_writer::begin
iterator begin()
Returns start of the stream.
Definition bit_stream.h:798
etl::bit_stream_writer::bit_stream_writer
bit_stream_writer(const etl::span< unsigned char, Length > &span_, etl::bit_order bit_order_, callback_type callback_=callback_type(), etl::endian byte_order_=etl::endian::big)
Construct from span.
Definition bit_stream.h:576
etl::bit_stream::get
etl::enable_if< etl::is_integral< T >::value, bool >::type get(T &value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:241
etl::bit_stream::put
etl::enable_if< etl::is_integral< T >::value, bool >::type put(T value, uint_least8_t nbits=CHAR_BIT *sizeof(T))
For integral types.
Definition bit_stream.h:172
etl::bit_stream::put
bool put(int64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(int64_t))
For 64bit integral types.
Definition bit_stream.h:181
etl::bit_stream::put
etl::enable_if< etl::is_floating_point< T >::value, bool >::type put(T value)
For floating point types.
Definition bit_stream.h:199
etl::bit_stream::restart
void restart()
Sets the indexes back to the beginning of the stream.
Definition bit_stream.h:133
etl::bit_stream::size
size_t size() const
Returns the number of bytes used in the stream.
Definition bit_stream.h:314
etl::bit_stream::bits
size_t bits() const
Returns the number of bits used in the stream.
Definition bit_stream.h:330
etl::bit_stream::bit_stream
bit_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:95
etl::bit_stream::put
bool put(uint64_t value, uint_least8_t nbits=CHAR_BIT *sizeof(uint64_t))
For 64bit integral types.
Definition bit_stream.h:189
etl::bit_stream::bit_stream
bit_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:105
etl::bit_stream::get
etl::enable_if< etl::is_floating_point< T >::value, bool >::type get(T &value)
For floating point types.
Definition bit_stream.h:283
etl::bit_stream::at_end
bool at_end() const
Returns true if the bitsteam indexes have reached the end.
Definition bit_stream.h:143
etl::bit_stream::put
bool put(bool value)
Writes a boolean to the stream.
Definition bit_stream.h:151
etl::bit_stream::bit_stream
bit_stream()
Default constructor.
Definition bit_stream.h:85
etl::bit_stream::get
bool get(bool &value)
For bool types.
Definition bit_stream.h:220
etl::bit_stream::set_stream
void set_stream(void *begin_, size_t length_)
Construct from begin and length.
Definition bit_stream.h:115
etl::bit_stream::set_stream
void set_stream(void *begin_, void *end_)
Construct from range.
Definition bit_stream.h:125
etl::bit_stream::end
const_iterator end() const
Returns end of the stream.
Definition bit_stream.h:346
etl::bit_stream::begin
const_iterator begin() const
Returns start of the stream.
Definition bit_stream.h:338
etl::delegate
Declaration.
Definition delegate_cpp03.h:191
etl::span
Span - Fixed Extent.
Definition span.h:208
delegate.h
endianness.h
enum_type.h
error_handler.h
exception.h
etl::uninitialized_buffer_of
Definition memory.h:3153
etl::reverse_bits
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value &&(etl::integral_limits< T >::bits==16U), T >::type reverse_bits(T value)
Definition binary.h:542
etl::reverse_bytes
ETL_CONSTEXPR14 etl::enable_if< etl::is_integral< T >::value &&etl::is_unsigned< T >::value &&(etl::integral_limits< T >::bits==16U), T >::type reverse_bytes(T value)
Definition binary.h:745
etl::sign_extend
ETL_CONSTEXPR14 TReturn sign_extend(TValue value)
Definition binary.h:273
etl::endian
Definition endianness.h:100
ETL_ASSERT
#define ETL_ASSERT(b, e)
Definition error_handler.h:511
etl::optional
Definition optional.h:1238
ETL_DECLARE_ENUM_TYPE
#define ETL_DECLARE_ENUM_TYPE(TypeName, ValueType)
Definition enum_type.h:90
integral_limits.h
iterator.h
limits.h
memory.h
minmax_pop.h
minmax_push.h
etl
Definition absolute.h:40
etl::data
ETL_CONSTEXPR TContainer::pointer data(TContainer &container)
Definition iterator.h:1470
etl::read_unchecked< bool >
bool read_unchecked< bool >(etl::bit_stream_reader &stream)
Read an unchecked bool from a stream.
Definition bit_stream.h:1445
etl::read
etl::optional< T > read(etl::bit_stream_reader &stream)
Read a checked type from a stream.
Definition bit_stream.h:1430
etl::write_unchecked
void write_unchecked(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:1026
etl::size
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1434
etl::get
T & get(array< T, Size > &a)
Definition array.h:1158
etl::read< bool >
etl::optional< bool > read< bool >(etl::bit_stream_reader &stream)
Read a bool from a stream.
Definition bit_stream.h:1454
etl::read_unchecked
T read_unchecked(etl::bit_stream_reader &stream)
Read an unchecked type from a stream.
Definition bit_stream.h:1415
etl::write
bool write(etl::bit_stream_writer &stream, bool value)
Definition bit_stream.h:1035
nullptr.h
optional.h
platform.h
span.h
etl::bit_order
Definition bit_stream.h:59
etl::bit_order::enum_type
enum_type
Definition bit_stream.h:61
etl::bit_order::lsb_first
@ lsb_first
Least significant bit first.
Definition bit_stream.h:62
etl::bit_order::msb_first
@ msb_first
Most significant bit first.
Definition bit_stream.h:63
etl::is_signed
is_signed
Definition type_traits.h:458
etl::type
type_traits.h