3#include "nalchi/character.hpp"
4#include "nalchi/export.hpp"
5#include "nalchi/make_unsigned_allow_bool.hpp"
6#include "nalchi/shared_payload.hpp"
18#define NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(ret_val) \
25#define NALCHI_BIT_STREAM_WRITER_FAIL_IF_WRITE_AFTER_FINAL_FLUSH(ret_val) \
35#define NALCHI_BIT_STREAM_FAIL_IF_MIN_MAX_RANGE_INVALID(ret_val) \
45#define NALCHI_BIT_STREAM_WRITER_FAIL_IF_DATA_OUT_OF_RANGE(ret_val) \
48 if (data < min || data > max) \
55#define NALCHI_BIT_STREAM_WRITER_FAIL_IF_STR_OVERFLOW(prefix_bytes, str_len_bytes) \
58 if (_logical_used_bits + STR_LEN_PREFIX_PREFIX_BITS + (8 * (prefix_bytes)) + (8 * (str_len_bytes)) > \
59 _logical_total_bits) \
66#define NALCHI_BIT_STREAM_READER_FAIL_IF_STR_OVERFLOW(str_len_bytes) \
69 if (_logical_used_bits + (8 * (str_len_bytes)) > _logical_total_bits) \
97 static_assert(std::is_unsigned_v<scratch_type>);
98 static_assert(std::is_unsigned_v<word_type>);
101 static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big,
102 "Mixed endian system is not supported");
107 static constexpr size_type STR_LEN_PREFIX_PREFIX_BITS = 2u;
108 static constexpr size_type MIN_STR_LEN_PREFIX_PREFIX = 0u;
109 static constexpr size_type MAX_STR_LEN_PREFIX_PREFIX = 3u;
113 std::span<word_type> _words;
181 NALCHI_API
bool fail() const noexcept
199 NALCHI_API
operator bool() const noexcept
209 return _logical_total_bits / 8;
216 return _logical_total_bits;
227 return _logical_used_bits;
299 return _final_flushed;
317 template <std::
integral SInt>
318 requires(
sizeof(SInt) <=
sizeof(
word_type))
319 auto write(SInt data, SInt min = std::numeric_limits<SInt>::min(), SInt max = std::numeric_limits<SInt>::max())
322 return do_write<true>(data, min, max);
331 template <std::
integral BInt>
332 requires(
sizeof(BInt) >
sizeof(
word_type))
333 auto write(BInt data, BInt min = std::numeric_limits<BInt>::min(), BInt max = std::numeric_limits<BInt>::max())
336 return do_write<true>(data, min, max);
354 template <
character CharT,
typename CharTraits>
357 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
358 NALCHI_BIT_STREAM_WRITER_FAIL_IF_WRITE_AFTER_FINAL_FLUSH(*
this);
361 const auto len = str.length();
365 if (len <= std::numeric_limits<std::uint8_t>::max())
367 NALCHI_BIT_STREAM_WRITER_FAIL_IF_STR_OVERFLOW(
sizeof(std::uint8_t), len *
sizeof(CharT));
368 do_write<false>(
size_type(0), MIN_STR_LEN_PREFIX_PREFIX,
369 MAX_STR_LEN_PREFIX_PREFIX);
370 do_write<false>(
static_cast<std::uint8_t
>(len));
372 else if (len <= std::numeric_limits<std::uint16_t>::max())
374 NALCHI_BIT_STREAM_WRITER_FAIL_IF_STR_OVERFLOW(
sizeof(std::uint16_t), len *
sizeof(CharT));
375 do_write<false>(
size_type(1), MIN_STR_LEN_PREFIX_PREFIX,
376 MAX_STR_LEN_PREFIX_PREFIX);
377 do_write<false>(
static_cast<std::uint16_t
>(len));
379 else if (len <= std::numeric_limits<std::uint32_t>::max())
381 NALCHI_BIT_STREAM_WRITER_FAIL_IF_STR_OVERFLOW(
sizeof(std::uint32_t), len *
sizeof(CharT));
382 do_write<false>(
size_type(2), MIN_STR_LEN_PREFIX_PREFIX,
383 MAX_STR_LEN_PREFIX_PREFIX);
384 do_write<false>(
static_cast<std::uint32_t
>(len));
388 NALCHI_BIT_STREAM_WRITER_FAIL_IF_STR_OVERFLOW(
sizeof(std::uint64_t), len *
sizeof(CharT));
389 do_write<false>(
size_type(3), MIN_STR_LEN_PREFIX_PREFIX,
390 MAX_STR_LEN_PREFIX_PREFIX);
391 do_write<false>(
static_cast<std::uint64_t
>(len));
395 for (
const auto ch : str)
407 template <
character CharT,
typename CharTraits,
typename Allocator>
410 return write(std::basic_string_view<CharT, CharTraits>(str));
417 template <
character CharT>
420 return write(std::basic_string_view<CharT>(str));
431 template <
bool Checked, std::
integral SInt>
432 requires(
sizeof(SInt) <=
sizeof(
word_type))
433 auto do_write(SInt data, SInt min = std::numeric_limits<SInt>::min(), SInt max = std::numeric_limits<SInt>::max())
436 if constexpr (Checked)
438 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
439 NALCHI_BIT_STREAM_WRITER_FAIL_IF_WRITE_AFTER_FINAL_FLUSH(*
this);
440 NALCHI_BIT_STREAM_FAIL_IF_MIN_MAX_RANGE_INVALID(*
this);
441 NALCHI_BIT_STREAM_WRITER_FAIL_IF_DATA_OUT_OF_RANGE(*
this);
444 using UInt = make_unsigned_allow_bool_t<SInt>;
447 const scratch_type value =
static_cast<UInt
>(((UInt)data) - ((UInt)min));
448 const int bits = std::bit_width(
static_cast<UInt
>(((UInt)max) - ((UInt)min)));
450 if constexpr (Checked)
453 if (_logical_used_bits + bits > _logical_total_bits)
461 _scratch |= (value << _scratch_index);
462 _scratch_index += bits;
463 flush_if_scratch_overflow();
466 _logical_used_bits += bits;
478 template <
bool Checked, std::
integral BInt>
479 requires(
sizeof(BInt) >
sizeof(
word_type))
480 auto do_write(BInt data, BInt min = std::numeric_limits<BInt>::min(), BInt max = std::numeric_limits<BInt>::max())
483 if constexpr (Checked)
485 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
486 NALCHI_BIT_STREAM_WRITER_FAIL_IF_WRITE_AFTER_FINAL_FLUSH(*
this);
487 NALCHI_BIT_STREAM_FAIL_IF_MIN_MAX_RANGE_INVALID(*
this);
488 NALCHI_BIT_STREAM_WRITER_FAIL_IF_DATA_OUT_OF_RANGE(*
this);
492 static_assert(
sizeof(BInt) == 2 *
sizeof(
word_type));
494 using UInt = make_unsigned_allow_bool_t<BInt>;
497 const scratch_type value =
static_cast<UInt
>(((UInt)data) - ((UInt)min));
498 const int bits = std::bit_width(
static_cast<UInt
>(((UInt)max) - ((UInt)min)));
500 if constexpr (Checked)
503 if (_logical_used_bits + bits > _logical_total_bits)
512 const int low_bits = std::min(bits,
static_cast<int>(8 *
sizeof(
word_type)));
515 _scratch |= (low << _scratch_index);
516 _scratch_index += low_bits;
517 flush_if_scratch_overflow();
519 const int high_bits = bits - low_bits;
526 _scratch |= (high << _scratch_index);
527 _scratch_index += high_bits;
528 flush_if_scratch_overflow();
532 _logical_used_bits += bits;
538 NALCHI_API
void flush_if_scratch_overflow();
546 NALCHI_API
void do_flush_word_unchecked();
581 return _logical_used_bits;
588 _logical_used_bits = 0;
598 _logical_used_bits += 8 * size;
608 template <std::
integral Int>
609 auto write([[maybe_unused]] Int data, Int min = std::numeric_limits<Int>::min(),
612 using UInt = make_unsigned_allow_bool_t<Int>;
615 const int bits = std::bit_width(
static_cast<UInt
>(((UInt)max) - ((UInt)min)));
618 _logical_used_bits +=
static_cast<size_type>(bits);
628 _logical_used_bits +=
static_cast<size_type>(8 *
sizeof(data));
637 _logical_used_bits +=
static_cast<size_type>(8 *
sizeof(data));
646 template <
character CharT,
typename CharTraits>
650 _logical_used_bits += bit_stream_writer::STR_LEN_PREFIX_PREFIX_BITS;
653 const auto len = str.length();
656 if (len <= std::numeric_limits<std::uint8_t>::max())
658 _logical_used_bits += (8 *
sizeof(std::uint8_t));
660 else if (len <= std::numeric_limits<std::uint16_t>::max())
662 _logical_used_bits += (8 *
sizeof(std::uint16_t));
664 else if (len <= std::numeric_limits<std::uint32_t>::max())
666 _logical_used_bits += (8 *
sizeof(std::uint32_t));
670 _logical_used_bits += (8 *
sizeof(std::uint64_t));
674 _logical_used_bits +=
static_cast<size_type>(8 * len *
sizeof(CharT));
685 template <
character CharT,
typename CharTraits,
typename Allocator>
688 return write(std::basic_string_view<CharT, CharTraits>(str));
695 template <
character CharT>
698 return write(std::basic_string_view<CharT>(str));
719 std::span<const word_type> _words;
774 NALCHI_API
bool fail() const noexcept
792 NALCHI_API
operator bool() const noexcept
802 return _logical_total_bits / 8;
809 return _logical_total_bits;
820 return _logical_used_bits;
879 template <std::
integral SInt>
880 requires(
sizeof(SInt) <=
sizeof(
word_type))
881 auto read(SInt& data, SInt min = std::numeric_limits<SInt>::min(), SInt max = std::numeric_limits<SInt>::max())
884 return do_read<true>(data, min, max);
893 template <std::
integral BInt>
894 requires(
sizeof(BInt) >
sizeof(
word_type))
895 auto read(BInt& data, BInt min = std::numeric_limits<BInt>::min(), BInt max = std::numeric_limits<BInt>::max())
898 return do_read<true>(data, min, max);
922 template <
character CharT,
typename CharTraits,
typename Allocator>
925 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
929 if (len < 0 ||
static_cast<size_type>(len) > max_length)
935 NALCHI_BIT_STREAM_READER_FAIL_IF_STR_OVERFLOW(len *
sizeof(CharT));
957 template <
character CharT>
960 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
964 if (len < 0 ||
static_cast<size_type>(len) > max_length)
970 NALCHI_BIT_STREAM_READER_FAIL_IF_STR_OVERFLOW(len *
sizeof(CharT));
974 do_read<false>(str[i]);
997 NALCHI_API
auto read_string_length() ->
ssize_type;
1006 template <
bool Checked, std::
integral SInt>
1007 requires(
sizeof(SInt) <=
sizeof(
word_type))
1008 auto do_read(SInt& data, SInt min = std::numeric_limits<SInt>::min(), SInt max = std::numeric_limits<SInt>::max())
1011 if constexpr (Checked)
1013 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
1014 NALCHI_BIT_STREAM_FAIL_IF_MIN_MAX_RANGE_INVALID(*
this);
1017 using UInt = make_unsigned_allow_bool_t<SInt>;
1020 const int bits = std::bit_width(
static_cast<UInt
>(((UInt)max) - ((UInt)min)));
1022 if constexpr (Checked)
1025 if (_logical_used_bits + bits > _logical_total_bits)
1033 if (bits > _scratch_bits)
1034 do_fetch_word_unchecked();
1037 UInt value =
static_cast<UInt
>(_scratch & ((((
scratch_type)1) << bits) - 1));
1041 _scratch_bits -= bits;
1044 const SInt conv =
static_cast<SInt
>(((SInt)value) + min);
1046 if constexpr (Checked)
1060 _logical_used_bits += bits;
1072 template <
bool Checked, std::
integral BInt>
1073 requires(
sizeof(BInt) >
sizeof(
word_type))
1074 auto do_read(BInt& data, BInt min = std::numeric_limits<BInt>::min(), BInt max = std::numeric_limits<BInt>::max())
1077 if constexpr (Checked)
1079 NALCHI_BIT_STREAM_RETURN_IF_STREAM_ALREADY_FAILED(*
this);
1080 NALCHI_BIT_STREAM_FAIL_IF_MIN_MAX_RANGE_INVALID(*
this);
1084 static_assert(
sizeof(BInt) == 2 *
sizeof(
word_type));
1086 using UInt = make_unsigned_allow_bool_t<BInt>;
1089 const int bits = std::bit_width(
static_cast<UInt
>(((UInt)max) - ((UInt)min)));
1091 if constexpr (Checked)
1094 if (_logical_used_bits + bits > _logical_total_bits)
1101 const int low_bits = std::min(bits,
static_cast<int>(8 *
sizeof(
word_type)));
1104 if (low_bits > _scratch_bits)
1105 do_fetch_word_unchecked();
1108 UInt value =
static_cast<UInt
>(_scratch & ((((
scratch_type)1) << low_bits) - 1));
1111 _scratch >>= low_bits;
1112 _scratch_bits -= low_bits;
1114 const int high_bits = bits - low_bits;
1118 if (high_bits > _scratch_bits)
1119 do_fetch_word_unchecked();
1122 value |= (
static_cast<UInt
>(_scratch & ((((
scratch_type)1) << high_bits) - 1)) << low_bits);
1125 _scratch >>= high_bits;
1126 _scratch_bits -= high_bits;
1130 const BInt conv =
static_cast<BInt
>(((BInt)value) + min);
1132 if constexpr (Checked)
1146 _logical_used_bits += bits;
1152 NALCHI_API
void do_fetch_word_unchecked();
Measures the bytes bit_stream_writer will use.
Definition bit_stream.hpp:555
auto used_bits() const -> size_type
Gets the number of used (measured) bits.
Definition bit_stream.hpp:579
bit_stream_measurer(const bit_stream_measurer &)=delete
Deleted copy constructor.
auto used_bytes() const -> size_type
Gets the number of used (measured) bytes.
auto write(const std::basic_string< CharT, CharTraits, Allocator > &str) -> bit_stream_measurer &
Fake-writes a string to the bit stream.
Definition bit_stream.hpp:686
auto write(const CharT *str) -> bit_stream_measurer &
Fake-writes a null-terminated string to the bit stream.
Definition bit_stream.hpp:696
auto write(const void *data, size_type size) -> bit_stream_measurer &
Fake-writes some arbitrary data to the bit stream.
Definition bit_stream.hpp:596
bit_stream_measurer()=default
Constructs a bit_stream_measurer instance.
bit_stream_writer::size_type size_type
Size type representing number of bits and bytes.
Definition bit_stream.hpp:557
auto write(float data) -> bit_stream_measurer &
Fake-writes a float value to the bit stream.
Definition bit_stream.hpp:626
auto operator=(const bit_stream_measurer &) -> bit_stream_measurer &=delete
Deleted copy assignment operator.
void restart()
Restarts the measure from zero.
Definition bit_stream.hpp:586
auto write(std::basic_string_view< CharT, CharTraits > str) -> bit_stream_measurer &
Fake-writes a string view to the bit stream.
Definition bit_stream.hpp:647
auto write(Int data, Int min=std::numeric_limits< Int >::min(), Int max=std::numeric_limits< Int >::max()) -> bit_stream_measurer &
Fake-writes an integral value to the bit stream.
Definition bit_stream.hpp:609
auto write(double data) -> bit_stream_measurer &
Fake-writes a double value to the bit stream.
Definition bit_stream.hpp:635
Helper stream to read bits from your buffer.
Definition bit_stream.hpp:708
bit_stream_reader(const bit_stream_reader &)=delete
Deleted copy constructor.
void reset_with(std::span< const word_type > buffer, size_type logical_bytes_length)
Resets the stream with a std::span<word_type> buffer.
bit_stream_writer::scratch_type scratch_type
Internal scratch type to store the temporary scratch data.
Definition bit_stream.hpp:713
void reset()
Resets the stream so that it no longer holds your buffer anymore.
bit_stream_reader(const word_type *begin, size_type words_length, size_type logical_bytes_length)
Constructs a bit_stream_reader instance with a word begin pointer and the word length.
void restart()
Restarts the stream so that it can read from the beginning again.
auto unused_bits() const -> size_type
Gets the number of unused bits in the stream.
Definition bit_stream.hpp:832
auto read(SInt &data, SInt min=std::numeric_limits< SInt >::min(), SInt max=std::numeric_limits< SInt >::max()) -> bit_stream_reader &
Reads an integral value from the bit stream.
Definition bit_stream.hpp:881
void reset_with(const word_type *begin, size_type words_length, size_type logical_bytes_length)
Resets the stream with a word begin pointer and the word length.
auto peek_string_length() -> ssize_type
Peeks the string length prefix from the current stream position.
bool fail() const noexcept
Check if reading from your buffer has been failed or not.
Definition bit_stream.hpp:774
auto operator=(const bit_stream_reader &) -> bit_stream_reader &=delete
Deleted copy assignment operator.
auto read(double &data) -> bit_stream_reader &
Reads a double value from the bit stream.
bit_stream_reader(const word_type *begin, const word_type *end, size_type logical_bytes_length)
Constructs a bit_stream_reader instance with a word range.
auto read(std::basic_string< CharT, CharTraits, Allocator > &str, size_type max_length) -> bit_stream_reader &
Reads a string from the bit stream.
Definition bit_stream.hpp:923
bit_stream_writer::word_type word_type
Internal word type used to read from your buffer.
Definition bit_stream.hpp:715
auto read(float &data) -> bit_stream_reader &
Reads a float value from the bit stream.
auto unused_bytes() const -> size_type
Gets the number of unused bytes in the stream.
Definition bit_stream.hpp:825
void reset_with(const word_type *begin, const word_type *end, size_type logical_bytes_length)
Resets the stream with a word range.
auto total_bits() const -> size_type
Gets the number of total bits in the stream.
Definition bit_stream.hpp:807
auto used_bits() const -> size_type
Gets the number of used bits in the stream.
Definition bit_stream.hpp:818
auto read(BInt &data, BInt min=std::numeric_limits< BInt >::min(), BInt max=std::numeric_limits< BInt >::max()) -> bit_stream_reader &
Reads an integral value from the bit stream.
Definition bit_stream.hpp:895
auto read(void *data, size_type size) -> bit_stream_reader &
Reads some arbitrary data from the bit stream.
auto total_bytes() const -> size_type
Gets the number of total bytes in the stream.
Definition bit_stream.hpp:800
bit_stream_writer::size_type size_type
Size type representing number of bits and bytes.
Definition bit_stream.hpp:710
bit_stream_reader()
Constructs a bit_stream_reader instance without a buffer.
auto read(CharT *str, size_type max_length) -> bit_stream_reader &
Reads a null-terminated string from the bit stream.
Definition bit_stream.hpp:958
auto used_bytes() const -> size_type
Gets the number of used bytes in the stream.
std::make_signed_t< size_type > ssize_type
Signed size type to allow negative error value.
Definition bit_stream.hpp:711
bool operator!() const noexcept
Check if there was an error in the reading to your buffer. This is effectively same as fail().
Definition bit_stream.hpp:783
void set_fail()
Force set the fail flag.
Definition bit_stream.hpp:765
bit_stream_reader(std::span< const word_type > buffer, size_type logical_bytes_length)
Constructs a bit_stream_reader instance with a std::span<word_type> buffer.
Helper stream to write bits to your buffer.
Definition bit_stream.hpp:90
bool fail() const noexcept
Check if writing to your buffer has been failed or not.
Definition bit_stream.hpp:181
auto operator=(const bit_stream_writer &) -> bit_stream_writer &=delete
Deleted copy assignment operator.
void set_fail()
Force set the fail flag.
Definition bit_stream.hpp:172
bit_stream_writer()
Constructs a bit_stream_writer instance without a buffer.
bit_stream_writer(word_type *begin, size_type words_length, size_type logical_bytes_length)
Constructs a bit_stream_writer instance with a word begin pointer and the word length.
void restart()
Restarts the stream so that it can write from the beginning again.
auto unused_bytes() const -> size_type
Gets the number of unused bytes in the stream.
Definition bit_stream.hpp:232
void reset_with(std::span< word_type > buffer, size_type logical_bytes_length)
Resets the stream with a std::span<word_type> buffer.
std::uint64_t scratch_type
Internal scratch type to store the temporary scratch data.
Definition bit_stream.hpp:94
auto used_bits() const -> size_type
Gets the number of used bits in the stream.
Definition bit_stream.hpp:225
bool operator!() const noexcept
Check if there was an error in the writing to your buffer. This is effectively same as fail().
Definition bit_stream.hpp:190
void reset()
Resets the stream so that it no longer holds your buffer anymore.
auto total_bits() const -> size_type
Gets the number of total bits in the stream.
Definition bit_stream.hpp:214
auto flush_final() -> bit_stream_writer &
Flushes the last remaining bytes on the internal scratch buffer to your buffer.
auto total_bytes() const -> size_type
Gets the number of total bytes in the stream.
Definition bit_stream.hpp:207
auto write(SInt data, SInt min=std::numeric_limits< SInt >::min(), SInt max=std::numeric_limits< SInt >::max()) -> bit_stream_writer &
Writes an integral value to the bit stream.
Definition bit_stream.hpp:319
void reset_with(shared_payload buffer, size_type logical_bytes_length)
Resets the stream with a shared_payload buffer.
bit_stream_writer(shared_payload buffer, size_type logical_bytes_length)
Constructs a bit_stream_writer instance with a shared_payload buffer.
auto write(const std::basic_string< CharT, CharTraits, Allocator > &str) -> bit_stream_writer &
Writes a string to the bit stream.
Definition bit_stream.hpp:408
auto write(const CharT *str) -> bit_stream_writer &
Writes a null-terminated string to the bit stream.
Definition bit_stream.hpp:418
auto write(BInt data, BInt min=std::numeric_limits< BInt >::min(), BInt max=std::numeric_limits< BInt >::max()) -> bit_stream_writer &
Writes an integral value to the bit stream.
Definition bit_stream.hpp:333
bit_stream_writer(const bit_stream_writer &)=delete
Deleted copy constructor.
auto used_bytes() const -> size_type
Gets the number of used bytes in the stream.
std::uint32_t size_type
Size type representing number of bits and bytes.
Definition bit_stream.hpp:92
auto write(float data) -> bit_stream_writer &
Writes a float value to the bit stream.
void reset_with(word_type *begin, size_type words_length, size_type logical_bytes_length)
Resets the stream with a word begin pointer and the word length.
auto unused_bits() const -> size_type
Gets the number of unused bits in the stream.
Definition bit_stream.hpp:239
auto write(double data) -> bit_stream_writer &
Writes a double value to the bit stream.
std::uint32_t word_type
Internal word type used to write to your buffer.
Definition bit_stream.hpp:95
bool flushed() const
Checks if flush_final() has been called or not.
Definition bit_stream.hpp:297
bit_stream_writer(std::span< word_type > buffer, size_type logical_bytes_length)
Constructs a bit_stream_writer instance with a std::span<word_type> buffer.
bit_stream_writer(word_type *begin, word_type *end, size_type logical_bytes_length)
Constructs a bit_stream_writer instance with a word range.
auto write(std::basic_string_view< CharT, CharTraits > str) -> bit_stream_writer &
Writes a string view to the bit stream.
Definition bit_stream.hpp:355
auto write(const void *data, size_type size) -> bit_stream_writer &
Writes some arbitrary data to the bit stream.
void reset_with(word_type *begin, word_type *end, size_type logical_bytes_length)
Resets the stream with a word range.
Shared payload to store data to send.
Definition shared_payload.hpp:20