diff options
Diffstat (limited to 'src/common/bit_set.h')
| -rw-r--r-- | src/common/bit_set.h | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/common/bit_set.h b/src/common/bit_set.h new file mode 100644 index 000000000..9235ad412 --- /dev/null +++ b/src/common/bit_set.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018-2020 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include <array> | ||
| 20 | #include <bit> | ||
| 21 | |||
| 22 | #include "common/alignment.h" | ||
| 23 | #include "common/bit_util.h" | ||
| 24 | #include "common/common_types.h" | ||
| 25 | |||
| 26 | namespace Common { | ||
| 27 | |||
| 28 | namespace impl { | ||
| 29 | |||
| 30 | template <typename Storage, size_t N> | ||
| 31 | class BitSet { | ||
| 32 | |||
| 33 | public: | ||
| 34 | constexpr BitSet() = default; | ||
| 35 | |||
| 36 | constexpr void SetBit(size_t i) { | ||
| 37 | this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord); | ||
| 38 | } | ||
| 39 | |||
| 40 | constexpr void ClearBit(size_t i) { | ||
| 41 | this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord); | ||
| 42 | } | ||
| 43 | |||
| 44 | constexpr size_t CountLeadingZero() const { | ||
| 45 | for (size_t i = 0; i < NumWords; i++) { | ||
| 46 | if (this->words[i]) { | ||
| 47 | return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | return FlagsPerWord * NumWords; | ||
| 51 | } | ||
| 52 | |||
| 53 | constexpr size_t GetNextSet(size_t n) const { | ||
| 54 | for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) { | ||
| 55 | Storage word = this->words[i]; | ||
| 56 | if (!IsAligned(n + 1, FlagsPerWord)) { | ||
| 57 | word &= GetBitMask(n % FlagsPerWord) - 1; | ||
| 58 | } | ||
| 59 | if (word) { | ||
| 60 | return FlagsPerWord * i + CountLeadingZeroImpl(word); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | return FlagsPerWord * NumWords; | ||
| 64 | } | ||
| 65 | |||
| 66 | private: | ||
| 67 | static_assert(std::is_unsigned_v<Storage>); | ||
| 68 | static_assert(sizeof(Storage) <= sizeof(u64)); | ||
| 69 | |||
| 70 | static constexpr size_t FlagsPerWord = BitSize<Storage>(); | ||
| 71 | static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord; | ||
| 72 | |||
| 73 | static constexpr auto CountLeadingZeroImpl(Storage word) { | ||
| 74 | return std::countl_zero(static_cast<unsigned long long>(word)) - | ||
| 75 | (BitSize<unsigned long long>() - FlagsPerWord); | ||
| 76 | } | ||
| 77 | |||
| 78 | static constexpr Storage GetBitMask(size_t bit) { | ||
| 79 | return Storage(1) << (FlagsPerWord - 1 - bit); | ||
| 80 | } | ||
| 81 | |||
| 82 | std::array<Storage, NumWords> words{}; | ||
| 83 | }; | ||
| 84 | |||
| 85 | } // namespace impl | ||
| 86 | |||
| 87 | template <size_t N> | ||
| 88 | using BitSet8 = impl::BitSet<u8, N>; | ||
| 89 | |||
| 90 | template <size_t N> | ||
| 91 | using BitSet16 = impl::BitSet<u16, N>; | ||
| 92 | |||
| 93 | template <size_t N> | ||
| 94 | using BitSet32 = impl::BitSet<u32, N>; | ||
| 95 | |||
| 96 | template <size_t N> | ||
| 97 | using BitSet64 = impl::BitSet<u64, N>; | ||
| 98 | |||
| 99 | } // namespace Common | ||