/* * Copyright (C) 2014 Cloudius Systems, Ltd. */ /* * Imported from OSv: * * Copyright (C) 2014 Cloudius Systems, Ltd. * * This work is open source software, licensed under the terms of the * BSD license as described in the LICENSE file in the top-level directory. */ #ifndef __OSV_BITSET_ITER #define __OSV_BITSET_ITER #include #include namespace bitsets { static constexpr int ulong_bits = std::numeric_limits::digits; /** * Returns the number of leading zeros in value's binary representation. * * If value == 0 the result is undefied. If T is signed and value is negative * the result is undefined. * * The highest value that can be returned is std::numeric_limits::digits - 1, * which is returned when value == 1. */ template inline size_t count_leading_zeros(T value); /** * Returns the number of trailing zeros in value's binary representation. * * If value == 0 the result is undefied. If T is signed and value is negative * the result is undefined. * * The highest value that can be returned is std::numeric_limits::digits - 1. */ template static inline size_t count_trailing_zeros(T value); template<> inline size_t count_leading_zeros(unsigned long value) { return __builtin_clzl(value); } template<> inline size_t count_leading_zeros(long value) { return __builtin_clzl((unsigned long)value) - 1; } template<> inline size_t count_trailing_zeros(unsigned long value) { return __builtin_ctzl(value); } template<> inline size_t count_trailing_zeros(long value) { return __builtin_ctzl((unsigned long)value); } /** * Returns the index of the first set bit. * Result is undefined if bitset.any() == false. */ template static inline size_t get_first_set(const std::bitset& bitset) { static_assert(N <= ulong_bits, "bitset too large"); return count_trailing_zeros(bitset.to_ulong()); } /** * Returns the index of the last set bit in the bitset. * Result is undefined if bitset.any() == false. */ template static inline size_t get_last_set(const std::bitset& bitset) { static_assert(N <= ulong_bits, "bitset too large"); return ulong_bits - 1 - count_leading_zeros(bitset.to_ulong()); } template class set_iterator : public std::iterator { private: void advance() { if (_bitset.none()) { _index = -1; } else { auto shift = get_first_set(_bitset) + 1; _index += shift; _bitset >>= shift; } } public: set_iterator(std::bitset bitset, int offset = 0) : _bitset(bitset) , _index(offset - 1) { static_assert(N <= ulong_bits, "This implementation is inefficient for large bitsets"); _bitset >>= offset; advance(); } void operator++() { advance(); } int operator*() const { return _index; } bool operator==(const set_iterator& other) const { return _index == other._index; } bool operator!=(const set_iterator& other) const { return !(*this == other); } private: std::bitset _bitset; int _index; }; template class set_range { public: using iterator = set_iterator; using value_type = int; set_range(std::bitset bitset, int offset = 0) : _bitset(bitset) , _offset(offset) { } iterator begin() const { return iterator(_bitset, _offset); } iterator end() const { return iterator(0); } private: std::bitset _bitset; int _offset; }; template static inline set_range for_each_set(std::bitset bitset, int offset = 0) { return set_range(bitset, offset); } } #endif