bitSet.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2018-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "bitSet.H"
29#include "labelRange.H"
30#include "IOstreams.H"
31
32// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33
34namespace Foam
35{
37}
38
39
40// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
41
43{
44 if (&other == this)
45 {
46 // Self '-=' : clears all bits
47 if (debug & 2)
48 {
50 << "Perform -= on self: clears all bits" << nl;
51 }
52
53 reset();
54 return *this;
55 }
56 else if (none() || other.none())
57 {
58 // no-op: nothing can change
59 return *this;
60 }
61
62 // The operation (on overlapping blocks)
63 {
64 const label nblocks = num_blocks(std::min(size(), other.size()));
65 const auto& rhs = other.blocks_;
66
67 for (label blocki = 0; blocki < nblocks; ++blocki)
68 {
69 blocks_[blocki] &= ~rhs[blocki];
70 }
71 }
72
73 return *this;
74}
75
76
78{
79 if (&other == this)
80 {
81 // Self '&=' : no-op
82
83 if (debug & 2)
84 {
86 << "Perform &= on self: ignore" << nl;
87 }
88
89 return *this;
90 }
91 else if (none())
92 {
93 // no-op: nothing is set - no intersection possible
94 return *this;
95 }
96 else if (other.none())
97 {
98 // no-op: other has nothing set - no intersection possible
99 reset();
100 return *this;
101 }
102
103
104 const label origSize(size());
105 const label otherSize(other.size());
106
107 if (origSize > otherSize)
108 {
109 // Clear bits (and blocks) that do not overlap at all
110 resize(otherSize);
111 resize(origSize);
112 }
113
114 // The operation (on overlapping blocks)
115 {
116 const label nblocks = num_blocks(std::min(origSize, otherSize));
117 const auto& rhs = other.blocks_;
118
119 for (label blocki = 0; blocki < nblocks; ++blocki)
120 {
121 blocks_[blocki] &= rhs[blocki];
122 }
123 }
124
125 return *this;
126}
127
128
130{
131 if (&other == this)
132 {
133 // Self '|=' : no-op
134
135 if (debug & 2)
136 {
138 << "Perform |= on self: ignore" << nl;
139 }
140
141 return *this;
142 }
143 else if (other.none())
144 {
145 // no-op: nothing can change
146 return *this;
147 }
148
149
150 // Largest new bit that could be introduced
151 const label otherMax(other.find_last());
152
153 if (otherMax >= size())
154 {
155 // Extend to accommodate bits from 'other'
156 resize(otherMax+1);
157 }
158
159 // The operation (on overlapping blocks)
160 {
161 const label nblocks = num_blocks(std::min(size(), other.size()));
162 const auto& rhs = other.blocks_;
163
164 for (label blocki = 0; blocki < nblocks; ++blocki)
165 {
166 blocks_[blocki] |= rhs[blocki];
167 }
168 }
169
170 return *this;
171}
172
173
175{
176 if (&other == this)
177 {
178 // Self '^=' : clears all bits
179
180 if (debug & 2)
181 {
183 << "Perform ^= on self: clears all bits" << nl;
184 }
185
186 reset();
187 return *this;
188 }
189 else if (other.none())
190 {
191 // no-op: nothing can change
192 return *this;
193 }
194
195
196 // Largest new bit that could be introduced
197 const label otherMax(other.find_last());
198
199 if (otherMax >= size())
200 {
201 // Extend to accommodate bits from 'other'
202 resize(otherMax+1);
203 }
204
205 // The operation (on overlapping blocks)
206 {
207 const label nblocks = num_blocks(std::min(size(), other.size()));
208 const auto& rhs = other.blocks_;
209
210 for (label blocki = 0; blocki < nblocks; ++blocki)
211 {
212 blocks_[blocki] ^= rhs[blocki];
213 }
214 }
215
216 return *this;
217}
218
219
220// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
221
223:
224 PackedList<1>()
225{
226 is >> *this;
227}
228
229
230Foam::bitSet::bitSet(const bitSet& bitset, const labelUList& addr)
231:
232 bitSet(addr.size())
233{
234 const label len = addr.size();
235
236 for (label i = 0; i < len; ++i)
237 {
238 set(i, bitset.get(addr[i]));
239 }
240}
241
242
244:
245 bitSet(range.size())
246{
247 label pos = range.start();
248 const label len = range.size();
249
250 for (label i = 0; i < len; ++i)
251 {
252 set(i, bitset.get(pos));
253 ++pos;
254 }
255}
256
257
259:
260 bitSet(n)
261{
262 this->set(range);
263}
264
265
267{
268 this->set(range);
269}
270
271
272// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
273
275{
276 const label len = bools.size();
277
278 clear();
279 resize(len);
280
281 // Could also handle block-wise (in the future?)
282
283 // Set according to indices that are true.
284 for (label i = 0; i < len; ++i)
285 {
286 if (bools[i])
287 {
288 set(i);
289 }
290 }
291}
292
293
294bool Foam::bitSet::intersects(const bitSet& other) const
295{
296 if (size() && other.size())
297 {
298 const label nblocks = num_blocks(std::min(size(), other.size()));
299 const auto& rhs = other.blocks_;
300
301 for (label blocki = 0; blocki < nblocks; ++blocki)
302 {
303 if (bool(blocks_[blocki] & rhs[blocki]))
304 {
305 return true;
306 }
307 }
308 }
309
310 return false;
311}
312
313
315{
316 labelRange slice(range);
317 slice.adjust(); // No negative start, size adjusted accordingly
318
319 // Range is invalid (zero-sized or entirely negative) - noop
320 if (slice.empty())
321 {
322 return;
323 }
324
325 // Range finishes at or beyond the right side.
326 // - zero fill any gaps that we might create.
327 // - flood-fill the reset, which now corresponds to the full range.
328 //
329 // NB: use labelRange after() for the exclusive end-value, which
330 // corresponds to our new set size.
331 if (slice.after() >= size())
332 {
333 reserve(slice.after());
334 resize(slice.start(), false);
335 resize(slice.after(), true);
336 return;
337 }
338
339 // The more difficult case - everything in between.
340 // 1. sequence may begin/end in the same block
341 // 2. Cover more than one block
342 // a. with partial coverage in the first block
343 // b. with partial coverage in the end block
344
345 // The begin block/offset
346 unsigned int bblock = slice.first() / elem_per_block;
347 unsigned int bmask = slice.first() % elem_per_block;
348
349 // The end block/offset
350 unsigned int eblock = slice.after() / elem_per_block;
351 unsigned int emask = slice.after() % elem_per_block;
352
353 // Transform offsets to lower bit masks
354 if (bmask) bmask = mask_lower(bmask);
355 if (emask) emask = mask_lower(emask);
356
357 if (bblock == eblock)
358 {
359 // Same block - flll between the begin/end bits.
360 // Example:
361 // bmask = 0000000000001111 (lower bits)
362 // emask = 0000111111111111 (lower bits)
363 // -> set 0000111111110000 (xor)
364
365 blocks_[bblock] |= (emask^bmask);
366 }
367 else
368 {
369 if (bmask)
370 {
371 // The first (partial) block
372 // - set everything above the bmask.
373 blocks_[bblock] |= (~bmask);
374 ++bblock;
375 }
376
377 // Fill these blocks
378 for (unsigned blocki = bblock; blocki < eblock; ++blocki)
379 {
380 blocks_[blocki] = (~0u);
381 }
382
383 if (emask)
384 {
385 // The last (partial) block.
386 // - set everything below emask.
387 blocks_[eblock] |= (emask);
388 }
389 }
390}
391
392
394{
395 // Require intersection with the current bitset
396 const labelRange slice = range.subset0(size());
397
398 // Range does not intersect (invalid, empty, bitset is empty)
399 if (slice.empty())
400 {
401 return;
402 }
403
404 // Range finishes at or beyond the right side.
405 //
406 // NB: use labelRange after() for the exclusive end-value, which
407 // corresponds to our new set size.
408 if (slice.after() >= size())
409 {
410 // The original size
411 const label orig = size();
412
413 resize(slice.start(), false);
414 resize(orig, false);
415 return;
416 }
417
418
419 // The more difficult case - everything in between.
420 // 1. sequence may begin/end in the same block
421 // 2. Cover more than one block
422 // a. with partial coverage in the first block
423 // b. with partial coverage in the end block
424
425 // The begin block/offset
426 unsigned int bblock = slice.first() / elem_per_block;
427 unsigned int bmask = slice.first() % elem_per_block;
428
429 // The end block/offset
430 unsigned int eblock = slice.after() / elem_per_block;
431 unsigned int emask = slice.after() % elem_per_block;
432
433 // Transform offsets to lower bit masks
434 if (bmask) bmask = mask_lower(bmask);
435 if (emask) emask = mask_lower(emask);
436
437 if (bblock == eblock)
438 {
439 // Same block - flll between the begin/end bits.
440 // Example:
441 // bmask = 0000000000001111 (lower bits)
442 // emask = 0000111111111111 (lower bits)
443 // -> set 0000111111110000 (xor)
444 // -> ~ 1111000000001111
445
446 blocks_[bblock] &= (~(emask^bmask));
447 }
448 else
449 {
450 if (bmask)
451 {
452 // The first (partial) block
453 // - only retain things below bmask.
454 blocks_[bblock] &= (bmask);
455 ++bblock;
456 }
457
458 // Clear these blocks
459 for (unsigned blocki = bblock; blocki < eblock; ++blocki)
460 {
461 blocks_[blocki] = (0u);
462 }
463
464 if (emask)
465 {
466 // The last (partial) block.
467 // - only retain things above bmask.
468 blocks_[eblock] &= (~emask);
469 }
470 }
471}
472
473
475{
476 // Number of used (set) entries
477 const label total = any() ? count() : 0;
478
479 if (!total)
480 {
481 return labelList();
482 }
483
484 labelList output(total);
485 label nItem = 0;
486
487 // Process block-wise, detecting any '1' bits
488
489 const label nblocks = num_blocks(size());
490 for (label blocki = 0; blocki < nblocks; ++blocki)
491 {
492 unsigned int blockval = blocks_[blocki];
493
494 if (blockval)
495 {
496 for (label pos = (blocki * elem_per_block); blockval; ++pos)
497 {
498 if (blockval & 1u)
499 {
500 output[nItem] = pos;
501 ++nItem;
502 }
503 blockval >>= 1u;
504 }
505 if (nItem == total) break; // Terminate early
506 }
507 }
508
509 return output;
510}
511
512
514{
515 List<bool> output(size(), false);
516
517 // Process block-wise, detecting any '1' bits
518
519 const label nblocks = num_blocks(size());
520 for (label blocki = 0; blocki < nblocks; ++blocki)
521 {
522 label pos = (blocki * elem_per_block);
523
524 for
525 (
526 unsigned int blockval = blocks_[blocki];
527 blockval;
528 blockval >>= 1u
529 )
530 {
531 if (blockval & 1u)
532 {
533 output[pos] = true;
534 }
535 ++pos;
536 }
537 }
538
539 return output;
540}
541
542
543// ************************************************************************* //
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
scalar range
label n
bool empty() const noexcept
True if range is empty (zero-sized)
Definition: IntRangeI.H:436
IntType start() const noexcept
The (inclusive) lower value of the range.
Definition: IntRangeI.H:408
IntType first() const noexcept
The (inclusive) lower value of the range. Same as start()
Definition: IntRangeI.H:443
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
A dynamic list of packed unsigned integers, with the number of bits per item specified by the <Width>...
Definition: PackedList.H:129
block_container blocks_
The blocks of raw data.
Definition: PackedList.H:184
label size() const noexcept
Number of entries.
Definition: PackedListI.H:377
unsigned int get(const label i) const
Get value at index i or 0 for out-of-range.
Definition: PackedListI.H:630
static constexpr label num_blocks(label numElem) noexcept
Definition: PackedList.H:163
void reset()
Clear all bits but do not adjust the addressable size.
Definition: PackedListI.H:505
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:66
label find_last() const
Locate the last bit set.
Definition: bitSetI.H:375
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:590
bool none() const
True if no bits in this bitset are set.
Definition: bitSetI.H:488
bitSet & xorEq(const bitSet &other)
The set logical XOR.
Definition: bitSet.C:174
labelList toc() const
The indices of the on bits as a sorted labelList.
Definition: bitSet.C:474
void assign(const UList< bool > &bools)
Copy assign all entries from a list of bools.
Definition: bitSet.C:274
bitSet() noexcept
Default construct an empty, zero-sized bitSet.
Definition: bitSetI.H:77
List< bool > values() const
Return the bitset values as a boolList.
Definition: bitSet.C:513
bitSet & andEq(const bitSet &other)
The set logical AND.
Definition: bitSet.C:77
bitSet & orEq(const bitSet &other)
The set logical OR.
Definition: bitSet.C:129
bool intersects(const bitSet &other) const
True if any bits in the other bitset intersect (are the same).
Definition: bitSet.C:294
bitSet & minusEq(const bitSet &other)
The set difference.
Definition: bitSet.C:42
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:58
void adjust() noexcept
Adjust the start to avoid negative indices.
Definition: labelRange.C:81
label after() const noexcept
The value after the last element in the range.
Definition: labelRangeI.H:95
static const triad unset
Definition: triad.H:97
bool set() const
Are all the vector set.
Definition: triadI.H:76
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
patchWriters resize(patchIds.size())
patchWriters clear()
#define InfoInFunction
Report an information message using Foam::Info.
Namespace for OpenFOAM.
dimensionedScalar pos(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition: List.H:66
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:66
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53