ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
bitbuffer.cpp
1//##################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
16
17//============================================== Module ============================================
18#if ALIB_C20_MODULES
19 module ALib.BitBuffer;
20#else
21# include "ALib.BitBuffer.H"
22#endif
23//========================================== Implementation ========================================
24namespace alib {
25
26//==================================================================================================
27/// This \alibmod implements a buffer that is write- and readable bit by bit.
28/// Conversion for standard numerical types is provided. Furthermore several array compression
29/// algorithms are given, which allow the bit buffers to be compressed before transported or
30/// stored.
31///
32/// Please consult the little quick
33/// \ref alib_mod_bitbuffer "ALib Module BitBuffer - Programmer's Manual" for further information.
34//==================================================================================================
35namespace bitbuffer {
36
38 // write termination bit
39 {
40 BitWriter bw(*this, idx);
41 bw.Write<1>(1);
42 idx= bw.GetIndex();
43 }// <bw.Flush
44
45 // fast forward to next word
46 if(idx.bit) {
47 idx.pos++;
48 idx.bit= 0;
49 }
50 return idx;
51}
52
54 ALIB_ASSERT_ERROR( terminationIndex.pos > 0
55 && terminationIndex.bit == 0
56 && data[terminationIndex.pos - 1] != 0,
57 "BITBUFFER", "Given index is no termination index" )
58
59 // go back to previous word...
60 terminationIndex.pos--;
61 TStorage word= GetWord(terminationIndex);
62
63 //...search and delete MSB
64 terminationIndex.bit= lang::MSB(word );
65 terminationIndex.bit--;
66 word^= BitBuffer::TStorage(1) << terminationIndex.bit;
67
68 // store word and return new reduced index
69 SetWord(terminationIndex, word );
70 return terminationIndex;
71}
72
73#if !DOXYGEN
74// anonymous check if this platform has little endian encoding
75// already (done once). If so, this method does nothing.
76namespace
77{
78 static int isLittleEndianEncoding= 0;
79 static BitBufferBase::TStorage testWord;
80bool IsLittleEndianEncoding() {
81 if( isLittleEndianEncoding == 0 ) {
82 ALIB_STATIC_ASSERT( Sizeof_int_must_be_16_32_or_64,
86 "Platform not supported")
87
88 isLittleEndianEncoding= 2;
89 if constexpr ( bitsof(BitBufferBase::TStorage) == 16 ) {
90 testWord= 0x2211;
91 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
92 if( *bytes == 0x11 && *(bytes+1) == 0x22)
93 isLittleEndianEncoding= 1;
94 }
95
96 else if constexpr ( bitsof(BitBufferBase::TStorage) == 32 ) {
97 testWord= 0x44332211;
98 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
99 if( * bytes == 0x11 && *(bytes+1) == 0x22
100 && *(bytes+2) == 0x33 && *(bytes+3) == 0x44 )
101 isLittleEndianEncoding= 1;
102 }
103
104 else if constexpr ( bitsof(BitBufferBase::TStorage) == 64 ) {
106 testWord= 0x8877665544332211u;
107 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
108 if( * bytes == 0x11 && *(bytes+1) == 0x22
109 && *(bytes+2) == 0x33 && *(bytes+3) == 0x44
110 && *(bytes+4) == 0x55 && *(bytes+5) == 0x66
111 && *(bytes+6) == 0x77 && *(bytes+7) == 0x88 )
112 isLittleEndianEncoding= 1;
114
115 } }
116
117 return (isLittleEndianEncoding == 1);
118}
119}
120#endif
121
122void BitBufferBase::ToLittleEndianEncoding( const Index& startIndex, const Index& endIndex ) {
123 ALIB_ASSERT_ERROR( startIndex.IsAligned(), "BITBUFFER",
124 "Given start index is not algined. The easiest way to get an aligned "
125 "index is to terminate the buffer." )
126
127 if( IsLittleEndianEncoding())
128 return;
129
130 const size_t end= endIndex.pos + (endIndex.bit != 0 );
131 for (size_t pos= startIndex.pos; pos < end; ++pos) {
132 TStorage word = data[pos];
133 uint8_t* bytes= reinterpret_cast<uint8_t*>( &data[pos] );
134 bytes[0]= word & 0xFF;
135 word>>= 8; bytes[1]= word & 0xFF;
136
137 if constexpr ( bitsof(TStorage) > 16 ) {
138 word>>= 8; bytes[2]= word & 0xFF;
139 word>>= 8; bytes[3]= word & 0xFF;
140 }
141
142 if constexpr ( bitsof(TStorage) > 32 ) {
143 word>>= 8; bytes[4]= word & 0xFF;
144 word>>= 8; bytes[5]= word & 0xFF;
145 word>>= 8; bytes[6]= word & 0xFF;
146 word>>= 8; bytes[7]= word & 0xFF;
147} } }
148
149void BitBufferBase::FromLittleEndianEncoding( const Index& startIndex, const Index& endIndex ) {
150 if( IsLittleEndianEncoding())
151 return;
152
153 size_t end= endIndex.pos + (endIndex.bit != 0 );
154 for (size_t pos= startIndex.pos; pos < end; ++pos) {
155 TStorage word = 0;
156 uint8_t* bytes= reinterpret_cast<uint8_t*>( &data[pos] );
157 word|= TStorage(bytes[0]);
158 word|= TStorage(bytes[1]) << 8;
159
160 if constexpr ( bitsof(TStorage) > 16 ) {
161 word|= TStorage(bytes[2]) << 16;
162 word|= TStorage(bytes[3]) << 24;
163 }
164
165 if constexpr ( bitsof(TStorage) > 32 ) {
167 word|= TStorage(bytes[4]) << 32;
168 word|= TStorage(bytes[5]) << 40;
169 word|= TStorage(bytes[6]) << 48;
170 word|= TStorage(bytes[7]) << 56;
172 }
173
174 data[pos]= word;
175} }
176
177
178
179// write 8-bit values
180void BitWriter::writeUIntegral(uint8_t val) {
181 if( val < (1<<3) ) {
182 Write<4>( val << 1); // | 0
183 return;
184 }
185
186 Write<9>( (val << 1) |1 ) ;
187}
188
189// write 16-bit values
190void BitWriter::writeUIntegral(uint16_t val) {
191 if( val < (1<<8) ) {
192 Write<9>( val << 1);
193 return;
194 }
195
196 Write<17>( ( val << 1 ) | 1 ) ;
197}
198
199// write 32-bit byte values
200void BitWriter::writeUIntegral(uint32_t val) {
201 if( val < (1<< 8) ) { Write<10>( val << 2 ); }
202 else if( val < (1<<16) ) { Write<18>(( val << 2) | 1u ); }
203 else if( val < (1<<24) ) { Write<26>(( val << 2) | 2u ); }
204 else { Write< 2>( 3 );
205 Write<32>( val ); }
206}
207
208// write 64-bit byte values
209void BitWriter::writeUIntegral(uint64_t val) {
210 if( val < uint64_t(1) << 8 ) { Write<11>( int16_t (val) << 3 ); }
211 else if( val < uint64_t(1) << 16 ) { Write<19>( ( uint32_t (val) << 3 ) | 1u); }
212 else if( val < uint64_t(1) << 24 ) { Write<27>( ( uint32_t (val) << 3 ) | 2u); }
213 else if( val < uint64_t(1) << 32 ) { Write<35>( ( val << 3 ) | 3u); }
214 else if( val < uint64_t(1) << 40 ) { Write<43>( ( val << 3 ) | 4u); }
215 else if( val < uint64_t(1) << 48 ) { Write<51>( ( val << 3 ) | 5u); }
216 else if( val < uint64_t(1) << 56 ) { Write<59>( ( val << 3 ) | 6u); }
217 else { Write< 3>( 7 );
218 Write<64>( val ); }
219}
220
221
222// read 8-bit values
224 auto result= Read<4>();
225 if( !(result & 1))
226 return uint8_t(result >> 1);
227
228 return uint8_t( result >> 1
229 | Read<5>() << 3 );
230}
231
233 auto result= Read< 9>();
234 if( !(result & 1))
235 return uint16_t(result >> 1);
236
237 return uint16_t( result >> 1
238 | Read<8>() << 8 );
239}
240
242 uint32_t result= Read< 10, uint32_t>();
243 switch (result & 3) {
244 case 0: return uint32_t(result >> 2);
245 case 1: return uint32_t(result >> 2 | (Read< 8, uint32_t>() << 8 ) );
246 case 2: return uint32_t(result >> 2 | (Read< 16, uint32_t>() << 8 ) );
247 default: return uint32_t(result >> 2 | (Read< 24, uint32_t>() << 8 ) );
248} }
249
251 uint64_t result= Read< 11, uint64_t>();
252 switch (result & 7) {
253 case 0: return uint64_t(result >> 3);
254 case 1: return uint64_t(result >> 3 | (Read< 8, uint64_t>() << 8 ));
255 case 2: return uint64_t(result >> 3 | (Read< 16, uint64_t>() << 8 ));
256 case 3: return uint64_t(result >> 3 | (Read< 24, uint64_t>() << 8 ));
257 case 4: return uint64_t(result >> 3 | (Read< 32, uint64_t>() << 8 ));
258 case 5: return uint64_t(result >> 3 | (Read< 40, uint64_t>() << 8 ));
259 case 6: return uint64_t(result >> 3 | (Read< 48, uint64_t>() << 8 ));
260 default: return uint64_t(result >> 3 | (Read< 56, uint64_t>() << 8 ));
261} }
262
263}} // namespace [alib::bitbuffer]
lang::ShiftOpRHS bit
Current bit index in the current word.
Definition bitbuffer.inl:63
uinteger pos
Index of the current word to read/write.
Definition bitbuffer.inl:62
ALIB_DLL Index Unterminate(Index terminationIndex)
Definition bitbuffer.cpp:53
void SetWord(const Index &index, TStorage value)
ALIB_DLL Index Terminate(Index writerIndex)
Definition bitbuffer.cpp:37
ALIB_DLL void ToLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
ALIB_DLL void FromLittleEndianEncoding(const Index &startIndex, const Index &endIndex)
TStorage GetWord(const Index &index) const
BitBufferBase::Index GetIndex() const
ALIB_DLL uint64_t readUIntegral64()
ALIB_DLL uint32_t readUIntegral32()
ALIB_DLL uint16_t readUIntegral16()
ALIB_DLL uint8_t readUIntegral8()
Writes bits into a BitBufferBase.
void Write(TIntegral value)
ALIB_DLL void writeUIntegral(uint8_t value)
#define bitsof(type)
Definition alib.inl:1435
#define ALIB_WARNINGS_IGNORE_INTEGRAL_CONSTANT_OVERFLOW
Definition alib.inl:699
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:719
#define ALIB_STATIC_ASSERT(CondVariable, Cond, Message)
Definition alib.inl:971
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
#define ALIB_WARNINGS_IGNORE_INTEGER_OVERFLOW
Definition alib.inl:710
constexpr int MSB(TIntegral value)
Definition bits.inl:314