diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index 53bf9eac3..5656d33e3 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -21,6 +21,7 @@ #include "util/util_size.hpp" #include "util/util_fourcc.hpp" #include "util/util_bitpack.hpp" +#include "util/util_bitset.hpp" #include "util/util_scope_guard.hpp" #include "util/util_typed_storage.hpp" #include "util/util_intrusive_list.hpp" diff --git a/libraries/libvapours/include/vapours/util/util_bitset.hpp b/libraries/libvapours/include/vapours/util/util_bitset.hpp new file mode 100644 index 000000000..e3f9ae732 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_bitset.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "../defines.hpp" + +namespace ams::util { + + namespace impl { + + template + class BitSet { + private: + static_assert(std::is_integral::value); + static_assert(std::is_unsigned::value); + static_assert(sizeof(Storage) <= sizeof(u64)); + + static constexpr size_t FlagsPerWord = BITSIZEOF(Storage); + static constexpr size_t NumWords = util::AlignUp(N, FlagsPerWord) / FlagsPerWord; + + static constexpr ALWAYS_INLINE auto CountLeadingZeroImpl(Storage word) { + return __builtin_clzll(static_cast(word)) - (BITSIZEOF(unsigned long long) - FlagsPerWord); + } + + static constexpr ALWAYS_INLINE Storage GetBitMask(size_t bit) { + return Storage(1) << (FlagsPerWord - 1 - bit); + } + private: + Storage words[NumWords]; + public: + constexpr ALWAYS_INLINE BitSet() : words() { /* ... */ } + + constexpr ALWAYS_INLINE void SetBit(size_t i) { + this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord); + } + + constexpr ALWAYS_INLINE void ClearBit(size_t i) { + this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord); + } + + constexpr ALWAYS_INLINE size_t CountLeadingZero() const { + for (size_t i = 0; i < NumWords; i++) { + if (this->words[i]) { + return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]); + } + } + return FlagsPerWord * NumWords; + } + + constexpr ALWAYS_INLINE size_t GetNextSet(size_t n) const { + for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) { + Storage word = this->words[i]; + if (!util::IsAligned(n + 1, FlagsPerWord)) { + word &= GetBitMask(n % FlagsPerWord) - 1; + } + if (word) { + return FlagsPerWord * i + CountLeadingZeroImpl(word); + } + } + return FlagsPerWord * NumWords; + } + }; + + } + + template + using BitSet8 = impl::BitSet; + + template + using BitSet16 = impl::BitSet; + + template + using BitSet32 = impl::BitSet; + + template + using BitSet64 = impl::BitSet; + +}