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 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 {
36  defineTypeNameAndDebug(bitSet, 0);
37 }
38 
39 
40 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
41 
43 {
44  if (&other == this)
45  {
46  // Self '-=' : results in clearing 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 (empty() || other.empty())
57  {
58  return *this;
59  }
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 (empty())
92  {
93  // empty set : no-op (no overlap possible)
94  return *this;
95  }
96  else if (other.empty())
97  {
98  reset(); // Other is empty - no overlap possible
99  return *this;
100  }
101 
102 
103  // The operation (on overlapping blocks)
104  {
105  const label nblocks = num_blocks(std::min(size(), other.size()));
106  const auto& rhs = other.blocks_;
107 
108  for (label blocki = 0; blocki < nblocks; ++blocki)
109  {
110  blocks_[blocki] &= rhs[blocki];
111  }
112  }
113 
114  return *this;
115 }
116 
117 
118 Foam::bitSet& Foam::bitSet::orEq(const bitSet& other, const bool strict)
119 {
120  if (&other == this)
121  {
122  // Self '|=' : no-op
123 
124  if (debug & 2)
125  {
127  << "Perform |= on self: ignore" << nl;
128  }
129 
130  return *this;
131  }
132  else if (other.empty())
133  {
134  if ((debug & 2) && !empty())
135  {
136  // OK if both are empty
138  << "Perform |= using empty operand: ignore" << nl;
139  }
140 
141  // No (normal) overlap: no-op
142  return *this;
143  }
144  else if (empty())
145  {
146  if (debug & 2)
147  {
149  << "Perform |= on empty bitSet" << nl;
150  }
151 
152  if (strict)
153  {
154  // No (normal) overlap: no-op
155  return *this;
156  }
157  }
158  else if ((debug & 2) && (size() != other.size()))
159  {
161  << "Perform |= on dissimilar sized bitSets: "
162  << size() << " vs. " << other.size() << nl;
163  }
164 
165  label minpos = -1; // Min trim point
166 
167  if ((size() < other.size()) && !strict)
168  {
169  // The size (B > A) and we are non-strict (greedy), which means we may
170  // acquire additional bits from B. However, we would like to avoid
171  // spurious changes in the size of A (ie, B is longer but the extra
172  // bits are unset and thus don't affect the logical result).
173 
174  minpos = size();
175  resize(other.size()); // Blocks now overlap
176  }
177 
178 
179  // The operation (on overlapping blocks)
180  {
181  const label nblocks = num_blocks(std::min(size(), other.size()));
182  const auto& rhs = other.blocks_;
183 
184  for (label blocki = 0; blocki < nblocks; ++blocki)
185  {
186  blocks_[blocki] |= rhs[blocki];
187  }
188  }
189 
190 
191  // Cleanup - minpos >= 0 means we need to check/adjust the trim point
192  if (minpos >= 0)
193  {
194  trim(minpos); // Adjust the trim point (size)
195  }
196  else
197  {
198  clear_trailing_bits();
199  }
200 
201  return *this;
202 }
203 
204 
205 Foam::bitSet& Foam::bitSet::xorEq(const bitSet& other, const bool strict)
206 {
207  if (&other == this)
208  {
209  // Self '^=' : results in clearing all bits
210 
211  if (debug & 2)
212  {
214  << "Perform ^= on self: clears all bits" << nl;
215  }
216 
217  reset();
218  return *this;
219  }
220  else if (other.empty())
221  {
222  if ((debug & 2) && !empty())
223  {
224  // OK if both are empty
226  << "Perform ^= using empty operand: ignore" << nl;
227  }
228 
229  // No (normal) overlap: no-op
230  return *this;
231  }
232  else if (empty())
233  {
234  if (debug & 2)
235  {
237  << "Perform ^= on empty bitSet" << nl;
238  }
239 
240  if (strict)
241  {
242  // No (normal) overlap: no-op
243  return *this;
244  }
245  }
246  else if ((debug & 2) && (size() != other.size()))
247  {
249  << "Perform ^= on dissimilar sized bitSets: "
250  << size() << " vs. " << other.size() << nl;
251  }
252 
253  label minpos = -1; // Min trim point
254 
255  if ((size() < other.size()) && !strict)
256  {
257  minpos = size(); // This logic is explained in the orEq() method
258  resize(other.size()); // Blocks now overlap
259  }
260 
261 
262  // The operation (on overlapping blocks)
263  {
264  const label nblocks = num_blocks(std::min(size(), other.size()));
265  const auto& rhs = other.blocks_;
266 
267  for (label blocki = 0; blocki < nblocks; ++blocki)
268  {
269  blocks_[blocki] ^= rhs[blocki];
270  }
271  }
272 
273 
274  // Cleanup - minpos >= 0 means we need to check/adjust the trim point
275  if (minpos >= 0)
276  {
277  trim(minpos); // Adjust the trim point (size)
278  }
279  else
280  {
281  clear_trailing_bits();
282  }
283 
284  return *this;
285 }
286 
287 
288 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
289 
291 :
292  PackedList<1>()
293 {
294  is >> *this;
295 }
296 
297 
299 :
300  bitSet(addr.size())
301 {
302  const label len = addr.size();
303 
304  for (label i = 0; i < len; ++i)
305  {
306  set(i, bitset.get(addr[i]));
307  }
308 }
309 
310 
312 :
313  bitSet(range.size())
314 {
315  label pos = range.start();
316  const label len = range.size();
317 
318  for (label i = 0; i < len; ++i)
319  {
320  set(i, bitset.get(pos));
321  ++pos;
322  }
323 }
324 
325 
326 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
327 
329 {
330  const label len = bools.size();
331 
332  clear();
333  resize(len);
334 
335  // Could also handle block-wise (in the future?)
336 
337  // Set according to indices that are true.
338  for (label i = 0; i < len; ++i)
339  {
340  if (bools[i])
341  {
342  set(i);
343  }
344  }
345 }
346 
347 
348 bool Foam::bitSet::intersects(const bitSet& other) const
349 {
350  if (size() && other.size())
351  {
352  const label nblocks = num_blocks(std::min(size(), other.size()));
353  const auto& rhs = other.blocks_;
354 
355  for (label blocki = 0; blocki < nblocks; ++blocki)
356  {
357  if (bool(blocks_[blocki] & rhs[blocki]))
358  {
359  return true;
360  }
361  }
362  }
363 
364  return false;
365 }
366 
367 
369 {
370  labelRange slice(range);
371  slice.adjust(); // No negative start, size adjusted accordingly
372 
373  // Range is invalid (zero-sized or entirely negative) - noop
374  if (slice.empty())
375  {
376  return;
377  }
378 
379  // Range finishes at or beyond the right side.
380  // - zero fill any gaps that we might create.
381  // - flood-fill the reset, which now corresponds to the full range.
382  //
383  // NB: use labelRange after() for the exclusive end-value, which
384  // corresponds to our new set size.
385  if (slice.after() >= size())
386  {
387  resize(slice.start(), false);
388  resize(slice.after(), true);
389  return;
390  }
391 
392  // The more difficult case - everything in between.
393  // 1. sequence may begin/end in the same block
394  // 2. Cover more than one block
395  // a. with partial coverage in the first block
396  // b. with partial coverage in the end block
397 
398  // The begin block/offset
399  unsigned int bblock = slice.first() / elem_per_block;
400  unsigned int bmask = slice.first() % elem_per_block;
401 
402  // The end block/offset
403  unsigned int eblock = slice.after() / elem_per_block;
404  unsigned int emask = slice.after() % elem_per_block;
405 
406  // Transform offsets to lower bit masks
407  if (bmask) bmask = mask_lower(bmask);
408  if (emask) emask = mask_lower(emask);
409 
410  if (bblock == eblock)
411  {
412  // Same block - flll between the begin/end bits.
413  // Example:
414  // bmask = 0000000000001111 (lower bits)
415  // emask = 0000111111111111 (lower bits)
416  // -> set 0000111111110000 (xor)
417 
418  blocks_[bblock] |= (emask^bmask);
419  }
420  else
421  {
422  if (bmask)
423  {
424  // The first (partial) block
425  // - set everything above the bmask.
426  blocks_[bblock] |= (~bmask);
427  ++bblock;
428  }
429 
430  // Fill these blocks
431  for (unsigned blocki = bblock; blocki < eblock; ++blocki)
432  {
433  blocks_[blocki] = (~0u);
434  }
435 
436  if (emask)
437  {
438  // The last (partial) block.
439  // - set everything below emask.
440  blocks_[eblock] |= (emask);
441  }
442  }
443 }
444 
445 
447 {
448  // Require intersection with the current bitset
449  const labelRange slice = range.subset0(size());
450 
451  // Range does not intersect (invalid, empty, bitset is empty)
452  if (slice.empty())
453  {
454  return;
455  }
456 
457  // Range finishes at or beyond the right side.
458  //
459  // NB: use labelRange after() for the exclusive end-value, which
460  // corresponds to our new set size.
461  if (slice.after() >= size())
462  {
463  // The original size
464  const label orig = size();
465 
466  resize(slice.start(), false);
467  resize(orig, false);
468  return;
469  }
470 
471 
472  // The more difficult case - everything in between.
473  // 1. sequence may begin/end in the same block
474  // 2. Cover more than one block
475  // a. with partial coverage in the first block
476  // b. with partial coverage in the end block
477 
478  // The begin block/offset
479  unsigned int bblock = slice.first() / elem_per_block;
480  unsigned int bmask = slice.first() % elem_per_block;
481 
482  // The end block/offset
483  unsigned int eblock = slice.after() / elem_per_block;
484  unsigned int emask = slice.after() % elem_per_block;
485 
486  // Transform offsets to lower bit masks
487  if (bmask) bmask = mask_lower(bmask);
488  if (emask) emask = mask_lower(emask);
489 
490  if (bblock == eblock)
491  {
492  // Same block - flll between the begin/end bits.
493  // Example:
494  // bmask = 0000000000001111 (lower bits)
495  // emask = 0000111111111111 (lower bits)
496  // -> set 0000111111110000 (xor)
497  // -> ~ 1111000000001111
498 
499  blocks_[bblock] &= (~(emask^bmask));
500  }
501  else
502  {
503  if (bmask)
504  {
505  // The first (partial) block
506  // - only retain things below bmask.
507  blocks_[bblock] &= (bmask);
508  ++bblock;
509  }
510 
511  // Clear these blocks
512  for (unsigned blocki = bblock; blocki < eblock; ++blocki)
513  {
514  blocks_[blocki] = (0u);
515  }
516 
517  if (emask)
518  {
519  // The last (partial) block.
520  // - only retain things above bmask.
521  blocks_[eblock] &= (~emask);
522  }
523  }
524 }
525 
526 
528 {
529  // Number of used (set) entries
530  const label total = any() ? count() : 0;
531 
532  if (!total)
533  {
534  return labelList();
535  }
536 
537  labelList output(total);
538  label nItem = 0;
539 
540  // Process block-wise, detecting any '1' bits
541 
542  const label nblocks = num_blocks(size());
543  for (label blocki = 0; blocki < nblocks; ++blocki)
544  {
545  unsigned int blockval = blocks_[blocki];
546 
547  if (blockval)
548  {
549  for (label pos = (blocki * elem_per_block); blockval; ++pos)
550  {
551  if (blockval & 1u)
552  {
553  output[nItem] = pos;
554  ++nItem;
555  }
556  blockval >>= 1u;
557  }
558  if (nItem == total) break; // Terminate early
559  }
560  }
561 
562  return output;
563 }
564 
565 
567 {
568  List<bool> output(size(), false);
569 
570  // Process block-wise, detecting any '1' bits
571 
572  const label nblocks = num_blocks(size());
573  for (label blocki = 0; blocki < nblocks; ++blocki)
574  {
575  label pos = (blocki * elem_per_block);
576 
577  for
578  (
579  unsigned int blockval = blocks_[blocki];
580  blockval;
581  blockval >>= 1u
582  )
583  {
584  if (blockval & 1u)
585  {
586  output[pos] = true;
587  }
588  ++pos;
589  }
590  }
591 
592  return output;
593 }
594 
595 
596 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::bitSet::andEq
bitSet & andEq(const bitSet &other)
The set logical AND.
Definition: bitSet.C:77
Foam::PackedList< 1 >::reset
void reset()
Clear all bits but do not adjust the addressable size.
Definition: PackedListI.H:505
InfoInFunction
#define InfoInFunction
Report an information message using Foam::Info.
Definition: messageStream.H:350
Foam::BitOps::set
void set(List< bool > &bools, const labelRange &range)
Set the specified range 'on' in a boolList.
Definition: BitOps.C:37
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Foam::output
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:66
Foam::bitSet::bitSet
bitSet() noexcept
Default construct an empty, zero-sized set.
Definition: bitSetI.H:77
Foam::HashSetOps::bools
List< bool > bools(const labelHashSet &locations)
Definition: HashOps.C:81
Foam::bitSet::xorEq
bitSet & xorEq(const bitSet &other, const bool strict=true)
The set logical XOR.
Definition: bitSet.C:205
Foam::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::bitSet::unset
bitSet & unset(const bitSet &other)
Definition: bitSetI.H:612
Foam::stringOps::trim
string trim(const std::string &s)
Return string trimmed of leading and trailing whitespace.
Definition: stringOps.C:1046
Foam::labelRange::adjust
void adjust() noexcept
Adjust the start to avoid negative indices.
Definition: labelRange.C:81
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
Foam::PackedList< 1 >::empty
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition: PackedListI.H:384
Foam::HashSetOps::bitset
bitSet bitset(const labelHashSet &locations)
Transform the on locations to a bitSet.
Definition: HashOps.C:72
bitSet.H
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::PackedList::get
unsigned int get(const label i) const
Get value at index i or 0 for out-of-range.
Definition: PackedListI.H:630
Foam::labelRange::after
label after() const noexcept
The value after the last element in the range.
Definition: labelRangeI.H:95
Foam::PackedList::blocks_
block_container blocks_
The blocks of raw data.
Definition: PackedList.H:184
Foam::bitSet::toc
labelList toc() const
The indices of the on bits as a sorted labelList.
Definition: bitSet.C:527
resize
patchWriters resize(patchIds.size())
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::IntRange::empty
bool empty() const noexcept
True if range is empty (zero-sized)
Definition: IntRangeI.H:436
Foam::labelRange
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:55
Foam::bitSet::assign
void assign(const UList< bool > &bools)
Copy assign all entries from a list of bools.
Definition: bitSet.C:328
Foam::bitSet::minusEq
bitSet & minusEq(const bitSet &other)
The set difference.
Definition: bitSet.C:42
Foam::BitOps::any
bool any(const UList< bool > &bools)
True if any entries are 'true'.
Definition: BitOps.H:91
Foam::bitSet::orEq
bitSet & orEq(const bitSet &other, const bool strict=true)
The set logical OR.
Definition: bitSet.C:118
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
reset
meshPtr reset(new Foam::fvMesh(Foam::IOobject(regionName, runTime.timeName(), runTime, Foam::IOobject::MUST_READ), false))
Foam::bitSet::intersects
bool intersects(const bitSet &other) const
True if any bits in the other bitset intersect (are the same).
Definition: bitSet.C:348
range
scalar range
Definition: LISASMDCalcMethod1.H:12
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:404
labelRange.H
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::List< label >
Foam::PackedList
A dynamic list of packed unsigned integers, with the number of bits per item specified by the <Width>...
Definition: PackedList.H:108
Foam::IntRange::first
IntType first() const noexcept
The (inclusive) lower value of the range. Same as start()
Definition: IntRangeI.H:443
Foam::PackedList< 1 >::size
label size() const noexcept
Number of entries.
Definition: PackedListI.H:377
Foam::UList< label >
Foam::UList::size
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Foam::IntRange::start
IntType start() const noexcept
The (inclusive) lower value of the range.
Definition: IntRangeI.H:408
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::PackedList< 1 >::num_blocks
static constexpr label num_blocks(label numElem) noexcept
Definition: PackedList.H:163
Foam::bitSet::values
List< bool > values() const
Return the bitset values as a boolList.
Definition: bitSet.C:566
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177