Skip to content

Commit 4cb3379

Browse files
committed
Add bit_stream_measurer
1 parent 529a4e4 commit 4cb3379

File tree

7 files changed

+430
-17
lines changed

7 files changed

+430
-17
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.25)
2-
project(nalchi VERSION 0.1.2)
2+
project(nalchi VERSION 0.1.3)
33

44
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
55

include/nalchi/bit_stream.hpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,159 @@ class bit_stream_writer final
546546
NALCHI_API void do_flush_word_unchecked();
547547
};
548548

549+
/// @brief Measures the bytes `bit_stream_writer` will use.
550+
///
551+
/// This never actually writes any data. \n
552+
/// Instead, it only measures how many bytes `bit_stream_writer` would use. \n
553+
/// You can use this to measure the required space for the `bit_stream_writer`.
554+
class bit_stream_measurer final
555+
{
556+
public:
557+
using size_type = bit_stream_writer::size_type; ///< Size type representing number of bits and bytes.
558+
559+
private:
560+
size_type _logical_used_bits = 0;
561+
562+
public:
563+
/// @brief Deleted copy constructor.
564+
bit_stream_measurer(const bit_stream_measurer&) = delete;
565+
566+
/// @brief Deleted copy assignment operator.
567+
auto operator=(const bit_stream_measurer&) -> bit_stream_measurer& = delete;
568+
569+
/// @brief Constructs a `bit_stream_measurer` instance.
570+
NALCHI_API bit_stream_measurer() = default;
571+
572+
public:
573+
/// @brief Gets the number of used (measured) bytes.
574+
/// @return Number of used (measured) bytes.
575+
NALCHI_API auto used_bytes() const -> size_type;
576+
577+
/// @brief Gets the number of used (measured) bits.
578+
/// @return Number of used (measured) bits.
579+
NALCHI_API auto used_bits() const -> size_type
580+
{
581+
return _logical_used_bits;
582+
}
583+
584+
public:
585+
/// @brief Restarts the measure from zero.
586+
NALCHI_API void restart()
587+
{
588+
_logical_used_bits = 0;
589+
}
590+
591+
public:
592+
/// @brief Fake-writes some arbitrary data to the bit stream.
593+
/// @param data Pointer to the arbitrary data.
594+
/// @param size Size in bytes of the data.
595+
/// @return The stream itself.
596+
NALCHI_API auto write([[maybe_unused]] const void* data, size_type size) -> bit_stream_measurer&
597+
{
598+
_logical_used_bits += 8 * size;
599+
return *this;
600+
}
601+
602+
/// @brief Fake-writes an integral value to the bit stream.
603+
/// @tparam Int Integer type.
604+
/// @param data Data to fake-write.
605+
/// @param min Minimum value allowed for @p data.
606+
/// @param max Maximum value allowed for @p data.
607+
/// @return The stream itself.
608+
template <std::integral Int>
609+
auto write([[maybe_unused]] Int data, Int min = std::numeric_limits<Int>::min(),
610+
Int max = std::numeric_limits<Int>::max()) -> bit_stream_measurer&
611+
{
612+
using UInt = make_unsigned_allow_bool_t<Int>;
613+
614+
// Convert `data` to `value`.
615+
const int bits = std::bit_width(static_cast<UInt>(((UInt)max) - ((UInt)min)));
616+
617+
// Adjust used bits
618+
_logical_used_bits += static_cast<size_type>(bits);
619+
620+
return *this;
621+
}
622+
623+
/// @brief Fake-writes a float value to the bit stream.
624+
/// @param data Data to fake-write.
625+
/// @return The stream itself.
626+
NALCHI_API auto write(float data) -> bit_stream_measurer&
627+
{
628+
_logical_used_bits += static_cast<size_type>(8 * sizeof(data));
629+
return *this;
630+
}
631+
632+
/// @brief Fake-writes a double value to the bit stream.
633+
/// @param data Data to fake-write.
634+
/// @return The stream itself.
635+
NALCHI_API auto write(double data) -> bit_stream_measurer&
636+
{
637+
_logical_used_bits += static_cast<size_type>(8 * sizeof(data));
638+
return *this;
639+
}
640+
641+
/// @brief Fake-writes a string view to the bit stream.
642+
/// @tparam CharT Underlying character type of `std::basic_string_view`.
643+
/// @tparam CharTraits Char traits for `CharT`.
644+
/// @param str String to fake-write.
645+
/// @return The stream itself.
646+
template <character CharT, typename CharTraits>
647+
auto write(std::basic_string_view<CharT, CharTraits> str) -> bit_stream_measurer&
648+
{
649+
// Fake-write a prefix of length prefix.
650+
_logical_used_bits += bit_stream_writer::STR_LEN_PREFIX_PREFIX_BITS;
651+
652+
// Get the length of the string.
653+
const auto len = str.length();
654+
655+
// Fake-write a length prefix.
656+
if (len <= std::numeric_limits<std::uint8_t>::max())
657+
{
658+
_logical_used_bits += (8 * sizeof(std::uint8_t));
659+
}
660+
else if (len <= std::numeric_limits<std::uint16_t>::max())
661+
{
662+
_logical_used_bits += (8 * sizeof(std::uint16_t));
663+
}
664+
else if (len <= std::numeric_limits<std::uint32_t>::max())
665+
{
666+
_logical_used_bits += (8 * sizeof(std::uint32_t));
667+
}
668+
else // len <= std::numeric_limits<std::uint64_t>::max()
669+
{
670+
_logical_used_bits += (8 * sizeof(std::uint64_t));
671+
}
672+
673+
// Fake-write the string payload.
674+
_logical_used_bits += static_cast<size_type>(8 * len * sizeof(CharT));
675+
676+
return *this;
677+
}
678+
679+
/// @brief Fake-writes a string to the bit stream.
680+
/// @tparam CharT Underlying character type of `std::basic_string`.
681+
/// @tparam CharTraits Char traits for `CharT`.
682+
/// @tparam Allocator Underlying allocator for `std::basic_string`.
683+
/// @param str String to fake-write.
684+
/// @return The stream itself.
685+
template <character CharT, typename CharTraits, typename Allocator>
686+
auto write(const std::basic_string<CharT, CharTraits, Allocator>& str) -> bit_stream_measurer&
687+
{
688+
return write(std::basic_string_view<CharT, CharTraits>(str));
689+
}
690+
691+
/// @brief Fake-writes a null-terminated string to the bit stream.
692+
/// @tparam CharT Character type of the null-terminated string.
693+
/// @param str String to fake-write.
694+
/// @return The stream itself.
695+
template <character CharT>
696+
auto write(const CharT* str) -> bit_stream_measurer&
697+
{
698+
return write(std::basic_string_view<CharT>(str));
699+
}
700+
};
701+
549702
/// @brief Helper stream to read bits from your buffer.
550703
///
551704
/// Its design is based on the articles by Glenn Fiedler, see:

