File indexing completed on 2025-09-15 08:55:03
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <climits>
0010 #include <cstdint>
0011 #include <type_traits>
0012
0013 #include "corecel/Config.hh"
0014
0015 #include "corecel/Assert.hh"
0016 #include "corecel/Macros.hh"
0017 #include "corecel/Types.hh"
0018 #include "corecel/math/Algorithms.hh"
0019
0020 namespace celeritas
0021 {
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 template<size_type N>
0041 class Bitset
0042 {
0043 static_assert(N > 0, "Zero-sized bitset is not supported");
0044
0045 public:
0046
0047
0048 using word_type = std::conditional_t<
0049 (N <= 8),
0050 std::uint8_t,
0051 std::conditional_t<(N <= 16), std::uint16_t, size_type>>;
0052
0053
0054 class reference;
0055
0056 public:
0057
0058
0059
0060 constexpr Bitset() = default;
0061
0062
0063 CELER_CONSTEXPR_FUNCTION Bitset(word_type value) noexcept;
0064
0065
0066
0067
0068 CELER_CONSTEXPR_FUNCTION bool
0069 operator==(Bitset const& other) const noexcept;
0070
0071
0072 CELER_CONSTEXPR_FUNCTION bool
0073 operator!=(Bitset const& other) const noexcept;
0074
0075
0076
0077
0078 CELER_CONSTEXPR_FUNCTION bool operator[](size_type pos) const
0079 noexcept(!CELERITAS_DEBUG);
0080
0081
0082 CELER_CONSTEXPR_FUNCTION reference
0083 operator[](size_type pos) noexcept(!CELERITAS_DEBUG);
0084
0085
0086 CELER_CONSTEXPR_FUNCTION bool all() const noexcept;
0087
0088
0089 CELER_CONSTEXPR_FUNCTION bool any() const noexcept;
0090
0091
0092 CELER_CONSTEXPR_FUNCTION bool none() const noexcept;
0093
0094
0095 CELER_CONSTEXPR_FUNCTION size_type count() const noexcept;
0096
0097
0098 CELER_CONSTEXPR_FUNCTION size_type size() const noexcept { return N; }
0099
0100
0101
0102
0103 CELER_CONSTEXPR_FUNCTION Bitset& operator&=(Bitset const& other) noexcept;
0104
0105
0106 CELER_CONSTEXPR_FUNCTION Bitset& operator|=(Bitset const& other) noexcept;
0107
0108
0109 CELER_CONSTEXPR_FUNCTION Bitset& operator^=(Bitset const& other) noexcept;
0110
0111
0112 CELER_CONSTEXPR_FUNCTION Bitset operator~() const noexcept;
0113
0114
0115 CELER_CONSTEXPR_FUNCTION Bitset& set() noexcept;
0116
0117
0118 CELER_CONSTEXPR_FUNCTION Bitset&
0119 set(size_type pos, bool value = true) noexcept(!CELERITAS_DEBUG);
0120
0121
0122 CELER_CONSTEXPR_FUNCTION Bitset& reset() noexcept;
0123
0124
0125 CELER_CONSTEXPR_FUNCTION Bitset&
0126 reset(size_type pos) noexcept(!CELERITAS_DEBUG);
0127
0128
0129 CELER_CONSTEXPR_FUNCTION Bitset& flip() noexcept;
0130
0131
0132 CELER_CONSTEXPR_FUNCTION Bitset&
0133 flip(size_type pos) noexcept(!CELERITAS_DEBUG);
0134
0135 private:
0136
0137
0138 static constexpr size_type bits_per_word_ = CHAR_BIT * sizeof(word_type);
0139 static constexpr size_type num_words_ = ceil_div(N, bits_per_word_);
0140
0141
0142
0143
0144 word_type words_[num_words_]{};
0145
0146
0147
0148
0149 static CELER_CONSTEXPR_FUNCTION size_type which_word(size_type pos) noexcept;
0150
0151 static CELER_CONSTEXPR_FUNCTION size_type which_bit(size_type pos) noexcept;
0152
0153
0154 static CELER_CONSTEXPR_FUNCTION word_type mask(size_type pos) noexcept;
0155
0156
0157 static CELER_CONSTEXPR_FUNCTION word_type neg_mask(size_type pos) noexcept;
0158
0159
0160 CELER_CONSTEXPR_FUNCTION word_type get_word(size_type pos) const
0161 noexcept(!CELERITAS_DEBUG);
0162
0163
0164 CELER_CONSTEXPR_FUNCTION word_type&
0165 get_word(size_type pos) noexcept(!CELERITAS_DEBUG);
0166
0167
0168 CELER_CONSTEXPR_FUNCTION word_type& last_word() noexcept;
0169
0170
0171 CELER_CONSTEXPR_FUNCTION word_type last_word() const noexcept;
0172
0173
0174 CELER_CONSTEXPR_FUNCTION void sanitize() noexcept;
0175 };
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 template<size_type N>
0186 class Bitset<N>::reference
0187 {
0188 public:
0189 CELER_CONSTEXPR_FUNCTION
0190 reference(Bitset& b, size_type pos) noexcept
0191 : word_pointer_(&b.get_word(pos)), bit_pos_(Bitset::which_bit(pos))
0192 {
0193 }
0194
0195 constexpr reference(reference const&) = default;
0196
0197 ~reference() noexcept = default;
0198
0199
0200 CELER_CONSTEXPR_FUNCTION
0201 reference& operator=(bool x) noexcept
0202 {
0203 if (x)
0204 {
0205 *word_pointer_ |= Bitset::mask(bit_pos_);
0206 }
0207 else
0208 {
0209 *word_pointer_ &= Bitset::neg_mask(bit_pos_);
0210 }
0211 return *this;
0212 }
0213
0214
0215 CELER_CONSTEXPR_FUNCTION
0216 reference& operator=(reference const& j) noexcept
0217 {
0218 if (this != &j)
0219 {
0220 if (*j.word_pointer_ & Bitset::mask(j.bit_pos_))
0221 {
0222 *word_pointer_ |= Bitset::mask(bit_pos_);
0223 }
0224 else
0225 {
0226 *word_pointer_ &= Bitset::neg_mask(bit_pos_);
0227 }
0228 }
0229 return *this;
0230 }
0231
0232
0233 CELER_CONSTEXPR_FUNCTION
0234 bool operator~() const noexcept { return !static_cast<bool>(*this); }
0235
0236
0237 CELER_CONSTEXPR_FUNCTION
0238 operator bool() const noexcept
0239 {
0240 return (*word_pointer_ & Bitset::mask(bit_pos_)) != 0;
0241 }
0242
0243
0244 CELER_CONSTEXPR_FUNCTION
0245 reference& flip() noexcept
0246 {
0247 *word_pointer_ ^= Bitset::mask(bit_pos_);
0248 return *this;
0249 }
0250
0251 private:
0252 word_type* word_pointer_{nullptr};
0253 size_type bit_pos_{0};
0254 };
0255
0256
0257
0258
0259
0260 template<size_type N>
0261 CELER_CONSTEXPR_FUNCTION Bitset<N>::Bitset(word_type value) noexcept
0262 : words_{value}
0263 {
0264 if constexpr (num_words_ == 1)
0265 {
0266 this->sanitize();
0267 }
0268 }
0269
0270
0271
0272 template<size_type N>
0273 CELER_CONSTEXPR_FUNCTION bool
0274 Bitset<N>::operator==(Bitset const& other) const noexcept
0275 {
0276 for (size_type i = 0; i < num_words_; ++i)
0277 {
0278 if (words_[i] != other.words_[i])
0279 {
0280 return false;
0281 }
0282 }
0283 return true;
0284 }
0285
0286
0287
0288 template<size_type N>
0289 CELER_CONSTEXPR_FUNCTION bool
0290 Bitset<N>::operator!=(Bitset const& other) const noexcept
0291 {
0292 return !(*this == other);
0293 }
0294
0295
0296
0297 template<size_type N>
0298 CELER_CONSTEXPR_FUNCTION bool Bitset<N>::operator[](size_type pos) const
0299 noexcept(!CELERITAS_DEBUG)
0300 {
0301 CELER_EXPECT(pos < N);
0302 return (this->get_word(pos) & Bitset::mask(pos))
0303 != static_cast<word_type>(0);
0304 }
0305
0306
0307
0308 template<size_type N>
0309 CELER_CONSTEXPR_FUNCTION auto
0310 Bitset<N>::operator[](size_type pos) noexcept(!CELERITAS_DEBUG) -> reference
0311 {
0312 CELER_EXPECT(pos < N);
0313 return reference(*this, pos);
0314 }
0315
0316
0317
0318 template<size_type N>
0319 CELER_CONSTEXPR_FUNCTION bool Bitset<N>::all() const noexcept
0320 {
0321 for (size_type i = 0; i < num_words_ - 1; ++i)
0322 {
0323 if (words_[i] != static_cast<word_type>(~word_type(0)))
0324 {
0325 return false;
0326 }
0327 }
0328
0329
0330 return this->last_word()
0331 == (static_cast<word_type>(~word_type(0))
0332 >> (num_words_ * bits_per_word_ - N));
0333 }
0334
0335
0336
0337 template<size_type N>
0338 CELER_CONSTEXPR_FUNCTION bool Bitset<N>::any() const noexcept
0339 {
0340 for (size_type i = 0; i < num_words_; ++i)
0341 {
0342 if (words_[i] != word_type(0))
0343 {
0344 return true;
0345 }
0346 }
0347
0348 return false;
0349 }
0350
0351
0352
0353 template<size_type N>
0354 CELER_CONSTEXPR_FUNCTION bool Bitset<N>::none() const noexcept
0355 {
0356 return !this->any();
0357 }
0358
0359
0360
0361 template<size_type N>
0362 CELER_CONSTEXPR_FUNCTION size_type Bitset<N>::count() const noexcept
0363 {
0364 size_type count = 0;
0365 for (size_type i = 0; i < num_words_; ++i)
0366 {
0367 count += celeritas::popcount(words_[i]);
0368 }
0369
0370 return count;
0371 }
0372
0373
0374
0375 template<size_type N>
0376 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0377 Bitset<N>::operator&=(Bitset const& other) noexcept
0378 {
0379 for (size_type i = 0; i < num_words_; ++i)
0380 {
0381 words_[i] &= other.words_[i];
0382 }
0383 return *this;
0384 }
0385
0386
0387
0388 template<size_type N>
0389 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0390 Bitset<N>::operator|=(Bitset const& other) noexcept
0391 {
0392 for (size_type i = 0; i < num_words_; ++i)
0393 {
0394 words_[i] |= other.words_[i];
0395 }
0396 return *this;
0397 }
0398
0399
0400
0401 template<size_type N>
0402 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0403 Bitset<N>::operator^=(Bitset const& other) noexcept
0404 {
0405 for (size_type i = 0; i < num_words_; ++i)
0406 {
0407 words_[i] ^= other.words_[i];
0408 }
0409 return *this;
0410 }
0411
0412
0413
0414 template<size_type N>
0415 CELER_CONSTEXPR_FUNCTION Bitset<N> Bitset<N>::operator~() const noexcept
0416 {
0417 return Bitset{*this}.flip();
0418 }
0419
0420
0421
0422 template<size_type N>
0423 CELER_CONSTEXPR_FUNCTION Bitset<N>& Bitset<N>::set() noexcept
0424 {
0425 for (size_type i = 0; i < num_words_; ++i)
0426 {
0427 words_[i] = static_cast<word_type>(~word_type(0));
0428 }
0429
0430
0431 this->sanitize();
0432
0433 return *this;
0434 }
0435
0436
0437
0438 template<size_type N>
0439 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0440 Bitset<N>::set(size_type pos, bool value) noexcept(!CELERITAS_DEBUG)
0441 {
0442 CELER_EXPECT(pos < N);
0443 (*this)[pos] = value;
0444 return *this;
0445 }
0446
0447
0448
0449 template<size_type N>
0450 CELER_CONSTEXPR_FUNCTION Bitset<N>& Bitset<N>::reset() noexcept
0451 {
0452 for (size_type i = 0; i < num_words_; ++i)
0453 {
0454 words_[i] = word_type(0);
0455 }
0456
0457 return *this;
0458 }
0459
0460
0461
0462 template<size_type N>
0463 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0464 Bitset<N>::reset(size_type pos) noexcept(!CELERITAS_DEBUG)
0465 {
0466 CELER_EXPECT(pos < N);
0467 this->get_word(pos) &= Bitset::neg_mask(pos);
0468 return *this;
0469 }
0470
0471
0472
0473 template<size_type N>
0474 CELER_CONSTEXPR_FUNCTION Bitset<N>& Bitset<N>::flip() noexcept
0475 {
0476 for (size_type i = 0; i < num_words_; ++i)
0477 {
0478 words_[i] = ~words_[i];
0479 }
0480
0481
0482 this->sanitize();
0483
0484 return *this;
0485 }
0486
0487
0488
0489 template<size_type N>
0490 CELER_CONSTEXPR_FUNCTION Bitset<N>&
0491 Bitset<N>::flip(size_type pos) noexcept(!CELERITAS_DEBUG)
0492 {
0493 CELER_EXPECT(pos < N);
0494 this->get_word(pos) ^= Bitset::mask(pos);
0495 return *this;
0496 }
0497
0498
0499
0500 template<size_type N>
0501 CELER_CONSTEXPR_FUNCTION size_type Bitset<N>::which_word(size_type pos) noexcept
0502 {
0503 return pos / bits_per_word_;
0504 }
0505
0506
0507
0508 template<size_type N>
0509 CELER_CONSTEXPR_FUNCTION size_type Bitset<N>::which_bit(size_type pos) noexcept
0510 {
0511 return pos % bits_per_word_;
0512 }
0513
0514
0515
0516 template<size_type N>
0517 CELER_CONSTEXPR_FUNCTION auto
0518 Bitset<N>::mask(size_type pos) noexcept -> word_type
0519 {
0520 return word_type(1) << Bitset::which_bit(pos);
0521 }
0522
0523
0524
0525
0526
0527
0528
0529 template<size_type N>
0530 CELER_CONSTEXPR_FUNCTION auto
0531 Bitset<N>::neg_mask(size_type pos) noexcept -> word_type
0532 {
0533 return ~(word_type(1) << Bitset::which_bit(pos));
0534 }
0535
0536
0537
0538 template<size_type N>
0539 CELER_CONSTEXPR_FUNCTION auto Bitset<N>::get_word(size_type pos) const
0540 noexcept(!CELERITAS_DEBUG) -> word_type
0541 {
0542 CELER_EXPECT(pos < N);
0543 return words_[Bitset::which_word(pos)];
0544 }
0545
0546
0547
0548 template<size_type N>
0549 CELER_CONSTEXPR_FUNCTION auto
0550 Bitset<N>::get_word(size_type pos) noexcept(!CELERITAS_DEBUG) -> word_type&
0551 {
0552 CELER_EXPECT(pos < N);
0553 return words_[Bitset::which_word(pos)];
0554 }
0555
0556
0557
0558 template<size_type N>
0559 CELER_CONSTEXPR_FUNCTION auto Bitset<N>::last_word() noexcept -> word_type&
0560 {
0561 return words_[num_words_ - 1];
0562 }
0563
0564
0565
0566 template<size_type N>
0567 CELER_CONSTEXPR_FUNCTION auto Bitset<N>::last_word() const noexcept -> word_type
0568 {
0569 return words_[num_words_ - 1];
0570 }
0571
0572
0573
0574 template<size_type N>
0575 CELER_CONSTEXPR_FUNCTION void Bitset<N>::sanitize() noexcept
0576 {
0577 constexpr size_type extra_bits = N % bits_per_word_;
0578 if constexpr (extra_bits != 0)
0579 {
0580 this->last_word() &= static_cast<word_type>(
0581 ~(static_cast<word_type>(~word_type(0)) << extra_bits));
0582 }
0583 }
0584
0585
0586
0587
0588
0589 template<size_type N>
0590 CELER_CONSTEXPR_FUNCTION Bitset<N>
0591 operator&(Bitset<N> const& lhs, Bitset<N> const& rhs)
0592 {
0593 return Bitset{lhs} &= rhs;
0594 }
0595
0596
0597
0598 template<size_type N>
0599 CELER_CONSTEXPR_FUNCTION Bitset<N>
0600 operator|(Bitset<N> const& lhs, Bitset<N> const& rhs)
0601 {
0602 return Bitset{lhs} |= rhs;
0603 }
0604
0605
0606
0607 template<size_type N>
0608 CELER_CONSTEXPR_FUNCTION Bitset<N>
0609 operator^(Bitset<N> const& lhs, Bitset<N> const& rhs)
0610 {
0611 return Bitset{lhs} ^= rhs;
0612 }
0613
0614
0615 }