12#ifndef JAU_IO_BIT_STREAM_HPP_
13#define JAU_IO_BIT_STREAM_HPP_
67 constexpr static jau::nsize_t ncount = std::numeric_limits<jau::nsize_t>::max();
68 typedef uint64_t data_type;
83 constexpr static bool useFastPathStream =
true;
84 constexpr static bool useFastPathTypes =
true;
86 std::unique_ptr<ByteStream> m_bytes;
90 data_type m_bitsDataMark;
106 : m_bytes(
std::move(stream)), m_access(access) {
108 validateMode1(access);
114 m_bitCacheSizeRead = 0;
117 m_bitsCountMark = ncount;
119 bool canRead0() const noexcept {
return m_bytes->canRead(); }
120 bool canWrite0() const noexcept {
return m_bytes->canWrite(); }
122 if( !canRead0() && !canWrite0() ) {
133 if( !canRead0() && !canWrite0() ) {
144 [[nodiscard]]
bool writeCache() noexcept {
145 const size_t s = (m_bitCount + 7) >> byte_shift;
149 w = m_bytes->write(&m_bitCache, s);
156 m_bitCacheSizeRead = 0;
162 void fillCache() noexcept {
164 m_bitCacheSizeRead = m_bytes->read(&m_bitCache,
sizeof(data_type)) << byte_shift;
185 if( !validateMode2(access) ) {
192 if( 0 != m_bytes->seek(0) ) {
218 m_bytes->setImmutable();
219 if( 0 != m_bytes->seek(0) ) {
270 if( 0 != m_bitCount ) {
271 if( !writeCache() ) {
292 if(!m_bytes->setMark(readLimit) ) {
295 m_bitsDataMark = m_bitCache;
296 m_bitsCountMark = m_bitCount;
304 uint64_t
markReadLimit() const noexcept {
return m_bytes->markReadLimit(); }
315 if( ncount == m_bitsCountMark || !m_bytes->seekMark() ) {
318 m_bitCache = m_bitsDataMark;
319 m_bitCount = m_bitsCountMark;
363 return m_bitCacheSizeRead - m_bitCount;
383 if ( !m_bytes->isOpen() ) {
386 const size_type streamBitPos = m_bytes->position() << byte_shift;
388 return streamBitPos + m_bitCount;
390 return streamBitPos - m_bitCount;
406 if( newPos == pos0 ) {
408 }
else if( newPos > pos0 ) {
409 return pos0 +
skip(newPos - pos0);
413 if( 0 < m_bitCount && !writeCache() ) {
418 if( 0 != m_bytes->seek(0) ) {
434 if( !
canWrite() && n <= m_bitCount ) {
446 if( 0 < m_bitCount && !writeCache() ) {
453 const size_type n4 = m_bytes->seek(m_bytes->position()+n3);
454 const size_type n5 = n1 - ( n3 << byte_shift );
455 const size_type nX = (n4 << byte_shift) + n5 + m_bitCount;
469 if( m_bitCacheSizeRead >= n5 ) {
470 m_bitCount = m_bitCacheSizeRead - n5;
472 notReadBits = n5 - m_bitCacheSizeRead;
477 DBG_PRINT(
"Bitstream.skip.F_X2: %" PRIu64
", notReadBits %zu - %s", n, (
size_t)notReadBits,
toStringImpl().c_str());
478 return nX - notReadBits;
491 if( 0 < m_bitCount ) {
493 return int((m_bitCache >> (m_bitCacheSizeRead - 1 - m_bitCount)) & data_type(0x01));
496 if( 0 < m_bitCacheSizeRead ) {
497 m_bitCount = m_bitCacheSizeRead - 1;
498 return int(m_bitCache & data_type(0x01));
511 [[nodiscard]]
bool writeBit(uint8_t bit)
noexcept {
515 m_bitCache |= data_type(0x01 & bit) << m_bitCount;
517 if( !writeCache() ) {
521 m_bitCacheSizeRead = m_bitCount;
535 if constexpr ( !useFastPathStream ) {
542 r |= data_type(b) << i;
549 const data_type
m1 = (data_type(1) << n1) - data_type(1);
550 const jau::nsize_t s1 = m_bitCacheSizeRead - m_bitCount;
553 r =
m1 & (m_bitCache >> s1);
558 assert(0 == m_bitCount);
560 if( 0 == m_bitCacheSizeRead ) {
563 const nsize_t n2 = std::min(c, m_bitCacheSizeRead);
564 const data_type
m2 = (data_type(1) << n2) - data_type(1);
565 m_bitCount = m_bitCacheSizeRead - n2;
567 r |= (
m2 & m_bitCache) << n1;
584 if constexpr ( !useFastPathStream ) {
587 if( !
writeBit( uint8_t( (bits >> i) & data_type(0x1) ) ) ) {
596 const data_type
m1 = (data_type(1) << n1) - data_type(1);
600 m_bitCache |= (
m1 & bits) << s1;
602 if( !writeCache() ) {
610 assert(0 == m_bitCount);
613 const data_type
m2 = (data_type(1) << n2) - data_type(1);
616 m_bitCache = (
m2 & (bits >> n1));
618 if( !writeCache() ) {
625 m_bitCacheSizeRead = m_bitCount;
639 if( 0 == m_bitCount && useFastPathTypes ) {
640 return m_bytes->read(bits);
646 bits =
static_cast<uint8_t
>(tmp);
655 if( 0 == m_bitCount && useFastPathTypes ) {
656 return m_bytes->write(bits);
670 if( 0 == m_bitCount && useFastPathTypes ) {
671 return m_bytes->readU16(bits);
677 bits =
static_cast<uint16_t
>(tmp);
690 [[nodiscard]]
bool readSInt16(int16_t& bits)
noexcept {
return readUInt16( *
reinterpret_cast<uint16_t*
>(&bits) ); }
706 if( 0 == m_bitCount && useFastPathTypes ) {
708 return 2 == m_bytes->write(&bits, 2);
721 [[nodiscard]]
bool readU32(uint32_t& bits)
noexcept {
722 if( 0 == m_bitCount && useFastPathTypes ) {
724 if(
canWrite() || 4 != m_bytes->read(&bits, 4) ) {
732 bits =
static_cast<uint32_t
>(tmp);
747 [[nodiscard]]
bool writeU32(uint32_t bits)
noexcept {
754 if( 0 == m_bitCount && useFastPathTypes ) {
756 return m_bytes->write(&bits, 4);
763 std::string s(
"Bitstream[");
769 if( !m_bytes->isOpen() ) {
770 s.append(
" [closed]");
772 s.append(
", order[byte ").append(
jau::to_string(m_bytes->byteOrder()))
774 .append(std::to_string(
position())).append(
" (").append(std::to_string(m_bytes->position()))
775 .append(
" bytes), cache[size ").append(std::to_string(
cachedBitCount())).append(
"/").append(std::to_string(m_bitCacheSizeRead))
776 .append(
", pos ").append(std::to_string(
cachedBitPos()))
782 unsigned nibbles = 0 == bitCount ? 2 : (bitCount + 3) / 4;
783 std::string fmt(
"[%u: 0x%0");
784 fmt.append(std::to_string(nibbles)).append(PRIx64);
Versatile Bitstream implementation supporting:
uint64_t markReadLimit() const noexcept
Returns the readLimit set via setMark().
bool writeUInt16(uint16_t bits) noexcept
Write uint16_t
size_type seek(size_type newPos) noexcept
Sets this stream's bit position.
bool writeU32(uint32_t bits) noexcept
Write uint32_t.
size_type mark() const noexcept
Returns the markpos set via setMark() or ByteStream::npos if unset.
static constexpr size_type npos
Invalid position constant, denoting unset mark() or invalid position.
bool writeUInt8(uint8_t bits) noexcept
Write the given 8 bits via writeBits31(int, int).
std::string toString() const
constexpr jau::nsize_t cachedBitPos() const noexcept
Return the next cached bit position.
bool setAccess(ioaccess_t access) noexcept
Changes the access-mode to write or read and resets position and cache to zero.
constexpr_cxx23 iomode_t mode() const noexcept
bool readSInt16(int16_t &bits) noexcept
Read int16_t.
data_type bitCache()
Returns the 64-bit MaxBitCacheSize cache buffer value.
constexpr jau::nsize_t bitCacheSizeRead() const noexcept
Returns filled read bit-cache-size, i.e.
bool setImmutable() noexcept
Changes the write-mode to read, sets the underlying ByteStream to read-only and resets position and c...
Bitstream(std::unique_ptr< ByteStream > &&stream, ioaccess_t access)
std::string toStringImpl() const
constexpr bool canWrite() const noexcept
Returns true in case stream is in write mode, false if in read mode.
bool writeBit(uint8_t bit) noexcept
Write given bit in least-significant-bit (LSB) first order.
static constexpr jau::nsize_t MaxBitCacheSize
Maximum read bitCacheSizeRead() and fixed 64-bit write cache size.
bool setMark(size_type readLimit) noexcept
Set markpos to current bit-position, allowing the stream to be seekMark().
bool readUInt8(uint8_t &bits) noexcept
Read incoming uint8_t via readBits32().
ByteStream & byteStream()
Returns the used underlying ByteStream.
bool readU32(uint32_t &bits) noexcept
Read uint32_t.
size_type skip(size_type n) noexcept
Skip given number of bits.
bool readUInt16(uint16_t &bits) noexcept
Read uint16_t.
jau::nsize_t readBits64(jau::nsize_t n, data_type &r) noexcept
Read incoming bits in least-significant-bit (LSB) first order.
constexpr jau::nsize_t cachedBitCount() const noexcept
Returns number of cached bits.
static std::string toHexBinaryString(uint64_t v, unsigned bitCount=MaxBitCacheSize)
constexpr ioaccess_t ioaccess() const noexcept
Returns ioaccess_t stream mode.
jau::io::ByteStream::size_type size_type
uint64_t size data type, bit position and count
int readBit() noexcept
Read incoming bit in least-significant-bit (LSB) first order.
void close() noexcept
Closing the underlying stream, implies flush().
constexpr_cxx23 lb_endian_t byteOrder() const noexcept
Returns endian byte-order of stream storage.
bool seekMark() noexcept
Seeks stream bit-position to markpos as set via setMark().
size_type flush() noexcept
Synchronizes underlying ByteStream output stream operations in writeMode(), or does nothing.
jau::nsize_t writeBits64(jau::nsize_t n, data_type bits) noexcept
Write given bits in least-significant-bit (LSB) first order.
size_type position() const noexcept
Returns the bit position in the stream.
uint64_t size_type
uint64_t size data type, bit position and count
static constexpr size_type npos
Invalid position constant, denoting unset mark() or invalid position.
#define DBG_PRINT(...)
Use for environment-variable environment::DEBUG conditional debug messages, prefix '[elapsed_time] De...
static constexpr T bit_mask(size_t n) noexcept
Returns the T bit mask of n-bits, i.e.
constexpr uint16_t bswap(uint16_t const source) noexcept
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
@ native
Identifier for native platform type, one of the above.
std::ostream & operator<<(std::ostream &os, const T v)
constexpr E & write(E &store, const E bits, bool set) noexcept
If set==true, sets the bits in store, i.e.
iomode_t
Stream I/O mode, e.g.
std::string to_string(const ioaccess_t v) noexcept
Return std::string representation of the given ioaccess_t.
ioaccess_t
I/O read or write access.
constexpr size_t log2_byteshift(const size_t bytesize) noexcept
Returns log2(bytesize*8), e.g.
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
std::string toBitString(const void *data, const nsize_t length, const bit_order_t bitOrder=bit_order_t::msb, const PrefixOpt prefix=PrefixOpt::prefix, size_t bit_len=0) noexcept
Produce a binary string representation of the given lsb-first byte values.
constexpr std::string format_string(const std::string_view format, const Args &...args)
Safely returns a (non-truncated) string according to snprintf() formatting rules and variable number ...
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2024 Gothel Software e.K.
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
static const Mat4f m1(m1_0)
static const Mat4f m2(m2_0)