ALib C++ Library
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 \ref mainpage_license "Boost Software 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 \alib{bitbuffer;BitWriter}
13/// and \alib{bitbuffer;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 \alib{bitbuffer;BitBuffer}, \alib{bitbuffer;BitBufferMA} and \alib{bitbuffer;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 #EnsureCapacity)
29/// 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 \alib{bitbuffer;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 \alib{bitbuffer;BitWriter} and \alib{bitbuffer;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 /// \alib{bitbuffer;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 \alib{bitbuffer;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 \alib{bitbuffer::BitBufferBase;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 \alib{bitbuffer;BitBufferMA}, which uses
342/// \ref alib_mods_contmono "monotonic allocation" and \alib{bitbuffer;BitBufferLocal}, which uses
343/// local (stack) memory.
344/// - For this class, a \ref 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 \ref alib_mods_contmono "monotonic allocation".
382/// \see
383/// Two alternatives are provided with \alib{bitbuffer;BitBuffer} and \alib{bitbuffer;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 \alib{bitbuffer;BitBuffer} and \alib{bitbuffer;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 \alib{bitbuffer;BitWriter} and \alib{bitbuffer;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 \alib{bitbuffer;BitWriter} \alib{bitbuffer;BitReader}.
498 /// Such index elements may be passed to methods
499 /// \alib{bitbuffer;BitWriter::Reset(const BitBufferBase::Index&)} and
500 /// \alib{bitbuffer;BitReader::Reset(const BitBufferBase::Index&)}
501 /// @return The index of the next bit to write.
503
504 /// Invokes \alib{bitbuffer;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 \alib{bitbuffer;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 \alib{bitbuffer;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 \alib{bitbuffer::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 /// #Write<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 Write( 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 Write(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 Write(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 Write( TValue value)
652 {
653 using TUI= typename std::make_unsigned<TValue>::type;
654 Write<TWidth, TUI, TMaskValue>( static_cast<TUI>( value ) );
655 }
656
657 template<typename TValue>
658 requires ( std::same_as<TValue, bool> )
659 void Write( TValue value)
660 { Write<1, unsigned int, false>( static_cast<unsigned int>( value ) ); }
661
662 #endif // doxygen
663
664 /// Writes the given integral value with the given number of bits to the stream.
665 /// \note Two overloads of this method, selected with keyword \c requires,
666 /// for different integral types exist.
667 /// This is version 1/2 which requires that the given value type is smaller than or equal
668 /// to the storage type.
669 /// \see
670 /// A method that uses a template parameter for the number of bits to write, is
671 /// available with #Write<TWidth,TIntegral>(TIntegral).
672 /// This might be slightly faster and should be used instead of this method, whenever the
673 /// number of bits to write is known at compilation time.
674 ///
675 /// @tparam TValue The integral type of the value to write.
676 /// (Deduced from parameter \p{value}.)
677 /// @tparam TMaskValue Determines if bits beyond \p{width} of given \p{value} may be set and
678 /// have to be masked out. Defaults to \c false.
679 /// @param width The number of bits in \p{value}.
680 /// @param value The value to write.
681 template<typename TValue, bool TMaskValue= false>
682 requires ( std::integral<TValue> && ( sizeof(TValue) <= sizeof(TStorage) ) )
683 void Write(lang::ShiftOpRHS width, TValue value) {
684 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
685 ALIB_ASSERT_ERROR( width <= bitsof(TValue),
686 "BITBUFFER", "BitBufferBase::Write: Width too high: ", width )
687
688 ALIB_ASSERT_ERROR( TMaskValue
689 || width>=bitsof(TValue)
690 || value == (value & lang::LowerMask<TValue>(width) ),
691 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
692
693 if constexpr (TMaskValue)
694 if( width < bitsof(TValue) )
695 value&= lang::LowerMask<TValue>(width);
696
697 word|= TStorage(value) << idx.bit ;
698 idx.bit+= width;
699 if(idx.bit >= bitsof(TStorage) ) {
700 bb.SetWord(idx, word);
701 idx.pos++;
702 word= 0;
703 idx.bit-= bitsof(TStorage);
704 if( idx.bit )
705 word|= ( TStorage(value) >> (width - idx.bit) );
706 } }
707
708 /// Writes the given integral value with the given number of bits to the stream.
709 /// \note Two overloads of this method, selected with keyword \c requires,
710 /// for different integral types exist.
711 /// This is version 2/2 which requires that the given value type is greater than
712 /// as the storage type.
713 ///
714 /// @tparam TValue The integral type of the value to write.
715 /// (Deduced from parameter \p{value}.)
716 /// @tparam TMaskValue Determines if bits beyond \p{width} of given \p{value} may be set and
717 /// have to be masked out. Defaults to \c false.
718 /// @param width The number of bits in \p{value}.
719 /// @param value The value to write.
720 template<typename TValue, bool TMaskValue= false>
721 requires ( std::integral<TValue> && ( sizeof(TValue) > sizeof(TStorage) ) )
722 void Write(lang::ShiftOpRHS width, TValue value) {
723 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
724 ALIB_ASSERT_ERROR( width <= bitsof(TValue), "BITBUFFER",
725 "BitBufferBase::Write: Width too high: ", width )
726 ALIB_ASSERT_ERROR( TMaskValue
727 || width==bitsof(TValue)
728 || value == (value & lang::LowerMask<TValue>(width) ),
729 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
730
731 if constexpr (TMaskValue)
732 if( width <= bitsof(TValue) )
733 value&= lang::LowerMask<TValue>(width);
734
735 if( width <= bitsof(TStorage) ) {
736 word|= TStorage(value) << idx.bit ;
737 idx.bit+= width;
738 if(idx.bit >= bitsof(TStorage) ) {
739 bb.SetWord(idx, word);
740 idx.pos++;
741 word= 0;
742 idx.bit-= bitsof(TStorage);
743 if( idx.bit )
744 word|= ( TStorage(value) >> (width - idx.bit) );
745 }
746 } else {
747 word|= (TStorage(value) << idx.bit);
748 lang::ShiftOpRHS bitsWritten= bitsof(TStorage) - idx.bit;
749 value>>= bitsWritten;
750 while(true) { // the loop is at least hit once and bit is 0! (but not written in bit)
751 bb.SetWord(idx, word);
752 idx.pos++;
753 word= TStorage(value);
754 bitsWritten+= bitsof(TStorage);
755 if(bitsWritten >= width )
756 break;
757 value>>= bitsof(TStorage);
758 }
759 idx.bit= (idx.bit + width) % bitsof(TStorage);
760 if(idx.bit == 0 ) { // next buffer value reached?
761 bb.SetWord(idx, word);
762 idx.pos++;
763 word= 0;
764 } } }
765
766 /// Writes the given unsigned integral value to the stream by writing lower values
767 /// with smaller sizes. The general assumption behind this is that lower values are more frequent
768 /// and the average written size is less than the unencode size - despite the overhead needed
769 /// to write information about how a value is encoded.
770 ///
771 /// The encoding for \e unsigned integrals is as follows:
772 /// - For byte value types, a single bit <c>'0'</c> is written if the value is below \c 8,
773 /// followed by the three bits containing the value. Otherwise, a single bit <c>'1'</c> is
774 /// written, followed by the full 8 bits.
775 /// - For all other value types (16-, 32- and 64-bit) the number of bytes needed is written
776 /// first (one bit in the case of 16-bit values, two bits in the case of 32-bit values
777 /// and three bits in the case of 64 bit values), and then the corresponding amount of
778 /// full bytes are written.
779 ///
780 /// \e Signed integrals are converted to unsigned integrals using the sometimes called
781 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
782 /// positive and uneven. This way, the least significant bit becomes the sign bit.
783 /// The advantage of this approach is that small numbers, negative or positive,
784 /// remain small in respect to their bitwise representation.<p>
785 /// The conversion hence is as follows:
786 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
787 ///
788 /// @tparam TUIntegral The type of the given unsigned integral.
789 /// @param value The value to write.
790 template<typename TUIntegral>
791 requires ( std::unsigned_integral<TUIntegral> && !std::same_as< TUIntegral, bool> )
792 void Write( TUIntegral value )
793 {
794 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
795 writeUIntegral(value);
796 }
797
798 /// Converts the given \e signed integral to an unsigned one using the so-called
799 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
800 /// positive and uneven. This way, the least significant bit becomes the sign bit.
801 /// The advantage of this approach is that small numbers, negative or positive,
802 /// remain small in respect to their bitwise representation.<p>
803 /// The conversion hence is as follows:
804 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
805 ///
806 /// Then calls \alib{bitbuffer::BitWriter;Write<TUIntegral>}.
807 /// @tparam TSIntegral The type of the given signed integral.
808 /// @param value The value to write.
809 template<typename TSIntegral>
810 requires ( std::signed_integral<TSIntegral> && !std::same_as< TSIntegral, bool> )
811 void Write( TSIntegral value ) {
812 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
813 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
814 writeUIntegral( value >= 0 ? TUnsigned( value << 1)
815 : TUnsigned( (TUnsigned(-(value+ 1)) << 1) | 1 ) );
816 }
817
818 protected:
819
820 /// Internal method that writes a unsigned 8-bit value.
821 /// @param value The value to write.
822 ALIB_DLL void writeUIntegral( uint8_t value );
823
824 /// Internal method that writes a unsigned 16-bit value.
825 /// @param value The value to write.
826 ALIB_DLL void writeUIntegral( uint16_t value );
827
828 /// Internal method that writes a unsigned 32-bit value.
829 /// @param value The value to write.
830 ALIB_DLL void writeUIntegral( uint32_t value );
831
832 /// Internal method that writes a unsigned 64-bit value.
833 /// @param value The value to write.
834 ALIB_DLL void writeUIntegral( uint64_t value );
835
836
837}; // class BitWriter
838
839
840//==================================================================================================
841/// Reads bits from a \alib{bitbuffer;BitBufferBase}.
842//==================================================================================================
843class BitReader : public BitRWBase
844{
845 protected:
846 /// Local type alias (shortcut)
848
849 /// The current word, which is partly read and shifted to start with current bit.
851
852 public:
853 /// Constructs a bit reader using the given bit buffer and starting to read at the beginning.
854 /// @param buffer The buffer to read from.
855 explicit BitReader( BitBufferBase& buffer )
856 : BitRWBase( buffer ) { word= bb.GetWord(idx); }
857
858
859 /// Constructs a bit reader using the given bit buffer, starting to read at the
860 /// given \alib{bitbuffer::BitBufferBase;Index}.
861 /// @param buffer The buffer to read from.
862 /// @param index An index providing the postion of the first bit to read in \p{buffer}.
863 explicit BitReader( BitBufferBase& buffer, const BitBufferBase::Index& index )
864 : BitRWBase( buffer ) {
865 idx.pos= index.pos;
866 idx.bit= index.bit;
867 word= bb.GetWord(idx) >> idx.bit;
868 }
869
870 /// Destructs a bit reader. In debug compilations an \alib_assertion is raised if the
871 /// read operation passed the end of the underlying buffer was performed.
873 {
874 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER",
875 "BitBufferBase overflow detected. Ensure a higher capacity" )
876 }
877
878 /// Resets this reader to the start of the bit buffer.
879 void Reset() {
880 idx.pos= 0;
881 idx.bit= 0;
882 word= bb.GetWord(idx);
883 }
884
885 /// Resets this reader to the given index position and calls #Sync().
886 /// @param index The next read position.
887 void Reset( const BitBufferBase::Index& index ) {
888 idx.pos= index.pos;
889 idx.bit= index.bit;
890 Sync();
891 }
892
893 /// Re-reads the currently fetched storage word from the memory.
894 /// \note This method is not needed in common use cases and implemented solely for the
895 /// purpose to support unit-tests which write and write in parallel to the same
896 /// bit buffer.
897 /// @return A reference to this \c BitReader to allow concatenated operations.
898 BitReader& Sync() { word= bb.GetWord(idx) >> idx.bit; return *this; }
899
900 /// Reads the given number of bits from the stream into the given unsigned integral value.
901 /// \note
902 /// Two different template functions (selected by keyword \c requires) for the different
903 /// integral types exist.<br>
904 /// This is version 1/2: Bits to read are less or equal to the internal buffer width
905 /// \see
906 /// This method uses a template parameter for the number of bits to read.
907 /// A slightly slower, non-templated version is available with #Read<TResult>(ShiftOpRHS),
908 /// which is to be used when the number of bits to write is determined only at run-time.
909 /// @tparam TWidth The number of bits in \p{value} to write.
910 /// @tparam TResult The type of the value to return.
911 /// @return The value read.
912 template<lang::ShiftOpRHS TWidth, typename TResult= int>
913 requires ( std::integral<TResult> && ( TWidth <= bitsof(TStorage)) )
914 TResult Read() {
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);
943 idx.bit-= bitsof(TStorage);
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 /// Reads the given number of bits from the stream into the given unsigned integral value.
960 /// \note
961 /// Two different template functions (selected by keyword \c requires) for the different
962 /// integral types exist.<br>
963 /// This is version 2/2: Bits to read are more than the internal buffer width.
964 /// \see
965 /// This method uses a template parameter for the number of bits to read.
966 /// A slightly slower, non-templated version is available with #Read<TResult>(ShiftOpRHS),
967 /// which is to be used when the number of bits to write is determined only at run-time.
968 /// @tparam TWidth The number of bits in \p{value} to write.
969 /// @tparam TResult The type of the value to return.
970 /// @return The value read.
971 template<lang::ShiftOpRHS TWidth, typename TResult= int>
972 requires ( std::integral<TResult> && ( TWidth > bitsof(TStorage)) )
973 TResult Read() {
974 static_assert(bitsof(TResult) >= TWidth, "Fixed size to read greater than given result type.");
975 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
976
977 TResult result = word;
978 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
979 do { // the loop is at least hit once and bit is 0! (but not written in bit)
980 idx.pos++;
981 word= bb.GetWord(idx);
982 result|= TResult(word) << bitsRead;
983 bitsRead+= bitsof(TStorage);
984 }
985 while( bitsRead < TWidth);
986
987 idx.bit= (idx.bit + TWidth) % bitsof(TStorage);
988
989 // next buffer value reached?
990 if(idx.bit == 0 )
991 idx.pos++;
992 else
993 result= lang::LowerBits<TWidth, TResult>( result );
994
995 word= bb.GetWord(idx) >> idx.bit;
996
997 return result;
998 }
999
1000 /// Reads the given number of bits from the stream into the given unsigned integral value.
1001 /// \note
1002 /// Different template functions for different integral types exist and are
1003 /// selected with keyword \c requires.
1004 ///
1005 /// \see
1006 /// A method that uses a template parameter for the number of bits to read, is available
1007 /// with #Read<TWidth,TResult>.
1008 /// This might be slightly faster and should be used instead of this method, whenever
1009 /// the number of bits to read is known at compilation time.
1010 ///
1011 /// @tparam TResult The type of the value to return. Defaults to type \c int.
1012 /// @param width The number of bits to read.
1013 /// @return The value read.
1014 template<typename TResult= int>
1015 requires ( sizeof(TResult) <= sizeof(TStorage) )
1016 TResult Read( lang::ShiftOpRHS width ) {
1017 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1018 ALIB_ASSERT_ERROR( bitsof(TResult) >= width, "BITBUFFER",
1019 "Read size given greater than value type.")
1020
1021 TResult result;
1022 if ( width < bitsof(TStorage) )
1023 result= TResult( word & lang::LowerMask<TStorage>(width) );
1024 else
1025 result= TResult( word );
1026 word>>= width;
1027
1028 idx.bit+= width;
1029 if(idx.bit >= bitsof(TStorage)) {
1030 idx.pos++;
1031 word= bb.GetWord(idx);
1032 idx.bit-= bitsof(TStorage);
1033
1034 if( idx.bit ) {
1035 lang::ShiftOpRHS bitsRead= width - idx.bit;
1036 result |= TResult( ( word << bitsRead )
1037 & lang::LowerMask<TStorage>(width) );
1038 word>>= idx.bit;
1039 } }
1040
1041 return result;
1042 }
1043
1044 /// Reads the given number of bits from the stream into the given unsigned integral value.
1045 /// \note
1046 /// Different template functions for different integral types exist and are
1047 /// selected with keyword \c requires.
1048 ///
1049 /// \see
1050 /// A method that uses a template parameter for the number of bits to read, is available
1051 /// with #Read<TWidth,TResult>.
1052 /// This might be slightly faster and should be used instead of this method, whenever
1053 /// the number of bits to read is known at compilation time.
1054 ///
1055 /// @tparam TResult The type of the value to return. Defaults to type \c int.
1056 /// @param width The number of bits to read.
1057 /// @return The value read.
1058 template<typename TResult= int>
1059 requires ( sizeof(TResult) > sizeof(TStorage) )
1060 TResult Read( lang::ShiftOpRHS width ) {
1061 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1062 ALIB_ASSERT_ERROR( bitsof(TResult) >= width , "BITBUFFER",
1063 "Read size given greater than value type.")
1064
1065 if( width <= bitsof(TStorage)) {
1066 TResult result;
1067 if ( width < bitsof(TStorage) )
1068 result= TResult( word & lang::LowerMask<TStorage>(width) );
1069 else
1070 result= TResult( word );
1071 word>>= width;
1072
1073 idx.bit+= width;
1074 if(idx.bit >= bitsof(TStorage)) {
1075 idx.pos++;
1076 word= bb.GetWord(idx);
1077 idx.bit-= bitsof(TStorage);
1078
1079 if( idx.bit ) {
1080 lang::ShiftOpRHS bitsRead= width - idx.bit;
1081 result |= TResult( ( word << bitsRead )
1082 & lang::LowerMask<TStorage>(width) );
1083 word>>= idx.bit;
1084 } }
1085
1086 return result;
1087 } else {
1088 TResult result = TResult( word );
1089 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
1090 do { // the loop is at least hit once and bit is 0! (but not written in bit)
1091 idx.pos++;
1092 word= bb.GetWord(idx);
1093 result|= TResult(word) << bitsRead;
1094 bitsRead+= bitsof(TStorage);
1095 }
1096 while( bitsRead < width);
1097
1098 idx.bit= (idx.bit + width) % bitsof(TStorage);
1099
1100 // next buffer value reached?
1101 if(idx.bit == 0 ) {
1102 idx.pos++;
1103 word= bb.GetWord(idx);
1104 } else {
1105 result= lang::LowerBits<TResult>( width, result );
1106 word>>= width;
1107 }
1108 return result;
1109 } }
1110
1111 /// Reads the given integral value from the stream.
1112 /// Information about the encoding of the values is given with the documentation of
1113 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1114 /// This overload reads unsigned integral types of 8-bit width.
1115 /// @tparam TUIntegral The unsigned integral type to read.
1116 /// @return The value read from the bit buffer.
1117 template< typename TUIntegral>
1118 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 8) )
1119 TUIntegral Read() { return readUIntegral8(); }
1120
1121 /// Reads the given integral value from the stream.
1122 /// Information about the encoding of the values is given with the documentation of
1123 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1124 /// This overload reads unsigned integral types of 16-bit width.
1125 /// @tparam TUIntegral The unsigned integral type to read.
1126 /// @return The value read from the bit buffer.
1127 template< typename TUIntegral>
1128 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 16) )
1129 TUIntegral Read() { return readUIntegral16(); }
1130
1131
1132 /// Reads the given integral value from the stream.
1133 /// Information about the encoding of the values is given with the documentation of
1134 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1135 /// This overload reads unsigned integral types of 32-bit width.
1136 /// @tparam TUIntegral The unsigned integral type to read.
1137 /// @return The value read from the bit buffer.
1138 template< typename TUIntegral>
1139 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 32) )
1140 TUIntegral Read() { return readUIntegral32(); }
1141
1142
1143 /// Reads the given integral value from the stream.
1144 /// Information about the encoding of the values is given with the documentation of
1145 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1146 /// This overload reads unsigned integral types of 64-bit width.
1147 /// @tparam TUIntegral The unsigned integral type to read.
1148 /// @return The value read from the bit buffer.
1149 template< typename TUIntegral>
1150 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 64) )
1151 TUIntegral Read() { return readUIntegral64(); }
1152
1153
1154 /// Reads the given signed integral value from the stream.
1155 /// Information about the encoding of the values is given with the documentation of
1156 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1157 /// This overload reads signed integral types.
1158 /// @tparam TSIntegral The signed integral type to read.
1159 /// @return The value read from the bit buffer.
1160 template< typename TSIntegral>
1161 requires( std::signed_integral<TSIntegral> )
1162 TSIntegral Read() {
1163 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
1164 TUnsigned result= Read<TUnsigned>();
1165 return result & 1 ? TSIntegral( -TSIntegral( result >> 1 ) - 1 )
1166 : TSIntegral( result >> 1 );
1167 }
1168
1169 protected:
1170 /// Internal method that reads a unsigned 8-bit value.
1171 /// @return The value read.
1172 ALIB_DLL uint8_t readUIntegral8();
1173
1174 /// Internal method that reads a unsigned 16-bit value.
1175 /// @return The value read.
1176 ALIB_DLL uint16_t readUIntegral16();
1177
1178 /// Internal method that reads a unsigned 32-bit value.
1179 /// @return The value read.
1180 ALIB_DLL uint32_t readUIntegral32();
1181
1182 /// Internal method that reads a unsigned 64-bit value.
1183 /// @return The value read.
1184 ALIB_DLL uint64_t readUIntegral64();
1185
1186
1187}; // class BitReader
1188
1189} // namespace alib[::bitbuffer]
1190
1191/// Type alias in namespace \b alib.
1193
1194/// Type alias in namespace \b alib.
1196
1197/// Type alias in namespace \b alib.
1198template<uinteger TCapacity>
1200
1201/// Type alias in namespace \b alib.
1203
1204/// Type alias in namespace \b alib.
1206
1207/// Type alias in namespace \b alib.
1208using ShiftOpRHS = int;
1209
1210} // namespace [alib]
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
virtual ALIB_DLL uinteger Capacity() const =0
uinteger RemainingSize(const Index &idx) const
ALIB_DLL Index Unterminate(Index terminationIndex)
Definition bitbuffer.cpp:53
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).
ALIB_DLL Index Terminate(Index writerIndex)
Definition bitbuffer.cpp:37
ALIB_DLL void ToLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
virtual ALIB_DLL bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index index)=0
ALIB_DLL void FromLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
TStorage GetWord(const Index &index) const
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)
TResult Read(lang::ShiftOpRHS width)
ALIB_DLL uint64_t readUIntegral64()
BitBufferBase::TStorage TStorage
Local type alias (shortcut)
ALIB_DLL uint32_t readUIntegral32()
ALIB_DLL uint16_t readUIntegral16()
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 Read(lang::ShiftOpRHS width)
ALIB_DLL uint8_t readUIntegral8()
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 Write(TIntegral value)
void Write(lang::ShiftOpRHS width, TValue value)
void Write(lang::ShiftOpRHS width, TValue value)
void Reset()
Resets the internal index of this writer to the start of the bit buffer.
void Write(TSIntegral 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)
ALIB_DLL void writeUIntegral(uint8_t value)
void Write(TUIntegral value)
BitBufferBase::TStorage TStorage
Local type alias (shortcut)
#define bitsof(type)
Definition alib.inl:1435
#define ALIB_DLL
Definition alib.inl:503
#define ALIB_ERROR(domain,...)
Definition alib.inl:1062
#define ALIB_EXPORT
Definition alib.inl:497
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
constexpr int Log2OfSize()
Definition bits.inl:199
int ShiftOpRHS
Definition bits.inl:20
constexpr TIntegral LowerBits(TIntegral value)
Definition bits.inl:164
constexpr TIntegral LowerMask()
Definition bits.inl:51
bitbuffer::BitReader BitReader
Type alias in namespace alib.
std::vector< T, StdMA< T > > StdVectorMA
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.
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
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
int ShiftOpRHS
Type alias in namespace alib.