123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- #pragma once
- #include <c10/macros/Macros.h>
- #include <c10/util/C++17.h>
- #include <c10/util/Optional.h>
- #if defined(_MSC_VER)
- #include <intrin.h>
- #endif
- namespace c10 {
- namespace utils {
- /**
- * This is a simple bitset class with sizeof(long long int) bits.
- * You can set bits, unset bits, query bits by index,
- * and query for the first set bit.
- * Before using this class, please also take a look at std::bitset,
- * which has more functionality and is more generic. It is probably
- * a better fit for your use case. The sole reason for c10::utils::bitset
- * to exist is that std::bitset misses a find_first_set() method.
- */
- struct bitset final {
- private:
- #if defined(_MSC_VER)
- // MSVCs _BitScanForward64 expects int64_t
- using bitset_type = int64_t;
- #else
- // POSIX ffsll expects long long int
- using bitset_type = long long int;
- #endif
- public:
- static constexpr size_t NUM_BITS() {
- return 8 * sizeof(bitset_type);
- }
- constexpr bitset() noexcept = default;
- constexpr bitset(const bitset&) noexcept = default;
- constexpr bitset(bitset&&) noexcept = default;
- // there is an issure for gcc 5.3.0 when define default function as constexpr
- // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68754.
- bitset& operator=(const bitset&) noexcept = default;
- bitset& operator=(bitset&&) noexcept = default;
- constexpr void set(size_t index) noexcept {
- bitset_ |= (static_cast<long long int>(1) << index);
- }
- constexpr void unset(size_t index) noexcept {
- bitset_ &= ~(static_cast<long long int>(1) << index);
- }
- constexpr bool get(size_t index) const noexcept {
- return bitset_ & (static_cast<long long int>(1) << index);
- }
- constexpr bool is_entirely_unset() const noexcept {
- return 0 == bitset_;
- }
- // Call the given functor with the index of each bit that is set
- template <class Func>
- void for_each_set_bit(Func&& func) const {
- bitset cur = *this;
- size_t index = cur.find_first_set();
- while (0 != index) {
- // -1 because find_first_set() is not one-indexed.
- index -= 1;
- func(index);
- cur.unset(index);
- index = cur.find_first_set();
- }
- }
- private:
- // Return the index of the first set bit. The returned index is one-indexed
- // (i.e. if the very first bit is set, this function returns '1'), and a
- // return of '0' means that there was no bit set.
- size_t find_first_set() const {
- #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
- unsigned long result;
- bool has_bits_set = (0 != _BitScanForward64(&result, bitset_));
- if (!has_bits_set) {
- return 0;
- }
- return result + 1;
- #elif defined(_MSC_VER) && defined(_M_IX86)
- unsigned long result;
- if (static_cast<uint32_t>(bitset_) != 0) {
- bool has_bits_set =
- (0 != _BitScanForward(&result, static_cast<uint32_t>(bitset_)));
- if (!has_bits_set) {
- return 0;
- }
- return result + 1;
- } else {
- bool has_bits_set =
- (0 != _BitScanForward(&result, static_cast<uint32_t>(bitset_ >> 32)));
- if (!has_bits_set) {
- return 32;
- }
- return result + 33;
- }
- #else
- return __builtin_ffsll(bitset_);
- #endif
- }
- friend bool operator==(bitset lhs, bitset rhs) noexcept {
- return lhs.bitset_ == rhs.bitset_;
- }
- bitset_type bitset_{0};
- };
- inline bool operator!=(bitset lhs, bitset rhs) noexcept {
- return !(lhs == rhs);
- }
- } // namespace utils
- } // namespace c10
|