From 482c4b9701894e1d2fbd671e8db9c062513a9cc4 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Tue, 24 Jun 2025 12:31:06 +0200 Subject: [PATCH] Move all the function definitions to a separate file Reason: Improving readability of the class template declaration. This separation was not originally possible due to limitations in older compilers (see the removed comment at the start of the definition of dynamic_bitset), but is now feasible. --- .../boost/dynamic_bitset/dynamic_bitset.hpp | 1555 +-------------- .../dynamic_bitset/impl/dynamic_bitset.tpp | 1751 +++++++++++++++++ 2 files changed, 1798 insertions(+), 1508 deletions(-) create mode 100644 include/boost/dynamic_bitset/impl/dynamic_bitset.tpp diff --git a/include/boost/dynamic_bitset/dynamic_bitset.hpp b/include/boost/dynamic_bitset/dynamic_bitset.hpp index c2362fe..17abf49 100644 --- a/include/boost/dynamic_bitset/dynamic_bitset.hpp +++ b/include/boost/dynamic_bitset/dynamic_bitset.hpp @@ -50,14 +50,6 @@ namespace boost { template class dynamic_bitset { - // Portability note: member function templates are defined inside - // this class definition to avoid problems with VC++. Similarly, - // with the member functions of nested classes. - // - // [October 2008: the note above is mostly historical; new versions - // of VC++ are likely able to digest a more drinking form of the - // code; but changing it now is probably not worth the risks...] - BOOST_STATIC_ASSERT((bool)detail::dynamic_bitset_impl::allowed_block_type::value); typedef std::vector buffer_type; @@ -79,12 +71,7 @@ public: // the one and only non-copy ctor - reference(block_type & b, block_width_type pos) - :m_block(b), - m_mask( (BOOST_ASSERT(pos < bits_per_block), - block_type(1) << pos ) - ) - { } + reference(block_type & b, block_width_type pos); void operator&(); // left undefined @@ -92,33 +79,33 @@ public: // copy constructor: compiler generated - operator bool() const { return (m_block & m_mask) != 0; } - bool operator~() const { return (m_block & m_mask) == 0; } + operator bool() const; + bool operator~() const; - reference& flip() { do_flip(); return *this; } + reference& flip(); - reference& operator=(bool x) { do_assign(x); return *this; } // for b[i] = x - reference& operator=(const reference& rhs) { do_assign(rhs); return *this; } // for b[i] = b[j] + reference& operator=(bool x); + reference& operator=(const reference& rhs); - reference& operator|=(bool x) { if (x) do_set(); return *this; } - reference& operator&=(bool x) { if (!x) do_reset(); return *this; } - reference& operator^=(bool x) { if (x) do_flip(); return *this; } - reference& operator-=(bool x) { if (x) do_reset(); return *this; } + reference& operator|=(bool x); + reference& operator&=(bool x); + reference& operator^=(bool x); + reference& operator-=(bool x); private: block_type & m_block; const block_type m_mask; - void do_set() { m_block |= m_mask; } - void do_reset() { m_block &= ~m_mask; } - void do_flip() { m_block ^= m_mask; } - void do_assign(bool x) { x? do_set() : do_reset(); } + void do_set(); + void do_reset(); + void do_flip(); + void do_assign(bool x); }; typedef bool const_reference; // constructors, etc. - dynamic_bitset() : m_num_bits(0) {} + dynamic_bitset(); explicit dynamic_bitset(const Allocator& alloc); @@ -144,43 +131,18 @@ public: typename std::basic_string::size_type pos, typename std::basic_string::size_type n, size_type num_bits = npos, - const Allocator& alloc = Allocator()) - - :m_bits(alloc), - m_num_bits(0) - { - init_from_string(s, pos, n, num_bits); - } + const Allocator& alloc = Allocator()); template explicit dynamic_bitset(const std::basic_string& s, - typename std::basic_string::size_type pos = 0) - - :m_bits(Allocator()), - m_num_bits(0) - { - init_from_string(s, pos, (std::basic_string::npos), - npos); - } + typename std::basic_string::size_type pos = 0); // The first bit in *first is the least significant bit, and the // last bit in the block just before *last is the most significant bit. template dynamic_bitset(BlockInputIterator first, BlockInputIterator last, - const Allocator& alloc = Allocator()) - - :m_bits(alloc), - m_num_bits(0) - { - using boost::detail::dynamic_bitset_impl::value_to_type; - using boost::detail::dynamic_bitset_impl::is_numeric; - - const value_to_type< - is_numeric::value> selector; - - dispatch_init(first, last, selector); - } + const Allocator& alloc = Allocator()); // copy constructor dynamic_bitset(const dynamic_bitset& b); @@ -205,14 +167,7 @@ public: void append(Block block); template - void append(BlockInputIterator first, BlockInputIterator last) // strong guarantee - { - if (first != last) { - typename std::iterator_traits::iterator_category cat; - m_append(first, last, cat); - } - } - + void append(BlockInputIterator first, BlockInputIterator last); // strong guarantee // bitset operations dynamic_bitset& operator&=(const dynamic_bitset& b); @@ -245,10 +200,8 @@ public: size_type count() const BOOST_NOEXCEPT; // subscript - reference operator[](size_type pos) { - return reference(m_bits[block_index(pos)], bit_index(pos)); - } - bool operator[](size_type pos) const { return test(pos); } + reference operator[](size_type pos); + bool operator[](size_type pos) const; unsigned long to_ulong() const; @@ -311,176 +264,54 @@ private: void m_zero_unused_bits(); bool m_check_invariants() const; - static bool m_not_empty(Block x){ return x != Block(0); }; + static bool m_not_empty(Block x); size_type m_do_find_from(size_type first_block) const; - block_width_type count_extra_bits() const BOOST_NOEXCEPT { return bit_index(size()); } - static size_type block_index(size_type pos) BOOST_NOEXCEPT { return pos / bits_per_block; } - static block_width_type bit_index(size_type pos) BOOST_NOEXCEPT { return static_cast(pos % bits_per_block); } - static Block bit_mask(size_type pos) BOOST_NOEXCEPT { return Block(1) << bit_index(pos); } - static Block bit_mask(size_type first, size_type last) BOOST_NOEXCEPT - { - Block res = (last == bits_per_block - 1) - ? detail::dynamic_bitset_impl::max_limit::value - : ((Block(1) << (last + 1)) - 1); - res ^= (Block(1) << first) - 1; - return res; - } + block_width_type count_extra_bits() const BOOST_NOEXCEPT; + static size_type block_index(size_type pos) BOOST_NOEXCEPT; + static block_width_type bit_index(size_type pos) BOOST_NOEXCEPT; + static Block bit_mask(size_type pos) BOOST_NOEXCEPT; + static Block bit_mask(size_type first, size_type last) BOOST_NOEXCEPT; static Block set_block_bits(Block block, size_type first, - size_type last, bool val) BOOST_NOEXCEPT - { - if (val) - return block | bit_mask(first, last); - else - return block & static_cast(~bit_mask(first, last)); - } + size_type last, bool val) BOOST_NOEXCEPT; // Functions for operations on ranges inline static Block set_block_partial(Block block, size_type first, - size_type last) BOOST_NOEXCEPT - { - return set_block_bits(block, first, last, true); - } - inline static Block set_block_full(Block) BOOST_NOEXCEPT - { - return detail::dynamic_bitset_impl::max_limit::value; - } + size_type last) BOOST_NOEXCEPT; + inline static Block set_block_full(Block) BOOST_NOEXCEPT; inline static Block reset_block_partial(Block block, size_type first, - size_type last) BOOST_NOEXCEPT - { - return set_block_bits(block, first, last, false); - } - inline static Block reset_block_full(Block) BOOST_NOEXCEPT - { - return 0; - } + size_type last) BOOST_NOEXCEPT; + inline static Block reset_block_full(Block) BOOST_NOEXCEPT; inline static Block flip_block_partial(Block block, size_type first, - size_type last) BOOST_NOEXCEPT - { - return block ^ bit_mask(first, last); - } - inline static Block flip_block_full(Block block) BOOST_NOEXCEPT - { - return ~block; - } + size_type last) BOOST_NOEXCEPT; + inline static Block flip_block_full(Block block) BOOST_NOEXCEPT; template void dispatch_init(T num_bits, unsigned long value, - detail::dynamic_bitset_impl::value_to_type) - { - init_from_unsigned_long(static_cast(num_bits), value); - } + detail::dynamic_bitset_impl::value_to_type); template void dispatch_init(T first, T last, - detail::dynamic_bitset_impl::value_to_type) - { - init_from_block_range(first, last); - } + detail::dynamic_bitset_impl::value_to_type); template - void init_from_block_range(BlockIter first, BlockIter last) - { - BOOST_ASSERT(m_bits.size() == 0); - m_bits.insert(m_bits.end(), first, last); - m_num_bits = m_bits.size() * bits_per_block; - } + void init_from_block_range(BlockIter first, BlockIter last); template void init_from_string(const std::basic_string& s, typename std::basic_string::size_type pos, typename std::basic_string::size_type n, - size_type num_bits) - { - BOOST_ASSERT(pos <= s.size()); - - typedef typename std::basic_string StrT; - typedef typename StrT::traits_type Tr; - - const typename StrT::size_type rlen = (std::min)(n, s.size() - pos); - const size_type sz = ( num_bits != npos? num_bits : rlen); - m_bits.resize(calc_num_blocks(sz)); - m_num_bits = sz; - - - BOOST_DYNAMIC_BITSET_CTYPE_FACET(CharT, fac, std::locale()); - const CharT one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); - - const size_type m = num_bits < rlen ? num_bits : rlen; - typename StrT::size_type i = 0; - for( ; i < m; ++i) { - - const CharT c = s[(pos + m - 1) - i]; - - BOOST_ASSERT( Tr::eq(c, one) - || Tr::eq(c, BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0')) ); - - if (Tr::eq(c, one)) - set(i); - - } - - } + size_type num_bits); void init_from_unsigned_long(size_type num_bits, unsigned long value/*, - const Allocator& alloc*/) - { - - BOOST_ASSERT(m_bits.size() == 0); - - m_bits.resize(calc_num_blocks(num_bits)); - m_num_bits = num_bits; - - typedef unsigned long num_type; - typedef boost::detail::dynamic_bitset_impl - ::shifter shifter; - - //if (num_bits == 0) - // return; - - // zero out all bits at pos >= num_bits, if any; - // note that: num_bits == 0 implies value == 0 - if (num_bits < static_cast(ulong_width)) { - const num_type mask = (num_type(1) << num_bits) - 1; - value &= mask; - } - - typename buffer_type::iterator it = m_bits.begin(); - for( ; value; shifter::left_shift(value), ++it) { - *it = static_cast(value); - } - - } + const Allocator& alloc*/); template - void m_append(BlockInputIterator first, BlockInputIterator last, std::input_iterator_tag) - { - std::vector v(first, last); - m_append(v.begin(), v.end(), std::random_access_iterator_tag()); - } + void m_append(BlockInputIterator first, BlockInputIterator last, std::input_iterator_tag); template - void m_append(BlockInputIterator first, BlockInputIterator last, std::forward_iterator_tag) - { - BOOST_ASSERT(first != last); - block_width_type r = count_extra_bits(); - std::size_t d = std::distance(first, last); - m_bits.reserve(num_blocks() + d); - if (r == 0) { - for( ; first != last; ++first) - m_bits.push_back(*first); // could use vector<>::insert() - } - else { - m_highest_block() |= (*first << r); - do { - Block b = *first >> (bits_per_block - r); - ++first; - m_bits.push_back(b | (first==last? 0 : *first << r)); - } while (first != last); - } - m_num_bits += bits_per_block * d; - } + void m_append(BlockInputIterator first, BlockInputIterator last, std::forward_iterator_tag); bool m_unchecked_test(size_type pos) const; static size_type calc_num_blocks(size_type num_bits); @@ -514,35 +345,11 @@ private: bit_appender & operator=(const bit_appender &); public: - bit_appender(dynamic_bitset & r) : bs(r), n(0), mask(0), current(0) {} - ~bit_appender() { - // reverse the order of blocks, shift - // if needed, and then resize - // - std::reverse(bs.m_bits.begin(), bs.m_bits.end()); - const block_width_type offs = bit_index(n); - if (offs) - bs >>= (bits_per_block - offs); - bs.resize(n); // doesn't enlarge, so can't throw - BOOST_ASSERT(bs.m_check_invariants()); - } - inline void do_append(bool value) { - - if (mask == 0) { - bs.append(Block(0)); - current = &bs.m_highest_block(); - mask = Block(1) << (bits_per_block - 1); - } - - if(value) - *current |= mask; - - mask /= 2; - ++n; - } - size_type get_count() const { return n; } + bit_appender(dynamic_bitset & r); + ~bit_appender(); + inline void do_append(bool value); + size_type get_count() const; }; - }; #if !defined BOOST_NO_INCLASS_MEMBER_INITIALIZATION @@ -631,1278 +438,10 @@ to_block_range(const dynamic_bitset& b, template inline void from_block_range(BlockIterator first, BlockIterator last, - dynamic_bitset& result) -{ - // PRE: distance(first, last) <= numblocks() - std::copy (first, last, result.m_bits.begin()); -} - -//============================================================================= -// dynamic_bitset implementation - - -//----------------------------------------------------------------------------- -// constructors, etc. - -template -dynamic_bitset::dynamic_bitset(const Allocator& alloc) - : m_bits(alloc), m_num_bits(0) -{ - -} - -template -dynamic_bitset:: -dynamic_bitset(size_type num_bits, unsigned long value, const Allocator& alloc) - : m_bits(alloc), - m_num_bits(0) -{ - init_from_unsigned_long(num_bits, value); -} - -// copy constructor -template -inline dynamic_bitset:: -dynamic_bitset(const dynamic_bitset& b) - : m_bits(b.m_bits), m_num_bits(b.m_num_bits) -{ - -} - -template -inline dynamic_bitset:: -~dynamic_bitset() -{ - BOOST_ASSERT(m_check_invariants()); -} - -template -inline void dynamic_bitset:: -swap(dynamic_bitset& b) BOOST_NOEXCEPT -{ - std::swap(m_bits, b.m_bits); - std::swap(m_num_bits, b.m_num_bits); -} - -template -dynamic_bitset& dynamic_bitset:: -operator=(const dynamic_bitset& b) -{ - m_bits = b.m_bits; - m_num_bits = b.m_num_bits; - return *this; -} - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - -template -inline dynamic_bitset:: -dynamic_bitset(dynamic_bitset&& b) - : m_bits(boost::move(b.m_bits)), m_num_bits(boost::move(b.m_num_bits)) -{ - // Required so that BOOST_ASSERT(m_check_invariants()); works. - BOOST_ASSERT((b.m_bits = buffer_type(get_allocator())).empty()); - b.m_num_bits = 0; -} - -template -inline dynamic_bitset& dynamic_bitset:: -operator=(dynamic_bitset&& b) -{ - if (&b == this) { return *this; } - - m_bits = boost::move(b.m_bits); - m_num_bits = boost::move(b.m_num_bits); - // Required so that BOOST_ASSERT(m_check_invariants()); works. - BOOST_ASSERT((b.m_bits = buffer_type(get_allocator())).empty()); - b.m_num_bits = 0; - return *this; -} - -#endif // BOOST_NO_CXX11_RVALUE_REFERENCES - -template -inline typename dynamic_bitset::allocator_type -dynamic_bitset::get_allocator() const -{ - return m_bits.get_allocator(); -} - -//----------------------------------------------------------------------------- -// size changing operations - -template -void dynamic_bitset:: -resize(size_type num_bits, bool value) // strong guarantee -{ - - const size_type old_num_blocks = num_blocks(); - const size_type required_blocks = calc_num_blocks(num_bits); - - const block_type v = value? detail::dynamic_bitset_impl::max_limit::value : Block(0); - - if (required_blocks != old_num_blocks) { - m_bits.resize(required_blocks, v); // s.g. (copy) - } - - - // At this point: - // - // - if the buffer was shrunk, we have nothing more to do, - // except a call to m_zero_unused_bits() - // - // - if it was enlarged, all the (used) bits in the new blocks have - // the correct value, but we have not yet touched those bits, if - // any, that were 'unused bits' before enlarging: if value == true, - // they must be set. - - if (value && (num_bits > m_num_bits)) { - - const block_width_type extra_bits = count_extra_bits(); - if (extra_bits) { - BOOST_ASSERT(old_num_blocks >= 1 && old_num_blocks <= m_bits.size()); - - // Set them. - m_bits[old_num_blocks - 1] |= (v << extra_bits); - } - - } - - m_num_bits = num_bits; - m_zero_unused_bits(); - -} - -template -void dynamic_bitset:: -clear() // no throw -{ - m_bits.clear(); - m_num_bits = 0; -} - - -template -void dynamic_bitset:: -push_back(bool bit) -{ - const size_type sz = size(); - resize(sz + 1, bit); -} - -template -void dynamic_bitset:: -pop_back() -{ - BOOST_ASSERT( !empty() ); - const size_type old_num_blocks = num_blocks(); - const size_type required_blocks = calc_num_blocks(m_num_bits - 1); - - if (required_blocks != old_num_blocks) { - m_bits.pop_back(); - } - - --m_num_bits; - m_zero_unused_bits(); -} - - -template -void dynamic_bitset:: -append(Block value) // strong guarantee -{ - const block_width_type r = count_extra_bits(); - - if (r == 0) { - // the buffer is empty, or all blocks are filled - m_bits.push_back(value); - } - else { - m_bits.push_back(value >> (bits_per_block - r)); - m_bits[m_bits.size() - 2] |= (value << r); // m_bits.size() >= 2 - } - - m_num_bits += bits_per_block; - BOOST_ASSERT(m_check_invariants()); - -} - - -//----------------------------------------------------------------------------- -// bitset operations -template -dynamic_bitset& -dynamic_bitset::operator&=(const dynamic_bitset& rhs) -{ - BOOST_ASSERT(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] &= rhs.m_bits[i]; - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::operator|=(const dynamic_bitset& rhs) -{ - BOOST_ASSERT(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] |= rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::operator^=(const dynamic_bitset& rhs) -{ - BOOST_ASSERT(size() == rhs.size()); - for (size_type i = 0; i < this->num_blocks(); ++i) - m_bits[i] ^= rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::operator-=(const dynamic_bitset& rhs) -{ - BOOST_ASSERT(size() == rhs.size()); - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] &= ~rhs.m_bits[i]; - //m_zero_unused_bits(); - return *this; -} - -// -// NOTE: -// Note that the 'if (r != 0)' is crucial to avoid undefined -// behavior when the left hand operand of >> isn't promoted to a -// wider type (because rs would be too large). -// -template -dynamic_bitset& -dynamic_bitset::operator<<=(size_type n) -{ - if (n >= m_num_bits) - return reset(); - //else - if (n > 0) { - - const size_type last = num_blocks() - 1; // num_blocks() is >= 1 - const size_type div = n / bits_per_block; // div is <= last - const block_width_type r = bit_index(n); - block_type * const b = &m_bits[0]; - - if (r != 0) { - - const block_width_type rs = bits_per_block - r; - - for (size_type i = last-div; i>0; --i) { - b[i+div] = (b[i] << r) | (b[i-1] >> rs); - } - b[div] = b[0] << r; - - } - else { - for (size_type i = last-div; i>0; --i) { - b[i+div] = b[i]; - } - b[div] = b[0]; - } - - // zero out div blocks at the less significant end - std::fill_n(m_bits.begin(), div, static_cast(0)); - - // zero out any 1 bit that flowed into the unused part - m_zero_unused_bits(); // thanks to Lester Gong - - } - - return *this; - - -} - - -// -// NOTE: -// see the comments to operator <<= -// -template -dynamic_bitset & dynamic_bitset::operator>>=(size_type n) { - if (n >= m_num_bits) { - return reset(); - } - //else - if (n>0) { - - const size_type last = num_blocks() - 1; // num_blocks() is >= 1 - const size_type div = n / bits_per_block; // div is <= last - const block_width_type r = bit_index(n); - block_type * const b = &m_bits[0]; - - - if (r != 0) { - - const block_width_type ls = bits_per_block - r; - - for (size_type i = div; i < last; ++i) { - b[i-div] = (b[i] >> r) | (b[i+1] << ls); - } - // r bits go to zero - b[last-div] = b[last] >> r; - } - - else { - for (size_type i = div; i <= last; ++i) { - b[i-div] = b[i]; - } - // note the '<=': the last iteration 'absorbs' - // b[last-div] = b[last] >> 0; - } - - - - // div blocks are zero filled at the most significant end - std::fill_n(m_bits.begin() + (num_blocks()-div), div, static_cast(0)); - } - - return *this; -} - - -template -dynamic_bitset -dynamic_bitset::operator<<(size_type n) const -{ - dynamic_bitset r(*this); - return r <<= n; -} - -template -dynamic_bitset -dynamic_bitset::operator>>(size_type n) const -{ - dynamic_bitset r(*this); - return r >>= n; -} - - -//----------------------------------------------------------------------------- -// basic bit operations - -template -dynamic_bitset& -dynamic_bitset::set(size_type pos, - size_type len, bool val) -{ - if (val) - return range_operation(pos, len, set_block_partial, set_block_full); - else - return range_operation(pos, len, reset_block_partial, reset_block_full); -} - -template -dynamic_bitset& -dynamic_bitset::set(size_type pos, bool val) -{ - BOOST_ASSERT(pos < m_num_bits); - - if (val) - m_bits[block_index(pos)] |= bit_mask(pos); - else - reset(pos); - - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::set() -{ - std::fill(m_bits.begin(), m_bits.end(), detail::dynamic_bitset_impl::max_limit::value); - m_zero_unused_bits(); - return *this; -} - -template -inline dynamic_bitset& -dynamic_bitset::reset(size_type pos, size_type len) -{ - return range_operation(pos, len, reset_block_partial, reset_block_full); -} - -template -dynamic_bitset& -dynamic_bitset::reset(size_type pos) -{ - BOOST_ASSERT(pos < m_num_bits); - m_bits[block_index(pos)] &= ~bit_mask(pos); - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::reset() -{ - std::fill(m_bits.begin(), m_bits.end(), Block(0)); - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::flip(size_type pos, size_type len) -{ - return range_operation(pos, len, flip_block_partial, flip_block_full); -} - -template -dynamic_bitset& -dynamic_bitset::flip(size_type pos) -{ - BOOST_ASSERT(pos < m_num_bits); - m_bits[block_index(pos)] ^= bit_mask(pos); - return *this; -} - -template -dynamic_bitset& -dynamic_bitset::flip() -{ - for (size_type i = 0; i < num_blocks(); ++i) - m_bits[i] = ~m_bits[i]; - m_zero_unused_bits(); - return *this; -} - -template -bool dynamic_bitset::m_unchecked_test(size_type pos) const -{ - return (m_bits[block_index(pos)] & bit_mask(pos)) != 0; -} - -template -typename dynamic_bitset::reference -dynamic_bitset::at(size_type pos) -{ - if (pos >= m_num_bits) - BOOST_THROW_EXCEPTION(std::out_of_range("boost::dynamic_bitset::at out_of_range")); - - return (*this)[pos]; -} - -template -bool dynamic_bitset::at(size_type pos) const -{ - if (pos >= m_num_bits) - BOOST_THROW_EXCEPTION(std::out_of_range("boost::dynamic_bitset::at out_of_range")); - - return (*this)[pos]; -} - -template -bool dynamic_bitset::test(size_type pos) const -{ - BOOST_ASSERT(pos < m_num_bits); - return m_unchecked_test(pos); -} - -template -bool dynamic_bitset::test_set(size_type pos, bool val) -{ - const bool b = test(pos); - if (b != val) { - set(pos, val); - } - return b; -} - -template -bool dynamic_bitset::all() const -{ - if (empty()) { - return true; - } - - const block_width_type extra_bits = count_extra_bits(); - const block_type all_ones = detail::dynamic_bitset_impl::max_limit::value; - - if (extra_bits == 0) { - for (size_type i = 0, e = num_blocks(); i < e; ++i) { - if (m_bits[i] != all_ones) { - return false; - } - } - } else { - for (size_type i = 0, e = num_blocks() - 1; i < e; ++i) { - if (m_bits[i] != all_ones) { - return false; - } - } - const block_type mask = (block_type(1) << extra_bits) - 1; - if (m_highest_block() != mask) { - return false; - } - } - return true; -} - -template -bool dynamic_bitset::any() const -{ - for (size_type i = 0; i < num_blocks(); ++i) - if (m_bits[i]) - return true; - return false; -} - -template -inline bool dynamic_bitset::none() const -{ - return !any(); -} - -template -dynamic_bitset -dynamic_bitset::operator~() const -{ - dynamic_bitset b(*this); - b.flip(); - return b; -} - -template -typename dynamic_bitset::size_type -dynamic_bitset::count() const BOOST_NOEXCEPT -{ - size_type result = 0; - for (block_type block : m_bits) { - result += core::popcount(block); - } - return result; -} - - -//----------------------------------------------------------------------------- -// conversions - - -template -void to_string_helper(const dynamic_bitset & b, stringT & s, - bool dump_all) -{ - typedef typename stringT::traits_type Tr; - typedef typename stringT::value_type Ch; - - BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, std::locale()); - const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); - const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); - - // Note that this function may access (when - // dump_all == true) bits beyond position size() - 1 - - typedef typename dynamic_bitset::size_type size_type; - - const size_type len = dump_all? - dynamic_bitset::bits_per_block * b.num_blocks(): - b.size(); - s.assign (len, zero); - - for (size_type i = 0; i < len; ++i) { - if (b.m_unchecked_test(i)) - Tr::assign(s[len - 1 - i], one); - - } - -} - - -// A comment similar to the one about the constructor from -// basic_string can be done here. Thanks to James Kanze for -// making me (Gennaro) realize this important separation of -// concerns issue, as well as many things about i18n. -// -template -inline void -to_string(const dynamic_bitset& b, stringT& s) -{ - to_string_helper(b, s, false); -} - - -// Differently from to_string this function dumps out -// every bit of the internal representation (may be -// useful for debugging purposes) -// -template -inline void -dump_to_string(const dynamic_bitset& b, stringT& s) -{ - to_string_helper(b, s, true /* =dump_all*/); -} - -template -inline void -to_block_range(const dynamic_bitset& b, - BlockOutputIterator result) -{ - // note how this copies *all* bits, including the - // unused ones in the last block (which are zero) - std::copy(b.m_bits.begin(), b.m_bits.end(), result); -} - -template -unsigned long dynamic_bitset:: -to_ulong() const -{ - - if (m_num_bits == 0) - return 0; // convention - - // Check for overflows. This may be a performance burden on very - // large bitsets but is required by the specification, sorry - if (find_first(ulong_width) != npos) - BOOST_THROW_EXCEPTION(std::overflow_error("boost::dynamic_bitset::to_ulong overflow")); - - - // Ok, from now on we can be sure there's no "on" bit - // beyond the "allowed" positions - typedef unsigned long result_type; - - const size_type maximum_size = - (std::min)(m_num_bits, static_cast(ulong_width)); - - const size_type last_block = block_index( maximum_size - 1 ); - - BOOST_ASSERT((last_block * bits_per_block) < static_cast(ulong_width)); - - result_type result = 0; - for (size_type i = 0; i <= last_block; ++i) { - const size_type offset = i * bits_per_block; - result |= (static_cast(m_bits[i]) << offset); - } - - return result; -} - -template -inline typename dynamic_bitset::size_type -dynamic_bitset::size() const BOOST_NOEXCEPT -{ - return m_num_bits; -} - -template -inline typename dynamic_bitset::size_type -dynamic_bitset::num_blocks() const BOOST_NOEXCEPT -{ - return m_bits.size(); -} - -template -inline typename dynamic_bitset::size_type -dynamic_bitset::max_size() const BOOST_NOEXCEPT -{ - // Semantics of vector<>::max_size() aren't very clear - // (see lib issue 197) and many library implementations - // simply return dummy values, _unrelated_ to the underlying - // allocator. - // - // Given these problems, I was tempted to not provide this - // function at all but the user could need it if he provides - // his own allocator. - // - - const size_type m = detail::dynamic_bitset_impl:: - vector_max_size_workaround(m_bits); - - return m <= (size_type(-1)/bits_per_block) ? - m * bits_per_block : - size_type(-1); -} - -template -inline bool dynamic_bitset::empty() const BOOST_NOEXCEPT -{ - return size() == 0; -} - -template -inline typename dynamic_bitset::size_type -dynamic_bitset::capacity() const BOOST_NOEXCEPT -{ - return m_bits.capacity() * bits_per_block; -} - -template -inline void dynamic_bitset::reserve(size_type num_bits) -{ - m_bits.reserve(calc_num_blocks(num_bits)); -} - -template -void dynamic_bitset::shrink_to_fit() -{ - if (m_bits.size() < m_bits.capacity()) { - buffer_type(m_bits).swap(m_bits); - } -} - -template -bool dynamic_bitset:: -is_subset_of(const dynamic_bitset& a) const -{ - BOOST_ASSERT(size() == a.size()); - for (size_type i = 0; i < num_blocks(); ++i) - if (m_bits[i] & ~a.m_bits[i]) - return false; - return true; -} - -template -bool dynamic_bitset:: -is_proper_subset_of(const dynamic_bitset& a) const -{ - BOOST_ASSERT(size() == a.size()); - - bool proper = false; - for (size_type i = 0; i < num_blocks(); ++i) { - const Block & bt = m_bits[i]; - const Block & ba = a.m_bits[i]; - - if (bt & ~ba) - return false; // not a subset at all - if (ba & ~bt) - proper = true; - } - return proper; -} - -template -bool dynamic_bitset::intersects(const dynamic_bitset & b) const -{ - size_type common_blocks = num_blocks() < b.num_blocks() - ? num_blocks() : b.num_blocks(); - - for(size_type i = 0; i < common_blocks; ++i) { - if(m_bits[i] & b.m_bits[i]) - return true; - } - return false; -} - -// -------------------------------- -// lookup - -// look for the first bit "on", starting -// from the block with index first_block -// - -template -typename dynamic_bitset::size_type -dynamic_bitset::m_do_find_from(size_type first_block) const -{ - - size_type i = std::distance(m_bits.begin(), - std::find_if(m_bits.begin() + first_block, m_bits.end(), m_not_empty) ); - - if (i >= num_blocks()) - return npos; // not found - - return i * bits_per_block + static_cast(detail::lowest_bit(m_bits[i])); -} - - -template -typename dynamic_bitset::size_type -dynamic_bitset::find_first() const -{ - return m_do_find_from(0); -} - -template -typename dynamic_bitset::size_type -dynamic_bitset::find_first(size_type pos) const -{ - const size_type sz = size(); - if (pos >= sz) return npos; - - const size_type blk = block_index(pos); - const block_width_type ind = bit_index(pos); - - // shift bits upto one immediately after current - const Block fore = m_bits[blk] >> ind; - - return fore? - pos + static_cast(detail::lowest_bit(fore)) - : - m_do_find_from(blk + 1); -} - - -template -typename dynamic_bitset::size_type -dynamic_bitset::find_next(size_type pos) const -{ - if (pos == npos) return npos; - return find_first(pos + 1); -} - - - -//----------------------------------------------------------------------------- -// comparison - -template -bool operator==(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - return (a.m_num_bits == b.m_num_bits) - && (a.m_bits == b.m_bits); -} - -template -inline bool operator!=(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - return !(a == b); -} - -template -bool operator<(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - typedef BOOST_DEDUCED_TYPENAME dynamic_bitset::size_type size_type; - - size_type asize(a.size()); - size_type bsize(b.size()); - - if (!bsize) - { - return false; - } - else if (!asize) - { - return true; - } - else if (asize == bsize) - { - for (size_type ii = a.num_blocks(); ii > 0; --ii) - { - size_type i = ii-1; - if (a.m_bits[i] < b.m_bits[i]) - return true; - else if (a.m_bits[i] > b.m_bits[i]) - return false; - } - return false; - } - else - { - size_type leqsize(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(asize,bsize)); - - for (size_type ii = 0; ii < leqsize; ++ii,--asize,--bsize) - { - size_type i = asize-1; - size_type j = bsize-1; - if (a[i] < b[j]) - return true; - else if (a[i] > b[j]) - return false; - } - return (a.size() < b.size()); - } -} - -template -inline bool operator<=(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - return !(a > b); -} - -template -inline bool operator>(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - return b < a; -} - -template -inline bool operator>=(const dynamic_bitset& a, - const dynamic_bitset& b) -{ - return !(a < b); -} - -//----------------------------------------------------------------------------- -// hash operations - -template -inline std::size_t hash_value(const dynamic_bitset& a) -{ - std::size_t res = hash_value(a.m_num_bits); - boost::hash_combine(res, a.m_bits); - return res; -} - -//----------------------------------------------------------------------------- -// stream operations - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, - const dynamic_bitset& b) -{ - - using namespace std; - - const ios_base::iostate ok = ios_base::goodbit; - ios_base::iostate err = ok; - - typename basic_ostream::sentry cerberos(os); - if (cerberos) { - - BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, os.getloc()); - const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); - const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); - - BOOST_TRY { - - typedef typename dynamic_bitset::size_type bitset_size_type; - typedef basic_streambuf buffer_type; - - buffer_type * buf = os.rdbuf(); - // careful: os.width() is signed (and can be < 0) - const bitset_size_type width = (os.width() <= 0) ? 0 : static_cast(os.width()); - streamsize npad = (width <= b.size()) ? 0 : width - b.size(); - - const Ch fill_char = os.fill(); - const ios_base::fmtflags adjustfield = os.flags() & ios_base::adjustfield; - - // if needed fill at left; pad is decreased along the way - if (adjustfield != ios_base::left) { - for (; 0 < npad; --npad) - if (Tr::eq_int_type(Tr::eof(), buf->sputc(fill_char))) { - err |= ios_base::failbit; - break; - } - } - - if (err == ok) { - // output the bitset - for (bitset_size_type i = b.size(); 0 < i; --i) { - typename buffer_type::int_type - ret = buf->sputc(b.test(i-1)? one : zero); - if (Tr::eq_int_type(Tr::eof(), ret)) { - err |= ios_base::failbit; - break; - } - } - } - - if (err == ok) { - // if needed fill at right - for (; 0 < npad; --npad) { - if (Tr::eq_int_type(Tr::eof(), buf->sputc(fill_char))) { - err |= ios_base::failbit; - break; - } - } - } - - - os.width(0); - - } BOOST_CATCH (...) { // see std 27.6.1.1/4 - bool rethrow = false; - BOOST_TRY { os.setstate(ios_base::failbit); } BOOST_CATCH (...) { rethrow = true; } BOOST_CATCH_END - - if (rethrow) - BOOST_RETHROW; - } - BOOST_CATCH_END - } - - if(err != ok) - os.setstate(err); // may throw exception - return os; - -} - -template -std::basic_istream& -operator>>(std::basic_istream& is, dynamic_bitset& b) -{ - - using namespace std; - - typedef dynamic_bitset bitset_type; - typedef typename bitset_type::size_type size_type; - - const streamsize w = is.width(); - const size_type limit = 0 < w && static_cast(w) < b.max_size()? - static_cast(w) : b.max_size(); - - ios_base::iostate err = ios_base::goodbit; - typename basic_istream::sentry cerberos(is); // skips whitespaces - if(cerberos) { - - // in accordance with prop. resol. of lib DR 303 [last checked 4 Feb 2004] - BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, is.getloc()); - const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); - const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); - - b.clear(); - BOOST_TRY { - typename bitset_type::bit_appender appender(b); - basic_streambuf * buf = is.rdbuf(); - typename Tr::int_type c = buf->sgetc(); - for( ; appender.get_count() < limit; c = buf->snextc() ) { - - if (Tr::eq_int_type(Tr::eof(), c)) { - err |= ios_base::eofbit; - break; - } - else { - const Ch to_c = Tr::to_char_type(c); - const bool is_one = Tr::eq(to_c, one); - - if (!is_one && !Tr::eq(to_c, zero)) - break; // non digit character - - appender.do_append(is_one); - - } - - } // for - } - BOOST_CATCH (...) { - // catches from stream buf, or from vector: - // - // bits_stored bits have been extracted and stored, and - // either no further character is extractable or we can't - // append to the underlying vector (out of memory) - - bool rethrow = false; // see std 27.6.1.1/4 - BOOST_TRY { is.setstate(ios_base::badbit); } - BOOST_CATCH(...) { rethrow = true; } - BOOST_CATCH_END - - if (rethrow) - BOOST_RETHROW; - - } - BOOST_CATCH_END - } - - is.width(0); - if (b.size() == 0 /*|| !cerberos*/) - err |= ios_base::failbit; - if (err != ios_base::goodbit) - is.setstate (err); // may throw - - return is; - -} - - - - -//----------------------------------------------------------------------------- -// bitset operations - -template -dynamic_bitset -operator&(const dynamic_bitset& x, - const dynamic_bitset& y) -{ - dynamic_bitset b(x); - return b &= y; -} - -template -dynamic_bitset -operator|(const dynamic_bitset& x, - const dynamic_bitset& y) -{ - dynamic_bitset b(x); - return b |= y; -} - -template -dynamic_bitset -operator^(const dynamic_bitset& x, - const dynamic_bitset& y) -{ - dynamic_bitset b(x); - return b ^= y; -} - -template -dynamic_bitset -operator-(const dynamic_bitset& x, - const dynamic_bitset& y) -{ - dynamic_bitset b(x); - return b -= y; -} - -//----------------------------------------------------------------------------- -// namespace scope swap - -template -inline void -swap(dynamic_bitset& left, - dynamic_bitset& right) BOOST_NOEXCEPT -{ - left.swap(right); -} - - -//----------------------------------------------------------------------------- -// private (on conforming compilers) member functions - - -template -inline typename dynamic_bitset::size_type -dynamic_bitset::calc_num_blocks(size_type num_bits) -{ - return num_bits / bits_per_block - + static_cast( num_bits % bits_per_block != 0 ); -} - -// gives a reference to the highest block -// -template -inline Block& dynamic_bitset::m_highest_block() -{ - return const_cast - (static_cast(this)->m_highest_block()); -} - -// gives a const-reference to the highest block -// -template -inline const Block& dynamic_bitset::m_highest_block() const -{ - BOOST_ASSERT(size() > 0 && num_blocks() > 0); - return m_bits.back(); -} - -template -dynamic_bitset& dynamic_bitset::range_operation( - size_type pos, size_type len, - Block (*partial_block_operation)(Block, size_type, size_type), - Block (*full_block_operation)(Block)) -{ - BOOST_ASSERT(pos + len <= m_num_bits); - - // Do nothing in case of zero length - if (!len) - return *this; - - // Use an additional asserts in order to detect size_type overflow - // For example: pos = 10, len = size_type_limit - 2, pos + len = 7 - // In case of overflow, 'pos + len' is always smaller than 'len' - BOOST_ASSERT(pos + len >= len); - - // Start and end blocks of the [pos; pos + len - 1] sequence - const size_type first_block = block_index(pos); - const size_type last_block = block_index(pos + len - 1); - - const size_type first_bit_index = bit_index(pos); - const size_type last_bit_index = bit_index(pos + len - 1); - - if (first_block == last_block) { - // Filling only a sub-block of a block - m_bits[first_block] = partial_block_operation(m_bits[first_block], - first_bit_index, last_bit_index); - } else { - // Check if the corner blocks won't be fully filled with 'val' - const size_type first_block_shift = bit_index(pos) ? 1 : 0; - const size_type last_block_shift = (bit_index(pos + len - 1) - == bits_per_block - 1) ? 0 : 1; - - // Blocks that will be filled with ~0 or 0 at once - const size_type first_full_block = first_block + first_block_shift; - const size_type last_full_block = last_block - last_block_shift; - - for (size_type i = first_full_block; i <= last_full_block; ++i) { - m_bits[i] = full_block_operation(m_bits[i]); - } - - // Fill the first block from the 'first' bit index to the end - if (first_block_shift) { - m_bits[first_block] = partial_block_operation(m_bits[first_block], - first_bit_index, bits_per_block - 1); - } - - // Fill the last block from the start to the 'last' bit index - if (last_block_shift) { - m_bits[last_block] = partial_block_operation(m_bits[last_block], - 0, last_bit_index); - } - } - - return *this; -} - -// If size() is not a multiple of bits_per_block -// then not all the bits in the last block are used. -// This function resets the unused bits (convenient -// for the implementation of many member functions) -// -template -inline void dynamic_bitset::m_zero_unused_bits() -{ - BOOST_ASSERT (num_blocks() == calc_num_blocks(m_num_bits)); - - // if != 0 this is the number of bits used in the last block - const block_width_type extra_bits = count_extra_bits(); - - if (extra_bits != 0) - m_highest_block() &= (Block(1) << extra_bits) - 1; -} - -// check class invariants -template -bool dynamic_bitset::m_check_invariants() const -{ - const block_width_type extra_bits = count_extra_bits(); - if (extra_bits > 0) { - const block_type mask = detail::dynamic_bitset_impl::max_limit::value << extra_bits; - if ((m_highest_block() & mask) != 0) - return false; - } - if (m_bits.size() > m_bits.capacity() || num_blocks() != calc_num_blocks(size())) - return false; - - return true; - -} - - -} // namespace boost + dynamic_bitset& result); -// std::hash support -#if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) && !defined(BOOST_DYNAMIC_BITSET_NO_STD_HASH) -#include -namespace std -{ - template - struct hash< boost::dynamic_bitset > - { - typedef boost::dynamic_bitset argument_type; - typedef std::size_t result_type; - result_type operator()(const argument_type& a) const BOOST_NOEXCEPT - { - boost::hash hasher; - return hasher(a); - } - }; } -#endif +#include "impl/dynamic_bitset.tpp" #endif // include guard diff --git a/include/boost/dynamic_bitset/impl/dynamic_bitset.tpp b/include/boost/dynamic_bitset/impl/dynamic_bitset.tpp new file mode 100644 index 0000000..e54bebb --- /dev/null +++ b/include/boost/dynamic_bitset/impl/dynamic_bitset.tpp @@ -0,0 +1,1751 @@ +// ----------------------------------------------------------- +// +// Copyright (c) 2001-2002 Chuck Allison and Jeremy Siek +// Copyright (c) 2003-2006, 2008, 2025 Gennaro Prota +// Copyright (c) 2014 Ahmed Charles +// +// Copyright (c) 2014 Glen Joseph Fernandes +// (glenjofe@gmail.com) +// +// Copyright (c) 2014 Riccardo Marcangelo +// Copyright (c) 2018 Evgeny Shulgin +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// ----------------------------------------------------------- + +namespace boost { + +template +dynamic_bitset::reference::reference(block_type & b, block_width_type pos) + : m_block(b), + m_mask( (BOOST_ASSERT(pos < bits_per_block), block_type(1) << pos )) +{ +} + +template +dynamic_bitset::reference::operator bool() const +{ + return (m_block & m_mask) != 0; +} + +template +bool +dynamic_bitset::reference::operator~() const +{ + return (m_block & m_mask) == 0; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::flip() +{ + do_flip(); + return *this; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator=(bool x) +{ + do_assign(x); + return *this; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator=(const reference& rhs) +{ + do_assign(rhs); + return *this; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator|=(bool x) +{ + if (x) { + do_set(); + } + return *this; +} + + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator&=(bool x) +{ + if (!x) { + do_reset(); + } + return *this; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator^=(bool x) +{ + if (x) { + do_flip(); + } + return *this; +} + +template +typename dynamic_bitset::reference& +dynamic_bitset::reference::operator-=(bool x) +{ + if (x) { + do_reset(); + } + return *this; +} + +template +void +dynamic_bitset::reference::do_set() +{ + m_block |= m_mask; +} + +template +void +dynamic_bitset::reference::do_reset() +{ + m_block &= ~m_mask; +} + +template +void +dynamic_bitset::reference::do_flip() +{ + m_block ^= m_mask; +} + +template +void +dynamic_bitset::reference::do_assign(bool x) +{ + if (x) { + do_set(); + } else { + do_reset(); + } +} + +template +inline void +from_block_range(BlockIterator first, BlockIterator last, + dynamic_bitset& result) +{ + // PRE: distance(first, last) <= numblocks() + std::copy (first, last, result.m_bits.begin()); +} + + +template +dynamic_bitset::dynamic_bitset() + : m_num_bits(0) +{ +} + +template +dynamic_bitset::dynamic_bitset(const Allocator& alloc) + : m_bits(alloc), m_num_bits(0) +{ +} + +template +dynamic_bitset:: +dynamic_bitset(size_type num_bits, unsigned long value, const Allocator& alloc) + : m_bits(alloc), + m_num_bits(0) +{ + init_from_unsigned_long(num_bits, value); +} + +template +template +dynamic_bitset::dynamic_bitset( + const std::basic_string& s, + typename std::basic_string::size_type pos, + typename std::basic_string::size_type n, + size_type num_bits, + const Allocator& alloc) + +:m_bits(alloc), + m_num_bits(0) +{ + init_from_string(s, pos, n, num_bits); +} + +template +template +dynamic_bitset::dynamic_bitset( + const std::basic_string& s, + typename std::basic_string::size_type pos) + : m_bits(Allocator()), + m_num_bits(0) +{ + init_from_string(s, pos, (std::basic_string::npos), npos); +} + +template +template +dynamic_bitset::dynamic_bitset( + BlockInputIterator first, + BlockInputIterator last, + const Allocator& alloc) + : m_bits(alloc), + m_num_bits(0) +{ + using boost::detail::dynamic_bitset_impl::value_to_type; + using boost::detail::dynamic_bitset_impl::is_numeric; + + const value_to_type< + is_numeric::value> selector; + + dispatch_init(first, last, selector); +} + + +// copy constructor +template +inline dynamic_bitset:: dynamic_bitset(const dynamic_bitset& b) + : m_bits(b.m_bits), m_num_bits(b.m_num_bits) +{ +} + +template +inline dynamic_bitset:: ~dynamic_bitset() +{ + BOOST_ASSERT(m_check_invariants()); +} + +template +inline void dynamic_bitset:: +swap(dynamic_bitset& b) BOOST_NOEXCEPT +{ + std::swap(m_bits, b.m_bits); + std::swap(m_num_bits, b.m_num_bits); +} + +template +dynamic_bitset& dynamic_bitset:: +operator=(const dynamic_bitset& b) +{ + m_bits = b.m_bits; + m_num_bits = b.m_num_bits; + return *this; +} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template +inline dynamic_bitset:: +dynamic_bitset(dynamic_bitset&& b) + : m_bits(boost::move(b.m_bits)), m_num_bits(boost::move(b.m_num_bits)) +{ + // Required so that BOOST_ASSERT(m_check_invariants()); works. + BOOST_ASSERT((b.m_bits = buffer_type(get_allocator())).empty()); + b.m_num_bits = 0; +} + +template +inline dynamic_bitset& dynamic_bitset:: +operator=(dynamic_bitset&& b) +{ + if (&b == this) { return *this; } + + m_bits = boost::move(b.m_bits); + m_num_bits = boost::move(b.m_num_bits); + // Required so that BOOST_ASSERT(m_check_invariants()); works. + BOOST_ASSERT((b.m_bits = buffer_type(get_allocator())).empty()); + b.m_num_bits = 0; + return *this; +} + +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + +template +inline typename dynamic_bitset::allocator_type +dynamic_bitset::get_allocator() const +{ + return m_bits.get_allocator(); +} + +//----------------------------------------------------------------------------- +// size changing operations + +template +void dynamic_bitset:: +resize(size_type num_bits, bool value) // strong guarantee +{ + + const size_type old_num_blocks = num_blocks(); + const size_type required_blocks = calc_num_blocks(num_bits); + + const block_type v = value? detail::dynamic_bitset_impl::max_limit::value : Block(0); + + if (required_blocks != old_num_blocks) { + m_bits.resize(required_blocks, v); // s.g. (copy) + } + + + // At this point: + // + // - if the buffer was shrunk, we have nothing more to do, + // except a call to m_zero_unused_bits() + // + // - if it was enlarged, all the (used) bits in the new blocks have + // the correct value, but we have not yet touched those bits, if + // any, that were 'unused bits' before enlarging: if value == true, + // they must be set. + + if (value && (num_bits > m_num_bits)) { + + const block_width_type extra_bits = count_extra_bits(); + if (extra_bits) { + BOOST_ASSERT(old_num_blocks >= 1 && old_num_blocks <= m_bits.size()); + + // Set them. + m_bits[old_num_blocks - 1] |= (v << extra_bits); + } + + } + + m_num_bits = num_bits; + m_zero_unused_bits(); +} + +template +void dynamic_bitset:: +clear() // no throw +{ + m_bits.clear(); + m_num_bits = 0; +} + +template +void dynamic_bitset:: +push_back(bool bit) +{ + const size_type sz = size(); + resize(sz + 1, bit); +} + +template +void dynamic_bitset:: +pop_back() +{ + BOOST_ASSERT( !empty() ); + const size_type old_num_blocks = num_blocks(); + const size_type required_blocks = calc_num_blocks(m_num_bits - 1); + + if (required_blocks != old_num_blocks) { + m_bits.pop_back(); + } + + --m_num_bits; + m_zero_unused_bits(); +} + + +template +void dynamic_bitset:: +append(Block value) // strong guarantee +{ + const block_width_type r = count_extra_bits(); + + if (r == 0) { + // the buffer is empty, or all blocks are filled + m_bits.push_back(value); + } + else { + m_bits.push_back(value >> (bits_per_block - r)); + m_bits[m_bits.size() - 2] |= (value << r); // m_bits.size() >= 2 + } + + m_num_bits += bits_per_block; + BOOST_ASSERT(m_check_invariants()); + +} + +template +template +void +dynamic_bitset::append(BlockInputIterator first, BlockInputIterator last) // strong guarantee +{ + if (first != last) { + typename std::iterator_traits::iterator_category cat; + m_append(first, last, cat); + } +} + +//----------------------------------------------------------------------------- +// bitset operations +template +dynamic_bitset& +dynamic_bitset::operator&=(const dynamic_bitset& rhs) +{ + BOOST_ASSERT(size() == rhs.size()); + for (size_type i = 0; i < num_blocks(); ++i) + m_bits[i] &= rhs.m_bits[i]; + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::operator|=(const dynamic_bitset& rhs) +{ + BOOST_ASSERT(size() == rhs.size()); + for (size_type i = 0; i < num_blocks(); ++i) + m_bits[i] |= rhs.m_bits[i]; + //m_zero_unused_bits(); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::operator^=(const dynamic_bitset& rhs) +{ + BOOST_ASSERT(size() == rhs.size()); + for (size_type i = 0; i < this->num_blocks(); ++i) + m_bits[i] ^= rhs.m_bits[i]; + //m_zero_unused_bits(); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::operator-=(const dynamic_bitset& rhs) +{ + BOOST_ASSERT(size() == rhs.size()); + for (size_type i = 0; i < num_blocks(); ++i) + m_bits[i] &= ~rhs.m_bits[i]; + //m_zero_unused_bits(); + return *this; +} + +// NOTE: +// Note that the 'if (r != 0)' is crucial to avoid undefined +// behavior when the left hand operand of >> isn't promoted to a +// wider type (because rs would be too large). +// +template +dynamic_bitset& +dynamic_bitset::operator<<=(size_type n) +{ + if (n >= m_num_bits) + return reset(); + //else + if (n > 0) { + + const size_type last = num_blocks() - 1; // num_blocks() is >= 1 + const size_type div = n / bits_per_block; // div is <= last + const block_width_type r = bit_index(n); + block_type * const b = &m_bits[0]; + + if (r != 0) { + + const block_width_type rs = bits_per_block - r; + + for (size_type i = last-div; i>0; --i) { + b[i+div] = (b[i] << r) | (b[i-1] >> rs); + } + b[div] = b[0] << r; + + } + else { + for (size_type i = last-div; i>0; --i) { + b[i+div] = b[i]; + } + b[div] = b[0]; + } + + // zero out div blocks at the less significant end + std::fill_n(m_bits.begin(), div, static_cast(0)); + + // zero out any 1 bit that flowed into the unused part + m_zero_unused_bits(); // thanks to Lester Gong + + } + + return *this; +} + +// +// NOTE: +// See the comments to operator <<=. +// +template +dynamic_bitset & dynamic_bitset::operator>>=(size_type n) { + if (n >= m_num_bits) { + return reset(); + } + //else + if (n>0) { + + const size_type last = num_blocks() - 1; // num_blocks() is >= 1 + const size_type div = n / bits_per_block; // div is <= last + const block_width_type r = bit_index(n); + block_type * const b = &m_bits[0]; + + if (r != 0) { + + const block_width_type ls = bits_per_block - r; + + for (size_type i = div; i < last; ++i) { + b[i-div] = (b[i] >> r) | (b[i+1] << ls); + } + // r bits go to zero + b[last-div] = b[last] >> r; + } + + else { + for (size_type i = div; i <= last; ++i) { + b[i-div] = b[i]; + } + // note the '<=': the last iteration 'absorbs' + // b[last-div] = b[last] >> 0; + } + + // div blocks are zero filled at the most significant end + std::fill_n(m_bits.begin() + (num_blocks()-div), div, static_cast(0)); + } + + return *this; +} + + +template +dynamic_bitset +dynamic_bitset::operator<<(size_type n) const +{ + dynamic_bitset r(*this); + return r <<= n; +} + +template +dynamic_bitset +dynamic_bitset::operator>>(size_type n) const +{ + dynamic_bitset r(*this); + return r >>= n; +} + + +//----------------------------------------------------------------------------- +// basic bit operations + +template +dynamic_bitset& +dynamic_bitset::set(size_type pos, + size_type len, bool val) +{ + if (val) + return range_operation(pos, len, set_block_partial, set_block_full); + else + return range_operation(pos, len, reset_block_partial, reset_block_full); +} + +template +dynamic_bitset& +dynamic_bitset::set(size_type pos, bool val) +{ + BOOST_ASSERT(pos < m_num_bits); + + if (val) + m_bits[block_index(pos)] |= bit_mask(pos); + else + reset(pos); + + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::set() +{ + std::fill(m_bits.begin(), m_bits.end(), detail::dynamic_bitset_impl::max_limit::value); + m_zero_unused_bits(); + return *this; +} + +template +inline dynamic_bitset& +dynamic_bitset::reset(size_type pos, size_type len) +{ + return range_operation(pos, len, reset_block_partial, reset_block_full); +} + +template +dynamic_bitset& +dynamic_bitset::reset(size_type pos) +{ + BOOST_ASSERT(pos < m_num_bits); + m_bits[block_index(pos)] &= ~bit_mask(pos); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::reset() +{ + std::fill(m_bits.begin(), m_bits.end(), Block(0)); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::flip(size_type pos, size_type len) +{ + return range_operation(pos, len, flip_block_partial, flip_block_full); +} + +template +dynamic_bitset& +dynamic_bitset::flip(size_type pos) +{ + BOOST_ASSERT(pos < m_num_bits); + m_bits[block_index(pos)] ^= bit_mask(pos); + return *this; +} + +template +dynamic_bitset& +dynamic_bitset::flip() +{ + for (size_type i = 0; i < num_blocks(); ++i) + m_bits[i] = ~m_bits[i]; + m_zero_unused_bits(); + return *this; +} + +template +typename dynamic_bitset::reference +dynamic_bitset::at(size_type pos) +{ + if (pos >= m_num_bits) + BOOST_THROW_EXCEPTION(std::out_of_range("boost::dynamic_bitset::at out_of_range")); + + return (*this)[pos]; +} + +template +bool dynamic_bitset::at(size_type pos) const +{ + if (pos >= m_num_bits) + BOOST_THROW_EXCEPTION(std::out_of_range("boost::dynamic_bitset::at out_of_range")); + + return (*this)[pos]; +} + +template +bool dynamic_bitset::test(size_type pos) const +{ + BOOST_ASSERT(pos < m_num_bits); + return m_unchecked_test(pos); +} + +template +bool dynamic_bitset::test_set(size_type pos, bool val) +{ + const bool b = test(pos); + if (b != val) { + set(pos, val); + } + return b; +} + +template +bool dynamic_bitset::all() const +{ + if (empty()) { + return true; + } + + const block_width_type extra_bits = count_extra_bits(); + const block_type all_ones = detail::dynamic_bitset_impl::max_limit::value; + + if (extra_bits == 0) { + for (size_type i = 0, e = num_blocks(); i < e; ++i) { + if (m_bits[i] != all_ones) { + return false; + } + } + } else { + for (size_type i = 0, e = num_blocks() - 1; i < e; ++i) { + if (m_bits[i] != all_ones) { + return false; + } + } + const block_type mask = (block_type(1) << extra_bits) - 1; + if (m_highest_block() != mask) { + return false; + } + } + return true; +} + +template +bool dynamic_bitset::any() const +{ + for (size_type i = 0; i < num_blocks(); ++i) + if (m_bits[i]) + return true; + return false; +} + +template +inline bool dynamic_bitset::none() const +{ + return !any(); +} + +template +dynamic_bitset +dynamic_bitset::operator~() const +{ + dynamic_bitset b(*this); + b.flip(); + return b; +} + +template +typename dynamic_bitset::size_type +dynamic_bitset::count() const BOOST_NOEXCEPT +{ + size_type result = 0; + for (block_type block : m_bits) { + result += core::popcount(block); + } + return result; +} + +//----------------------------------------------------------------------------- +// subscript + +template +typename dynamic_bitset::reference +dynamic_bitset::operator[](size_type pos) +{ + return reference(m_bits[block_index(pos)], bit_index(pos)); +} + +template +bool +dynamic_bitset::operator[](size_type pos) const +{ + return test(pos); +} + +//----------------------------------------------------------------------------- +// conversions + +template +unsigned long dynamic_bitset:: +to_ulong() const +{ + + if (m_num_bits == 0) + return 0; // convention + + // Check for overflows. This may be a performance burden on very large + // bitsets but is required by the specification, sorry. + if (find_first(ulong_width) != npos) + BOOST_THROW_EXCEPTION(std::overflow_error("boost::dynamic_bitset::to_ulong overflow")); + + + // Ok, from now on we can be sure there's no "on" bit beyond the + // "allowed" positions. + typedef unsigned long result_type; + + const size_type maximum_size = + (std::min)(m_num_bits, static_cast(ulong_width)); + + const size_type last_block = block_index( maximum_size - 1 ); + + BOOST_ASSERT((last_block * bits_per_block) < static_cast(ulong_width)); + + result_type result = 0; + for (size_type i = 0; i <= last_block; ++i) { + const size_type offset = i * bits_per_block; + result |= (static_cast(m_bits[i]) << offset); + } + + return result; +} + +// A comment similar to the one about the constructor from basic_string +// can be done here. Thanks to James Kanze for making me (Gennaro) +// realize this important separation of concerns issue, as well as many +// things about i18n. +template +inline void +to_string(const dynamic_bitset& b, stringT& s) +{ + to_string_helper(b, s, false); +} + +// Differently from to_string this function dumps out every bit of the +// internal representation (may be useful for debugging purposes) +template +inline void +dump_to_string(const dynamic_bitset& b, stringT& s) +{ + to_string_helper(b, s, true /* =dump_all*/); +} + +template +inline void +to_block_range(const dynamic_bitset& b, + BlockOutputIterator result) +{ + // Note how this copies *all* bits, including the unused ones in the + // last block (which are zero). + std::copy(b.m_bits.begin(), b.m_bits.end(), result); +} + +template +inline typename dynamic_bitset::size_type +dynamic_bitset::size() const BOOST_NOEXCEPT +{ + return m_num_bits; +} + +template +inline typename dynamic_bitset::size_type +dynamic_bitset::num_blocks() const BOOST_NOEXCEPT +{ + return m_bits.size(); +} + +template +inline typename dynamic_bitset::size_type +dynamic_bitset::max_size() const BOOST_NOEXCEPT +{ + // The semantics of vector<>::max_size() aren't very clear (see lib + // issue 197) and many library implementations simply return dummy + // values, _unrelated_ to the underlying allocator. + // + // Given these problems, I was tempted to not provide this function + // at all, but the user could need it if he provides his own + // allocator. + + const size_type m = detail::dynamic_bitset_impl:: + vector_max_size_workaround(m_bits); + + return m <= (size_type(-1)/bits_per_block) ? + m * bits_per_block : + size_type(-1); +} + +template +inline bool dynamic_bitset::empty() const BOOST_NOEXCEPT +{ + return size() == 0; +} + +template +inline typename dynamic_bitset::size_type +dynamic_bitset::capacity() const BOOST_NOEXCEPT +{ + return m_bits.capacity() * bits_per_block; +} + +template +inline void dynamic_bitset::reserve(size_type num_bits) +{ + m_bits.reserve(calc_num_blocks(num_bits)); +} + +template +void dynamic_bitset::shrink_to_fit() +{ + if (m_bits.size() < m_bits.capacity()) { + buffer_type(m_bits).swap(m_bits); + } +} + +template +bool dynamic_bitset:: +is_subset_of(const dynamic_bitset& a) const +{ + BOOST_ASSERT(size() == a.size()); + for (size_type i = 0; i < num_blocks(); ++i) + if (m_bits[i] & ~a.m_bits[i]) + return false; + return true; +} + +template +bool dynamic_bitset:: +is_proper_subset_of(const dynamic_bitset& a) const +{ + BOOST_ASSERT(size() == a.size()); + + bool proper = false; + for (size_type i = 0; i < num_blocks(); ++i) { + const Block & bt = m_bits[i]; + const Block & ba = a.m_bits[i]; + + if (bt & ~ba) + return false; // not a subset at all + if (ba & ~bt) + proper = true; + } + return proper; +} + +template +bool dynamic_bitset::intersects(const dynamic_bitset & b) const +{ + size_type common_blocks = num_blocks() < b.num_blocks() + ? num_blocks() : b.num_blocks(); + + for(size_type i = 0; i < common_blocks; ++i) { + if(m_bits[i] & b.m_bits[i]) + return true; + } + return false; +} + +// -------------------------------- +// lookup + +// Look for the first bit "on", starting from the block with index +// first_block. +template +typename dynamic_bitset::size_type +dynamic_bitset::m_do_find_from(size_type first_block) const +{ + + size_type i = std::distance(m_bits.begin(), + std::find_if(m_bits.begin() + first_block, m_bits.end(), m_not_empty) ); + + if (i >= num_blocks()) + return npos; // not found + + return i * bits_per_block + static_cast(detail::lowest_bit(m_bits[i])); +} + + +template +typename dynamic_bitset::size_type +dynamic_bitset::find_first() const +{ + return m_do_find_from(0); +} + +template +typename dynamic_bitset::size_type +dynamic_bitset::find_first(size_type pos) const +{ + const size_type sz = size(); + if (pos >= sz) return npos; + + const size_type blk = block_index(pos); + const block_width_type ind = bit_index(pos); + + // shift bits upto one immediately after current + const Block fore = m_bits[blk] >> ind; + + return fore? + pos + static_cast(detail::lowest_bit(fore)) + : + m_do_find_from(blk + 1); +} + + +template +typename dynamic_bitset::size_type +dynamic_bitset::find_next(size_type pos) const +{ + if (pos == npos) return npos; + return find_first(pos + 1); +} + +//----------------------------------------------------------------------------- +// comparison + +template +bool operator==(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return (a.m_num_bits == b.m_num_bits) + && (a.m_bits == b.m_bits); +} + +template +inline bool operator!=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a == b); +} + +template +bool operator<(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + typedef BOOST_DEDUCED_TYPENAME dynamic_bitset::size_type size_type; + + size_type asize(a.size()); + size_type bsize(b.size()); + + if (!bsize) + { + return false; + } + else if (!asize) + { + return true; + } + else if (asize == bsize) + { + for (size_type ii = a.num_blocks(); ii > 0; --ii) + { + size_type i = ii-1; + if (a.m_bits[i] < b.m_bits[i]) + return true; + else if (a.m_bits[i] > b.m_bits[i]) + return false; + } + return false; + } + else + { + size_type leqsize(std::min BOOST_PREVENT_MACRO_SUBSTITUTION(asize,bsize)); + + for (size_type ii = 0; ii < leqsize; ++ii,--asize,--bsize) + { + size_type i = asize-1; + size_type j = bsize-1; + if (a[i] < b[j]) + return true; + else if (a[i] > b[j]) + return false; + } + return (a.size() < b.size()); + } +} + +template +inline bool operator<=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a > b); +} + +template +inline bool operator>(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return b < a; +} + +template +inline bool operator>=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a < b); +} + +template +void to_string_helper(const dynamic_bitset & b, stringT & s, + bool dump_all) +{ + typedef typename stringT::traits_type Tr; + typedef typename stringT::value_type Ch; + + BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, std::locale()); + const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); + const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); + + // Note that this function may access (when + // dump_all == true) bits beyond position size() - 1 + + typedef typename dynamic_bitset::size_type size_type; + + const size_type len = dump_all? + dynamic_bitset::bits_per_block * b.num_blocks(): + b.size(); + s.assign (len, zero); + + for (size_type i = 0; i < len; ++i) { + if (b.m_unchecked_test(i)) + Tr::assign(s[len - 1 - i], one); + + } +} + +//----------------------------------------------------------------------------- +// hash operations + +template +inline std::size_t hash_value(const dynamic_bitset& a) +{ + std::size_t res = hash_value(a.m_num_bits); + boost::hash_combine(res, a.m_bits); + return res; +} + +//----------------------------------------------------------------------------- +// stream operations + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const dynamic_bitset& b) +{ + + using namespace std; + + const ios_base::iostate ok = ios_base::goodbit; + ios_base::iostate err = ok; + + typename basic_ostream::sentry cerberos(os); + if (cerberos) { + + BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, os.getloc()); + const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); + const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); + + BOOST_TRY { + + typedef typename dynamic_bitset::size_type bitset_size_type; + typedef basic_streambuf buffer_type; + + buffer_type * buf = os.rdbuf(); + // careful: os.width() is signed (and can be < 0) + const bitset_size_type width = (os.width() <= 0) ? 0 : static_cast(os.width()); + streamsize npad = (width <= b.size()) ? 0 : width - b.size(); + + const Ch fill_char = os.fill(); + const ios_base::fmtflags adjustfield = os.flags() & ios_base::adjustfield; + + // if needed fill at left; pad is decreased along the way + if (adjustfield != ios_base::left) { + for (; 0 < npad; --npad) + if (Tr::eq_int_type(Tr::eof(), buf->sputc(fill_char))) { + err |= ios_base::failbit; + break; + } + } + + if (err == ok) { + // output the bitset + for (bitset_size_type i = b.size(); 0 < i; --i) { + typename buffer_type::int_type + ret = buf->sputc(b.test(i-1)? one : zero); + if (Tr::eq_int_type(Tr::eof(), ret)) { + err |= ios_base::failbit; + break; + } + } + } + + if (err == ok) { + // if needed fill at right + for (; 0 < npad; --npad) { + if (Tr::eq_int_type(Tr::eof(), buf->sputc(fill_char))) { + err |= ios_base::failbit; + break; + } + } + } + + + os.width(0); + + } BOOST_CATCH (...) { // see std 27.6.1.1/4 + bool rethrow = false; + BOOST_TRY { os.setstate(ios_base::failbit); } BOOST_CATCH (...) { rethrow = true; } BOOST_CATCH_END + + if (rethrow) + BOOST_RETHROW; + } + BOOST_CATCH_END + } + + if(err != ok) + os.setstate(err); // may throw exception + return os; + +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, dynamic_bitset& b) +{ + + using namespace std; + + typedef dynamic_bitset bitset_type; + typedef typename bitset_type::size_type size_type; + + const streamsize w = is.width(); + const size_type limit = 0 < w && static_cast(w) < b.max_size()? + static_cast(w) : b.max_size(); + + ios_base::iostate err = ios_base::goodbit; + typename basic_istream::sentry cerberos(is); // skips whitespaces + if(cerberos) { + + // in accordance with prop. resol. of lib DR 303 [last checked 4 Feb 2004] + BOOST_DYNAMIC_BITSET_CTYPE_FACET(Ch, fac, is.getloc()); + const Ch zero = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0'); + const Ch one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); + + b.clear(); + BOOST_TRY { + typename bitset_type::bit_appender appender(b); + basic_streambuf * buf = is.rdbuf(); + typename Tr::int_type c = buf->sgetc(); + for( ; appender.get_count() < limit; c = buf->snextc() ) { + + if (Tr::eq_int_type(Tr::eof(), c)) { + err |= ios_base::eofbit; + break; + } + else { + const Ch to_c = Tr::to_char_type(c); + const bool is_one = Tr::eq(to_c, one); + + if (!is_one && !Tr::eq(to_c, zero)) + break; // non digit character + + appender.do_append(is_one); + + } + + } // for + } + BOOST_CATCH (...) { + // catches from stream buf, or from vector: + // + // bits_stored bits have been extracted and stored, and + // either no further character is extractable or we can't + // append to the underlying vector (out of memory) + + bool rethrow = false; // see std 27.6.1.1/4 + BOOST_TRY { is.setstate(ios_base::badbit); } + BOOST_CATCH(...) { rethrow = true; } + BOOST_CATCH_END + + if (rethrow) + BOOST_RETHROW; + + } + BOOST_CATCH_END + } + + is.width(0); + if (b.size() == 0 /*|| !cerberos*/) + err |= ios_base::failbit; + if (err != ios_base::goodbit) + is.setstate (err); // may throw + + return is; + +} + +//----------------------------------------------------------------------------- +// bitset operations + +template +dynamic_bitset +operator&(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b &= y; +} + +template +dynamic_bitset +operator|(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b |= y; +} + +template +dynamic_bitset +operator^(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b ^= y; +} + +template +dynamic_bitset +operator-(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b -= y; +} + +//----------------------------------------------------------------------------- +// namespace scope swap + +template +inline void +swap(dynamic_bitset& left, + dynamic_bitset& right) BOOST_NOEXCEPT +{ + left.swap(right); +} + +template +bool dynamic_bitset::m_unchecked_test(size_type pos) const +{ + return (m_bits[block_index(pos)] & bit_mask(pos)) != 0; +} + +template +inline typename dynamic_bitset::size_type +dynamic_bitset::calc_num_blocks(size_type num_bits) +{ + return num_bits / bits_per_block + + static_cast( num_bits % bits_per_block != 0 ); +} + +// gives a reference to the highest block +// +template +inline Block& dynamic_bitset::m_highest_block() +{ + return const_cast + (static_cast(this)->m_highest_block()); +} + +// gives a const-reference to the highest block +// +template +inline const Block& dynamic_bitset::m_highest_block() const +{ + BOOST_ASSERT(size() > 0 && num_blocks() > 0); + return m_bits.back(); +} + +template +dynamic_bitset& dynamic_bitset::range_operation( + size_type pos, size_type len, + Block (*partial_block_operation)(Block, size_type, size_type), + Block (*full_block_operation)(Block)) +{ + BOOST_ASSERT(pos + len <= m_num_bits); + + // Do nothing in case of zero length + if (!len) + return *this; + + // Use an additional asserts in order to detect size_type overflow + // For example: pos = 10, len = size_type_limit - 2, pos + len = 7 + // In case of overflow, 'pos + len' is always smaller than 'len' + BOOST_ASSERT(pos + len >= len); + + // Start and end blocks of the [pos; pos + len - 1] sequence + const size_type first_block = block_index(pos); + const size_type last_block = block_index(pos + len - 1); + + const size_type first_bit_index = bit_index(pos); + const size_type last_bit_index = bit_index(pos + len - 1); + + if (first_block == last_block) { + // Filling only a sub-block of a block + m_bits[first_block] = partial_block_operation(m_bits[first_block], + first_bit_index, last_bit_index); + } else { + // Check if the corner blocks won't be fully filled with 'val' + const size_type first_block_shift = bit_index(pos) ? 1 : 0; + const size_type last_block_shift = (bit_index(pos + len - 1) + == bits_per_block - 1) ? 0 : 1; + + // Blocks that will be filled with ~0 or 0 at once + const size_type first_full_block = first_block + first_block_shift; + const size_type last_full_block = last_block - last_block_shift; + + for (size_type i = first_full_block; i <= last_full_block; ++i) { + m_bits[i] = full_block_operation(m_bits[i]); + } + + // Fill the first block from the 'first' bit index to the end + if (first_block_shift) { + m_bits[first_block] = partial_block_operation(m_bits[first_block], + first_bit_index, bits_per_block - 1); + } + + // Fill the last block from the start to the 'last' bit index + if (last_block_shift) { + m_bits[last_block] = partial_block_operation(m_bits[last_block], + 0, last_bit_index); + } + } + + return *this; +} + +// If size() is not a multiple of bits_per_block then not all the bits +// in the last block are used. This function resets the unused bits +// (convenient for the implementation of many member functions). +template +inline void dynamic_bitset::m_zero_unused_bits() +{ + BOOST_ASSERT (num_blocks() == calc_num_blocks(m_num_bits)); + + // if != 0, this is the number of bits used in the last block. + const block_width_type extra_bits = count_extra_bits(); + + if (extra_bits != 0) + m_highest_block() &= (Block(1) << extra_bits) - 1; +} + +// check class invariants +template +bool dynamic_bitset::m_check_invariants() const +{ + const block_width_type extra_bits = count_extra_bits(); + if (extra_bits > 0) { + const block_type mask = detail::dynamic_bitset_impl::max_limit::value << extra_bits; + if ((m_highest_block() & mask) != 0) + return false; + } + if (m_bits.size() > m_bits.capacity() || num_blocks() != calc_num_blocks(size())) + return false; + + return true; + +} + +template +bool +dynamic_bitset::m_not_empty(Block x) +{ + return x != Block(0); +} + + +template +typename dynamic_bitset::block_width_type +dynamic_bitset::count_extra_bits() const BOOST_NOEXCEPT +{ + return bit_index(size()); +} + +template +typename dynamic_bitset::size_type +dynamic_bitset::block_index(size_type pos) BOOST_NOEXCEPT +{ + return pos / bits_per_block; +} + +template +typename dynamic_bitset::block_width_type +dynamic_bitset::bit_index(size_type pos) BOOST_NOEXCEPT +{ + return static_cast(pos % bits_per_block); +} + +template +Block +dynamic_bitset::bit_mask(size_type pos) BOOST_NOEXCEPT +{ + return Block(1) << bit_index(pos); +} + +template +Block +dynamic_bitset::bit_mask(size_type first, size_type last) BOOST_NOEXCEPT +{ + Block res = (last == bits_per_block - 1) + ? detail::dynamic_bitset_impl::max_limit::value + : ((Block(1) << (last + 1)) - 1); + res ^= (Block(1) << first) - 1; + return res; +} + +template +Block +dynamic_bitset::set_block_bits( + Block block, + size_type first, + size_type last, + bool val) BOOST_NOEXCEPT +{ + if (val) + return block | bit_mask(first, last); + else + return block & static_cast(~bit_mask(first, last)); +} + + // Functions for operations on ranges +template +Block +dynamic_bitset::set_block_partial( + Block block, + size_type first, + size_type last) BOOST_NOEXCEPT +{ + return set_block_bits(block, first, last, true); +} + +template +Block +dynamic_bitset::set_block_full(Block) BOOST_NOEXCEPT +{ + return detail::dynamic_bitset_impl::max_limit::value; +} + + +template +Block +dynamic_bitset::reset_block_partial( + Block block, + size_type first, + size_type last) BOOST_NOEXCEPT +{ + return set_block_bits(block, first, last, false); +} + +template +Block +dynamic_bitset::reset_block_full(Block) BOOST_NOEXCEPT +{ + return 0; +} + + +template +Block +dynamic_bitset::flip_block_partial( + Block block, + size_type first, + size_type last) BOOST_NOEXCEPT +{ + return block ^ bit_mask(first, last); +} + +template +Block +dynamic_bitset::flip_block_full(Block block) BOOST_NOEXCEPT +{ + return ~block; +} + + +template +template +void +dynamic_bitset::dispatch_init( + T num_bits, + unsigned long value, + detail::dynamic_bitset_impl::value_to_type) +{ + init_from_unsigned_long(static_cast(num_bits), value); +} + + +template +template +void +dynamic_bitset::dispatch_init( + T first, + T last, + detail::dynamic_bitset_impl::value_to_type) +{ + init_from_block_range(first, last); +} + +template +template +void +dynamic_bitset::init_from_block_range(BlockIter first, BlockIter last) +{ + BOOST_ASSERT(m_bits.size() == 0); + m_bits.insert(m_bits.end(), first, last); + m_num_bits = m_bits.size() * bits_per_block; +} + +template< typename Block, typename Allocator> +template +void +dynamic_bitset::init_from_string( + const std::basic_string& s, + typename std::basic_string::size_type pos, + typename std::basic_string::size_type n, + size_type num_bits) +{ + BOOST_ASSERT(pos <= s.size()); + + typedef typename std::basic_string StrT; + typedef typename StrT::traits_type Tr; + + const typename StrT::size_type rlen = (std::min)(n, s.size() - pos); + const size_type sz = ( num_bits != npos? num_bits : rlen); + m_bits.resize(calc_num_blocks(sz)); + m_num_bits = sz; + + + BOOST_DYNAMIC_BITSET_CTYPE_FACET(CharT, fac, std::locale()); + const CharT one = BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '1'); + + const size_type m = num_bits < rlen ? num_bits : rlen; + typename StrT::size_type i = 0; + for( ; i < m; ++i) { + + const CharT c = s[(pos + m - 1) - i]; + + BOOST_ASSERT( Tr::eq(c, one) + || Tr::eq(c, BOOST_DYNAMIC_BITSET_WIDEN_CHAR(fac, '0')) ); + + if (Tr::eq(c, one)) + set(i); + } +} + +template +void +dynamic_bitset::init_from_unsigned_long( + size_type num_bits, + unsigned long value/*, + const Allocator& alloc*/) +{ + + BOOST_ASSERT(m_bits.size() == 0); + + m_bits.resize(calc_num_blocks(num_bits)); + m_num_bits = num_bits; + + typedef unsigned long num_type; + typedef boost::detail::dynamic_bitset_impl + ::shifter shifter; + + //if (num_bits == 0) + // return; + + // zero out all bits at pos >= num_bits, if any; + // note that: num_bits == 0 implies value == 0 + if (num_bits < static_cast(ulong_width)) { + const num_type mask = (num_type(1) << num_bits) - 1; + value &= mask; + } + + typename buffer_type::iterator it = m_bits.begin(); + for( ; value; shifter::left_shift(value), ++it) { + *it = static_cast(value); + } + +} + +template +template +void +dynamic_bitset::m_append(BlockInputIterator first, BlockInputIterator last, std::input_iterator_tag) +{ + std::vector v(first, last); + m_append(v.begin(), v.end(), std::random_access_iterator_tag()); +} + +template +template +void +dynamic_bitset::m_append(BlockInputIterator first, BlockInputIterator last, std::forward_iterator_tag) +{ + BOOST_ASSERT(first != last); + block_width_type r = count_extra_bits(); + std::size_t d = std::distance(first, last); + m_bits.reserve(num_blocks() + d); + if (r == 0) { + for( ; first != last; ++first) + m_bits.push_back(*first); // could use vector<>::insert() + } + else { + m_highest_block() |= (*first << r); + do { + Block b = *first >> (bits_per_block - r); + ++first; + m_bits.push_back(b | (first==last? 0 : *first << r)); + } while (first != last); + } + m_num_bits += bits_per_block * d; +} + +// bit appender + +template +dynamic_bitset::bit_appender::bit_appender(dynamic_bitset & r) + : bs(r), n(0), mask(0), current(0) +{ +} + +template +dynamic_bitset::bit_appender::~bit_appender() +{ + // Reverse the order of the blocks, shift if needed, and then + // resize. + // + std::reverse(bs.m_bits.begin(), bs.m_bits.end()); + const block_width_type offs = bit_index(n); + if (offs) + bs >>= (bits_per_block - offs); + bs.resize(n); // doesn't enlarge, so can't throw + BOOST_ASSERT(bs.m_check_invariants()); +} + +template +void +dynamic_bitset< Block, Allocator>::bit_appender::do_append(bool value) +{ + + if (mask == 0) { + bs.append(Block(0)); + current = &bs.m_highest_block(); + mask = Block(1) << (bits_per_block - 1); + } + + if (value) { + *current |= mask; + } + mask /= 2; + ++n; +} + +template +typename dynamic_bitset::size_type +dynamic_bitset::bit_appender::get_count() const +{ + return n; +} + +} // namespace boost + +// std::hash support +#if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) && !defined(BOOST_DYNAMIC_BITSET_NO_STD_HASH) +#include +namespace std +{ +template +struct hash< boost::dynamic_bitset > +{ + typedef boost::dynamic_bitset argument_type; + typedef std::size_t result_type; + result_type operator()(const argument_type& a) const BOOST_NOEXCEPT + { + boost::hash hasher; + return hasher(a); + } +}; +} +#endif + +// Local Variables: +// mode: c++ +// End: +// vim: set ft=cpp: