ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
bitbuffer.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_bitbuffer of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace bitbuffer {
9
10//==================================================================================================
11/// An array of integral values used for serializing and deserializing data on bit-level.
12/// While writing and reading bits is performed with associated classes #"BitWriter"
13/// and #"BitReader", this class is responsible for storing the data and transferring
14/// it to an <em>integral</em>-arrays, which may, for example, be written and read to and from
15/// <c>std::[i/o]stream</c> objects.
16/// With this, platform independence is guaranteed (in respect to little/big-endian storage and
17/// similar matters).
18///
19/// This class is abstract (pure virtual), and does not perform the allocation.
20/// With #"BitBuffer", #"BitBufferMA" and #"BitBufferLocal",
21/// three descendants with different allocation strategies are provided.
22/// A customized version may be easily created by implementing pure virtual methods
23/// #".Capacity" and #".EnsureCapacity".
24///
25/// \attention
26/// To avoid the use of virtual function calls bit write operations, methods #".Capacity" and
27/// #".EnsureCapacity" are <b>not invoked automatically!</b>.
28/// In contrast, it is the users' responsibility to invoke these methods (or only
29/// #".EnsureCapacity") before performing data insertions.<br>
30/// This behavior is a design decision to maximize execution performance, hence rather a feature.
31///
32/// Own Implementations have to set field #".data" when reallocating the internal buffer.
33//==================================================================================================
35{
36 public:
37 /// The storage type of bit buffers. This is chosen as being <c>unsigned int</c>, which
38 /// should be the "fasted" integral type for any compiler/platform combination.
39 using TStorage= unsigned int;
40
41 static_assert( bitsof(TStorage) == 32 || bitsof(TStorage) == 64,
42 "Unsupported size of C++ int type" );
43
44 /// Defines a bit position within outer class #"BitBufferBase". A bit position is
45 /// determined by the index in the storage array along with the number of the currently
46 /// written (or read) bit. Types #"BitWriter" and #"BitReader"
47 /// use this type to define their current write (read) position.
48 ///
49 /// Methods #"Encode32" and #"Encode64" shorten the information, by storing the bit position in
50 /// the upper bits of a \e 32, respectively \e 64 bit value. This is useful whenever a
51 /// broader number of bit buffer indices are to be stored. The use case to mention here is
52 /// "lazy decoding of data", where only the index to the bit buffer is kept in memory.)
53 /// positions
54 class Index
55 {
56 #if !DOXYGEN
57 friend class BitBufferBase;
58 friend class BitReader;
59 friend class BitWriter;
60 #endif
61
62 uinteger pos= 0; ///< Index of the current word to read/write.
63 lang::ShiftOpRHS bit= 0; ///< Current bit index in the current word.
64
65 public:
66
67 /// Default constructor initializing members #"pos" and #".bit" to zero.
68 Index() =default;
69
70 /// Constructor
71 /// @param pPos The initial value for member #"pos".
72 /// @param pBit The initial value for member #".bit".
74 : pos(pPos)
75 , bit(pBit) {}
76
77 /// Returns the index of the actual storage word in the buffer.
78 /// @return The index of the current word containing the next bit to read/write.
79 uinteger Pos() const { return pos; }
80
81 /// Returns the number of the actual bit in the actual word of the buffer buffer.
82 /// @return The number of the next bit to read/write.
83 lang::ShiftOpRHS Bit() const { return bit; }
84
85 /// Returns true, if the next bit to read/write is the first of the current storage
86 /// word in the buffer. Alignment of buffers may become important when buffers are
87 /// serialized (e.g., to mass storage devices). Method
88 /// #"BitBufferBase::Terminate;*" may be used to receive an aligned
89 /// index.
90 ///
91 /// @return The result of <c>Bit() == 0</c>.
92 bool IsAligned() const { return bit == 0; }
93
94 /// Sets this index to zero, hence pointing to the first bit in the buffer.
95 void Clear() { pos= 0; bit= 0; }
96
97 /// Returns the size of the memory from given \p{startIdx} to this index occupied by
98 /// the internal storage words of the buffer.
99 ///
100 /// @param startIdx The starting index. Defaults to <c>{0,0}</c>.
101 /// @return The size of the buffer (part) in bytes.
102 integer GetByteOffset( Index startIdx= Index(0, 0) ) const {
103 ALIB_ASSERT_ERROR( startIdx.pos < pos
104 || (startIdx.pos == pos && startIdx.bit < bit), "BITBUFFER",
105 "Given buffer start index is greater than this index." )
106 return integer((pos - startIdx.Pos()) * sizeof(TStorage) );
107 }
108
109 /// Sets this index to point to the word and bit given by a byte offset.<br>
110 /// This method is useful when bit buffers are deserialized from character streams.
111 /// @param byteOffset The position within the buffer in bytes.
112 void SetFromByteOffset( uinteger byteOffset )
113 {
114 pos= byteOffset / sizeof( TStorage );
115 bit= (byteOffset % sizeof( TStorage )) * 8 ;
116 }
117
118 /// Returns the number of bits used in respect to this index.
119 /// @return The number of bits written or read.
121 { return uinteger( pos * bitsof(TStorage) + uinteger(bit) ); }
122
123 /// Encodes this index information into a 32-bit variable by using the upper 5 (or 6)
124 /// bits for the bit index. As a result, the possible value range of index data is
125 /// reduced. The reduction depends on the platform's size of type \c int. In case of
126 /// 32-bit, five bits are needed to store the bit position. In the case of 64-bit,
127 /// six bits are needed.<br>
128 /// As the underlying \e TStorage type changes as well, in both cases, the resulting
129 /// addressable storage bytes is limited to the same value:
130 /// - TStorage 64-bit: <em>2^(32-6) * 8 bytes = 512 megabytes</em>
131 /// - TStorage 32-bit: <em>2^(32-5) * 4 bytes = 512 megabytes</em>
132 ///
133 /// In case bit buffers grow to over half a gigabyte, 64-bit encoding should be performed
134 /// by using alternative method #"Encode64".
135 ///
136 /// @return The encoded index.
137 uint32_t Encode32() {
139 "BITBUFFER", "32bit too narrow for endcoding BitBuffer::Index." )
140 return uint32_t(pos) | (uint32_t(bit) << (31 - lang::Log2OfSize<TStorage>() ));
141 }
142
143 /// Encodes this index information into a 64-bit value by using the upper five (or six)
144 /// bits for the bit index.
145 ///
146 /// @see For a shorter encoding, limited to bit buffer sizes of 512 megabytes,
147 /// see method #"Encode32".
148 ///
149 /// @return The encoded index.
150 uint64_t Encode64()
151 { return uint64_t(pos) | (uint64_t(bit) << (63L - lang::Log2OfSize<TStorage>() )); }
152
153 /// Static method that decodes an index information, encoded with #"Encode32", to an
154 /// instance of this class.
155 ///
156 /// @param code The encoded information.
157 /// @return The decoded index.
158 static
159 Index Decode32(uint32_t code)
160 {
161 return Index { uinteger (code & lang::LowerMask< 31 - lang::Log2OfSize<TStorage>() , uint32_t>() ),
163 }
164
165
166 /// Static method that decodes an index information, encoded with #"Encode64", to an
167 /// instance of this class.
168 ///
169 /// @param code The encoded information.
170 /// @return The decoded index.
171 static
172 Index Decode64(uint64_t code) {
173 return Index{uinteger( code & lang::LowerMask< 63L - lang::Log2OfSize<TStorage>() , uint64_t>() ),
175 }
176
177 /// Comparison operator.
178 ///
179 /// @param rhs The right-hand side argument of the comparison.
180 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
181 bool operator==(const Index& rhs) const { return (pos == rhs.pos) && (bit == rhs.bit); }
182
183 /// Comparison operator.
184 ///
185 /// @param rhs The right-hand side argument of the comparison.
186 /// @return \c true if this object does not equal \p{rhs}, \c false otherwise.
187 bool operator!=(const Index& rhs) const { return !(*this == rhs); }
188
189 /// Comparison operator.
190 ///
191 /// @param rhs The right-hand side argument of the comparison.
192 /// @return \c true if this object is smaller than \p{rhs}, \c false otherwise.
193 bool operator<(const Index& rhs) const {
194 return (pos < rhs.pos) || ((pos == rhs.pos)
195 && (bit < rhs.bit) );
196 }
197
198 /// Comparison operator.
199 ///
200 /// @param rhs The right-hand side argument of the comparison.
201 /// @return \c true if this object is smaller or equal than \p{rhs}, \c false otherwise.
202 bool operator<=(const Index& rhs) const {
203 return (pos < rhs.pos) || ((pos == rhs.pos)
204 && (bit <= rhs.bit) );
205 }
206
207 /// Comparison operator.
208 ///
209 /// @param rhs The right-hand side argument of the comparison.
210 /// @return \c true if this object is greater or equal than \p{rhs}, \c false otherwise.
211 bool operator>=(const Index& rhs) const { return !(*this < rhs); }
212
213 /// Comparison operator.
214 ///
215 /// @param rhs The right-hand side argument of the comparison.
216 /// @return \c true if this object is greater than \p{rhs}, \c false otherwise.
217 bool operator>(const Index& rhs) const { return !(*this <= rhs); }
218 }; // inner struct Index
219
220 protected:
221
222 /// A pointer to the storage. Implementations of this abstract type have to set this field
223 /// when reallocating the internal buffer.
225
226 public:
227 /// Default Constructor (the only one).
228 BitBufferBase() noexcept : data(nullptr) {}
229
230 /// Virtual destructor (does nothing, needed for abstract virtual class).
231 virtual
233
234 /// Virtual function to determine the (currently allocated) capacity.
235 /// @return The size of the internal storage in bits.
237 virtual uinteger Capacity() const =0;
238
239 /// Virtual function to reserve buffer space by optionally increasing the buffer to
240 /// enable the writing of the given bits.
241 ///
242 /// @param bitsRequired The number of bits required.
243 /// @param index The index to which the capacity is currently used.
244 /// @return \c true if the space is available or could be made available,
245 /// \c false otherwise.
247 virtual bool EnsureCapacity( uinteger bitsRequired, BitBufferBase::Index index ) =0;
248
249 /// Returns the storage word at the given position
250 /// @param index The index to read the word from. Note that the bit number in this value is
251 /// ignored.
252 /// @return The word at the given index.
253 TStorage GetWord(const Index& index) const { return data[index.pos]; }
254
255 /// Stores the given \p{value} at the given \p{index}.
256 /// @param index The index to read the word at. Note that the bit number in this value is
257 /// ignored.
258 /// @param value The value to store
259 void SetWord(const Index& index, TStorage value) { data[index.pos]= value; }
260
261 /// Returns the number of remaining bits in this buffer in relation to a given index.
262 /// @param idx An actual writing/reading position.
263 /// @return The number of bits dived remaining in this buffer.
264 uinteger RemainingSize(const Index& idx) const
265 { return Capacity() - idx.CountBits(); }
266
267 /// Returns the start of the internal storage.
268 /// @return A pointer to the data array provided by the decendent types.
269 TStorage* Data() const { return data; }
270
271 /// Returns the memory address of the internal storage word denoted by \p{idx}
272 /// reinterpreted to C++ type <c>char*</c>.
273 /// @param idx The index of the word to point to. The bit position within this index is
274 /// ignored.
275 /// @return A \c char pointer to the internal storage word the given index refers to.
276 char* CharStream( Index idx= Index(0, 0) )
277 { return reinterpret_cast<char*>( &data[idx.pos] ); }
278
279 /// Writes a termination bit of value \c 1 and lets this buffer's index point to the next
280 /// buffer word.\n
281 /// Termination can be undone using the result index of this method with #Unterminate.
282 /// This method should be invoked before serializing a buffer and method
283 /// #Unterminate may be used after deserialization to continue writing to the buffer without
284 /// creating a gap.
285 ///
286 /// @param writerIndex The index to the last bit before termination.
287 ///
288 /// @return The #"BitBufferBase::Index::IsAligned;aligned" index after termination
289 /// which is aligned point to the first bit behind the last used storage word.
290 /// Such index may be later fed into method #Unterminate to undo the termination.
292 Index Terminate (Index writerIndex);
293
294 /// Removes the termination bit found in the word before given \p{terminationIndex}.
295 /// @param terminationIndex The index returned by previous invocation of method #Terminate.
296 ///
297 /// @return The index of the next bit to write to the now unterminated buffer.
299 Index Unterminate(Index terminationIndex);
300
301 /// Converts the internal storage words into the platform-independent
302 /// "Little Endian Encoding", which means it may change the byte order within the storage
303 /// words of the buffer.
304 ///
305 /// This method is recommended to be used before writing buffer contents to a file to
306 /// make files system independent.
307 ///
308 /// \attention The start index needs to be aligned to a storage word. This is asserted
309 /// in debug compilations.
310 /// See method #"Index::IsAligned" for more information.
311 ///
312 /// \note It is recommended to terminate the buffer before using this method.
313 /// and to pass the index returned by method #Terminate as second parameter
314 /// \p{endIndex}.
315 ///
316 /// \see Method #FromLittleEndianEncoding.
317 ///
318 /// @param startIndex The first storage word to convert. (The bit position of the index
319 /// is ignored).
320 /// @param endIndex The first bit behind the storage to be converted. Hence, if the bit
321 /// position within this argument is not \c 0, then the whole word that
322 /// this index points to, will be converted. Otherwise it won't.
324 void ToLittleEndianEncoding( const Index& startIndex,
325 const Index& endIndex );
326
327 /// The counter-method to #ToLittleEndianEncoding.
328 ///
329 /// @param startIndex The first storage word to convert. (The bit position of the index
330 /// is ignored).
331 /// @param endIndex The first bit behind the storage to be converted. Hence, if the bit
332 /// position within this argument is not \c 0, then the whole word that
333 /// this index points to, will be converted. Otherwise it won't.
335 void FromLittleEndianEncoding( const Index& startIndex, const Index& endIndex );
336}; // class BitBufferBase
337
338//==================================================================================================
339/// A bit buffer using dynamic allocation.
340/// \see
341/// - Two alternatives are provided with #"BitBufferMA", which uses
342/// #"alib_mods_contmono;monotonic allocation" and #"BitBufferLocal", which uses
343/// local (stack) memory.
344/// - For this class, a #"alibtools_debug_helpers_gdb;pretty printer" for the
345/// GNU debugger is provided.
346//==================================================================================================
348{
349 protected:
350 /// The vector that holds the data.
351 std::vector<TStorage> storage;
352
353 public:
354 /// Constructor.
355 /// @param initialCapacity The requested initial capacity of the buffer in bits.
356 BitBuffer( uinteger initialCapacity ) { EnsureCapacity(initialCapacity, Index()); }
357
358 /// Returns the (currently allocated) capacity.
359 /// @return The size of the internal storage in bits.
360 virtual uinteger Capacity() const override { return storage.capacity() * bitsof(TStorage); }
361
362 /// Checks if the given required storage space is internally reserved. If not,
363 /// the internal capacity is doubled, or, if more is required, set to the required space.
364 ///
365 /// @param bitsRequired The number of bits required.
366 /// @param idx The index of current buffer use.
367 /// @return \c true if the space is available or could be made available,
368 /// \c false otherwise.
369 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override {
370 uinteger capacityNeeded= (idx.CountBits() + bitsRequired + (bitsof(TStorage) - 1) )
371 / bitsof(TStorage);
372 if( capacityNeeded > storage.capacity() )
373 storage.reserve( (std::max)( capacityNeeded, uinteger(storage.capacity()) * 2 ));
374 data= storage.data();
375
376 return true;
377 }
378}; // class BitBuffer
379
380//==================================================================================================
381/// A bit buffer using #"alib_mods_contmono;monotonic allocation".
382/// \see
383/// Two alternatives are provided with #"BitBuffer" and #"BitBufferLocal".
384//==================================================================================================
386{
387 protected:
388 /// The monotonic allocator used internally to allocate the storage. This is provided
389 /// with construction.
391
392 /// The vector that holds the data.
394
395 public:
396 /// Constructor taking an external monotonic allocator and the initial capacity.
397 /// @param monoAllocator A reference to a monotonic allocator to use to allocate buffer
398 /// storage data.
399 /// @param initialCapacity The requested initial capacity of the buffer in bits.
400 BitBufferMA( MonoAllocator& monoAllocator, uinteger initialCapacity )
401 : ma( monoAllocator )
402 , storage(ma) { EnsureCapacity(initialCapacity, Index()); }
403
404
405 /// Returns the (currently allocated) capacity.
406 /// @return The size of the internal storage in bits.
407 virtual uinteger Capacity() const override { return storage.capacity() * bitsof(TStorage); }
408
409 /// Checks if the given required storage space is internally reserved. If not,
410 /// the internal capacity is doubled, or, if more is required, set to the required space.
411 ///
412 /// @param bitsRequired The number of bits divided required.
413 /// @param idx The index of current buffer use.
414 /// @return \c true if the space is available or could be made available,
415 /// \c false otherwise.
416 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override {
417 uinteger capacityNeeded= (idx.CountBits() + bitsRequired + (bitsof(TStorage) - 1) )
418 / bitsof(TStorage);
419 if( capacityNeeded > storage.capacity() )
420 storage.reserve( (std::max)( capacityNeeded, uinteger(storage.capacity()) * 2 ));
421 data= storage.data();
422
423 return true;
424 }
425
426 /// Returns the internal monotonic allocator for external use.
427 /// @return The monotonic allocator given on construction.
429}; // class BitBufferMA
430
431//==================================================================================================
432/// A bit buffer using local storage, which means a fixed size internal array.
433/// If used as function member, the storage is located on the stack and hence its size has
434/// platform-specific limitations.<br>
435/// This class is useful to read and write smaller pieces of data, for example, header information
436/// of binary data files which furthermore are filled/loaded with bit buffers using of other memory
437/// allocations.
438/// \see
439/// Two alternatives are provided with #"BitBuffer" and #"BitBufferMA".
440/// @tparam TCapacity The number of bits to reserve internally
441//==================================================================================================
442template<uinteger TCapacity>
444{
445 protected:
446 /// The array that holds the data.
447 TStorage storage[ (TCapacity + bitsof(TStorage) - 1) / bitsof(TStorage) ];
448
449 public:
450 /// Constructor.
451 BitBufferLocal() noexcept { data= storage; }
452
453 /// Returns the (in this case fixed size!) capacity.
454 /// @return The size of the internal storage in bits.
455 virtual uinteger Capacity() const override { return TCapacity; }
456
457 /// Checks if the given required storage space is internally reserved.
458 /// If not, in debug compilations an \alib_assertion is raised because this is a fixed size
459 /// buffer.
460 ///
461 /// @param bitsRequired The number of bits required.
462 /// @param idx The index of current buffer use.
463 /// @return \c true if the space is available or could be made available,
464 /// \c false otherwise.
465 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override {
466 uinteger capacityNeeded= idx.CountBits() + bitsRequired;
467 if( capacityNeeded > TCapacity ) {
468 ALIB_ERROR("BITBUFFER", "Local bit buffer cannot expand its capacity" )
469 return false;
470 }
471
472 return true;
473 }
474}; // class BitBufferLocal
475
476
477//==================================================================================================
478/// Non-instantiatable base class for types #"BitWriter" and #"BitReader".
479//==================================================================================================
481{
482 protected:
483 BitBufferBase& bb; ///< The bit buffer to write into. Provided on construction.
484 BitBufferBase::Index idx; ///< The current reading/writing index within #bb.
485
486 /// Protected constructor, used by derived classes only.
487 /// @param buffer The bit buffer to work on.
488 explicit BitRWBase( BitBufferBase& buffer )
489 : bb ( buffer ) {}
490
491 public:
492 /// Retrieves the internal bit buffer.
493 /// @return The buffer the derived reader or writer works with.
494 BitBufferBase& GetBuffer() const { return bb; }
495
496 /// Returns a copy of the current index in the bit buffer in respect to writing or
497 /// reading progress of derived classes #"BitWriter" #"BitReader".
498 /// Such index elements may be passed to methods
499 /// #"BitWriter::Reset(const BitBufferBase::Index&)" and
500 /// #"BitReader::Reset(const BitBufferBase::Index&)"
501 /// @return The index of the next bit to write.
503
504 /// Invokes #"BitBufferBase::Index::CountBits;*" on the index returned by #GetIndex.
505 /// @return The number of bits currently read from or written to the buffer.
506 uinteger Usage() const { return idx.CountBits(); }
507
508 /// Invokes #"BitBufferBase::RemainingSize;*" on the internal bit buffer, passing
509 /// the result of #GetIndex.
510 /// @return The number of bits dived by 8 remaining in this buffer.
511 uinteger RemainingSize() const { return bb.RemainingSize(idx); }
512
513};
514
515//==================================================================================================
516/// Writes bits into a #"BitBufferBase".
517//==================================================================================================
518class BitWriter : public BitRWBase
519{
520 /// Local type alias (shortcut)
522
523 /// The current word, which is partly written and not stored in buffer, yet.
525
526 public:
527 /// Constructs a bit writer operating on the given bit buffer.
528 /// @param buffer The buffer to write to (starting at the beginning).
529 explicit BitWriter( BitBufferBase& buffer )
530 : BitRWBase( buffer ) { word= 0; }
531
532 /// Constructs a bit writer operating on the given bit buffer, starting to write at the
533 /// given #"BitBufferBase::Index".
534 /// @param buffer The buffer to write to.
535 /// @param index An index providing the postion of the first bit to (over-) write in
536 /// \p{buffer}.
537 explicit BitWriter( BitBufferBase& buffer, const BitBufferBase::Index& index )
538 : BitRWBase ( buffer )
539 {
540 idx= index;
541 word= bb.GetWord(idx) & lang::LowerMask<TStorage>( idx.bit );
542 }
543
544 /// Destructs a bit writer. Invokes #Flush().
546
547 /// Resets the internal index of this writer to the start of the bit buffer.
548 void Reset() { idx = BitBufferBase::Index(); word= 0; }
549
550 /// Resets the internal index of this writer to the given one.
551 /// @param index The position of the next bit in the buffer to write to.
552 void Reset( const BitBufferBase::Index& index ) {
553 idx.pos= index.pos;
554 idx.bit= index.bit;
555 word= bb.GetWord(idx) & lang::LowerMask<TStorage>(idx.bit );
556 }
557
558 /// Writes the last word of bits into the underlying buffer.
559 /// This method has to be called before writing the buffer to a file or similar.
560 /// The method is automatically invoked on destruction.
561 void Flush() { bb.SetWord(idx, word); }
562
563 #if DOXYGEN
564 /// Writes the given integral value with the given number of bits to the stream.
565 /// \note
566 /// Internally, different template functions selected with keyword \c requires
567 /// for the different integral types exist.
568 ///
569 /// \see
570 /// This method uses a template parameter for the number of bits to write.
571 /// A slightly slower, non-templated version is available with
572 /// #WriteBits<TValue, TMaskValue>( ShiftOpRHS, TValue)
573 /// which is to be used when the value is determined only at run-time.
574 ///
575 /// @tparam TWidth The number of bits in \p{value} to write.
576 /// @tparam TValue The type of \p{value} to write. (Deduced from parameter \p{value}.)
577 /// @tparam TMaskValue Determines if bits beyond \p{width} of given \p{value} may be set and
578 /// have to be masked out.
579 /// Defaults to \c false.
580 /// @param value The value to write.
581 template<ShiftOpRHS TWidth, typename TIntegral, bool TMaskValue= false>
582 void WriteBits( TIntegral value );
583 #else
584 // Version 1/2: #Bits to write are less or equal to internal buffer width
585 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
586 requires ( std::unsigned_integral<TValue>
587 && !std::same_as < TValue, bool>
588 && ( TWidth <= bitsof(TStorage) ) )
589 void WriteBits(TValue value ) {
590 static_assert(bitsof(TValue) >= TWidth, "Fixed size given greater than value type.");
591 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
592 ALIB_ASSERT_ERROR( TMaskValue
593 || TWidth == bitsof(TValue)
594 || value == (value & lang::LowerMask<TValue>(TWidth) ), "BITBUFFER",
595 "Upper bits dirty while TMaskValue flag not set." )
596
597 if constexpr ( (TWidth < bitsof(TValue)) && TMaskValue )
598 value&= lang::LowerMask<TWidth, TValue >();
599
600 word|= TStorage(value) << idx.bit ;
601 idx.bit+= TWidth;
602 if(idx.bit >= bitsof(TStorage) ) {
603 bb.SetWord(idx, word);
604 idx.pos++;
605 word= 0;
606 idx.bit-= bitsof(TStorage);
607 if( idx.bit )
608 word|= (TStorage(value) >> (TWidth - idx.bit) );
609 } }
610
611 // Version 2/2: #Bits to write is greater than internal buffer width
612 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
613 requires ( std::unsigned_integral<TValue>
614 && !std::same_as < TValue, bool>
615 && ( TWidth > bitsof(TStorage) ) )
616 void WriteBits(TValue value ) {
617 static_assert(bitsof(TValue) >= TWidth, "Fixed size given greater than value type.");
618 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
619 ALIB_ASSERT_ERROR( TMaskValue
620 || TWidth == bitsof(TValue)
621 || value == (value & lang::LowerMask<TValue>(TWidth) ), "BITBUFFER",
622 "Upper bits dirty while TMaskValue not set." )
623
624 if constexpr ( (TWidth < bitsof(TValue)) && TMaskValue )
625 value&= lang::LowerMask<TWidth, TValue>();
626
627 word|= (TStorage(value) << idx.bit);
628 lang::ShiftOpRHS bitsWritten= bitsof(TStorage) - idx.bit;
629 value>>= bitsWritten;
630 while(true) { // the loop is at least hit once and bit is 0! (but not written in bit)
631 bb.SetWord(idx, word);
632 idx.pos++;
633 word= TStorage(value);
634 bitsWritten+= bitsof(TStorage);
635 if(bitsWritten >= TWidth )
636 break;
637
638 value>>= bitsof(TStorage);
639 }
640
641 idx.bit= (idx.bit + TWidth) % bitsof(TStorage);
642 if(idx.bit == 0 ) { // next buffer value reached?
643 bb.SetWord(idx, word);
644 idx.pos++;
645 word= 0;
646 } }
647
648 // Helper-versions for signed and bool
649 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
650 requires ( std::signed_integral<TValue> && !std::same_as<TValue, bool> )
651 void WriteBits(TValue value) {
652 using TUI= typename std::make_unsigned<TValue>::type;
653 WriteBits<TWidth, TUI, TMaskValue>( static_cast<TUI>( value ) );
654 }
655
656 template<typename TValue>
657 requires ( std::same_as<TValue, bool> )
658 void WriteBits(TValue value)
659 { WriteBits<1, unsigned int, false>( static_cast<unsigned int>( value ) ); }
660
661 #endif // doxygen
662
663
664// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
665// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
666#if DOXYGEN
667 /// Writes the given integral value with the given number of bits to the stream.
668 /// \note Internally, two versions of this method, selected with keyword \c requires,
669 /// for different integral types exist.
670 /// \see
671 /// A method that uses a template parameter for the number of bits to write, is
672 /// available with #WriteBits<TWidth,TIntegral>(TIntegral).
673 /// This might be slightly faster and should be used instead of this method, whenever the
674 /// number of bits to write is known at compilation time.
675 ///
676 /// @tparam TValue The integral type of the value to write.
677 /// (Deduced from parameter \p{value}.)
678 /// @tparam TMaskValue Determines if bits beyond \p{width} of given \p{value} may be set and
679 /// have to be masked out. Defaults to \c false.
680 /// @param width The number of bits in \p{value}.
681 /// @param value The value to write.
682 template<typename TValue, bool TMaskValue= false>
683 requires ( std::integral<TValue> && ( sizeof(TValue) <= sizeof(TStorage) ) )
684 void WriteBits(lang::ShiftOpRHS width, TValue value);
685#else
686 template<typename TValue, bool TMaskValue= false>
687 requires ( std::integral<TValue> && ( sizeof(TValue) <= sizeof(TStorage) ) )
688 void WriteBits(lang::ShiftOpRHS width, TValue value) {
689 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
690 ALIB_ASSERT_ERROR( width <= bitsof(TValue),
691 "BITBUFFER", "BitBufferBase::Write: Width too high: ", width )
692
693 ALIB_ASSERT_ERROR( TMaskValue
694 || width>=bitsof(TValue)
695 || value == (value & lang::LowerMask<TValue>(width) ),
696 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
697
698 if constexpr (TMaskValue)
699 if( width < bitsof(TValue) )
700 value&= lang::LowerMask<TValue>(width);
701
702 word|= TStorage(value) << idx.bit ;
703 idx.bit+= width;
704 if(idx.bit >= bitsof(TStorage) ) {
705 bb.SetWord(idx, word);
706 idx.pos++;
707 word= 0;
708 idx.bit-= bitsof(TStorage);
709 if( idx.bit )
710 word|= ( TStorage(value) >> (width - idx.bit) );
711 } }
712
713 template<typename TValue, bool TMaskValue= false>
714 requires ( std::integral<TValue> && ( sizeof(TValue) > sizeof(TStorage) ) )
715 void WriteBits(lang::ShiftOpRHS width, TValue value) {
716 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
717 ALIB_ASSERT_ERROR( width <= bitsof(TValue), "BITBUFFER",
718 "BitBufferBase::Write: Width too high: ", width )
719 ALIB_ASSERT_ERROR( TMaskValue
720 || width==bitsof(TValue)
721 || value == (value & lang::LowerMask<TValue>(width) ),
722 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
723
724 if constexpr (TMaskValue)
725 if( width <= bitsof(TValue) )
726 value&= lang::LowerMask<TValue>(width);
727
728 if( width <= bitsof(TStorage) ) {
729 word|= TStorage(value) << idx.bit ;
730 idx.bit+= width;
731 if(idx.bit >= bitsof(TStorage) ) {
732 bb.SetWord(idx, word);
733 idx.pos++;
734 word= 0;
736 if( idx.bit )
737 word|= ( TStorage(value) >> (width - idx.bit) );
738 }
739 } else {
740 word|= (TStorage(value) << idx.bit);
741 lang::ShiftOpRHS bitsWritten= bitsof(TStorage) - idx.bit;
742 value>>= bitsWritten;
743 while(true) { // the loop is at least hit once and bit is 0! (but not written in bit)
744 bb.SetWord(idx, word);
745 idx.pos++;
746 word= TStorage(value);
747 bitsWritten+= bitsof(TStorage);
748 if(bitsWritten >= width )
749 break;
750 value>>= bitsof(TStorage);
751 }
752 idx.bit= (idx.bit + width) % bitsof(TStorage);
753 if(idx.bit == 0 ) { // next buffer value reached?
754 bb.SetWord(idx, word);
755 idx.pos++;
756 word= 0;
757 } } }
758#endif
759
760 /// Writes the given unsigned integral value to the stream by writing lower values
761 /// with smaller sizes. The general assumption behind this is that lower values are more frequent
762 /// and the average written size is less than the unencode size - despite the overhead needed
763 /// to write information about how a value is encoded.
764 ///
765 /// The encoding for \e unsigned integrals is as follows:
766 /// - For byte value types, a single bit <c>'0'</c> is written if the value is below \c 8,
767 /// followed by the three bits containing the value. Otherwise, a single bit <c>'1'</c> is
768 /// written, followed by the full 8 bits.
769 /// - For all other value types (16-, 32- and 64-bit) the number of bytes needed is written
770 /// first (one bit in the case of 16-bit values, two bits in the case of 32-bit values
771 /// and three bits in the case of 64 bit values), and then the corresponding amount of
772 /// full bytes are written.
773 ///
774 /// \e Signed integrals are converted to unsigned integrals using the sometimes called
775 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
776 /// positive and uneven. This way, the least significant bit becomes the sign bit.
777 /// The advantage of this approach is that small numbers, negative or positive,
778 /// remain small in respect to their bitwise representation.<p>
779 /// The conversion hence is as follows:
780 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
781 ///
782 /// @tparam TUIntegral The type of the given unsigned integral.
783 /// @param value The value to write.
784 template<typename TUIntegral>
785 requires ( std::unsigned_integral<TUIntegral> && !std::same_as< TUIntegral, bool> )
786 void WriteInt( TUIntegral value )
787 {
788 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
789 writeUIntegral(value);
790 }
791
792 /// Converts the given \e signed integral to an unsigned one using the so-called
793 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
794 /// positive and uneven. This way, the least significant bit becomes the sign bit.
795 /// The advantage of this approach is that small numbers, negative or positive,
796 /// remain small in respect to their bitwise representation.<p>
797 /// The conversion hence is as follows:
798 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
799 ///
800 /// Then calls #"BitWriter::WriteInt(TUIntegral)".
801 /// @tparam TSIntegral The type of the given signed integral.
802 /// @param value The value to write.
803 template<typename TSIntegral>
804 requires ( std::signed_integral<TSIntegral> && !std::same_as< TSIntegral, bool> )
805 void WriteInt( TSIntegral value ) {
806 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
807 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
808 writeUIntegral( value >= 0 ? TUnsigned( value << 1)
809 : TUnsigned( (TUnsigned(-(value+ 1)) << 1) | 1 ) );
810 }
811
812 protected:
813
814 /// Internal method that writes a unsigned 8-bit value.
815 /// @param value The value to write.
816 ALIB_DLL void writeUIntegral( uint8_t value );
817
818 /// Internal method that writes a unsigned 16-bit value.
819 /// @param value The value to write.
820 ALIB_DLL void writeUIntegral( uint16_t value );
821
822 /// Internal method that writes a unsigned 32-bit value.
823 /// @param value The value to write.
824 ALIB_DLL void writeUIntegral( uint32_t value );
825
826 /// Internal method that writes a unsigned 64-bit value.
827 /// @param value The value to write.
828 ALIB_DLL void writeUIntegral( uint64_t value );
829
830}; // class BitWriter
831
832
833//==================================================================================================
834/// Reads bits from a #"BitBufferBase".
835//==================================================================================================
836class BitReader : public BitRWBase
837{
838 protected:
839 /// Local type alias (shortcut)
841
842 /// The current word, which is partly read and shifted to start with current bit.
844
845 public:
846 /// Constructs a bit reader using the given bit buffer and starting to read at the beginning.
847 /// @param buffer The buffer to read from.
848 explicit BitReader( BitBufferBase& buffer )
849 : BitRWBase( buffer ) { word= bb.GetWord(idx); }
850
851
852 /// Constructs a bit reader using the given bit buffer, starting to read at the
853 /// given #"BitBufferBase::Index".
854 /// @param buffer The buffer to read from.
855 /// @param index An index providing the postion of the first bit to read in \p{buffer}.
856 explicit BitReader( BitBufferBase& buffer, const BitBufferBase::Index& index )
857 : BitRWBase( buffer ) {
858 idx.pos= index.pos;
859 idx.bit= index.bit;
860 word= bb.GetWord(idx) >> idx.bit;
861 }
862
863 /// Destructs a bit reader. In debug compilations an \alib_assertion is raised if the
864 /// read operation passed the end of the underlying buffer was performed.
866 {
867 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER",
868 "BitBufferBase overflow detected. Ensure a higher capacity" )
869 }
870
871 /// Resets this reader to the start of the bit buffer.
872 void Reset() {
873 idx.pos= 0;
874 idx.bit= 0;
875 word= bb.GetWord(idx);
876 }
877
878 /// Resets this reader to the given index position and calls #Sync().
879 /// @param index The next read position.
880 void Reset( const BitBufferBase::Index& index ) {
881 idx.pos= index.pos;
882 idx.bit= index.bit;
883 Sync();
884 }
885
886 /// Re-reads the currently fetched storage word from the memory.
887 /// \note This method is not needed in common use cases and implemented solely for the
888 /// purpose to support unit-tests which write and write in parallel to the same
889 /// bit buffer.
890 /// @return A reference to this \c BitReader to allow concatenated operations.
891 BitReader& Sync() { word= bb.GetWord(idx) >> idx.bit; return *this; }
892
893// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
894// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
895#if DOXYGEN
896 /// Reads the given number of bits from the stream into the given unsigned integral value.
897 /// \note
898 /// Two different template functions (selected by keyword \c requires) for the different
899 /// integral types exist.
900 /// One to read a number of bits that are less or equal to the internal buffer width, and
901 /// one if there is more to read than the internal buffer width.
902 /// \see
903 /// This method uses a template parameter for the number of bits to read.
904 /// A slightly slower, non-templated version is available with #ReadBits<TResult>(ShiftOpRHS),
905 /// which is to be used when the number of bits to read is determined only at run-time.
906 /// @tparam TWidth The number of bits in \p{value} to write.
907 /// @tparam TResult The type of the value to return.
908 /// @return The value read.
909 template<lang::ShiftOpRHS TWidth, typename TResult= int>
910 TResult ReadBits();
911#else
912 template<lang::ShiftOpRHS TWidth, typename TResult= int>
913 requires ( std::integral<TResult> && ( TWidth <= bitsof(TStorage)) )
914 TResult ReadBits() {
915 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
916
917 TResult result;
918
919 // the one bit case. Could have been left to the compiler to optimize, but who knows.
920 if constexpr ( TWidth == 1 ) {
921 result= word & 1;
922 word>>= 1;
923 if(++idx.bit == bitsof(TStorage)) {
924 idx.pos++;
925 word= bb.GetWord(idx);
926 idx.bit= 0;
927 }
928 return result;
929 }
930
931 static_assert(bitsof(TResult) >= TWidth, "Fixed size to read greater than given result type.");
932 if constexpr ( TWidth == bitsof(TStorage) )
933 result= TResult( word );
934 else {
935 result= TResult( word & lang::LowerMask<TWidth, TStorage>() );
936 word>>= TWidth;
937 }
938
939 idx.bit+= TWidth;
940 if(idx.bit >= bitsof(TStorage)) {
941 idx.pos++;
942 word= bb.GetWord(idx);
944 if( idx.bit ) {
945 lang::ShiftOpRHS bitsRead= TWidth - idx.bit;
946 if constexpr ( TWidth < bitsof(TStorage) )
947 result |= TResult( ( word << bitsRead )
949 else
950 result |= TResult( word << bitsRead );
951 }
952
953 word>>= idx.bit;
954 }
955
956 return result;
957 }
958
959 template<lang::ShiftOpRHS TWidth, typename TResult= int>
960 requires ( std::integral<TResult> && ( TWidth > bitsof(TStorage)) )
961 TResult ReadBits() {
962 static_assert(bitsof(TResult) >= TWidth, "Fixed size to read greater than given result type.");
963 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
964
965 TResult result = word;
966 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
967 do { // the loop is at least hit once and bit is 0! (but not written in bit)
968 idx.pos++;
969 word= bb.GetWord(idx);
970 result|= TResult(word) << bitsRead;
971 bitsRead+= bitsof(TStorage);
972 }
973 while( bitsRead < TWidth);
974
975 idx.bit= (idx.bit + TWidth) % bitsof(TStorage);
976
977 // next buffer value reached?
978 if(idx.bit == 0 )
979 idx.pos++;
980 else
981 result= lang::LowerBits<TWidth, TResult>( result );
982
983 word= bb.GetWord(idx) >> idx.bit;
984
985 return result;
986 }
987#endif
988
989// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
990// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
991#if DOXYGEN
992 /// Reads the given number of bits from the stream into the given unsigned integral value.
993 /// \note
994 /// Two different implementations for different integral types exist and are
995 /// selected with keyword \c requires.
996 ///
997 /// \see
998 /// A method that uses a template parameter for the number of bits to read, is available
999 /// with #ReadBits<TWidth,TResult>.
1000 /// This might be slightly faster and should be used instead of this method, whenever
1001 /// the number of bits to read is known at compilation time.
1002 ///
1003 /// @tparam TResult The type of the value to return. Defaults to type \c int.
1004 /// @param width The number of bits to read.
1005 /// @return The value read.
1006 template<typename TResult= int>
1007 TResult ReadBits( lang::ShiftOpRHS width );
1008#else
1009 template<typename TResult= int>
1010 requires ( sizeof(TResult) <= sizeof(TStorage) )
1011 TResult ReadBits( lang::ShiftOpRHS width ) {
1012 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1013 ALIB_ASSERT_ERROR( bitsof(TResult) >= width, "BITBUFFER",
1014 "Read size given greater than value type.")
1015
1016 TResult result;
1017 if ( width < bitsof(TStorage) )
1018 result= TResult( word & lang::LowerMask<TStorage>(width) );
1019 else
1020 result= TResult( word );
1021 word>>= width;
1022
1023 idx.bit+= width;
1024 if(idx.bit >= bitsof(TStorage)) {
1025 idx.pos++;
1026 word= bb.GetWord(idx);
1027 idx.bit-= bitsof(TStorage);
1028
1029 if( idx.bit ) {
1030 lang::ShiftOpRHS bitsRead= width - idx.bit;
1031 result |= TResult( ( word << bitsRead )
1032 & lang::LowerMask<TStorage>(width) );
1033 word>>= idx.bit;
1034 } }
1035
1036 return result;
1037 }
1038
1039 template<typename TResult= int>
1040 requires ( sizeof(TResult) > sizeof(TStorage) )
1041 TResult ReadBits( lang::ShiftOpRHS width ) {
1042 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1043 ALIB_ASSERT_ERROR( bitsof(TResult) >= width , "BITBUFFER",
1044 "Read size given greater than value type.")
1045
1046 if( width <= bitsof(TStorage)) {
1047 TResult result;
1048 if ( width < bitsof(TStorage) )
1049 result= TResult( word & lang::LowerMask<TStorage>(width) );
1050 else
1051 result= TResult( word );
1052 word>>= width;
1053
1054 idx.bit+= width;
1055 if(idx.bit >= bitsof(TStorage)) {
1056 idx.pos++;
1057 word= bb.GetWord(idx);
1059
1060 if( idx.bit ) {
1061 lang::ShiftOpRHS bitsRead= width - idx.bit;
1062 result |= TResult( ( word << bitsRead )
1063 & lang::LowerMask<TStorage>(width) );
1064 word>>= idx.bit;
1065 } }
1066
1067 return result;
1068 } else {
1069 TResult result = TResult( word );
1070 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
1071 do { // the loop is at least hit once and bit is 0! (but not written in bit)
1072 idx.pos++;
1073 word= bb.GetWord(idx);
1074 result|= TResult(word) << bitsRead;
1075 bitsRead+= bitsof(TStorage);
1076 }
1077 while( bitsRead < width);
1078
1079 idx.bit= (idx.bit + width) % bitsof(TStorage);
1080
1081 // next buffer value reached?
1082 if(idx.bit == 0 ) {
1083 idx.pos++;
1084 word= bb.GetWord(idx);
1085 } else {
1086 result= lang::LowerBits<TResult>( width, result );
1087 word>>= width;
1088 }
1089 return result;
1090 } }
1091
1092#endif
1093
1094
1095// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
1096// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
1097#if DOXYGEN
1098 /// Reads the given integral value from the stream.
1099 /// Information about the encoding of the values is given with the documentation of
1100 /// #"BitWriter::WriteBits(TIntegral);WriteBits<TIntegral>(TIntegral)".<br>
1101 ///
1102 /// Note that the implementation of this method consists of various versions which
1103 /// are selected using C++20 keyword \c requires.
1104 /// @tparam TUIntegral The unsigned integral type to read.
1105 /// @return The value read from the bit buffer.
1106 template< typename TUIntegral>
1107 TUIntegral ReadInt() { return readUIntegral8(); }
1108#else
1109 template< typename TUIntegral>
1110 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 8) )
1111 TUIntegral ReadInt() { return readUIntegral8(); }
1112
1113 template< typename TUIntegral>
1114 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 16) )
1115 TUIntegral ReadInt() { return readUIntegral16(); }
1116
1117
1118 template< typename TUIntegral>
1119 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 32) )
1120 TUIntegral ReadInt() { return readUIntegral32(); }
1121
1122 template< typename TUIntegral>
1123 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 64) )
1124 TUIntegral ReadInt() { return readUIntegral64(); }
1125
1126 template< typename TSIntegral>
1127 requires( std::signed_integral<TSIntegral> )
1128 TSIntegral ReadInt() {
1129 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
1130 TUnsigned result= ReadInt<TUnsigned>();
1131 return result & 1 ? TSIntegral( -TSIntegral( result >> 1 ) - 1 )
1132 : TSIntegral( result >> 1 );
1133 }
1134#endif
1135
1136 protected:
1137 /// Internal method that reads a unsigned 8-bit value.
1138 /// @return The value read.
1139 ALIB_DLL uint8_t readUIntegral8();
1140
1141 /// Internal method that reads a unsigned 16-bit value.
1142 /// @return The value read.
1143 ALIB_DLL uint16_t readUIntegral16();
1144
1145 /// Internal method that reads a unsigned 32-bit value.
1146 /// @return The value read.
1147 ALIB_DLL uint32_t readUIntegral32();
1148
1149 /// Internal method that reads a unsigned 64-bit value.
1150 /// @return The value read.
1151 ALIB_DLL uint64_t readUIntegral64();
1152
1153
1154}; // class BitReader
1155
1156} // namespace alib[::bitbuffer]
1157
1158/// Type alias in namespace \b alib.
1160
1161/// Type alias in namespace \b alib.
1163
1164/// Type alias in namespace \b alib.
1165template<uinteger TCapacity>
1167
1168/// Type alias in namespace \b alib.
1170
1171/// Type alias in namespace \b alib.
1173
1174/// Type alias in namespace \b alib.
1175using ShiftOpRHS = int;
1176
1177} // namespace [alib]
#define bitsof(type)
Definition alib.inl:1509
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_ERROR(domain,...)
Definition alib.inl:1140
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
bool operator!=(const Index &rhs) const
bool operator<=(const Index &rhs) const
void SetFromByteOffset(uinteger byteOffset)
lang::ShiftOpRHS bit
Current bit index in the current word.
Definition bitbuffer.inl:63
void Clear()
Sets this index to zero, hence pointing to the first bit in the buffer.
Definition bitbuffer.inl:95
integer GetByteOffset(Index startIdx=Index(0, 0)) const
bool operator<(const Index &rhs) const
static Index Decode64(uint64_t code)
bool operator>(const Index &rhs) const
uinteger pos
Index of the current word to read/write.
Definition bitbuffer.inl:62
bool operator==(const Index &rhs) const
bool operator>=(const Index &rhs) const
Index()=default
Default constructor initializing members #"pos" and #".bit" to zero.
static Index Decode32(uint32_t code)
Index(uinteger pPos, lang::ShiftOpRHS pBit)
Definition bitbuffer.inl:73
lang::ShiftOpRHS Bit() const
Definition bitbuffer.inl:83
uinteger RemainingSize(const Index &idx) const
Index Unterminate(Index terminationIndex)
Definition bitbuffer.cpp:53
virtual uinteger Capacity() const =0
void SetWord(const Index &index, TStorage value)
virtual ~BitBufferBase()
Virtual destructor (does nothing, needed for abstract virtual class).
BitBufferBase() noexcept
Default Constructor (the only one).
Index Terminate(Index writerIndex)
Definition bitbuffer.cpp:37
void ToLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
void FromLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
TStorage GetWord(const Index &index) const
virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index index)=0
char * CharStream(Index idx=Index(0, 0))
BitBufferLocal() noexcept
Constructor.
virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
TStorage storage[(TCapacity+bitsof(TStorage) - 1)/bitsof(TStorage)]
The array that holds the data.
virtual uinteger Capacity() const override
StdVectorMA< TStorage > storage
The vector that holds the data.
MonoAllocator & GetAllocator()
virtual uinteger Capacity() const override
BitBufferMA(MonoAllocator &monoAllocator, uinteger initialCapacity)
virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
std::vector< TStorage > storage
The vector that holds the data.
virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
virtual uinteger Capacity() const override
BitBuffer(uinteger initialCapacity)
BitBufferBase & bb
The bit buffer to write into. Provided on construction.
uinteger RemainingSize() const
BitBufferBase::Index idx
The current reading/writing index within bb.
BitBufferBase & GetBuffer() const
BitBufferBase::Index GetIndex() const
BitRWBase(BitBufferBase &buffer)
Reads bits from a #"BitBufferBase".
BitReader(BitBufferBase &buffer)
BitBufferBase::TStorage TStorage
Local type alias (shortcut).
BitReader(BitBufferBase &buffer, const BitBufferBase::Index &index)
BitBufferBase::TStorage word
The current word, which is partly read and shifted to start with current bit.
void Reset(const BitBufferBase::Index &index)
TResult ReadBits(lang::ShiftOpRHS width)
void Reset()
Resets this reader to the start of the bit buffer.
Writes bits into a #"BitBufferBase".
void Reset(const BitBufferBase::Index &index)
~BitWriter()
Destructs a bit writer. Invokes Flush().
void WriteInt(TUIntegral value)
void Reset()
Resets the internal index of this writer to the start of the bit buffer.
void WriteBits(lang::ShiftOpRHS width, TValue value)
BitBufferBase::TStorage word
The current word, which is partly written and not stored in buffer, yet.
BitWriter(BitBufferBase &buffer)
BitWriter(BitBufferBase &buffer, const BitBufferBase::Index &index)
void writeUIntegral(uint8_t value)
void WriteInt(TSIntegral value)
BitBufferBase::TStorage TStorage
Local type alias (shortcut).
void WriteBits(TIntegral value)
constexpr TIntegral LowerMask()
int ShiftOpRHS
Definition bits.inl:20
constexpr int Log2OfSize()
Definition bits.inl:194
constexpr TIntegral LowerBits(TIntegral value)
Definition bits.inl:159
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
bitbuffer::BitReader BitReader
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
bitbuffer::BitBufferMA BitBufferMA
Type alias in namespace alib.
bitbuffer::BitBufferLocal< TCapacity > BitBufferLocal
Type alias in namespace alib.
bitbuffer::BitBuffer BitBuffer
Type alias in namespace alib.
bitbuffer::BitWriter BitWriter
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace alib.
int ShiftOpRHS
Type alias in namespace alib.