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 -------------------------------------------------------------------------------
10 License
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 
34 namespace 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 
77 Foam::bitSet& Foam::bitSet::andEq(const bitSet& other)
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 
129 Foam::bitSet& Foam::bitSet::orEq(const bitSet& other)
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 
174 Foam::bitSet& Foam::bitSet::xorEq(const bitSet& other)
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  }
216  return *this;
217 }
218 
219 
220 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
221 
223 :
224  PackedList<1>()
225 {
226  is >> *this;
227 }
228 
229 
230 Foam::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 
243 Foam::bitSet::bitSet(const bitSet& bitset, const labelRange& range)
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 
258 Foam::bitSet::bitSet(const label n, const labelRange& range)
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 
294 bool 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 
314 void Foam::bitSet::set(const labelRange& range)
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 end_value() for the exclusive end-value, which
330  // corresponds to our new set size.
331  if (slice.end_value() >= size())
332  {
333  reserve(slice.end_value());
334  resize(slice.begin_value(), false);
335  resize(slice.end_value(), 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.begin_value() / elem_per_block;
347  unsigned int bmask = slice.begin_value() % elem_per_block;
348 
349  // The end block/offset
350  unsigned int eblock = slice.end_value() / elem_per_block;
351  unsigned int emask = slice.end_value() % 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 
393 void Foam::bitSet::unset(const labelRange& range)
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 end_value() for the exclusive end-value, which
407  // corresponds to our new set size.
408  if (slice.end_value() >= size())
409  {
410  // The original size
411  const label orig = size();
412 
413  resize(slice.begin_value(), 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.begin_value() / elem_per_block;
427  unsigned int bmask = slice.begin_value() % elem_per_block;
428 
429  // The end block/offset
430  unsigned int eblock = slice.end_value() / elem_per_block;
431  unsigned int emask = slice.end_value() % 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 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
bitSet & orEq(const bitSet &other)
The set logical OR.
Definition: bitSet.C:122
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:504
bool any(const UList< bool > &bools)
True if any entries are &#39;true&#39;.
Definition: BitOps.H:93
bool none(const UList< bool > &bools)
True if no entries are &#39;true&#39;.
Definition: BitOps.H:103
patchWriters resize(patchIds.size())
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
List< bool > values() const
Return the bitset values as a boolList.
Definition: bitSet.C:506
bitSet & minusEq(const bitSet &other)
The set difference.
Definition: bitSet.C:35
bitSet & xorEq(const bitSet &other)
The set logical XOR.
Definition: bitSet.C:167
scalar range
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
dimensionedScalar pos(const dimensionedScalar &ds)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
A dynamic list of packed unsigned integers, with the number of bits per item specified by the <Width>...
Definition: PackedList.H:104
bitSet & unset(const bitSet &other)
Unset (subtract) the bits specified in the other bitset, which is a set difference corresponds to the...
Definition: bitSetI.H:542
patchWriters clear()
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
constexpr bitSet() noexcept
Default construct an empty, zero-sized bitSet.
Definition: bitSetI.H:23
List< bool > bools(const labelHashSet &locations)
Transform the on locations to a boolList, with true for each non-negative location and false for all ...
Definition: HashOps.C:72
bitSet & andEq(const bitSet &other)
The set logical AND.
Definition: bitSet.C:70
int debug
Static debugging option.
defineTypeNameAndDebug(combustionModel, 0)
labelList toc() const
The indices of the on bits as a sorted labelList.
Definition: bitSet.C:467
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
triangles reserve(surf.size())
void assign(const UList< bool > &bools)
Copy assign all entries from a list of bools.
Definition: bitSet.C:267
bool intersects(const bitSet &other) const
True if any bits in the other bitset intersect (are the same).
Definition: bitSet.C:287
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:44
block_container blocks_
The blocks of raw data.
Definition: PackedList.H:203
label n
static constexpr label num_blocks(label numElem) noexcept
Calculate the number of blocks required to _address_ the requested number of elements.
Definition: PackedList.H:175
void reset()
Clear all bits but do not adjust the addressable size.
Definition: PackedListI.H:551
List< label > labelList
A List of labels.
Definition: List.H:62
unsigned int get(const label i) const
Get value at index i or 0 for out-of-range.
Definition: PackedListI.H:683
bool none() const
True if no bits in this bitset are set.
Definition: bitSetI.H:420
bitSet bitset(const labelHashSet &locations)
Transform the on locations to a bitSet.
Definition: HashOps.C:63
label size() const noexcept
Number of entries.
Definition: PackedList.H:371
Namespace for OpenFOAM.
#define InfoInFunction
Report an information message using Foam::Info.