Spaces:
Running
Running
namespace c10::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: | |
// MSVCs _BitScanForward64 expects int64_t | |
using bitset_type = int64_t; | |
// POSIX ffsll expects long long int | |
using bitset_type = long long int; | |
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 { | |
unsigned long result; | |
bool has_bits_set = (0 != _BitScanForward64(&result, bitset_)); | |
if (!has_bits_set) { | |
return 0; | |
} | |
return result + 1; | |
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; | |
} | |
return __builtin_ffsll(bitset_); | |
} | |
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 c10::utils | |