ALib C++ Library
Library Version: 2510 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} and
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
78 /// Returns the index of the actual storage word in the buffer.
79 /// @return The index of the current word containing the next bit to read/write.
80 uinteger Pos() const { return pos; }
81
82 /// Returns the number of the actual bit in the actual word of the buffer buffer.
83 /// @return The number of the next bit to read/write.
84 lang::ShiftOpRHS Bit() const { return bit; }
85
86 /// Returns true, if the next bit to read/write is the first of the current storage
87 /// word in the buffer. Alignment of buffers may become important when buffers are
88 /// serialized (e.g., to mass storage devices). Method
89 /// \alib{bitbuffer;BitBufferBase::Terminate} may be used to receive an aligned
90 /// index.
91 ///
92 /// @return The result of <c>Bit() == 0</c>.
93 bool IsAligned() const { return bit == 0; }
94
95 /// Sets this index to zero, hence pointing to the first bit in the buffer.
96 void Clear()
97 {
98 pos= 0;
99 bit= 0;
100 }
101
102 /// Returns the size of the memory from given \p startIdx to this index occupied by
103 /// the internal storage words of the buffer.
104 ///
105 /// @param startIdx The starting index. Defaults to <c>{0,0}</c>.
106 /// @return The size of the buffer (part) in bytes.
107 integer GetByteOffset( Index startIdx= Index(0, 0) ) const
108 {
109 ALIB_ASSERT_ERROR( startIdx.pos < pos
110 || (startIdx.pos == pos && startIdx.bit < bit), "BITBUFFER",
111 "Given buffer start index is greater than this index." )
112 return integer((pos - startIdx.Pos()) * sizeof(TStorage) );
113 }
114
115 /// Sets this index to point to the word and bit given by a byte offset.<br>
116 /// This method is useful when bit buffers are deserialized from character streams.
117 /// @param byteOffset The position within the buffer in bytes.
118 void SetFromByteOffset( uinteger byteOffset )
119 {
120 pos= byteOffset / sizeof( TStorage );
121 bit= (byteOffset % sizeof( TStorage )) * 8 ;
122 }
123
124 /// Returns the number of bits used in respect to this index.
125 /// @return The number of bits written or read.
127 {
128 return uinteger( pos * bitsof(TStorage) + uinteger(bit) );
129 }
130
131 /// Encodes this index information into a 32-bit variable by using the upper 5 (or 6)
132 /// bits for the bit index. As a result, the possible value range of index data is
133 /// reduced. The reduction depends on the platform's size of type \c int. In case of
134 /// 32-bit, five bits are needed to store the bit position. In the case of 64-bit,
135 /// six bits are needed.<br>
136 /// As the underlying \e TStorage type changes as well, in both cases, the resulting
137 /// addressable storage bytes is limited to the same value:
138 /// - TStorage 64-bit: <em>2^(32-6) * 8 bytes = 512 megabytes</em>
139 /// - TStorage 32-bit: <em>2^(32-5) * 4 bytes = 512 megabytes</em>
140 ///
141 /// In case bit buffers grow to over half a gigabyte, 64-bit encoding should be performed
142 /// by using alternative method #Encode64.
143 ///
144 /// @return The encoded index.
145 uint32_t Encode32()
146 {
148 "BITBUFFER", "32bit too narrow for endcoding BitBuffer::Index." )
149 return uint32_t(pos) | (uint32_t(bit) << (31 - lang::Log2OfSize<TStorage>() ));
150 }
151
152 /// Encodes this index information into a 64-bit value by using the upper 5 5 (or 6)
153 /// bits for the bit index.
154 ///
155 /// @see For a shorter encoding, limited to bit buffer sizes of 512 megabytes,
156 /// see method #Encode32.
157 ///
158 /// @return The encoded index.
159 uint64_t Encode64()
160 { return uint64_t(pos) | (uint64_t(bit) << (63L - lang::Log2OfSize<TStorage>() )); }
161
162 /// Static method that decodes an index information, encoded with #Encode32, to an
163 /// instance of this class.
164 ///
165 /// @param code The encoded information.
166 /// @return The decoded index.
167 static
168 Index Decode32(uint32_t code)
169 {
170 return Index { uinteger (code & lang::LowerMask< 31 - lang::Log2OfSize<TStorage>() , uint32_t>() ),
172 }
173
174
175 /// Static method that decodes an index information, encoded with #Encode64, to an
176 /// instance of this class.
177 ///
178 /// @param code The encoded information.
179 /// @return The decoded index.
180 static
181 Index Decode64(uint64_t code)
182 { return Index { uinteger (code & lang::LowerMask< 63L - lang::Log2OfSize<TStorage>() , uint64_t>() ),
183 lang::ShiftOpRHS(code >>(63L - lang::Log2OfSize<TStorage>())) }; }
184
185 //======================================================================================
186 /// Comparison operator.
187 ///
188 /// @param rhs The right hand side argument of the comparison.
189 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
190 //======================================================================================
191 bool operator==(const Index& rhs) const
192 {
193 return (pos == rhs.pos)
194 && (bit == rhs.bit);
195 }
196
197 //======================================================================================
198 /// Comparison operator.
199 ///
200 /// @param rhs The right hand side argument of the comparison.
201 /// @return \c true if this object does not equal \p{rhs}, \c false otherwise.
202 //======================================================================================
203 bool operator!=(const Index& rhs) const
204 {
205 return !(*this == rhs);
206 }
207
208 //======================================================================================
209 /// Comparison operator.
210 ///
211 /// @param rhs The right hand side argument of the comparison.
212 /// @return \c true if this object is smaller than \p{rhs}, \c false otherwise.
213 //======================================================================================
214 bool operator<(const Index& rhs) const
215 {
216 return (pos < rhs.pos) || ((pos == rhs.pos)
217 && (bit < rhs.bit) );
218 }
219
220 //======================================================================================
221 /// Comparison operator.
222 ///
223 /// @param rhs The right hand side argument of the comparison.
224 /// @return \c true if this object is smaller or equal than \p{rhs}, \c false otherwise.
225 //======================================================================================
226 bool operator<=(const Index& rhs) const
227 {
228 return (pos < rhs.pos) || ((pos == rhs.pos)
229 && (bit <= rhs.bit) );
230 }
231
232 //======================================================================================
233 /// Comparison operator.
234 ///
235 /// @param rhs The right hand side argument of the comparison.
236 /// @return \c true if this object is greater or equal than \p{rhs}, \c false otherwise.
237 //======================================================================================
238 bool operator>=(const Index& rhs) const
239 {
240 return !(*this < rhs);
241 }
242
243 //======================================================================================
244 /// Comparison operator.
245 ///
246 /// @param rhs The right hand side argument of the comparison.
247 /// @return \c true if this object is greater than \p{rhs}, \c false otherwise.
248 //======================================================================================
249 bool operator>(const Index& rhs) const
250 {
251 return !(*this <= rhs);
252 }
253 }; // inner struct Index
254
255 protected:
256
257 /// A pointer to the storage. Implementations of this abstract type have to set this field
258 /// when reallocating the internal buffer.
260
261 public:
262 //==========================================================================================
263 /// Default Constructor (the only one).
264 //==========================================================================================
265 BitBufferBase() noexcept : data(nullptr) {}
266
267 //==========================================================================================
268 /// Virtual destructor (does nothing, needed for abstract virtual class).
269 //==========================================================================================
271 {}
272
273 //==========================================================================================
274 /// Virtual function to determine the (currently allocated) capacity.
275 /// @return The size of the internal storage in bits.
276 //==========================================================================================
278 virtual uinteger Capacity() const = 0;
279
280 //==========================================================================================
281 /// Virtual function to reserve buffer space by optionally increasing the buffer to
282 /// enable the writing of the given bits.
283 ///
284 /// @param bitsRequired The number of bits required.
285 /// @param index The index to which the capacity is currently used.
286 /// @return \c true if the space is available or could be made available,
287 /// \c false otherwise.
288 //==========================================================================================
290 virtual bool EnsureCapacity( uinteger bitsRequired, BitBufferBase::Index index ) = 0;
291
292 //==========================================================================================
293 /// Returns the storage word at the given position
294 /// @param index The index to read the word from. Note that the bit number in this value is
295 /// ignored.
296 /// @return The word at the given index.
297 //==========================================================================================
298 TStorage GetWord(const Index& index) const
299 {
300 return data[index.pos];
301 }
302
303 //==========================================================================================
304 /// Stores the given \p value at the given \p index.
305 /// @param index The index to read the word at. Note that the bit number in this value is
306 /// ignored.
307 /// @param value The value to store
308 //==========================================================================================
309 void SetWord(const Index& index, TStorage value)
310 {
311 data[index.pos]= value;
312 }
313
314 //==========================================================================================
315 /// Returns the number of remaining bits in this buffer in relation to a given index.
316 /// @param idx An actual writing/reading position.
317 /// @return The number of bits dived remaining in this buffer.
318 //==========================================================================================
319 uinteger RemainingSize(const Index& idx) const
320 {
321 return Capacity() - idx.CountBits();
322 }
323
324 //==========================================================================================
325 /// Returns the start of the internal storage.
326 /// @return A pointer to the data array provided by the decendent types.
327 //==========================================================================================
328 TStorage* Data() const
329 {
330 return data;
331 }
332
333 //==========================================================================================
334 /// Returns the memory address of the internal storage word denoted by \p idx
335 /// reinterpreted to C++ type <c>char*</c>.
336 /// @param idx The index of the word to point to. The bit position within this index is
337 /// ignored.
338 /// @return A \c char pointer to the internal storage word the given index refers to.
339 //==========================================================================================
340 char* CharStream( Index idx= Index(0, 0) )
341 {
342 return reinterpret_cast<char*>( &data[idx.pos] );
343 }
344
345 //==========================================================================================
346 /// Writes a termination bit of value \c 1 and lets this buffer's index point to the next
347 /// buffer word.\n
348 /// Termination can be undone using the result index of this method with #Unterminate.
349 /// This method should be invoked before serializing a buffer and method
350 /// #Unterminate may be used after deserialization to continue writing to the buffer without
351 /// creating a gap.
352 ///
353 /// @param writerIndex The index to the last bit before termination.
354 ///
355 /// @return The \alib{bitbuffer;BitBufferBase::Index::IsAligned;aligned} index after termination
356 /// which is aligned point to the first bit behind the last used storage word.
357 /// Such index may be later fed into method #Unterminate to undo the termination.
358 //==========================================================================================
360 Index Terminate (Index writerIndex);
361
362 //==========================================================================================
363 /// Removes the termination bit found in the word before given \p terminationIndex.
364 /// @param terminationIndex The index returned by previous invocation of method #Terminate.
365 ///
366 /// @return The index of the next bit to write to the now unterminated buffer.
367 //==========================================================================================
369 Index Unterminate(Index terminationIndex);
370
371 //==========================================================================================
372 /// Converts the internal storage words into the platform-independent
373 /// "Little Endian Encoding", which means it may change the byte order within the storage
374 /// words of the buffer.
375 ///
376 /// This method is recommended to be used before writing buffer contents to a file to
377 /// make files system independent.
378 ///
379 /// \attention The start index needs to be aligned to a storage word. This is asserted
380 /// in debug compilations.
381 /// See method \alib{bitbuffer::BitBufferBase;Index::IsAligned} for more information.
382 ///
383 /// \note It is recommended to terminate the buffer before using this method.
384 /// and to pass the index returned by method #Terminate as second parameter
385 /// \p endIndex.
386 ///
387 /// \see Method #FromLittleEndianEncoding.
388 ///
389 /// @param startIndex The first storage word to convert. (The bit position of the index
390 /// is ignored).
391 /// @param endIndex The first bit behind the storage to be converted. Hence, if the bit
392 /// position within this argument is not \c 0, then the whole word that
393 /// this index points to, will be converted. Otherwise it won't.
394 //==========================================================================================
396 void ToLittleEndianEncoding( const Index& startIndex,
397 const Index& endIndex );
398
399 //==========================================================================================
400 /// The counter-method to #ToLittleEndianEncoding.
401 ///
402 /// @param startIndex The first storage word to convert. (The bit position of the index
403 /// is ignored).
404 /// @param endIndex The first bit behind the storage to be converted. Hence, if the bit
405 /// position within this argument is not \c 0, then the whole word that
406 /// this index points to, will be converted. Otherwise it won't.
407 //==========================================================================================
409 void FromLittleEndianEncoding( const Index& startIndex, const Index& endIndex );
410}; // class BitBufferBase
411
412//==================================================================================================
413/// A bit buffer using dynamic allocation.
414/// \see
415/// - Two alternatives are provided with \alib{bitbuffer;BitBufferMA}, which uses
416/// \ref alib_mods_contmono "monotonic allocation" and \alib{bitbuffer;BitBufferLocal}, which uses
417/// local (stack) memory.
418/// - For this class, a \ref alibtools_debug_helpers_gdb "pretty printer" for the
419/// GNU debugger is provided.
420//==================================================================================================
422{
423 protected:
424 /// The vector that holds the data.
425 std::vector<TStorage> storage;
426
427 public:
428 //==========================================================================================
429 /// Constructor.
430 /// @param initialCapacity The requested initial capacity of the buffer in bits.
431 //==========================================================================================
432 BitBuffer( uinteger initialCapacity )
433 {
434 EnsureCapacity(initialCapacity, Index());
435 }
436
437 //==========================================================================================
438 /// Returns the (currently allocated) capacity.
439 /// @return The size of the internal storage in bits.
440 //==========================================================================================
441 virtual uinteger Capacity() const override
442 {
443 return storage.capacity() * bitsof(TStorage);
444 }
445
446 //==========================================================================================
447 /// Checks if the given required storage space is internally reserved. If not,
448 /// the internal capacity is doubled, or, if more is required, set to the required space.
449 ///
450 /// @param bitsRequired The number of bits required.
451 /// @param idx The index of current buffer use.
452 /// @return \c true if the space is available or could be made available,
453 /// \c false otherwise.
454 //==========================================================================================
455 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
456 {
457 uinteger capacityNeeded= (idx.CountBits() + bitsRequired + (bitsof(TStorage) - 1) )
458 / bitsof(TStorage);
459 if( capacityNeeded > storage.capacity() )
460 storage.reserve( (std::max)( capacityNeeded, uinteger(storage.capacity()) * 2 ));
461 data= storage.data();
462
463 return true;
464 }
465}; // class BitBuffer
466
467//==================================================================================================
468/// A bit buffer using \ref alib_mods_contmono "monotonic allocation".
469/// \see
470/// Two alternatives are provided with \alib{bitbuffer;BitBuffer} and \alib{bitbuffer;BitBufferLocal}.
471//==================================================================================================
473{
474 protected:
475 /// The monotonic allocator used internally to allocate the storage. This is provided
476 /// with construction.
478
479 /// The vector that holds the data.
481
482 public:
483 //==========================================================================================
484 /// Constructor taking an external monotonic allocator and the initial capacity.
485 /// @param monoAllocator A reference to a monotonic allocator to use to allocate buffer
486 /// storage data.
487 /// @param initialCapacity The requested initial capacity of the buffer in bits.
488 //==========================================================================================
489 BitBufferMA( MonoAllocator& monoAllocator, uinteger initialCapacity )
490 : ma( monoAllocator )
491 , storage(ma)
492 {
493 EnsureCapacity(initialCapacity, Index());
494 }
495
496
497 //==========================================================================================
498 /// Returns the (currently allocated) capacity.
499 /// @return The size of the internal storage in bits.
500 //==========================================================================================
501 virtual uinteger Capacity() const override
502 {
503 return storage.capacity() * bitsof(TStorage);
504 }
505
506 //==========================================================================================
507 /// Checks if the given required storage space is internally reserved. If not,
508 /// the internal capacity is doubled, or, if more is required, set to the required space.
509 ///
510 /// @param bitsRequired The number of bits divided required.
511 /// @param idx The index of current buffer use.
512 /// @return \c true if the space is available or could be made available,
513 /// \c false otherwise.
514 //==========================================================================================
515 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
516 {
517 uinteger capacityNeeded= (idx.CountBits() + bitsRequired + (bitsof(TStorage) - 1) )
518 / bitsof(TStorage);
519 if( capacityNeeded > storage.capacity() )
520 storage.reserve( (std::max)( capacityNeeded, uinteger(storage.capacity()) * 2 ));
521 data= storage.data();
522
523 return true;
524 }
525
526 //==========================================================================================
527 /// Returns the internal monotonic allocator for external use.
528 /// @return The monotonic allocator given on construction.
529 //==========================================================================================
531 {
532 return ma;
533 }
534}; // class BitBufferMA
535
536//==================================================================================================
537/// A bit buffer using local storage, which means a fixed size internal array.
538/// If used as function member, the storage is located on the stack and hence its size has
539/// platform-specific limitations.<br>
540/// This class is useful to read and write smaller pieces of data, for example header information
541/// of binary data files which furthermore are filled/loaded with bit buffers using of other memory
542/// allocations.
543/// \see
544/// Two alternatives are provided with \alib{bitbuffer;BitBuffer} and \alib{bitbuffer;BitBufferMA}.
545/// @tparam TCapacity The number of bits to reserve internally
546//==================================================================================================
547template<uinteger TCapacity>
549{
550 protected:
551 /// The array that holds the data.
552 TStorage storage[ (TCapacity + bitsof(TStorage) - 1) / bitsof(TStorage) ];
553
554 public:
555 //==========================================================================================
556 /// Constructor.
557 //==========================================================================================
558 BitBufferLocal() noexcept
559 {
560 data= storage;
561 }
562
563 //==========================================================================================
564 /// Returns the (in this case fixed size!) capacity.
565 /// @return The size of the internal storage in bits.
566 //==========================================================================================
567 virtual uinteger Capacity() const override
568 {
569 return TCapacity;
570 }
571
572 //==========================================================================================
573 /// Checks if the given required storage space is internally reserved.
574 /// If not, in debug compilations, an \alib assertion is raised, as this is a fixed size
575 /// buffer.
576 ///
577 /// @param bitsRequired The number of bits required.
578 /// @param idx The index of current buffer use.
579 /// @return \c true if the space is available or could be made available,
580 /// \c false otherwise.
581 //==========================================================================================
582 virtual bool EnsureCapacity(uinteger bitsRequired, BitBufferBase::Index idx) override
583 {
584 uinteger capacityNeeded= idx.CountBits() + bitsRequired;
585 if( capacityNeeded > TCapacity )
586 {
587 ALIB_ERROR("BITBUFFER", "Local bit buffer cannot expand its capacity" )
588 return false;
589 }
590
591 return true;
592 }
593}; // class BitBufferLocal
594
595
596//==================================================================================================
597/// Non-instantiatable base class for types \alib{bitbuffer;BitWriter} and \alib{bitbuffer;BitReader}.
598//==================================================================================================
600{
601 protected:
602 BitBufferBase& bb; ///< The bit buffer to write into. Provided on construction.
603 BitBufferBase::Index idx; ///< The current reading/writing index within #bb.
604
605 /// Protected constructor, used by derived classes only.
606 /// @param buffer The bit buffer to work on.
607 explicit BitRWBase( BitBufferBase& buffer )
608 : bb ( buffer )
609 {}
610
611 public:
612 /// Retrieves the internal bit buffer.
613 /// @return The buffer the derived reader or writer works with.
615 {
616 return bb;
617 }
618
619 //==========================================================================================
620 /// Returns a copy of the current index in the bit buffer in respect to writing or
621 /// reading progress of derived classes \alib{bitbuffer;BitWriter} \alib{bitbuffer;BitReader}.
622 /// Such index elements may be passed to methods
623 /// \alib{bitbuffer;BitWriter::Reset(const BitBufferBase::Index&)} and
624 /// \alib{bitbuffer;BitReader::Reset(const BitBufferBase::Index&)}
625 /// @return The index of the next bit to write.
626 //==========================================================================================
628 {
629 return idx;
630 }
631
632 /// Invokes \alib{bitbuffer;BitBufferBase::Index::CountBits} on the index returned by #GetIndex.
633 /// @return The number of bits currently read from or written to the buffer.
635 {
636 return idx.CountBits();
637 }
638
639 /// Invokes \alib{bitbuffer;BitBufferBase::RemainingSize} on the internal bit buffer, passing
640 /// the result of #GetIndex.
641 /// @return The number of bits dived by 8 remaining in this buffer.
643 {
644 return bb.RemainingSize(idx);
645 }
646
647};
648
649//==================================================================================================
650/// Writes bits into a \alib{bitbuffer;BitBufferBase}.
651//==================================================================================================
652class BitWriter : public BitRWBase
653{
654 /// Local type alias (shortcut)
656
657 /// The current word, which is partly written and not stored in buffer, yet.
659
660 public:
661 /// Constructs a bit writer operating on the given bit buffer.
662 /// @param buffer The buffer to write to (starting at the beginning).
663 explicit BitWriter( BitBufferBase& buffer )
664 : BitRWBase( buffer )
665 {
666 word= 0;
667 }
668
669 /// Constructs a bit writer operating on the given bit buffer, starting to write at the
670 /// given \alib{bitbuffer::BitBufferBase;Index}.
671 /// @param buffer The buffer to write to.
672 /// @param index An index providing the postion of the first bit to (over-) write in
673 /// \p buffer.
674 explicit BitWriter( BitBufferBase& buffer, const BitBufferBase::Index& index )
675 : BitRWBase ( buffer )
676 {
677 idx= index;
678 word= bb.GetWord(idx) & lang::LowerMask<TStorage>( idx.bit );
679 }
680
681 /// Destructs a bit writer. Invokes #Flush().
683 {
684 Flush();
685 }
686
687 /// Resets the internal index of this writer to the start of the bit buffer.
688 void Reset()
689 {
691 word= 0;
692 }
693
694 /// Resets the internal index of this writer to the given one.
695 /// @param index The position of the next bit in the buffer to write to.
696 void Reset( const BitBufferBase::Index& index )
697 {
698 idx.pos= index.pos;
699 idx.bit= index.bit;
700 word= bb.GetWord(idx) & lang::LowerMask<TStorage>(idx.bit );
701 }
702
703 /// Writes the last word of bits into the underlying buffer.
704 /// This method has to be called before writing the buffer to a file or similar.
705 /// The method is automatically invoked on destruction.
706 void Flush()
707 {
708 bb.SetWord(idx, word);
709 }
710
711 #if DOXYGEN
712 /// Writes the given integral value with the given number of bits to the stream.
713 /// \note
714 /// Internally, different template functions selected with keyword \c requires
715 /// for the different integral types exist.
716 ///
717 /// \see
718 /// This method uses a template parameter for the number of bits to write.
719 /// A slightly slower, non-templated version is available with
720 /// #Write<TValue, TMaskValue>( ShiftOpRHS, TValue)
721 /// which is to be used when the value is determined only at run-time.
722 ///
723 /// @tparam TWidth The number of bits in \p value to write.
724 /// @tparam TValue The type of \p value to write. (Deduced from parameter \p value.)
725 /// @tparam TMaskValue Determines if bits beyond \p width of given \p value may be set and
726 /// have to be masked out.
727 /// Defaults to \c false.
728 /// @param value The value to write.
729 template<ShiftOpRHS TWidth, typename TIntegral, bool TMaskValue= false>
730 void Write( TIntegral value );
731 #else
732 // Version 1/2: #Bits to write are less or equal to internal buffer width
733 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
734 requires ( std::unsigned_integral<TValue>
735 && !std::same_as < TValue, bool>
736 && ( TWidth <= bitsof(TStorage) ) )
737 void Write(TValue value )
738 {
739 static_assert(bitsof(TValue) >= TWidth, "Fixed size given greater than value type.");
740 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
741 ALIB_ASSERT_ERROR( TMaskValue
742 || TWidth == bitsof(TValue)
743 || value == (value & lang::LowerMask<TValue>(TWidth) ), "BITBUFFER",
744 "Upper bits dirty while TMaskValue flag not set." )
745
746 if constexpr ( (TWidth < bitsof(TValue)) && TMaskValue )
747 value&= lang::LowerMask<TWidth, TValue >();
748
749 word|= TStorage(value) << idx.bit ;
750 idx.bit+= TWidth;
751 if(idx.bit >= bitsof(TStorage) )
752 {
753 bb.SetWord(idx, word);
754 idx.pos++;
755 word= 0;
756 idx.bit-= bitsof(TStorage);
757 if( idx.bit )
758 word|= (TStorage(value) >> (TWidth - idx.bit) );
759 }
760 }
761
762 // Version 2/2: #Bits to write is greater than internal buffer width
763 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
764 requires ( std::unsigned_integral<TValue>
765 && !std::same_as < TValue, bool>
766 && ( TWidth > bitsof(TStorage) ) )
767 void Write(TValue value )
768 {
769 static_assert(bitsof(TValue) >= TWidth, "Fixed size given greater than value type.");
770 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
771 ALIB_ASSERT_ERROR( TMaskValue
772 || TWidth == bitsof(TValue)
773 || value == (value & lang::LowerMask<TValue>(TWidth) ), "BITBUFFER",
774 "Upper bits dirty while TMaskValue not set." )
775
776 if constexpr ( (TWidth < bitsof(TValue)) && TMaskValue )
777 value&= lang::LowerMask<TWidth, TValue>();
778
779 word|= (TStorage(value) << idx.bit);
780 lang::ShiftOpRHS bitsWritten= bitsof(TStorage) - idx.bit;
781 value>>= bitsWritten;
782 while(true) // the loop is at least hit once and bit is 0! (but not written in bit)
783 {
784 bb.SetWord(idx, word);
785 idx.pos++;
786 word= TStorage(value);
787 bitsWritten+= bitsof(TStorage);
788 if(bitsWritten >= TWidth )
789 break;
790
791 value>>= bitsof(TStorage);
792 }
793
794 idx.bit= (idx.bit + TWidth) % bitsof(TStorage);
795 if(idx.bit == 0 ) // next buffer value reached?
796 {
797 bb.SetWord(idx, word);
798 idx.pos++;
799 word= 0;
800 }
801 }
802
803 // Helper-versions for signed and bool
804 template<lang::ShiftOpRHS TWidth, typename TValue, bool TMaskValue= false>
805 requires ( std::signed_integral<TValue> && !std::same_as<TValue, bool> )
806 void Write( TValue value)
807 {
808 using TUI= typename std::make_unsigned<TValue>::type;
809 Write<TWidth, TUI, TMaskValue>( static_cast<TUI>( value ) );
810 }
811
812 template<typename TValue>
813 requires ( std::same_as<TValue, bool> )
814 void Write( TValue value)
815 { Write<1, unsigned int, false>( static_cast<unsigned int>( value ) ); }
816
817 #endif // doxygen
818
819 /// Writes the given integral value with the given number of bits to the stream.
820 /// \note Two overloads of this method, selected with keyword \c requires,
821 /// for different integral types exist.
822 /// This is version 1/2 which requires that the given value type is smaller than or equal
823 /// to the storage type.
824 /// \see
825 /// A method that uses a template parameter for the number of bits to write, is
826 /// available with #Write<TWidth,TIntegral>(TIntegral).
827 /// This might be slightly faster and should be used instead of this method, whenever the
828 /// number of bits to write is known at compilation time.
829 ///
830 /// @tparam TValue The integral type of the value to write.
831 /// (Deduced from parameter \p value.)
832 /// @tparam TMaskValue Determines if bits beyond \p width of given \p value may be set and
833 /// have to be masked out. Defaults to \c false.
834 /// @param width The number of bits in \p value.
835 /// @param value The value to write.
836 template<typename TValue, bool TMaskValue= false>
837 requires ( std::integral<TValue> && ( sizeof(TValue) <= sizeof(TStorage) ) )
838 void Write(lang::ShiftOpRHS width, TValue value)
839 {
840 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
841 ALIB_ASSERT_ERROR( width <= bitsof(TValue),
842 "BITBUFFER", "BitBufferBase::Write: Width too high: ", width )
843
844 ALIB_ASSERT_ERROR( TMaskValue
845 || width>=bitsof(TValue)
846 || value == (value & lang::LowerMask<TValue>(width) ),
847 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
848
849 if constexpr (TMaskValue)
850 if( width < bitsof(TValue) )
851 value&= lang::LowerMask<TValue>(width);
852
853 word|= TStorage(value) << idx.bit ;
854 idx.bit+= width;
855 if(idx.bit >= bitsof(TStorage) )
856 {
857 bb.SetWord(idx, word);
858 idx.pos++;
859 word= 0;
860 idx.bit-= bitsof(TStorage);
861 if( idx.bit )
862 word|= ( TStorage(value) >> (width - idx.bit) );
863 }
864 }
865
866 /// Writes the given integral value with the given number of bits to the stream.
867 /// \note Two overloads of this method, selected with keyword \c requires,
868 /// for different integral types exist.
869 /// This is version 2/2 which requires that the given value type is greater than
870 /// as the storage type.
871 ///
872 /// @tparam TValue The integral type of the value to write.
873 /// (Deduced from parameter \p value.)
874 /// @tparam TMaskValue Determines if bits beyond \p width of given \p value may be set and
875 /// have to be masked out. Defaults to \c false.
876 /// @param width The number of bits in \p value.
877 /// @param value The value to write.
878 template<typename TValue, bool TMaskValue= false>
879 requires ( std::integral<TValue> && ( sizeof(TValue) > sizeof(TStorage) ) )
880 void Write(lang::ShiftOpRHS width, TValue value)
881 {
882 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
883 ALIB_ASSERT_ERROR( width <= bitsof(TValue), "BITBUFFER",
884 "BitBufferBase::Write: Width too high: ", width )
885 ALIB_ASSERT_ERROR( TMaskValue
886 || width==bitsof(TValue)
887 || value == (value & lang::LowerMask<TValue>(width) ),
888 "BITBUFFER", "Upper bits dirty while TMaskValue not set.")
889
890 if constexpr (TMaskValue)
891 if( width <= bitsof(TValue) )
892 value&= lang::LowerMask<TValue>(width);
893
894 if( width <= bitsof(TStorage) )
895 {
896 word|= TStorage(value) << idx.bit ;
897 idx.bit+= width;
898 if(idx.bit >= bitsof(TStorage) )
899 {
900 bb.SetWord(idx, word);
901 idx.pos++;
902 word= 0;
903 idx.bit-= bitsof(TStorage);
904 if( idx.bit )
905 word|= ( TStorage(value) >> (width - idx.bit) );
906 }
907 }
908 else
909 {
910 word|= (TStorage(value) << idx.bit);
911 lang::ShiftOpRHS bitsWritten= bitsof(TStorage) - idx.bit;
912 value>>= bitsWritten;
913 while(true) // the loop is at least hit once and bit is 0! (but not written in bit)
914 {
915 bb.SetWord(idx, word);
916 idx.pos++;
917 word= TStorage(value);
918 bitsWritten+= bitsof(TStorage);
919 if(bitsWritten >= width )
920 break;
921 value>>= bitsof(TStorage);
922 }
923 idx.bit= (idx.bit + width) % bitsof(TStorage);
924 if(idx.bit == 0 ) // next buffer value reached?
925 {
926 bb.SetWord(idx, word);
927 idx.pos++;
928 word= 0;
929 }
930 }
931 }
932
933 /// Writes the given unsigned integral value to the stream by writing lower values
934 /// with smaller sizes. The general assumption behind this is that lower values are more frequent
935 /// and the average written size is less than the unencode size - despite the overhead needed
936 /// to write information about how a value is encoded.
937 ///
938 /// The encoding for \e unsigned integrals is as follows:
939 /// - For byte value types, a single bit <c>'0'</c> is written if the value is below \c 8,
940 /// followed by the three bits containing the value. Otherwise, a single bit <c>'1'</c> is
941 /// written, followed by the full 8 bits.
942 /// - For all other value types (16-, 32- and 64-bit) the number of bytes needed is written
943 /// first (one bit in the case of 16-bit values, two bits in the case of 32-bit values
944 /// and three bits in the case of 64 bit values), and then the corresponding amount of
945 /// full bytes are written.
946 ///
947 /// \e Signed integrals are converted to unsigned integrals using the sometimes called
948 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
949 /// positive and uneven. This way, the least significant bit becomes the sign bit.
950 /// The advantage of this approach is that small numbers, negative or positive,
951 /// remain small in respect to their bitwise representation.<p>
952 /// The conversion hence is as follows:
953 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
954 ///
955 /// @tparam TUIntegral The type of the given unsigned integral.
956 /// @param value The value to write.
957 template<typename TUIntegral>
958 requires ( std::unsigned_integral<TUIntegral> && !std::same_as< TUIntegral, bool> )
959 void Write( TUIntegral value )
960 {
961 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
962 writeUIntegral(value);
963 }
964
965 /// Converts the given \e signed integral to an unsigned one using the so-called
966 /// "zig-zag coding". Here, all numbers are doubled and negative numbers are turned
967 /// positive and uneven. This way, the least significant bit becomes the sign bit.
968 /// The advantage of this approach is that small numbers, negative or positive,
969 /// remain small in respect to their bitwise representation.<p>
970 /// The conversion hence is as follows:
971 /// unsigned = signed >= 0 ? signed * 2 : ( (-signed -1 ) * 2 ) | 1
972 ///
973 /// Then calls \alib{bitbuffer::BitWriter;Write<TUIntegral>}.
974 /// @tparam TSIntegral The type of the given signed integral.
975 /// @param value The value to write.
976 template<typename TSIntegral>
977 requires ( std::signed_integral<TSIntegral> && !std::same_as< TSIntegral, bool> )
978 void Write( TSIntegral value )
979 {
980 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
981 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
982 writeUIntegral( value >= 0 ? TUnsigned( value << 1)
983 : TUnsigned( (TUnsigned(-(value+ 1)) << 1) | 1 ) );
984 }
985
986 protected:
987
988 /// Internal method that writes a unsigned 8-bit value.
989 /// @param value The value to write.
990 ALIB_DLL void writeUIntegral( uint8_t value );
991
992 /// Internal method that writes a unsigned 16-bit value.
993 /// @param value The value to write.
994 ALIB_DLL void writeUIntegral( uint16_t value );
995
996 /// Internal method that writes a unsigned 32-bit value.
997 /// @param value The value to write.
998 ALIB_DLL void writeUIntegral( uint32_t value );
999
1000 /// Internal method that writes a unsigned 64-bit value.
1001 /// @param value The value to write.
1002 ALIB_DLL void writeUIntegral( uint64_t value );
1003
1004
1005}; // class BitWriter
1006
1007
1008//==================================================================================================
1009/// Reads bits from a \alib{bitbuffer;BitBufferBase}.
1010//==================================================================================================
1011class BitReader : public BitRWBase
1012{
1013 protected:
1014 /// Local type alias (shortcut)
1016
1017 /// The current word, which is partly read and shifted to start with current bit.
1019
1020 public:
1021 /// Constructs a bit reader using the given bit buffer and starting to read at the beginning.
1022 /// @param buffer The buffer to read from.
1023 explicit BitReader( BitBufferBase& buffer )
1024 : BitRWBase( buffer )
1025 {
1026 word= bb.GetWord(idx);
1027 }
1028
1029
1030 /// Constructs a bit reader using the given bit buffer, starting to read at the
1031 /// given \alib{bitbuffer::BitBufferBase;Index}.
1032 /// @param buffer The buffer to read from.
1033 /// @param index An index providing the postion of the first bit to read in \p buffer.
1034 explicit BitReader( BitBufferBase& buffer, const BitBufferBase::Index& index )
1035 : BitRWBase( buffer )
1036 {
1037 idx.pos= index.pos;
1038 idx.bit= index.bit;
1039 word= bb.GetWord(idx) >> idx.bit;
1040 }
1041
1042 /// Destructs a bit reader. In debug compilations an \alib assertion is raised if the
1043 /// a read operation passed the end of the underlying buffer was performed.
1045 {
1046 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER",
1047 "BitBufferBase overflow detected. Ensure a higher capacity" )
1048 }
1049
1050 /// Resets this reader to the start of the bit buffer.
1051 void Reset()
1052 {
1053 idx.pos= 0;
1054 idx.bit= 0;
1055 word= bb.GetWord(idx);
1056 }
1057
1058 /// Resets this reader to the given index position and calls #Sync().
1059 /// @param index The next read position.
1060 void Reset( const BitBufferBase::Index& index )
1061 {
1062 idx.pos= index.pos;
1063 idx.bit= index.bit;
1064 Sync();
1065 }
1066
1067 /// Re-reads the currently fetched storage word from the memory.
1068 /// \note This method is not needed in common use cases and implemented solely for the
1069 /// purpose to support unit-tests which write and write in parallel to the same
1070 /// bit buffer.
1071 /// @return A reference to this \c BitReader to allow concatenated operations.
1073 {
1074 word= bb.GetWord(idx) >> idx.bit;
1075 return *this;
1076 }
1077
1078 /// Reads the given number of bits from the stream into the given unsigned integral value.
1079 /// \note
1080 /// Two different template functions (selected by keyword \c requires) for the different
1081 /// integral types exist.<br>
1082 /// This is version 1/2: Bits to read are less or equal to the internal buffer width
1083 /// \see
1084 /// This method uses a template parameter for the number of bits to read.
1085 /// A slightly slower, non-templated version is available with #Read<TResult>(ShiftOpRHS),
1086 /// which is to be used when the number of bits to write is determined only at run-time.
1087 /// @tparam TWidth The number of bits in \p{value} to write.
1088 /// @tparam TResult The type of the value to return.
1089 /// @return The value read.
1090 template<lang::ShiftOpRHS TWidth, typename TResult= int>
1091 requires ( std::integral<TResult> && ( TWidth <= bitsof(TStorage)) )
1092 TResult Read()
1093 {
1094 ALIB_ASSERT_ERROR(idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1095
1096 TResult result;
1097
1098 // the one bit case. Could have been left to the compiler to optimize, but who knows.
1099 if constexpr ( TWidth == 1 )
1100 {
1101 result= word & 1;
1102 word>>= 1;
1103 if(++idx.bit == bitsof(TStorage))
1104 {
1105 idx.pos++;
1106 word= bb.GetWord(idx);
1107 idx.bit= 0;
1108 }
1109 return result;
1110 }
1111
1112 static_assert(bitsof(TResult) >= TWidth, "Fixed size to read greater than given result type.");
1113 if constexpr ( TWidth == bitsof(TStorage) )
1114 result= TResult( word );
1115 else
1116 {
1117 result= TResult( word & lang::LowerMask<TWidth, TStorage>() );
1118 word>>= TWidth;
1119 }
1120
1121 idx.bit+= TWidth;
1122 if(idx.bit >= bitsof(TStorage))
1123 {
1124 idx.pos++;
1125 word= bb.GetWord(idx);
1126 idx.bit-= bitsof(TStorage);
1127 if( idx.bit )
1128 {
1129 lang::ShiftOpRHS bitsRead= TWidth - idx.bit;
1130 if constexpr ( TWidth < bitsof(TStorage) )
1131 result |= TResult( ( word << bitsRead )
1133 else
1134 result |= TResult( word << bitsRead );
1135 }
1136
1137 word>>= idx.bit;
1138 }
1139
1140 return result;
1141 }
1142
1143 /// Reads the given number of bits from the stream into the given unsigned integral value.
1144 /// \note
1145 /// Two different template functions (selected by keyword \c requires) for the different
1146 /// integral types exist.<br>
1147 /// This is version 2/2: Bits to read are more than the internal buffer width.
1148 /// \see
1149 /// This method uses a template parameter for the number of bits to read.
1150 /// A slightly slower, non-templated version is available with #Read<TResult>(ShiftOpRHS),
1151 /// which is to be used when the number of bits to write is determined only at run-time.
1152 /// @tparam TWidth The number of bits in \p{value} to write.
1153 /// @tparam TResult The type of the value to return.
1154 /// @return The value read.
1155 template<lang::ShiftOpRHS TWidth, typename TResult= int>
1156 requires ( std::integral<TResult> && ( TWidth > bitsof(TStorage)) )
1157 TResult Read()
1158 {
1159 static_assert(bitsof(TResult) >= TWidth, "Fixed size to read greater than given result type.");
1160 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1161
1162 TResult result = word;
1163 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
1164 do // the loop is at least hit once and bit is 0! (but not written in bit)
1165 {
1166 idx.pos++;
1167 word= bb.GetWord(idx);
1168 result|= TResult(word) << bitsRead;
1169 bitsRead+= bitsof(TStorage);
1170 }
1171 while( bitsRead < TWidth);
1172
1173 idx.bit= (idx.bit + TWidth) % bitsof(TStorage);
1174
1175 // next buffer value reached?
1176 if(idx.bit == 0 )
1177 idx.pos++;
1178 else
1179 result= lang::LowerBits<TWidth, TResult>( result );
1180
1181 word= bb.GetWord(idx) >> idx.bit;
1182
1183 return result;
1184 }
1185
1186 /// Reads the given number of bits from the stream into the given unsigned integral value.
1187 /// \note
1188 /// Different template functions for different integral types exist and are
1189 /// selected with keyword \c requires.
1190 ///
1191 /// \see
1192 /// A method that uses a template parameter for the number of bits to read, is available
1193 /// with #Read<TWidth,TResult>.
1194 /// This might be slightly faster and should be used instead of this method, whenever
1195 /// the number of bits to read is known at compilation time.
1196 ///
1197 /// @tparam TResult The type of the value to return. Defaults to type \c int.
1198 /// @param width The number of bits to read.
1199 /// @return The value read.
1200 template<typename TResult= int>
1201 requires ( sizeof(TResult) <= sizeof(TStorage) )
1202 TResult Read( lang::ShiftOpRHS width )
1203 {
1204 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1205 ALIB_ASSERT_ERROR( bitsof(TResult) >= width, "BITBUFFER",
1206 "Read size given greater than value type.")
1207
1208 TResult result;
1209 if ( width < bitsof(TStorage) )
1210 result= TResult( word & lang::LowerMask<TStorage>(width) );
1211 else
1212 result= TResult( word );
1213 word>>= width;
1214
1215 idx.bit+= width;
1216 if(idx.bit >= bitsof(TStorage))
1217 {
1218 idx.pos++;
1219 word= bb.GetWord(idx);
1220 idx.bit-= bitsof(TStorage);
1221
1222 if( idx.bit )
1223 {
1224 lang::ShiftOpRHS bitsRead= width - idx.bit;
1225 result |= TResult( ( word << bitsRead )
1226 & lang::LowerMask<TStorage>(width) );
1227 word>>= idx.bit;
1228 }
1229 }
1230
1231 return result;
1232 }
1233
1234 /// Reads the given number of bits from the stream into the given unsigned integral value.
1235 /// \note
1236 /// Different template functions for different integral types exist and are
1237 /// selected with keyword \c requires.
1238 ///
1239 /// \see
1240 /// A method that uses a template parameter for the number of bits to read, is available
1241 /// with #Read<TWidth,TResult>.
1242 /// This might be slightly faster and should be used instead of this method, whenever
1243 /// the number of bits to read is known at compilation time.
1244 ///
1245 /// @tparam TResult The type of the value to return. Defaults to type \c int.
1246 /// @param width The number of bits to read.
1247 /// @return The value read.
1248 template<typename TResult= int>
1249 requires ( sizeof(TResult) > sizeof(TStorage) )
1250 TResult Read( lang::ShiftOpRHS width )
1251 {
1252 ALIB_ASSERT_ERROR( idx.pos < bb.Capacity(), "BITBUFFER", "BitBufferBase overflow" )
1253 ALIB_ASSERT_ERROR( bitsof(TResult) >= width , "BITBUFFER",
1254 "Read size given greater than value type.")
1255
1256 if( width <= bitsof(TStorage))
1257 {
1258 TResult result;
1259 if ( width < bitsof(TStorage) )
1260 result= TResult( word & lang::LowerMask<TStorage>(width) );
1261 else
1262 result= TResult( word );
1263 word>>= width;
1264
1265 idx.bit+= width;
1266 if(idx.bit >= bitsof(TStorage))
1267 {
1268 idx.pos++;
1269 word= bb.GetWord(idx);
1270 idx.bit-= bitsof(TStorage);
1271
1272 if( idx.bit )
1273 {
1274 lang::ShiftOpRHS bitsRead= width - idx.bit;
1275 result |= TResult( ( word << bitsRead )
1276 & lang::LowerMask<TStorage>(width) );
1277 word>>= idx.bit;
1278 }
1279 }
1280
1281 return result;
1282 }
1283 else
1284 {
1285 TResult result = TResult( word );
1286 lang::ShiftOpRHS bitsRead= bitsof(TStorage) - idx.bit;
1287 do // the loop is at least hit once and bit is 0! (but not written in bit)
1288 {
1289 idx.pos++;
1290 word= bb.GetWord(idx);
1291 result|= TResult(word) << bitsRead;
1292 bitsRead+= bitsof(TStorage);
1293 }
1294 while( bitsRead < width);
1295
1296 idx.bit= (idx.bit + width) % bitsof(TStorage);
1297
1298 // next buffer value reached?
1299 if(idx.bit == 0 )
1300 {
1301 idx.pos++;
1302 word= bb.GetWord(idx);
1303 }
1304 else
1305 {
1306 result= lang::LowerBits<TResult>( width, result );
1307 word>>= width;
1308 }
1309 return result;
1310 }
1311 }
1312
1313 /// Reads the given integral value from the stream.
1314 /// Information about the encoding of the values is given with the documentation of
1315 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1316 /// This overload reads unsigned integral types of 8-bit width.
1317 /// @tparam TUIntegral The unsigned integral type to read.
1318 /// @return The value read from the bit buffer.
1319 template< typename TUIntegral>
1320 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 8) )
1321 TUIntegral Read() { return readUIntegral8(); }
1322
1323 /// Reads the given integral value from the stream.
1324 /// Information about the encoding of the values is given with the documentation of
1325 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1326 /// This overload reads unsigned integral types of 16-bit width.
1327 /// @tparam TUIntegral The unsigned integral type to read.
1328 /// @return The value read from the bit buffer.
1329 template< typename TUIntegral>
1330 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 16) )
1331 TUIntegral Read() { return readUIntegral16(); }
1332
1333
1334 /// Reads the given integral value from the stream.
1335 /// Information about the encoding of the values is given with the documentation of
1336 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1337 /// This overload reads unsigned integral types of 32-bit width.
1338 /// @tparam TUIntegral The unsigned integral type to read.
1339 /// @return The value read from the bit buffer.
1340 template< typename TUIntegral>
1341 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 32) )
1342 TUIntegral Read() { return readUIntegral32(); }
1343
1344
1345 /// Reads the given integral value from the stream.
1346 /// Information about the encoding of the values is given with the documentation of
1347 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1348 /// This overload reads unsigned integral types of 64-bit width.
1349 /// @tparam TUIntegral The unsigned integral type to read.
1350 /// @return The value read from the bit buffer.
1351 template< typename TUIntegral>
1352 requires( std::unsigned_integral<TUIntegral> && (bitsof(TUIntegral) == 64) )
1353 TUIntegral Read() { return readUIntegral64(); }
1354
1355
1356 /// Reads the given signed integral value from the stream.
1357 /// Information about the encoding of the values is given with the documentation of
1358 /// \alib{bitbuffer;BitWriter::Write<TIntegral>(TIntegral)}.<br>
1359 /// This overload reads signed integral types.
1360 /// @tparam TSIntegral The signed integral type to read.
1361 /// @return The value read from the bit buffer.
1362 template< typename TSIntegral>
1363 requires( std::signed_integral<TSIntegral> )
1364 TSIntegral Read()
1365 {
1366 using TUnsigned= typename std::make_unsigned<TSIntegral>::type;
1367 TUnsigned result= Read<TUnsigned>();
1368 return result & 1 ? -TSIntegral( result >> 1 ) - 1
1369 : TSIntegral( result >> 1 );
1370 }
1371
1372 protected:
1373 /// Internal method that reads a unsigned 8-bit value.
1374 /// @return The value read.
1375 ALIB_DLL uint8_t readUIntegral8();
1376
1377 /// Internal method that reads a unsigned 16-bit value.
1378 /// @return The value read.
1379 ALIB_DLL uint16_t readUIntegral16();
1380
1381 /// Internal method that reads a unsigned 32-bit value.
1382 /// @return The value read.
1383 ALIB_DLL uint32_t readUIntegral32();
1384
1385 /// Internal method that reads a unsigned 64-bit value.
1386 /// @return The value read.
1387 ALIB_DLL uint64_t readUIntegral64();
1388
1389
1390}; // class BitReader
1391
1392} // namespace alib[::bitbuffer]
1393
1394/// Type alias in namespace \b alib.
1396
1397/// Type alias in namespace \b alib.
1399
1400/// Type alias in namespace \b alib.
1401template<uinteger TCapacity>
1403
1404/// Type alias in namespace \b alib.
1406
1407/// Type alias in namespace \b alib.
1409
1410/// Type alias in namespace \b alib.
1411using ShiftOpRHS = int;
1412
1413} // namespace [alib]
1414
1415
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:96
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:84
virtual ALIB_DLL uinteger Capacity() const =0
uinteger RemainingSize(const Index &idx) const
ALIB_DLL Index Unterminate(Index terminationIndex)
Definition bitbuffer.cpp:55
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
StdVectorMono< 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:1418
#define ALIB_DLL
Definition alib.inl:496
#define ALIB_ERROR(domain,...)
Definition alib.inl:1045
#define ALIB_EXPORT
Definition alib.inl:488
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
constexpr int Log2OfSize()
Definition bits.inl:205
int ShiftOpRHS
Definition bits.inl:20
constexpr TIntegral LowerBits(TIntegral value)
Definition bits.inl:169
constexpr TIntegral LowerMask()
Definition bits.inl:53
bitbuffer::BitReader BitReader
Type alias in namespace alib.
std::vector< T, SCAMono< T > > StdVectorMono
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.