A library for working with phylogenetic and population genetic data.
v0.32.0
bitvector.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2024 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
34 
35 #include <algorithm>
36 #include <cstring>
37 #include <functional>
38 #include <limits>
39 #include <stdexcept>
40 
41 namespace genesis {
42 namespace utils {
43 
44 // =============================================================================
45 // Constants
46 // =============================================================================
47 
48 const Bitvector::IntType Bitvector::all_0_ = 0ul;
49 const Bitvector::IntType Bitvector::all_1_ = (((1ul << 32) - 1) << 32) + ((1ul << 32) - 1);
50 
51 const std::array<Bitvector::IntType, Bitvector::IntSize> Bitvector::bit_mask_ =
52 {{
53  1ul << 0, 1ul << 1, 1ul << 2, 1ul << 3, 1ul << 4, 1ul << 5, 1ul << 6, 1ul << 7,
54  1ul << 8, 1ul << 9, 1ul << 10, 1ul << 11, 1ul << 12, 1ul << 13, 1ul << 14, 1ul << 15,
55  1ul << 16, 1ul << 17, 1ul << 18, 1ul << 19, 1ul << 20, 1ul << 21, 1ul << 22, 1ul << 23,
56  1ul << 24, 1ul << 25, 1ul << 26, 1ul << 27, 1ul << 28, 1ul << 29, 1ul << 30, 1ul << 31,
57  1ul << 32, 1ul << 33, 1ul << 34, 1ul << 35, 1ul << 36, 1ul << 37, 1ul << 38, 1ul << 39,
58  1ul << 40, 1ul << 41, 1ul << 42, 1ul << 43, 1ul << 44, 1ul << 45, 1ul << 46, 1ul << 47,
59  1ul << 48, 1ul << 49, 1ul << 50, 1ul << 51, 1ul << 52, 1ul << 53, 1ul << 54, 1ul << 55,
60  1ul << 56, 1ul << 57, 1ul << 58, 1ul << 59, 1ul << 60, 1ul << 61, 1ul << 62, 1ul << 63
61 }};
62 
63 const std::array<Bitvector::IntType, Bitvector::IntSize> Bitvector::ones_mask_ =
64 {{
65  Bitvector::all_0_, Bitvector::all_1_ >> 63, Bitvector::all_1_ >> 62, Bitvector::all_1_ >> 61,
66  Bitvector::all_1_ >> 60, Bitvector::all_1_ >> 59, Bitvector::all_1_ >> 58, Bitvector::all_1_ >> 57,
67  Bitvector::all_1_ >> 56, Bitvector::all_1_ >> 55, Bitvector::all_1_ >> 54, Bitvector::all_1_ >> 53,
68  Bitvector::all_1_ >> 52, Bitvector::all_1_ >> 51, Bitvector::all_1_ >> 50, Bitvector::all_1_ >> 49,
69  Bitvector::all_1_ >> 48, Bitvector::all_1_ >> 47, Bitvector::all_1_ >> 46, Bitvector::all_1_ >> 45,
70  Bitvector::all_1_ >> 44, Bitvector::all_1_ >> 43, Bitvector::all_1_ >> 42, Bitvector::all_1_ >> 41,
71  Bitvector::all_1_ >> 40, Bitvector::all_1_ >> 39, Bitvector::all_1_ >> 38, Bitvector::all_1_ >> 37,
72  Bitvector::all_1_ >> 36, Bitvector::all_1_ >> 35, Bitvector::all_1_ >> 34, Bitvector::all_1_ >> 33,
73  Bitvector::all_1_ >> 32, Bitvector::all_1_ >> 31, Bitvector::all_1_ >> 30, Bitvector::all_1_ >> 29,
74  Bitvector::all_1_ >> 28, Bitvector::all_1_ >> 27, Bitvector::all_1_ >> 26, Bitvector::all_1_ >> 25,
75  Bitvector::all_1_ >> 24, Bitvector::all_1_ >> 23, Bitvector::all_1_ >> 22, Bitvector::all_1_ >> 21,
76  Bitvector::all_1_ >> 20, Bitvector::all_1_ >> 19, Bitvector::all_1_ >> 18, Bitvector::all_1_ >> 17,
77  Bitvector::all_1_ >> 16, Bitvector::all_1_ >> 15, Bitvector::all_1_ >> 14, Bitvector::all_1_ >> 13,
78  Bitvector::all_1_ >> 12, Bitvector::all_1_ >> 11, Bitvector::all_1_ >> 10, Bitvector::all_1_ >> 9,
79  Bitvector::all_1_ >> 8, Bitvector::all_1_ >> 7, Bitvector::all_1_ >> 6, Bitvector::all_1_ >> 5,
80  Bitvector::all_1_ >> 4, Bitvector::all_1_ >> 3, Bitvector::all_1_ >> 2, Bitvector::all_1_ >> 1
81 }};
82 
83 const std::array<Bitvector::IntType, 4> Bitvector::count_mask_ =
84 {{
85  0x5555555555555555, //binary: 0101...
86  0x3333333333333333, //binary: 00110011...
87  0x0f0f0f0f0f0f0f0f, //binary: 4 zeros, 4 ones...
88  0x0101010101010101 //the sum of 256 to the power of 0,1,2,3...
89 }};
90 
91 // =============================================================================
92 // Constructor and Rule of Five
93 // =============================================================================
94 
95 Bitvector::Bitvector( size_t size, Bitvector const& other )
96  : Bitvector::Bitvector( size, false )
97 {
98  // Static test, needs to be here, as the constant is private.
99  static_assert(
100  Bitvector::all_1_ == static_cast<Bitvector::IntType>(0) - 1,
101  "Bitvector::all_1_ is not all one"
102  );
103 
104  // if( &other == this ) {
105  // throw std::runtime_error(
106  // "In Bitvector::Bitvector( size_t, Bitvector const& ): Cannot self assign."
107  // );
108  // }
109 
110  // Copy over all data, making sure to not go past the end of either vector.
111  // If other is smaller than the size we are creating here, we are technically copying
112  // is padding bits as well, but those are false anyway, so that's okay.
113  auto const n = std::min( data_.size(), other.data_.size() );
114  for( size_t i = 0; i < n; ++i ) {
115  data_[i] = other.data_[i];
116  }
117  unset_padding_();
118 }
119 
120 Bitvector::Bitvector( std::string const& values )
121  : Bitvector::Bitvector( values.size(), false )
122 {
123  for( size_t i = 0; i < values.size(); ++i ) {
124  switch( values[i] ) {
125  case '0':
126  break;
127  case '1':
128  set(i);
129  break;
130  default:
131  throw std::invalid_argument(
132  "Cannot construct Bitvector from std::string that contains characters "
133  "other than 0 and 1."
134  );
135  }
136  }
137 }
138 
139 // Bitvector::Bitvector( Bitvector const& other, size_t max_size )
140 // {
141 // if( max_size > other.size() ) {
142 // max_size = other.size();
143 // }
144 // size_ = max_size;
145 // auto const ds = (size_ / IntSize) + (size_ % IntSize == 0 ? 0 : 1);
146 // assert( ds <= other.data_.size() );
147 // data_ = std::vector<IntType>( other.data_.begin(), other.data_.begin() + ds );
148 // unset_padding_();
149 // }
150 
151 // =============================================================================
152 // Bit Functions
153 // =============================================================================
154 
155 void Bitvector::set( size_t first, size_t last, bool value )
156 {
157  // Boundary checks
158  if( first >= size_ || last > size_ || first > last ) {
159  throw std::out_of_range(
160  "Cannot access invalid range [" + std::to_string(first) + ", " + std::to_string(last) +
161  ") in Bitvector of size " + std::to_string(size_)
162  );
163  }
164  assert( first < size_ );
165  assert( last <= size_ );
166  assert( first <= last );
167 
168  // Check special case, as we might otherwise access invalid data at the boundaries.
169  if( first == last ) {
170  return;
171  }
172  assert( last > 0 );
173 
174  // Get word indices, and bit position indices within those words.
175  // The last word is the one where the bit before `last` is, as `last` is past-the-end.
176  // However, the bit index is still needs to be past-the-end, to use the proper mask.
177  auto const f_wrd_idx = first / IntSize;
178  auto const l_wrd_idx = (last - 1) / IntSize;
179  auto const f_bit_idx = first % IntSize;
180  auto const l_bit_idx = last % IntSize;
181  assert( f_wrd_idx < data_.size() );
182  assert( l_wrd_idx < data_.size() );
183  assert( f_bit_idx < ones_mask_.size() );
184  assert( l_bit_idx < ones_mask_.size() );
185 
186  // Get the two words at the boundary. We later check if they are the same,
187  // so we do not repeat the code here, and treat the special case later.
188  auto const f_mask = ~ones_mask_[ f_bit_idx ];
189  auto const l_mask = l_bit_idx == 0 ? all_1_ : ones_mask_[ l_bit_idx ];
190 
191  // Now set the bits as needed for the range.
192  if( f_wrd_idx == l_wrd_idx ) {
193  if( value ) {
194  data_[ f_wrd_idx ] |= ( f_mask & l_mask );
195  } else {
196  data_[ f_wrd_idx ] &= ~( f_mask & l_mask );
197  }
198  } else {
199  if( value ) {
200  data_[ f_wrd_idx ] |= f_mask;
201  for( size_t i = f_wrd_idx + 1; i < l_wrd_idx; ++i ) {
202  data_[i] = all_1_;
203  }
204  data_[ l_wrd_idx ] |= l_mask;
205  } else {
206  data_[ f_wrd_idx ] &= ~f_mask;
207  for( size_t i = f_wrd_idx + 1; i < l_wrd_idx; ++i ) {
208  data_[i] = all_0_;
209  }
210  data_[ l_wrd_idx ] &= ~l_mask;
211  }
212  }
213 }
214 
215 // =============================================================================
216 // Operators
217 // =============================================================================
218 
220 {
221  if( size_ != rhs.size_ ) {
222  throw std::runtime_error(
223  "Cannot use operator `&` or `&=` on Bitvectors of different size. "
224  "Use bitwise_and() instead."
225  );
226  }
227 
228  for( size_t i = 0; i < data_.size(); ++i ) {
229  data_[i] &= rhs.data_[i];
230  }
231  return *this;
232 }
233 
235 {
236  if( size_ != rhs.size_ ) {
237  throw std::runtime_error(
238  "Cannot use operator `|` or `|=` on Bitvectors of different size. "
239  "Use bitwise_or() instead."
240  );
241  }
242 
243  for( size_t i = 0; i < data_.size(); ++i ) {
244  data_[i] |= rhs.data_[i];
245  }
246  return *this;
247 }
248 
250 {
251  if( size_ != rhs.size_ ) {
252  throw std::runtime_error(
253  "Cannot use operator `^` or `^=` on Bitvectors of different size. "
254  "Use bitwise_xor() instead."
255  );
256  }
257 
258  for( size_t i = 0; i < data_.size(); ++i ) {
259  data_[i] ^= rhs.data_[i];
260  }
261  return *this;
262 }
263 
265 {
266  Bitvector cpy = Bitvector(*this);
267  cpy.negate();
268  return cpy;
269 }
270 
271 Bitvector operator & (Bitvector const& lhs, Bitvector const& rhs)
272 {
273  Bitvector result = Bitvector(lhs);
274  result &= rhs;
275  return result;
276 }
277 
278 Bitvector operator | (Bitvector const& lhs, Bitvector const& rhs)
279 {
280  Bitvector result = Bitvector(lhs);
281  result |= rhs;
282  return result;
283 }
284 
285 Bitvector operator ^ (Bitvector const& lhs, Bitvector const& rhs)
286 {
287  Bitvector result = Bitvector(lhs);
288  result ^= rhs;
289  return result;
290 }
291 
292 bool Bitvector::operator == (const Bitvector &other) const
293 {
294  if (size_ != other.size_) {
295  return false;
296  }
297  for( size_t i = 0; i < data_.size(); ++i ) {
298  if (data_[i] != other.data_[i]) {
299  return false;
300  }
301  }
302  return true;
303 }
304 
305 bool Bitvector::operator != (const Bitvector &other) const
306 {
307  return !(*this == other);
308 }
309 
310 // =============================================================================
311 // Other Functions
312 // =============================================================================
313 
314 size_t Bitvector::count() const
315 {
316  // Use bit trickery to count quickly.
317  size_t res = 0;
318  for( auto x : data_ ) {
319  res += count_(x);
320  }
321 
322  // safe, but slow version...
323  //~ size_t tmp = 0;
324  //~ for( size_t i = 0; i < size_; ++i ) {
325  //~ if (get(i)) {
326  //~ ++tmp;
327  //~ }
328  //~ }
329  //~ assert(tmp == res);
330 
331  return res;
332 }
333 
334 size_t Bitvector::count( size_t first, size_t last ) const
335 {
336  // Boundary checks.
337  if( first >= size_ || last > size_ || first > last ) {
338  throw std::invalid_argument(
339  "Cannot compute pop count for Bitvector of size " + std::to_string( size_ ) +
340  " within invalid range [" + std::to_string(first) + "," + std::to_string( last ) + ")"
341  );
342  }
343  assert( first < size_ );
344  assert( last <= size_ );
345  assert( first <= last );
346 
347  // Check special case, as we might otherwise access invalid data at the boundaries.
348  if( first == last ) {
349  return 0;
350  }
351  assert( last > 0 );
352 
353  // We need to mask the first bits of the first word and last bits of the last word
354  // before counting, and then can process the in-between words normally.
355  // If first and last are the same word, we need special treatment as well.
356 
357  // Get word indices, and bit position indices within those words.
358  // The last word is the one where the bit before last is, as last is past-the-end.
359  // However, the bit index is still meant to be past-the-end, to use the proper mask.
360  auto const f_wrd_idx = first / IntSize;
361  auto const l_wrd_idx = (last - 1) / IntSize;
362  auto const f_bit_idx = first % IntSize;
363  auto const l_bit_idx = last % IntSize;
364  assert( f_wrd_idx < data_.size() );
365  assert( l_wrd_idx < data_.size() );
366  assert( f_bit_idx < ones_mask_.size() );
367  assert( l_bit_idx < ones_mask_.size() );
368 
369  // Get the two words at the boundary. We later check if they are the same,
370  // so we do not repeat the code here, and treat the special case later.
371  auto f_word = data_[ f_wrd_idx ];
372  auto l_word = data_[ l_wrd_idx ];
373 
374  // Mask out the beginning and end, respectively.
375  // Remove all bits before the first index, and all bits after and including the last index.
376  // No special case needed here, as the 0th mask is idempotent.
377  // That's because it's the mask that we also use for unset_padding_(),
378  // we are basically doing the same here.
379  f_word &= ~ones_mask_[ f_bit_idx ];
380  if( l_bit_idx != 0 ) {
381  l_word &= ones_mask_[ l_bit_idx ];
382  }
383 
384  // Finally, count up all the parts.
385  size_t result = 0;
386  if( f_wrd_idx == l_wrd_idx ) {
387  // Same word. Mask out the bits we don't want, using only the bits that remained after
388  // filtering both words (which are the same, just different ends of the word), then count.
389  result = count_( f_word & l_word );
390  } else {
391  // Count the first and last word, and then add everything in between the two.
392  result = count_( f_word ) + count_( l_word );
393  for( size_t i = f_wrd_idx + 1; i < l_wrd_idx; ++i ) {
394  result += count_( data_[i] );
395  }
396  }
397  return result;
398 }
399 
400 bool Bitvector::any_set() const
401 {
402  for( auto word : data_ ) {
403  if( word > 0 ) {
404  return true;
405  }
406  }
407  return false;
408 }
409 
410 size_t Bitvector::find_next_set( size_t start ) const
411 {
412  // Boundary check
413  if( start >= size_ ) {
414  // We mimic the behaviour of std::string::find(), which just never finds anything
415  // when used beyond the string, but also does not throw an exception in such cases.
416  return Bitvector::npos;
417 
418  // Alternative: Throw an exception.
419  // throw std::invalid_argument(
420  // "Invalid call to find_next_set() with start==" + std::to_string(start) +
421  // " and a Bitvector of size " + std::to_string( size_ )
422  // );
423  }
424 
425  // Helper function to find the index of the first set bit in a non-zero word.
426  auto find_next_set_in_word_ = []( IntType word ) {
427  assert( word != 0 );
428 
429  // We use ffs here, see https://man7.org/linux/man-pages/man3/ffs.3.html
430  // It returns the _position_ of the bit, so we need to subtract 1 to get the index.
431  // Alternatively, we could use __builtin_ctz, which returns the number of trailing
432  // zeros in the given word, but is a compiler intrinsic, so let's stay with POSIX.
433 
434  // Check the size of the input and call the appropriate ffs function.
435  // Any good compiler will see through this and make this constexpr.
436  // In C++17, we could do this ourselves ;-)
437  if( sizeof(word) <= sizeof(unsigned int) ) {
438  return ffs( static_cast<unsigned int>( word )) - 1;
439  } else if( sizeof(word) <= sizeof(unsigned long) ) {
440  return ffsl( static_cast<unsigned long>( word )) - 1;
441  } else {
442  return ffsll(word) - 1;
443  }
444  };
445 
446  // First see if there is anything in the word at the start position.
447  // We assume that this function might be called on a dense bitvector,
448  // where the given position is already set, so we check that as a shortcut.
449  if( get( start )) {
450  return start;
451  }
452 
453  // If that did not work, we see if there is anything in the current word.
454  auto wrd_idx = start / IntSize;
455  auto bit_idx = start % IntSize;
456  assert( wrd_idx < data_.size() );
457  assert( bit_idx < ones_mask_.size() );
458  auto word = data_[wrd_idx];
459 
460  // For this, we remove the bits before start, and then test the rest.
461  // Mask out the beginning of the word, and find the next bit on the remainder.
462  // Remove all bits before the first index.
463  word &= ~( ones_mask_[ bit_idx ]);
464  if( word != 0 ) {
465  return wrd_idx * IntSize + find_next_set_in_word_( word );
466  }
467 
468  // We did not find a bit in the word of the start. So now we look for the first word
469  // after the start one that has bits set, and return its first set bit position.
470  ++wrd_idx;
471  while( wrd_idx < data_.size() && data_[wrd_idx] == 0 ) {
472  ++wrd_idx;
473  }
474  if( wrd_idx == data_.size() ) {
475  return Bitvector::npos;
476 
477  }
478  assert( wrd_idx < data_.size() );
479  assert( data_[wrd_idx] != 0 );
480  return wrd_idx * IntSize + find_next_set_in_word_( data_[wrd_idx] );
481 }
482 
483 size_t Bitvector::hash() const
484 {
485  std::size_t res = 0;
486  for( auto word : data_ ) {
487  res = hash_combine( res, word );
488  }
489  return res;
490 }
491 
493 {
494  IntType res = 0;
495  for( auto word : data_ ) {
496  res ^= word;
497  }
498  return res;
499 }
500 
502 {
503  // flip all bits.
504  for( size_t i = 0; i < data_.size(); ++i ) {
505  data_[i] = ~ data_[i];
506  }
507 
508  // reset the surplus bits at the end of the vector.
509  unset_padding_();
510 }
511 
513 {
514  if( size_ > 0 && get(0) ) {
515  negate();
516  }
517 }
518 
519 void Bitvector::set_all( const bool value )
520 {
521  // set according to flag.
522  const auto v = value ? all_1_ : all_0_;
523  for( size_t i = 0; i < data_.size(); ++i ) {
524  data_[i] = v;
525  }
526 
527  // if we initialized with true, we need to unset the surplus bits at the end!
528  if( value ) {
529  unset_padding_();
530  }
531 }
532 
533 // =============================================================================
534 // Internal Members
535 // =============================================================================
536 
537 void Bitvector::unset_padding_()
538 {
539  // Only apply if there are actual padding bits.
540  if(( size_ % IntSize ) == 0 ) {
541  assert( size_ / IntSize == data_.size() );
542  return;
543  }
544 
545  // In the other cases, unset the padding.
546  assert( size_ / IntSize + 1 == data_.size() );
547  assert( size_ % IntSize < ones_mask_.size() );
548  data_.back() &= ones_mask_[ size_ % IntSize ];
549 
550  // other versions that might be helpful if i messed up with this little/big endian stuff...
551  // first one is slow but definitely works, second one is fast, but might have the same
552  // issue as the used version above (which currently works perfectly).
553  //~ for( size_t i = size_ % IntSize; i < IntSize; ++i ) {
554  //~ data_.back() &= ~bit_mask_[i];
555  //~ }
556  //~ data_.back() &= bit_mask_[size_ % IntSize] - 1;
557 }
558 
559 size_t Bitvector::count_( IntType x )
560 {
561  // Use some bit magic, see e.g., https://en.wikipedia.org/wiki/Hamming_weight
562 
563  // put count of each 2 bits into those 2 bits
564  x -= (x >> 1) & count_mask_[0];
565 
566  // put count of each 4 bits into those 4 bits
567  x = (x & count_mask_[1]) + ((x >> 2) & count_mask_[1]);
568 
569  // put count of each 8 bits into those 8 bits
570  x = (x + (x >> 4)) & count_mask_[2];
571 
572  // take left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
573  return (x * count_mask_[3]) >> 56;
574 }
575 
576 // =============================================================================
577 // Dump and Debug
578 // =============================================================================
579 
580 std::string Bitvector::dump() const
581 {
582  std::string res = "[" + std::to_string(size_) + "]\n";
583  for( size_t i = 0; i < size_; ++i ) {
584  res += (*this)[i] ? "1" : "0";
585  if( (i+1) % 64 == 0 ) {
586  res += "\n";
587  } else if( (i+1) % 8 == 0 ) {
588  res += " ";
589  }
590  }
591  return res;
592 }
593 
594 std::string Bitvector::dump_int(IntType x) const
595 {
596  std::string res = "";
597  for( size_t i = 0; i < IntSize; ++i ) {
598  res += (x & bit_mask_[i] ? "1" : "0");
599  if( (i+1) % 8 == 0 ) {
600  res += " ";
601  }
602  }
603  return res;
604 }
605 
606 } // namespace utils
607 } // namespace genesis
genesis::utils::Bitvector::operator~
Bitvector operator~() const
Definition: bitvector.cpp:264
genesis::utils::Bitvector::x_hash
IntType x_hash() const
Return a hash value of type IntType that is quicker to calculate than hash().
Definition: bitvector.cpp:492
genesis::utils::Bitvector::set
void set(size_t index)
Set the value of a single bit to true, with boundary check.
Definition: bitvector.hpp:184
genesis::utils::operator|
Bitvector operator|(Bitvector const &lhs, Bitvector const &rhs)
Definition: bitvector.cpp:278
genesis::utils::Bitvector::get
bool get(size_t index) const
Return the value of a single bit, with boundary check.
Definition: bitvector.hpp:167
genesis::utils::Bitvector::find_next_set
size_t find_next_set(size_t start) const
Return the index of the next position in the Bitvector that is set.
Definition: bitvector.cpp:410
genesis::utils::Bitvector::operator!=
bool operator!=(const Bitvector &other) const
Definition: bitvector.cpp:305
std.hpp
Provides some valuable additions to STD.
genesis::utils::Bitvector::operator&=
Bitvector & operator&=(Bitvector const &rhs)
Definition: bitvector.cpp:219
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: function/genome_locus.hpp:52
genesis::utils::Bitvector::dump
std::string dump() const
Definition: bitvector.cpp:580
genesis::utils::Bitvector::Bitvector
Bitvector()=default
Default constructor. Creates an empty Bitvector of size 0.
genesis::utils::Bitvector::operator|=
Bitvector & operator|=(Bitvector const &rhs)
Definition: bitvector.cpp:234
genesis::utils::Bitvector::negate
void negate()
Flip all bits.
Definition: bitvector.cpp:501
genesis::utils::operator&
constexpr bool operator&(SkipWhitespace lhs, SkipWhitespace rhs) noexcept
And-operator to check whether a SkipWhitespace is set.
Definition: scanner.hpp:97
genesis::utils::Bitvector::hash
size_t hash() const
Return an std::hash value for the Bitvector.
Definition: bitvector.cpp:483
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::Bitvector::IntSize
static const size_t IntSize
Definition: bitvector.hpp:59
genesis::utils::Bitvector::operator==
bool operator==(const Bitvector &other) const
Definition: bitvector.cpp:292
genesis::utils::Bitvector::dump_int
std::string dump_int(IntType x) const
Definition: bitvector.cpp:594
genesis::utils::Bitvector::normalize
void normalize()
Bring the Bitvector in a normalized form, where the first bit is always zero.
Definition: bitvector.cpp:512
genesis::utils::Bitvector::set_all
void set_all(const bool value=false)
Set all the bits to a specified value.
Definition: bitvector.cpp:519
genesis::utils::Bitvector::IntType
uint64_t IntType
Definition: bitvector.hpp:58
bitvector.hpp
genesis::utils::Bitvector::count
size_t count() const
Count the number of set bits in the Bitvector, that is, its Hamming weight, or population count (popc...
Definition: bitvector.cpp:314
genesis::utils::operator^
Bitvector operator^(Bitvector const &lhs, Bitvector const &rhs)
Definition: bitvector.cpp:285
genesis::utils::Bitvector::npos
static const size_t npos
Value to indicate that find_next_set() did not find any set bits.
Definition: bitvector.hpp:64
genesis::utils::Bitvector::any_set
bool any_set() const
Return if any bits are set at all.
Definition: bitvector.cpp:400
genesis::utils::Bitvector::operator^=
Bitvector & operator^=(Bitvector const &rhs)
Definition: bitvector.cpp:249
genesis::utils::hash_combine
constexpr std::size_t hash_combine(std::size_t seed, T const &value)
Combine a seed value (e.g., another hash) with the hash of a given type.
Definition: std.hpp:160
genesis::utils::Bitvector
Definition: bitvector.hpp:50