Algorithms Library Toolkit
A toolkit for algorithms, especially for algorithms on formal languages
SparseBoolVector.hpp
Go to the documentation of this file.
1
6#pragma once
7
8#include <alib/list>
9#include <alib/tuple>
10#include <alib/vector>
11
12/* Canonical representation kept by all operations is in form of blocks of pairs run and word, where each word must contain at least one set bit, with exception of the last word.
13 * Empty sequence of bits is represented by empty list of elements and size equal to zero.
14 * If the size of the representation is divisible by sizeof ( unsigned ) * BITS_IN_BYTE then the last block must either be of nonzero run or its word must contain at least one set bit. This is not with contradiction with the first line.
15 *
16 * Examples:
17 * least significant bit
18 * v
19 * size = 32 [(0, 00000000000000000000000000000000)] is representing 32 times zero
20 * size = 32 [(0, 00000000000000000000000000000001)] is representing 31 times zero and one
21 * size = 33 [(1, 00000000000000000000000000000000)] is representing 31 times zero
22 * size = 64 [(0, 00000000000000000000000000000001), (0, 00000000000000000000000000000000)] is representing 31 times zero, one and 32 times zero
23 * */
24
25namespace common {
26
28 static const size_t BITS_IN_BYTE = 8;
29public:
30// --------------------------------------------------------------------------------------------------------------------------------------------------
31
32 struct element {
33 unsigned run;
34 unsigned word;
35
36 bool operator == ( const element & other ) const {
37 return run == other.run && word == other.word;
38 }
39
40 std::strong_ordering operator <=> ( const element & other ) const {
41 return std::tie ( run, word ) <=> std::tie ( other.run, other.word );
42 }
43 };
44
46 size_t m_Size { 0 };
47
48private:
49 static inline unsigned getMask ( size_t dist ) {
50 return ( ( 1u ) << dist ) - 1;
51 }
52
53// --------------------------------------------------------------------------------------------------------------------------------------------------
54
55 void packData ( ) {
56 size_t sizeWithin = m_Size % ( sizeof ( unsigned ) * BITS_IN_BYTE );
57 size_t sizeBlocks = m_Size / ( sizeof ( unsigned ) * BITS_IN_BYTE ) + static_cast < unsigned > ( sizeWithin != 0 );
58 unsigned mask = getMask ( sizeWithin );
59
60 // crop by size
61 ext::list < element >::iterator elementIter = m_Data.begin ( );
62 for ( ; elementIter != m_Data.end ( ); ++ elementIter ) {
63 if ( sizeBlocks <= elementIter->run + 1 )
64 break;
65 sizeBlocks -= elementIter->run + 1;
66 }
67
68 // sizeBlocks is smaller or equal to elementIter->run + 1
69 if ( sizeBlocks == elementIter->run + 1 ) {
70 if ( mask != 0 )
71 elementIter->word &= mask;
72 } else {
73 elementIter->run = sizeBlocks - 1;
74 elementIter->word = 0;
75 }
76 ++ elementIter;
77
78 for ( ; elementIter != m_Data.end ( ); ) {
79 elementIter = m_Data.erase ( elementIter );
80 }
81
82 // erase not needed blocks
83 unsigned runCarry = 0;
84 for ( elementIter = m_Data.begin ( ); elementIter != m_Data.end ( ); ++ elementIter ) {
85 while ( elementIter->word == 0 && std::next ( elementIter ) != m_Data.end ( ) ) {
86 runCarry += elementIter->run + 1;
87 elementIter = m_Data.erase ( elementIter );
88 }
89 elementIter->run += runCarry;
90 runCarry = 0;
91 }
92 }
93
94// --------------------------------------------------------------------------------------------------------------------------------------------------
95
96public:
97 SparseBoolVector ( ) = default;
98
100 for ( bool boolean : raw ) {
101 push_back ( boolean );
102 }
103 }
104
106 packData ( );
107 }
108
109// --------------------------------------------------------------------------------------------------------------------------------------------------
110
111 void push_back ( bool boolean ) {
112 size_t sizeWithin = m_Size % ( sizeof ( unsigned ) * BITS_IN_BYTE );
113
114 if ( m_Data.empty ( ) ) {
115 m_Data.push_back ( element { 0, 0 } );
116 } else if ( sizeWithin == 0 && m_Data.back ( ).word == 0 ) {
117 m_Data.back ( ).run += 1;
118 } else if ( sizeWithin == 0 && m_Data.back ( ).word != 0 ) {
119 m_Data.push_back ( element { 0, 0 } );
120 }
121
122 m_Data.back ( ).word |= static_cast < unsigned > ( boolean ) << sizeWithin;
123 m_Size += 1;
124 }
125
126// --------------------------------------------------------------------------------------------------------------------------------------------------
127
128 bool operator [] ( size_t index ) const {
129 size_t sizeWithin = index % ( sizeof ( unsigned ) * BITS_IN_BYTE );
130 size_t sizeBlocks = index / ( sizeof ( unsigned ) * BITS_IN_BYTE );
131
132 ext::list < element >::const_iterator elementIter = m_Data.begin ( );
133 for ( ; elementIter != m_Data.end ( ); ++ elementIter ) {
134 if ( elementIter->run + 1 > sizeBlocks )
135 break;
136 sizeBlocks -= elementIter->run + 1;
137 }
138 if ( elementIter->run > sizeBlocks )
139 return false;
140 else
141 return static_cast < bool > ( elementIter->word & 1u << sizeWithin );
142 }
143
144private:
145 class BitReference {
148 size_t sizeWithin;
149 size_t sizeBlocks;
150 public:
151 BitReference ( ext::list < element > & d, ext::list < element >::iterator iter, size_t within, size_t blocks ) : data ( d ), elementIter ( iter ), sizeWithin ( within ), sizeBlocks ( blocks ) {
152 }
153
154 BitReference & operator = ( bool value ) {
155 if ( elementIter->run > sizeBlocks ) {
156 elementIter->run -= sizeBlocks + 1;
157 elementIter = data.insert ( elementIter, element { static_cast < unsigned > ( sizeBlocks ), 0 } );
158 }
159 if ( value )
160 elementIter->word |= 1u << sizeWithin;
161 else
162 elementIter->word &= ~ ( 1u << sizeWithin );
163
164 return * this;
165 }
166
167 operator bool ( ) {
168 if ( elementIter->run > sizeBlocks )
169 return false;
170 else
171 return elementIter->word & 1u << sizeWithin;
172 }
173
174 };
175
176public:
177 BitReference operator [] ( size_t index ) {
178 size_t sizeWithin = index % ( sizeof ( unsigned ) * BITS_IN_BYTE );
179 size_t sizeBlocks = index / ( sizeof ( unsigned ) * BITS_IN_BYTE );
180
181 ext::list < element >::iterator elementIter = m_Data.begin ( );
182 for ( ; elementIter != m_Data.end ( ); ++ elementIter ) {
183 if ( elementIter->run + 1 > sizeBlocks )
184 break;
185 sizeBlocks -= elementIter->run + 1;
186 }
187 return BitReference ( m_Data, elementIter, sizeWithin, sizeBlocks );
188 }
189
190// --------------------------------------------------------------------------------------------------------------------------------------------------
191
192 operator ext::vector < bool > ( ) const {
194
195 for ( const element & elem : m_Data ) {
196 for ( unsigned i = 0; i < elem.run ; ++i )
197 for ( size_t j = 0; j < sizeof ( unsigned ) * BITS_IN_BYTE; ++j )
198 res.push_back ( false );
199
200 for ( size_t i = 0; i < sizeof ( unsigned ) * BITS_IN_BYTE; ++i ) {
201 res.push_back ( elem.word & 1u << i );
202 }
203 }
204
205 res.resize ( m_Size );
206
207 return res;
208 }
209
210// --------------------------------------------------------------------------------------------------------------------------------------------------
211
212 void resize ( size_t newSize ) {
213 if ( newSize > m_Size ) {
214 // could be better
215 size_t added = ( newSize - m_Size ) / ( sizeof ( unsigned ) * BITS_IN_BYTE ) + 1;
216 m_Data.push_back ( element { static_cast < unsigned > ( added ), 0 } );
217 }
218 m_Size = newSize;
219
220 packData ( );
221 }
222
223 size_t size ( ) const {
224 return m_Size;
225 }
226
227 const ext::list < element > & data ( ) const {
228 return m_Data;
229 }
230
231// --------------------------------------------------------------------------------------------------------------------------------------------------
232
233 bool operator == ( const SparseBoolVector & other ) const {
234 return m_Size == other.m_Size && m_Data == other.m_Data;
235 }
236
237 std::strong_ordering operator <=> ( const SparseBoolVector & other ) const {
238 return ext::tie ( m_Size, m_Data ) <=> ext::tie ( other.m_Size, other.m_Data );
239 }
240
241// --------------------------------------------------------------------------------------------------------------------------------------------------
242
243 friend SparseBoolVector & operator <<= ( SparseBoolVector & A, size_t dist ) {
244 if ( A.m_Size == 0 || dist == 0 )
245 return A;
246
247 size_t distBlocks = dist / ( sizeof ( unsigned ) * BITS_IN_BYTE );
248 size_t distWithin = dist % ( sizeof ( unsigned ) * BITS_IN_BYTE );
249 size_t backDist = sizeof ( unsigned ) * BITS_IN_BYTE - distWithin;
250
251 // shift by block
252 A.m_Data.front ( ).run += distBlocks;
253
254 if ( distWithin == 0 ) {
255 A.packData ( );
256 return A;
257 }
258
259 unsigned shiftedWord = 0;
260
261 for ( auto elementIter = A.m_Data.begin ( ); elementIter != A.m_Data.end ( ); ++ elementIter ) {
262 if ( shiftedWord != 0 && elementIter->run != 0 ) {
263 // shift into new block borrow from this run
264 elementIter->run -= 1;
265
266 elementIter = A.m_Data.insert ( elementIter, element { 0, shiftedWord } );
267
268 shiftedWord = 0;
269 } else {
270 unsigned tmp = elementIter->word >> backDist;
271 elementIter->word = elementIter->word << distWithin | shiftedWord;
272 shiftedWord = tmp;
273 }
274 }
275
276 A.packData ( );
277
278 return A;
279 }
280
282 A <<= dist;
283 return A;
284 }
285
286// --------------------------------------------------------------------------------------------------------------------------------------------------
287
289 out << "(" << elem.m_Size << ", " << elem.m_Data << ")";
290 return out;
291 }
292
294 out << "(" << elem.run << ", ";
295 for ( size_t i = 0; i < sizeof ( elem.word ) * BITS_IN_BYTE; ++ i )
296 out << static_cast < bool > ( elem.word & 1u << i );
297 out << ")";
298 return out;
299 }
300
301// --------------------------------------------------------------------------------------------------------------------------------------------------
302
306 size_t index;
307
308 public:
309 SparseBoolVectorOnesIterator ( ext::list < element >::const_iterator iterBegin, ext::list < element >::const_iterator iterEnd, size_t ind ) : underlying ( iterBegin ), underlyingEnd ( iterEnd ), index ( ind ) {
310 if ( underlying == underlyingEnd ) {
311 return;
312 }
313
314 // if we have one at the exact place we are done
315 index = sizeof ( unsigned ) * BITS_IN_BYTE * underlying->run;
316 if ( underlying->word & 1u )
317 return;
318
319 // othervise increment to a closest one
320 ++ * this;
321 }
322
324 if ( underlying == underlyingEnd )
325 return *this;
326
327 // get the index within word from global index and increment both
328 size_t innerIndex = index % ( sizeof ( unsigned ) * BITS_IN_BYTE );
329 ++ innerIndex;
330 ++ index;
331
332 // if we crossed the boundary of the word increment underlying iterator
333 if ( innerIndex == sizeof ( unsigned ) * BITS_IN_BYTE )
334 ++ underlying;
335
336 // if we reached the end iterator there is no next one
337 if ( underlying == underlyingEnd )
338 return *this;
339
340 // othervise skip sizeof word times the run size
341 if ( innerIndex == sizeof ( unsigned ) * BITS_IN_BYTE )
342 index += sizeof ( unsigned ) * BITS_IN_BYTE * underlying->run;
343
344 while ( true ) {
345 // from the current position try to find next one in the current word
346 for ( innerIndex = index % ( sizeof ( unsigned ) * BITS_IN_BYTE ); innerIndex < sizeof ( unsigned ) * BITS_IN_BYTE; ++ innerIndex ) {
347 // if we have it we are done
348 if ( underlying->word & ( 1u << innerIndex ) )
349 return *this;
350
351 ++ index;
352 }
353
354 // if we got here there was no next one in the current word, try next one
355 ++ underlying;
356
357 // which however may not exist we could have got out of the container
358 if ( underlying == underlyingEnd )
359 return *this;
360
361 // if we didn't increase the index by sizeof word times the run size
362 index += sizeof ( unsigned ) * BITS_IN_BYTE * underlying->run;
363 }
364 }
365
367 SparseBoolVectorOnesIterator tmp ( * this );
368
369 operator ++( );
370 return tmp;
371 }
372
373 bool operator == ( const SparseBoolVectorOnesIterator & other ) const {
374 return underlying == underlyingEnd && other.underlying == other.underlyingEnd && underlying == other.underlying;
375 }
376
377 bool operator != ( const SparseBoolVectorOnesIterator & other ) const {
378 return ! ( *this == other );
379 }
380
381 size_t operator * ( ) const {
382 return index;
383 }
384 };
385
387 return SparseBoolVectorOnesIterator ( m_Data.begin ( ), m_Data.end ( ), 0 );
388 }
389
391 return SparseBoolVectorOnesIterator ( m_Data.end ( ), m_Data.end ( ), m_Size );
392 }
393
394// --------------------------------------------------------------------------------------------------------------------------------------------------
395
397 A.resize ( std::max ( A.size ( ), B.size ( ) ) );
398
399 ext::list < element >::iterator iterA = A.m_Data.begin ( );
401
402 size_t blocksA = iterA->run;
403 size_t blocksB = iterB->run;
404
405 while ( iterA != A.m_Data.end ( ) && iterB != B.m_Data.end ( ) ) {
406 if ( blocksA == blocksB ) {
407 iterA->word &= iterB->word;
408
409 ++ iterA;
410 blocksA += 1 + iterA->run;
411
412 ++ iterB;
413 blocksB += 1 + iterB->run;
414 } else if ( blocksA < blocksB ) {
415 iterA->word = 0;
416
417 ++ iterA;
418 blocksA += 1 + iterA->run;
419 } else { // blockA > blockB
420 ++ iterB;
421 blocksB += 1 + iterB->run;
422 }
423 }
424
425 while ( iterA != A.m_Data.end ( ) ) {
426 iterA->word = 0;
427 ++ iterA;
428 }
429
430 A.packData();
431
432 return A;
433 }
434
436 A &= B;
437 return A;
438 }
439
440};
441
442} /* namespace common */
443
Definition: SparseBoolVector.hpp:303
SparseBoolVectorOnesIterator(ext::list< element >::const_iterator iterBegin, ext::list< element >::const_iterator iterEnd, size_t ind)
Definition: SparseBoolVector.hpp:309
bool operator!=(const SparseBoolVectorOnesIterator &other) const
Definition: SparseBoolVector.hpp:377
bool operator==(const SparseBoolVectorOnesIterator &other) const
Definition: SparseBoolVector.hpp:373
SparseBoolVectorOnesIterator & operator++()
Definition: SparseBoolVector.hpp:323
size_t operator*() const
Definition: SparseBoolVector.hpp:381
Definition: SparseBoolVector.hpp:27
bool operator==(const SparseBoolVector &other) const
Definition: SparseBoolVector.hpp:233
bool operator[](size_t index) const
Definition: SparseBoolVector.hpp:128
size_t m_Size
Definition: SparseBoolVector.hpp:46
size_t size() const
Definition: SparseBoolVector.hpp:223
SparseBoolVectorOnesIterator end() const
Definition: SparseBoolVector.hpp:390
ext::list< element > m_Data
Definition: SparseBoolVector.hpp:45
void resize(size_t newSize)
Definition: SparseBoolVector.hpp:212
friend SparseBoolVector operator&(SparseBoolVector A, const SparseBoolVector &B)
Definition: SparseBoolVector.hpp:435
const ext::list< element > & data() const
Definition: SparseBoolVector.hpp:227
void push_back(bool boolean)
Definition: SparseBoolVector.hpp:111
friend SparseBoolVector operator<<(SparseBoolVector A, size_t dist)
Definition: SparseBoolVector.hpp:281
friend SparseBoolVector & operator<<=(SparseBoolVector &A, size_t dist)
Definition: SparseBoolVector.hpp:243
SparseBoolVector(const ext::vector< bool > &raw)
Definition: SparseBoolVector.hpp:99
friend SparseBoolVector & operator&=(SparseBoolVector &A, const SparseBoolVector &B)
Definition: SparseBoolVector.hpp:396
SparseBoolVectorOnesIterator begin() const
Definition: SparseBoolVector.hpp:386
std::strong_ordering operator<=>(const SparseBoolVector &other) const
Definition: SparseBoolVector.hpp:237
SparseBoolVector(ext::list< element > data, size_t size)
Definition: SparseBoolVector.hpp:105
Class extending the list class from the standard library. Original reason is to allow printing of the...
Definition: list.hpp:44
Definition: ostream.h:14
Class extending the vector class from the standard library. Original reason is to allow printing of t...
Definition: vector.hpp:45
int i
Definition: AllEpsilonClosure.h:118
return res
Definition: MinimizeByPartitioning.h:145
for(const auto &transition:automaton.getTransitionsFromState(automaton.getInitialState())) stack.push(ext if(automaton.getFinalStates().count(automaton.getInitialState())) res.addFinalState(automaton.getInitialState())
Definition: Compaction.h:87
Definition: Permutation.hpp:18
constexpr tuple< Elements &... > tie(Elements &... args) noexcept
Helper of extended tuple of references construction. The tuple is constructed to reffer to values in ...
Definition: tuple.hpp:218
constexpr const T & max(const T &a)
Root case of maximum computation. The maximum from one value is the value itself.
Definition: algorithm.hpp:278
typename std::conditional< value, std::true_type, std::false_type >::type boolean
Definition: type_traits.hpp:145
Definition: RawRegistration.hpp:13
Definition: FordFulkerson.hpp:16
Definition: SparseBoolVector.hpp:32
unsigned run
Definition: SparseBoolVector.hpp:33
unsigned word
Definition: SparseBoolVector.hpp:34
bool operator==(const element &other) const
Definition: SparseBoolVector.hpp:36
std::strong_ordering operator<=>(const element &other) const
Definition: SparseBoolVector.hpp:40