ALib C++ Library
Library Version: 2510 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{
39 // write termination bit
40 {
41 BitWriter bw(*this, idx);
42 bw.Write<1>(1);
43 idx= bw.GetIndex();
44 }// <bw.Flush
45
46 // fast forward to next word
47 if(idx.bit)
48 {
49 idx.pos++;
50 idx.bit= 0;
51 }
52 return idx;
53}
54
56{
57 ALIB_ASSERT_ERROR( terminationIndex.pos > 0
58 && terminationIndex.bit == 0
59 && data[terminationIndex.pos - 1] != 0,
60 "BITBUFFER", "Given index is no termination index" )
61
62 // go back to previous word...
63 terminationIndex.pos--;
64 TStorage word= GetWord(terminationIndex);
65
66 //...search and delete MSB
67 terminationIndex.bit= lang::MSB(word );
68 terminationIndex.bit--;
69 word^= BitBuffer::TStorage(1) << terminationIndex.bit;
70
71 // store word and return new reduced index
72 SetWord(terminationIndex, word );
73 return terminationIndex;
74}
75
76#if !DOXYGEN
77// anonymous check if this platform has little endian encoding
78// already (done once). If so, this method does nothing.
79namespace
80{
81 static int isLittleEndianEncoding= 0;
82 static BitBufferBase::TStorage testWord;
83 bool IsLittleEndianEncoding()
84 {
85 if( isLittleEndianEncoding == 0 )
86 {
87 ALIB_STATIC_ASSERT( Sizeof_int_must_be_16_32_or_64,
91 "Platform not supported")
92
93 isLittleEndianEncoding= 2;
94 if constexpr ( bitsof(BitBufferBase::TStorage) == 16 )
95 {
96 testWord= 0x2211;
97 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
98 if( *bytes == 0x11 && *(bytes+1) == 0x22)
99 isLittleEndianEncoding= 1;
100 }
101
102 else if constexpr ( bitsof(BitBufferBase::TStorage) == 32 )
103 {
104 testWord= 0x44332211;
105 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
106 if( * bytes == 0x11 && *(bytes+1) == 0x22
107 && *(bytes+2) == 0x33 && *(bytes+3) == 0x44 )
108 isLittleEndianEncoding= 1;
109 }
110
111 else if constexpr ( bitsof(BitBufferBase::TStorage) == 64 )
112 {
114 testWord= 0x8877665544332211u;
115 uint8_t* bytes= reinterpret_cast<uint8_t*>( &testWord );
116 if( * bytes == 0x11 && *(bytes+1) == 0x22
117 && *(bytes+2) == 0x33 && *(bytes+3) == 0x44
118 && *(bytes+4) == 0x55 && *(bytes+5) == 0x66
119 && *(bytes+6) == 0x77 && *(bytes+7) == 0x88 )
120 isLittleEndianEncoding= 1;
122
123 }
124 }
125
126 return (isLittleEndianEncoding == 1);
127 }
128}
129#endif
130
131void BitBufferBase::ToLittleEndianEncoding( const Index& startIndex, const Index& endIndex )
132{
133 ALIB_ASSERT_ERROR( startIndex.IsAligned(), "BITBUFFER",
134 "Given start index is not algined. The easiest way to get an aligned "
135 "index is to terminate the buffer." )
136
137 if( IsLittleEndianEncoding())
138 return;
139
140 const size_t end= endIndex.pos + (endIndex.bit != 0 );
141 for (size_t pos= startIndex.pos; pos < end; ++pos)
142 {
143 TStorage word = data[pos];
144 uint8_t* bytes= reinterpret_cast<uint8_t*>( &data[pos] );
145 bytes[0]= word & 0xFF;
146 word>>= 8; bytes[1]= word & 0xFF;
147
148 if constexpr ( bitsof(TStorage) > 16 )
149 {
150 word>>= 8; bytes[2]= word & 0xFF;
151 word>>= 8; bytes[3]= word & 0xFF;
152 }
153
154 if constexpr ( bitsof(TStorage) > 32 )
155 {
156 word>>= 8; bytes[4]= word & 0xFF;
157 word>>= 8; bytes[5]= word & 0xFF;
158 word>>= 8; bytes[6]= word & 0xFF;
159 word>>= 8; bytes[7]= word & 0xFF;
160 }
161 }
162}
163
164void BitBufferBase::FromLittleEndianEncoding( const Index& startIndex, const Index& endIndex )
165{
166 if( IsLittleEndianEncoding())
167 return;
168
169 size_t end= endIndex.pos + (endIndex.bit != 0 );
170 for (size_t pos= startIndex.pos; pos < end; ++pos)
171 {
172 TStorage word = 0;
173 uint8_t* bytes= reinterpret_cast<uint8_t*>( &data[pos] );
174 word|= TStorage(bytes[0]);
175 word|= TStorage(bytes[1]) << 8;
176
177 if constexpr ( bitsof(TStorage) > 16 )
178 {
179 word|= TStorage(bytes[2]) << 16;
180 word|= TStorage(bytes[3]) << 24;
181 }
182
183 if constexpr ( bitsof(TStorage) > 32 )
184 {
186 word|= TStorage(bytes[4]) << 32;
187 word|= TStorage(bytes[5]) << 40;
188 word|= TStorage(bytes[6]) << 48;
189 word|= TStorage(bytes[7]) << 56;
191 }
192
193 data[pos]= word;
194 }
195}
196
197
198
199// write 8-bit values
201{
202 if( val < (1<<3) )
203 {
204 Write<4>( val << 1); // | 0
205 return;
206 }
207
208 Write<9>( (val << 1) |1 ) ;
209}
210
211// write 16-bit values
213{
214 if( val < (1<<8) )
215 {
216 Write<9>( val << 1);
217 return;
218 }
219
220 Write<17>( ( val << 1 ) | 1 ) ;
221}
222
223// write 32-bit byte values
225{
226 if( val < (1<< 8) ) { Write<10>( val << 2 ); }
227 else if( val < (1<<16) ) { Write<18>(( val << 2) | 1u ); }
228 else if( val < (1<<24) ) { Write<26>(( val << 2) | 2u ); }
229 else { Write< 2>( 3 );
230 Write<32>( val ); }
231}
232
233// write 64-bit byte values
235{
236 if( val < uint64_t(1) << 8 ) { Write<11>( int16_t (val) << 3 ); }
237 else if( val < uint64_t(1) << 16 ) { Write<19>( ( uint32_t (val) << 3 ) | 1u); }
238 else if( val < uint64_t(1) << 24 ) { Write<27>( ( uint32_t (val) << 3 ) | 2u); }
239 else if( val < uint64_t(1) << 32 ) { Write<35>( ( val << 3 ) | 3u); }
240 else if( val < uint64_t(1) << 40 ) { Write<43>( ( val << 3 ) | 4u); }
241 else if( val < uint64_t(1) << 48 ) { Write<51>( ( val << 3 ) | 5u); }
242 else if( val < uint64_t(1) << 56 ) { Write<59>( ( val << 3 ) | 6u); }
243 else { Write< 3>( 7 );
244 Write<64>( val ); }
245}
246
247
248// read 8-bit values
250{
251 auto result= Read<4>();
252 if( !(result & 1))
253 return uint8_t(result >> 1);
254
255 return uint8_t( result >> 1
256 | Read<5>() << 3 );
257}
258
260{
261 auto result= Read< 9>();
262 if( !(result & 1))
263 return uint16_t(result >> 1);
264
265 return uint16_t( result >> 1
266 | Read<8>() << 8 );
267}
268
270{
271 uint32_t result= Read< 10, uint32_t>();
272 switch (result & 3)
273 {
274 case 0: return uint32_t(result >> 2);
275 case 1: return uint32_t(result >> 2 | (Read< 8, uint32_t>() << 8 ) );
276 case 2: return uint32_t(result >> 2 | (Read< 16, uint32_t>() << 8 ) );
277 default: return uint32_t(result >> 2 | (Read< 24, uint32_t>() << 8 ) );
278 }
279}
280
282{
283 uint64_t result= Read< 11, uint64_t>();
284 switch (result & 7)
285 {
286 case 0: return uint64_t(result >> 3);
287 case 1: return uint64_t(result >> 3 | (Read< 8, uint64_t>() << 8 ));
288 case 2: return uint64_t(result >> 3 | (Read< 16, uint64_t>() << 8 ));
289 case 3: return uint64_t(result >> 3 | (Read< 24, uint64_t>() << 8 ));
290 case 4: return uint64_t(result >> 3 | (Read< 32, uint64_t>() << 8 ));
291 case 5: return uint64_t(result >> 3 | (Read< 40, uint64_t>() << 8 ));
292 case 6: return uint64_t(result >> 3 | (Read< 48, uint64_t>() << 8 ));
293 default: return uint64_t(result >> 3 | (Read< 56, uint64_t>() << 8 ));
294 }
295}
296
297}} // namespace [alib::bitbuffer]
298
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:55
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:1418
#define ALIB_WARNINGS_IGNORE_INTEGRAL_CONSTANT_OVERFLOW
Definition alib.inl:685
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:705
#define ALIB_STATIC_ASSERT(CondVariable, Cond, Message)
Definition alib.inl:954
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
#define ALIB_WARNINGS_IGNORE_INTEGER_OVERFLOW
Definition alib.inl:696
constexpr int MSB(TIntegral value)
Definition bits.inl:325