@@ -115,14 +115,27 @@ class ClusteredBitVector {
115
115
// / Return true if this vector is not using out-of-line storage and
116
116
// / does not have any bits set. This is a special-case representation
117
117
// / where the capacity can be smaller than the length.
118
+ // /
119
+ // / This is a necessary condition for hasSufficientChunkStorage(),
120
+ // / and it's quicker to test, so a lot of routines in this class
121
+ // / that need to work on chunk data in the general case test this
122
+ // / first.
118
123
bool isInlineAndAllClear () const {
119
124
assert (!hasOutOfLineData () || Data != 0 );
120
125
return Data == 0 ;
121
126
}
122
127
128
+ // / Return true if this vector is not in the special case where the
129
+ // / capacity is smaller than the length. If this is true, then
130
+ // / it's safe to call routines like getChunks().
131
+ bool hasSufficientChunkStorage () const {
132
+ return !(isInlineAndAllClear () && LengthInBits > ChunkSizeInBits);
133
+ }
134
+
123
135
// / Return the number of chunks required in order to store the full
124
136
// / length (not capacity) of this bit vector. This may be greater
125
- // / than the capacity in exactly one case, (2a).
137
+ // / than the capacity in exactly one case, (2a), i.e.
138
+ // / !hasSufficientChunkStorage().
126
139
size_t getLengthInChunks () const {
127
140
return getNumChunksForBits (LengthInBits);
128
141
}
@@ -147,7 +160,7 @@ class ClusteredBitVector {
147
160
// / that it's using out-of-line storage.
148
161
size_t getOutOfLineCapacityInBits () const {
149
162
assert (hasOutOfLineData ());
150
- return (size_t ) getOutOfLineData ()[-1 ];
163
+ return (size_t ) getOutOfLineChunksPtr ()[-1 ];
151
164
}
152
165
153
166
// / Return the current capacity of this bit vector, in chunks, given
@@ -157,36 +170,38 @@ class ClusteredBitVector {
157
170
}
158
171
159
172
// / Return a pointer to the data storage of this bit vector.
160
- ChunkType *getData () {
161
- return (hasOutOfLineData () ? getOutOfLineData () : &Data);
173
+ ChunkType *getChunksPtr () {
174
+ assert (hasSufficientChunkStorage ());
175
+ return (hasOutOfLineData () ? getOutOfLineChunksPtr () : &Data);
162
176
}
163
- const ChunkType *getData () const {
164
- return (hasOutOfLineData () ? getOutOfLineData () : &Data);
177
+ const ChunkType *getChunksPtr () const {
178
+ assert (hasSufficientChunkStorage ());
179
+ return (hasOutOfLineData () ? getOutOfLineChunksPtr () : &Data);
165
180
}
166
181
167
182
MutableArrayRef<ChunkType> getChunks () {
168
- assert (! isInlineAndAllClear ());
169
- return { getData (), getLengthInChunks () };
183
+ assert (hasSufficientChunkStorage ());
184
+ return { getChunksPtr (), getLengthInChunks () };
170
185
}
171
186
ArrayRef<ChunkType> getChunks () const {
172
- assert (! isInlineAndAllClear ());
173
- return { getData (), getLengthInChunks () };
187
+ assert (hasSufficientChunkStorage ());
188
+ return { getChunksPtr (), getLengthInChunks () };
174
189
}
175
190
176
191
MutableArrayRef<ChunkType> getOutOfLineChunks () {
177
- return { getOutOfLineData (), getLengthInChunks () };
192
+ return { getOutOfLineChunksPtr (), getLengthInChunks () };
178
193
}
179
194
ArrayRef<ChunkType> getOutOfLineChunks () const {
180
- return { getOutOfLineData (), getLengthInChunks () };
195
+ return { getOutOfLineChunksPtr (), getLengthInChunks () };
181
196
}
182
197
183
198
// / Return a pointer to the data storage of this bit vector, given
184
199
// / that it's using out-of-line storage.
185
- ChunkType *getOutOfLineData () {
200
+ ChunkType *getOutOfLineChunksPtr () {
186
201
assert (hasOutOfLineData ());
187
202
return reinterpret_cast <ChunkType*>(Data);
188
203
}
189
- const ChunkType *getOutOfLineData () const {
204
+ const ChunkType *getOutOfLineChunksPtr () const {
190
205
assert (hasOutOfLineData ());
191
206
return reinterpret_cast <const ChunkType*>(Data);
192
207
}
@@ -232,10 +247,10 @@ class ClusteredBitVector {
232
247
if (otherLengthInChunks <= getOutOfLineCapacityInChunks ()) {
233
248
LengthInBits = other.LengthInBits ;
234
249
if (other.isInlineAndAllClear ()) {
235
- memset (getOutOfLineData (), 0 ,
250
+ memset (getOutOfLineChunksPtr (), 0 ,
236
251
otherLengthInChunks * sizeof (ChunkType));
237
252
} else {
238
- memcpy (getOutOfLineData (), other.getData (),
253
+ memcpy (getOutOfLineChunksPtr (), other.getChunksPtr (),
239
254
otherLengthInChunks * sizeof (ChunkType));
240
255
}
241
256
return *this ;
@@ -288,10 +303,6 @@ class ClusteredBitVector {
288
303
// / Reserve space for an extra N bits. This may unnecessarily force
289
304
// / the vector to use an out-of-line representation.
290
305
void reserveExtra (size_t numBits) {
291
- // Other parts of the implementation rely on this method putting
292
- // the vector in a state where getData() can be safely assigned
293
- // into.
294
-
295
306
auto requiredBits = LengthInBits + numBits;
296
307
if (requiredBits > getCapacityInBits ()) {
297
308
auto requiredChunks = getNumChunksForBits (requiredBits);
@@ -307,6 +318,7 @@ class ClusteredBitVector {
307
318
308
319
reallocate (chunkCount);
309
320
}
321
+ // Postcondition: hasSufficientChunkStorage().
310
322
}
311
323
312
324
// / Reserve space for a total of N bits. This may unnecessarily
@@ -315,6 +327,7 @@ class ClusteredBitVector {
315
327
if (requiredSize > getCapacityInBits ()) {
316
328
reallocate (getNumChunksForBits (requiredSize));
317
329
}
330
+ // Postcondition: hasSufficientChunkStorage().
318
331
}
319
332
320
333
// / Append the bits from the given vector to this one.
@@ -347,7 +360,7 @@ class ClusteredBitVector {
347
360
if (other.isInlineAndAllClear ()) {
348
361
appendConstantBitsReserved (other.size (), 0 );
349
362
} else {
350
- appendReserved (other.size (), other.getData ());
363
+ appendReserved (other.size (), other.getChunksPtr ());
351
364
}
352
365
}
353
366
@@ -382,26 +395,39 @@ class ClusteredBitVector {
382
395
appendConstantBitsReserved (numBits, 0 );
383
396
}
384
397
398
+ // / Extend the vector out to the given length with clear bits.
399
+ void extendWithClearBits (size_t newSize) {
400
+ assert (newSize >= size ());
401
+ appendClearBits (newSize - size ());
402
+ }
403
+
404
+
385
405
// / Append a number of set bits to this vector.
386
406
void appendSetBits (size_t numBits) {
387
407
if (numBits == 0 ) return ;
388
408
reserveExtra (numBits);
389
409
appendConstantBitsReserved (numBits, 1 );
390
410
}
391
411
412
+ // / Extend the vector out to the given length with set bits.
413
+ void extendWithSetBits (size_t newSize) {
414
+ assert (newSize >= size ());
415
+ appendSetBits (newSize - size ());
416
+ }
417
+
392
418
// / Test whether a particular bit is set.
393
419
bool operator [](size_t i) const {
394
420
assert (i < size ());
395
421
if (isInlineAndAllClear ()) return false ;
396
- return getData ()[i / ChunkSizeInBits]
422
+ return getChunks ()[i / ChunkSizeInBits]
397
423
& (ChunkType (1 ) << (i % ChunkSizeInBits));
398
424
}
399
425
400
- // / Intersect two vectors of the same size.
426
+ // / Intersect a bit-vector of the same size into this vector .
401
427
ClusteredBitVector &operator &=(const ClusteredBitVector &other) {
402
428
assert (size () == other.size ());
403
429
404
- // If this vector is currently all-clear, this is a no-op.
430
+ // If this vector is all-clear, this is a no-op.
405
431
if (isInlineAndAllClear ())
406
432
return *this ;
407
433
@@ -414,27 +440,72 @@ class ClusteredBitVector {
414
440
415
441
// Otherwise, &= the chunks pairwise.
416
442
auto chunks = getChunks ();
417
- auto oi = other.getData ();
443
+ auto oi = other.getChunksPtr ();
418
444
for (auto i = chunks.begin (), e = chunks.end (); i != e; ++i, ++oi) {
419
445
*i &= *oi;
420
446
}
421
447
return *this ;
422
448
}
423
449
450
+ // / Union a bit-vector of the same size into this vector.
451
+ ClusteredBitVector &operator |=(const ClusteredBitVector &other) {
452
+ assert (size () == other.size ());
453
+
454
+ // If the other vector is all-clear, this is a no-op.
455
+ if (other.isInlineAndAllClear ())
456
+ return *this ;
457
+
458
+ // If this vector is all-clear, we just copy the other.
459
+ if (isInlineAndAllClear ()) {
460
+ return (*this = other);
461
+ }
462
+
463
+ // Otherwise, |= the chunks pairwise.
464
+ auto chunks = getChunks ();
465
+ auto oi = other.getChunksPtr ();
466
+ for (auto i = chunks.begin (), e = chunks.end (); i != e; ++i, ++oi) {
467
+ *i |= *oi;
468
+ }
469
+ return *this ;
470
+ }
471
+
424
472
// / Set bit i.
425
473
void setBit (size_t i) {
426
474
assert (i < size ());
427
475
if (isInlineAndAllClear ()) {
428
476
reserve (LengthInBits);
429
477
}
430
- getData ()[i / ChunkSizeInBits] |= (ChunkType (1 ) << (i % ChunkSizeInBits));
478
+ getChunks ()[i / ChunkSizeInBits] |= (ChunkType (1 ) << (i % ChunkSizeInBits));
431
479
}
432
480
433
481
// / Clear bit i.
434
482
void clearBit (size_t i) {
435
483
assert (i < size ());
436
484
if (isInlineAndAllClear ()) return ;
437
- getData ()[i / ChunkSizeInBits] |= (ChunkType (1 ) << (i % ChunkSizeInBits));
485
+ getChunksPtr ()[i / ChunkSizeInBits] &= ~(ChunkType (1 ) << (i % ChunkSizeInBits));
486
+ }
487
+
488
+ // / Toggle bit i.
489
+ void flipBit (size_t i) {
490
+ assert (i < size ());
491
+ if (isInlineAndAllClear ()) {
492
+ reserve (LengthInBits);
493
+ }
494
+ getChunksPtr ()[i / ChunkSizeInBits] ^= (ChunkType (1 ) << (i % ChunkSizeInBits));
495
+ }
496
+
497
+ // / Toggle all the bits in this vector.
498
+ void flipAll () {
499
+ if (empty ()) return ;
500
+ if (isInlineAndAllClear ()) {
501
+ reserve (LengthInBits);
502
+ }
503
+ for (auto &chunk : getChunks ()) {
504
+ chunk = ~chunk;
505
+ }
506
+ if (auto tailBits = size () % ChunkSizeInBits) {
507
+ getChunks ().back () &= ((ChunkType (1 ) << tailBits) - 1 );
508
+ }
438
509
}
439
510
440
511
// / Set the length of this vector to zero, but do not release any capacity.
@@ -482,7 +553,7 @@ class ClusteredBitVector {
482
553
CurChunkIndex = 0 ;
483
554
NumChunks = 0 ;
484
555
} else {
485
- Chunks = vector.getData ();
556
+ Chunks = vector.getChunksPtr ();
486
557
CurChunk = Chunks[0 ];
487
558
CurChunkIndex = 0 ;
488
559
NumChunks = vector.getLengthInChunks ();
@@ -534,6 +605,9 @@ class ClusteredBitVector {
534
605
// / the least significant bits of the number.
535
606
llvm::APInt asAPInt () const ;
536
607
608
+ // / Construct a bit-vector from an APInt.
609
+ static ClusteredBitVector fromAPInt (const llvm::APInt &value);
610
+
537
611
// / Pretty-print the vector.
538
612
void print (llvm::raw_ostream &out) const ;
539
613
void dump () const ;
@@ -545,7 +619,7 @@ class ClusteredBitVector {
545
619
void makeIndependentCopy () {
546
620
assert (hasOutOfLineData ());
547
621
auto lengthToCopy = getLengthInChunks ();
548
- allocateAndCopyFrom (getOutOfLineData (), lengthToCopy, lengthToCopy);
622
+ allocateAndCopyFrom (getOutOfLineChunksPtr (), lengthToCopy, lengthToCopy);
549
623
}
550
624
551
625
// / Reallocate this vector, copying the current data into the new space.
@@ -578,7 +652,7 @@ class ClusteredBitVector {
578
652
// / Destroy the out of line data currently stored in this object.
579
653
void destroy () {
580
654
assert (hasOutOfLineData ());
581
- delete[] (getOutOfLineData () - 1 );
655
+ delete[] (getOutOfLineChunksPtr () - 1 );
582
656
}
583
657
584
658
// / Append a certain number of constant bits to this vector, given
0 commit comments