include/nalchi/bit_stream_flat.hpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,113 @@ NALCHI_FLAT_API bool nalchi_bit_stream_writer_write_utf16_string(nalchi::bit_str
247247
/// @return `true` if writing has been successful, otherwise `false`.
248248
NALCHI_FLAT_API bool nalchi_bit_stream_writer_write_utf32_string(nalchi::bit_stream_writer* self, const char32_t* str);
249249

250+
/// @brief Constructs a `bit_stream_measurer` instance.
251+
NALCHI_FLAT_API nalchi::bit_stream_measurer* nalchi_bit_stream_measurer_construct();
252+
253+
/// @brief Destroys a `bit_stream_measurer` instance.
254+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_destroy(nalchi::bit_stream_measurer* self);
255+
256+
/// @brief Gets the number of used (measured) bytes.
257+
/// @return Number of used (measured) bytes.
258+
NALCHI_FLAT_API auto nalchi_bit_stream_measurer_used_bytes(const nalchi::bit_stream_measurer* self)
259+
-> nalchi::bit_stream_measurer::size_type;
260+
261+
/// @brief Gets the number of used (measured) bits.
262+
/// @return Number of used (measured) bits.
263+
NALCHI_FLAT_API auto nalchi_bit_stream_measurer_used_bits(const nalchi::bit_stream_measurer* self)
264+
-> nalchi::bit_stream_measurer::size_type;
265+
266+
/// @brief Restarts the measure from zero.
267+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_restart(nalchi::bit_stream_measurer* self);
268+
269+
/// @brief Fake-writes some arbitrary data to the bit stream.
270+
/// @param data Pointer to the arbitrary data.
271+
/// @param size Size in bytes of the data.
272+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_bytes(nalchi::bit_stream_measurer* self, const void* data,
273+
nalchi::bit_stream_measurer::size_type size);
274+
275+
/// @brief Fake-writes an bool value to the bit stream.
276+
/// @param data Data to fake-write.
277+
/// @param min Minimum value allowed for @p data.
278+
/// @param max Maximum value allowed for @p data.
279+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_bool(nalchi::bit_stream_measurer* self, bool data);
280+
281+
/// @brief Fake-writes a `std::int8_t` value to the bit stream.
282+
/// @param data Data to fake-write.
283+
/// @param min Minimum value allowed for @p data.
284+
/// @param max Maximum value allowed for @p data.
285+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_s8(nalchi::bit_stream_measurer* self, std::int8_t data, std::int8_t min, std::int8_t max);
286+
287+
/// @brief Fake-writes a `std::uint8_t` value to the bit stream.
288+
/// @param data Data to fake-write.
289+
/// @param min Minimum value allowed for @p data.
290+
/// @param max Maximum value allowed for @p data.
291+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_u8(nalchi::bit_stream_measurer* self, std::uint8_t data, std::uint8_t min, std::uint8_t max);
292+
293+
/// @brief Fake-writes a `std::int16_t` value to the bit stream.
294+
/// @param data Data to fake-write.
295+
/// @param min Minimum value allowed for @p data.
296+
/// @param max Maximum value allowed for @p data.
297+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_s16(nalchi::bit_stream_measurer* self, std::int16_t data, std::int16_t min, std::int16_t max);
298+
299+
/// @brief Fake-writes a `std::uint16_t` value to the bit stream.
300+
/// @param data Data to fake-write.
301+
/// @param min Minimum value allowed for @p data.
302+
/// @param max Maximum value allowed for @p data.
303+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_u16(nalchi::bit_stream_measurer* self, std::uint16_t data, std::uint16_t min, std::uint16_t max);
304+
305+
/// @brief Fake-writes a `std::int32_t` value to the bit stream.
306+
/// @param data Data to fake-write.
307+
/// @param min Minimum value allowed for @p data.
308+
/// @param max Maximum value allowed for @p data.
309+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_s32(nalchi::bit_stream_measurer* self, std::int32_t data, std::int32_t min, std::int32_t max);
310+
311+
/// @brief Fake-writes a `std::uint32_t` value to the bit stream.
312+
/// @param data Data to fake-write.
313+
/// @param min Minimum value allowed for @p data.
314+
/// @param max Maximum value allowed for @p data.
315+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_u32(nalchi::bit_stream_measurer* self, std::uint32_t data, std::uint32_t min, std::uint32_t max);
316+
317+
/// @brief Fake-writes a `std::int64_t` value to the bit stream.
318+
/// @param data Data to fake-write.
319+
/// @param min Minimum value allowed for @p data.
320+
/// @param max Maximum value allowed for @p data.
321+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_s64(nalchi::bit_stream_measurer* self, std::int64_t data, std::int64_t min, std::int64_t max);
322+
323+
/// @brief Fake-writes a `std::uint64_t` value to the bit stream.
324+
/// @param data Data to fake-write.
325+
/// @param min Minimum value allowed for @p data.
326+
/// @param max Maximum value allowed for @p data.
327+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_u64(nalchi::bit_stream_measurer* self, std::uint64_t data, std::uint64_t min, std::uint64_t max);
328+
329+
/// @brief Fake-writes a float value to the bit stream.
330+
/// @param data Data to fake-write.
331+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_float(nalchi::bit_stream_measurer* self, float data);
332+
333+
/// @brief Fake-writes a double value to the bit stream.
334+
/// @param data Data to fake-write.
335+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_double(nalchi::bit_stream_measurer* self, double data);
336+
337+
/// @brief Fake-writes a null-terminated ordinary string to the bit stream.
338+
/// @param str String to fake-write.
339+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_ordinary_string(nalchi::bit_stream_measurer* self, const char* str);
340+
341+
/// @brief Fake-writes a null-terminated wide string to the bit stream.
342+
/// @param str String to fake-write.
343+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_wide_string(nalchi::bit_stream_measurer* self, const wchar_t* str);
344+
345+
/// @brief Fake-writes a null-terminated UTF-8 string to the bit stream.
346+
/// @param str String to fake-write.
347+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_utf8_string(nalchi::bit_stream_measurer* self, const char8_t* str);
348+
349+
/// @brief Fake-writes a null-terminated UTF-16 string to the bit stream.
350+
/// @param str String to fake-write.
351+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_utf16_string(nalchi::bit_stream_measurer* self, const char16_t* str);
352+
353+
/// @brief Fake-writes a null-terminated UTF-32 string to the bit stream.
354+
/// @param str String to fake-write.
355+
NALCHI_FLAT_API void nalchi_bit_stream_measurer_write_utf32_string(nalchi::bit_stream_measurer* self, const char32_t* str);
356+
250357
/// @brief Constructs a `bit_stream_reader` instance without a buffer.
251358
///
252359
/// This constructor can be useful if you want to set the buffer afterwards. \n

src/bit_stream.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ NALCHI_API bit_stream_writer::bit_stream_writer(word_type* begin, word_type* end
4242
reset_with(begin, end, logical_bytes_length);
4343
}
4444

45-
NALCHI_API bit_stream_writer::bit_stream_writer(word_type* begin, size_type words_length, size_type logical_bytes_length)
45+
NALCHI_API bit_stream_writer::bit_stream_writer(word_type* begin, size_type words_length,
46+
size_type logical_bytes_length)
4647
{
4748
reset_with(begin, words_length, logical_bytes_length);
4849
}
@@ -179,6 +180,11 @@ NALCHI_API void bit_stream_writer::do_flush_word_unchecked()
179180
_scratch_index = std::max(0, _scratch_index - static_cast<int>(8 * sizeof(word_type)));
180181
}
181182

