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