183+
NALCHI_API auto bit_stream_measurer::used_bytes() const -> size_type
184+
{
185+
return ceil_to_multiple_of<8>(used_bits()) / 8;
186+
}
187+
182188
NALCHI_API bit_stream_reader::bit_stream_reader()
183189
{
184190
reset();
@@ -189,12 +195,14 @@ NALCHI_API bit_stream_reader::bit_stream_reader(std::span<const word_type> buffe
189195
reset_with(buffer, logical_bytes_length);
190196
}
191197

192-
NALCHI_API bit_stream_reader::bit_stream_reader(const word_type* begin, const word_type* end, size_type logical_bytes_length)
198+
NALCHI_API bit_stream_reader::bit_stream_reader(const word_type* begin, const word_type* end,
199+
size_type logical_bytes_length)
193200
{
194201
reset_with(begin, end, logical_bytes_length);
195202
}
196203

197-
NALCHI_API bit_stream_reader::bit_stream_reader(const word_type* begin, size_type words_length, size_type logical_bytes_length)
204+
NALCHI_API bit_stream_reader::bit_stream_reader(const word_type* begin, size_type words_length,
205+
size_type logical_bytes_length)
198206
{
199207
reset_with(begin, words_length, logical_bytes_length);
200208
}
@@ -233,12 +241,14 @@ NALCHI_API void bit_stream_reader::reset_with(std::span<const word_type> buffer,
233241
restart();
234242
}
235243

236-
NALCHI_API void bit_stream_reader::reset_with(const word_type* begin, const word_type* end, size_type logical_bytes_length)
244+
NALCHI_API void bit_stream_reader::reset_with(const word_type* begin, const word_type* end,
245+
size_type logical_bytes_length)
237246
{
238247
reset_with(std::span<const word_type>(begin, end), logical_bytes_length);
239248
}
240249

241-
NALCHI_API void bit_stream_reader::reset_with(const word_type* begin, size_type words_length, size_type logical_bytes_length)
250+
NALCHI_API void bit_stream_reader::reset_with(const word_type* begin, size_type words_length,
251+
size_type logical_bytes_length)
242252
{
243253
reset_with(std::span<const word_type>(begin, words_length), logical_bytes_length);
244254
}

0 commit comments

Comments
 (0)