diff options
Diffstat (limited to 'Runtime/Utilities/dynamic_bitset.h')
-rw-r--r-- | Runtime/Utilities/dynamic_bitset.h | 1144 |
1 files changed, 1144 insertions, 0 deletions
diff --git a/Runtime/Utilities/dynamic_bitset.h b/Runtime/Utilities/dynamic_bitset.h new file mode 100644 index 0000000..7dadb2c --- /dev/null +++ b/Runtime/Utilities/dynamic_bitset.h @@ -0,0 +1,1144 @@ +#ifndef DYNAMIC_BITSET_H +#define DYNAMIC_BITSET_H +// (C) Copyright Chuck Allison and Jeremy Siek 2001, 2002. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all +// copies. This software is provided "as is" without express or +// implied warranty, and with no claim as to its suitability for any +// purpose. + +// With optimizations, bug fixes, and improvements by Gennaro Prota. + +// See http://www.boost.org/libs/dynamic_bitset for documentation. + +// ------------------------------------- +// CHANGE LOG: +// +// - corrected workaround for Dinkum lib's allocate() [GP] +// - changed macro test for old iostreams [GP] +// - removed #include <vector> for now. [JGS] +// - Added __GNUC__ to compilers that cannot handle the constructor from basic_string. [JGS] +// - corrected to_block_range [GP] +// - corrected from_block_range [GP] +// - Removed __GNUC__ from compilers that cannot handle the constructor +// from basic_string and added the workaround suggested by GP. [JGS] +// - Removed __BORLANDC__ from the #if around the basic_string +// constructor. Luckily the fix by GP for g++ also fixes Borland. [JGS] + +#include <cassert> +#include <string> +#include <cstring> // for memset, memcpy, memcmp, etc. +#include <algorithm> // for std::swap, std::min, std::copy, std::fill +#include <memory> // for std::swap, std::min, std::copy, std::fill +#include <stdlib.h> +#include "LogAssert.h" + +namespace std +{ + typedef ::size_t size_t; +} +// (C) Copyright Chuck Allison and Jeremy Siek 2001, 2002. +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all +// copies. This software is provided "as is" without express or +// implied warranty, and with no claim as to its suitability for any +// purpose. + +// With optimizations by Gennaro Prota. + + class dynamic_bitset_base + { + typedef std::size_t size_type; + public: +#if defined(LINUX) && (defined (__LP64__) || defined(_AMD64_)) + typedef unsigned int Block; +#else + typedef unsigned long Block; +#endif + enum { bits_per_block = 8 * sizeof(Block) }; + + dynamic_bitset_base() + : m_bits(0), m_num_bits(0), m_num_blocks(0) { } + + dynamic_bitset_base(size_type num_bits) : + m_num_bits(num_bits), + m_num_blocks(calc_num_blocks(num_bits)) + { + if (m_num_blocks != 0) + { + m_bits = new Block[m_num_blocks]; + memset(m_bits, 0, m_num_blocks * sizeof(Block)); // G.P.S. ask to Jeremy + } + else + m_bits = 0; + } + ~dynamic_bitset_base() { + delete []m_bits;; + } + + Block* m_bits; + size_type m_num_bits; + size_type m_num_blocks; + + static size_type word(size_type bit) { return bit / bits_per_block; } // [gps] + static size_type offset(size_type bit){ return bit % bits_per_block; } // [gps] + static Block mask1(size_type bit) { return Block(1) << offset(bit); } + static Block mask0(size_type bit) { return ~(Block(1) << offset(bit)); } + static size_type calc_num_blocks(size_type num_bits) + { return (num_bits + bits_per_block - 1) / bits_per_block; } + }; + + + // ------- count table implementation -------------- + + typedef unsigned char byte_t; + + template <bool bogus = true> + struct bitcount { + typedef byte_t element_type; + static const byte_t table[]; + + }; + //typedef count<true> table_t; + + + // the table: wrapped in a class template, so + // that it is only instantiated if/when needed + // + template <bool bogus> + const byte_t bitcount<bogus>::table[] = + { + // Automatically generated by GPTableGen.exe v.1.0 + // + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 + }; + + + // ------------------------------------------------------- + template <typename BlockInputIterator> + std::size_t initial_num_blocks(BlockInputIterator first, + BlockInputIterator last) + { + std::size_t n = 0; + while (first != last) + ++first, ++n; + return n; + } + +class dynamic_bitset : public dynamic_bitset_base +{ + public: + + typedef Block block_type; + typedef std::size_t size_type; + enum { bits_per_block = 8 * sizeof(Block) }; + + // reference to a bit + class reference + { + friend class dynamic_bitset; + dynamic_bitset* bs; + size_type bit; + reference(); // intentionally not implemented + reference(dynamic_bitset& bs_, size_type bit_) : bs(&bs_), bit(bit_){ } + public: + reference& operator=(bool value) // for b[i] = x + { + if (value) + bs->set(bit); + else + bs->reset(bit); + return *this; + } + reference& operator|=(bool value) // for b[i] |= x + { + if (value) + bs->set(bit); + return *this; + } + reference& operator&=(bool value) // for b[i] &= x + { + if (! (value && bs->test(bit))) + bs->reset(bit); + return *this; + } + reference& operator^=(bool value) // for b[i] ^= x + { + bs->set(bit, bs->test(bit) ^ value); + return *this; + } + reference& operator-=(bool value) // for b[i] -= x + { + if (!value) + bs->reset(bit); + return *this; + } + reference& operator=(const reference& j) // for b[i] = b[j] + { + if (j.bs->test(j.bit)) + bs->set(bit); + else + bs->reset(bit); + return *this; + } + reference& operator|=(const reference& j) // for b[i] |= b[j] + { + if (j.bs->test(j.bit)) + bs->set(bit); + return *this; + } + reference& operator&=(const reference& j) // for b[i] &= b[j] + { + if (! (j.bs->test(j.bit) && bs->test(bit))) + bs->reset(bit); + return *this; + } + reference& operator^=(const reference& j) // for b[i] ^= b[j] + { + bs->set(bit, bs->test(bit) ^ j.bs->test(j.bit)); + return *this; + } + reference& operator-=(const reference& j) // for b[i] -= b[j] + { + if (!j.bs->test(j.bit)) + bs->reset(bit); + return *this; + } + bool operator~() const // flips the bit + { + return ! bs->test(bit); + } + operator bool() const // for x = b[i] + { + return bs->test(bit); + } + reference& flip() // for b[i].flip(); + { + bs->flip(bit); + return *this; + } + }; + typedef bool const_reference; + + dynamic_bitset (); + explicit + dynamic_bitset(size_type num_bits, unsigned long value = 0); + + // The parenthesis around std::basic_string<CharT, Traits, Alloc>::npos + // in the code below are to avoid a g++ 3.2 bug and a Borland bug. -JGS + template <typename String> + explicit + dynamic_bitset(const String& s, + typename String::size_type pos = 0, + typename String::size_type n + = (String::npos)) + : dynamic_bitset_base + (std::min(n, s.size() - pos)) + { + // Locate sub string + AssertIf (pos > s.length()); + from_string(s, pos, std::min(n, s.size() - pos)); + } + + // 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 <typename BlockInputIterator> + dynamic_bitset(BlockInputIterator first, BlockInputIterator last) + : dynamic_bitset_base + (initial_num_blocks(first, last) + * bits_per_block) + { + if (first != last) { + if (this->m_num_bits == 0) { // dealing with input iterators + this->append(first, last); + } else { + // dealing with forward iterators, memory has been allocated + for (std::size_t i = 0; first != last; ++first, ++i) + set_block_(i, *first); + } + } + } + + + // copy constructor + dynamic_bitset(const dynamic_bitset& b); + + void swap(dynamic_bitset& b); + + dynamic_bitset& operator=(const dynamic_bitset& b); + + // size changing operations + void resize(size_type num_bits, bool value = false); + void clear(); + void push_back(bool bit); + void append(Block block); + + // This is declared inside the class to avoid compiler bugs. + template <typename BlockInputIterator> + void append(BlockInputIterator first, BlockInputIterator last) + { + if (first != last) { + std::size_t nblocks = initial_num_blocks(first, last); + if (nblocks == 0) { // dealing with input iterators + for (; first != last; ++first) + append(*first); + } else { // dealing with forward iterators + if (size() % bits_per_block == 0) { + std::size_t old_nblocks = this->m_num_blocks; + resize(size() + nblocks * bits_per_block); + for (std::size_t i = old_nblocks; first != last; ++first) + set_block_(i++, *first); + } else { + // probably should optimize this, + // but I'm sick of bit twiddling + for (; first != last; ++first) + append(*first); + } + } + } + } + + + // bitset operations + dynamic_bitset& operator&=(const dynamic_bitset& b); + dynamic_bitset& operator|=(const dynamic_bitset& b); + dynamic_bitset& operator^=(const dynamic_bitset& b); + dynamic_bitset& operator-=(const dynamic_bitset& b); + dynamic_bitset& operator<<=(size_type n); + dynamic_bitset& operator>>=(size_type n); + dynamic_bitset operator<<(size_type n) const; + dynamic_bitset operator>>(size_type n) const; + + // basic bit operations + dynamic_bitset& set(size_type n, bool val = true); + dynamic_bitset& set(); + dynamic_bitset& reset(size_type n); + dynamic_bitset& reset(); + dynamic_bitset& flip(size_type n); + dynamic_bitset& flip(); + bool test(size_type n) const; + bool any() const; + bool none() const; + dynamic_bitset operator~() const; + size_type count() const; + + // subscript + reference operator[](size_type pos) { return reference(*this, pos); } + bool operator[](size_type pos) const + { + #if UNITY_EDITOR + if (pos < this->m_num_bits) + return test_(pos); + else + { + ErrorString("dynamic_bitset.test bit out of bounds"); + return false; + } + #else + AssertIf(pos >= this->m_num_bits); + return test_(pos); + #endif + } + + unsigned long to_ulong() const; + + size_type size() const; + size_type num_blocks() const; + + bool is_subset_of(const dynamic_bitset& a) const; + bool is_proper_subset_of(const dynamic_bitset& a) const; + + void m_zero_unused_bits(); + + +private: + void set_(size_type bit); + bool set_(size_type bit, bool val); + void reset_(size_type bit); + bool test_(size_type bit) const; + void set_block_(size_type blocknum, Block b); + +public: + + // This is templated on the whole String instead of just CharT, + // Traits, Alloc to avoid compiler bugs. + template <typename String> + void from_string(const String& s, typename String::size_type pos, + typename String::size_type rlen) + { + reset(); // bugfix [gps] + size_type const tot = std::min (rlen, s.length()); // bugfix [gps] + + // Assumes string contains only 0's and 1's + for (size_type i = 0; i < tot; ++i) { + if (s[pos + tot - i - 1] == '1') { + set_(i); + } else { + AssertIf(s[pos + tot - i - 1] != '0'); + } + } + } + +}; + +// Global Functions: + +// comparison +inline bool operator!=(const dynamic_bitset& a, + const dynamic_bitset& b); + +inline bool operator<=(const dynamic_bitset& a, + const dynamic_bitset& b); + +inline bool operator>(const dynamic_bitset& a, + const dynamic_bitset& b); + +inline bool operator>=(const dynamic_bitset& a, + const dynamic_bitset& b); + +// bitset operations +inline dynamic_bitset +operator&(const dynamic_bitset& b1, + const dynamic_bitset& b2); + +inline dynamic_bitset +operator|(const dynamic_bitset& b1, + const dynamic_bitset& b2); + +inline dynamic_bitset +operator^(const dynamic_bitset& b1, + const dynamic_bitset& b2); + +inline dynamic_bitset +operator-(const dynamic_bitset& b1, + const dynamic_bitset& b2); + + +template <typename String> +void +to_string(const dynamic_bitset& b, + String& s); + +template <typename BlockOutputIterator> +void +to_block_range(const dynamic_bitset& b, + BlockOutputIterator result); + +template <typename BlockIterator> +inline void +from_block_range(BlockIterator first, BlockIterator last, + dynamic_bitset& result); + + +//============================================================================= +// dynamic_bitset implementation + + +//----------------------------------------------------------------------------- +// constructors, etc. + +inline dynamic_bitset::dynamic_bitset() + : dynamic_bitset_base(0) { } + +inline dynamic_bitset:: +dynamic_bitset(size_type num_bits, unsigned long value) + : dynamic_bitset_base(num_bits) +{ + const size_type M = std::min(sizeof(unsigned long) * 8, num_bits); + for(size_type i = 0; i < M; ++i, value >>= 1) // [G.P.S.] to be optimized + if ( value & 0x1 ) + set_(i); +} + +// copy constructor +inline dynamic_bitset:: +dynamic_bitset(const dynamic_bitset& b) + : dynamic_bitset_base(b.size()) +{ + memcpy(this->m_bits, b.m_bits, this->m_num_blocks * sizeof(Block)); +} + +inline void dynamic_bitset:: +swap(dynamic_bitset& b) +{ + std::swap(this->m_bits, b.m_bits); + std::swap(this->m_num_bits, b.m_num_bits); + std::swap(this->m_num_blocks, b.m_num_blocks); +} + +inline dynamic_bitset& dynamic_bitset:: +operator=(const dynamic_bitset& b) +{ + dynamic_bitset tmp(b); + this->swap(tmp); + return *this; +} + +//----------------------------------------------------------------------------- +// size changing operations + +inline void dynamic_bitset:: +resize(size_type num_bits, bool value) +{ + if (num_bits == size()) + return; + if (num_bits == 0) + { + this->m_num_bits = 0; + this->m_num_blocks = 0; + delete this->m_bits; + this->m_bits = 0; + return; + } + size_type new_nblocks = this->calc_num_blocks(num_bits); + Block* d = new Block[new_nblocks]; + if (num_bits < size()) { // shrink + std::copy(this->m_bits, this->m_bits + new_nblocks, d); + std::swap(d, this->m_bits); + delete []d; + } else { // grow + std::copy(this->m_bits, this->m_bits + this->m_num_blocks, d); + Block val = value? ~static_cast<Block>(0) : static_cast<Block>(0); + std::fill(d + this->m_num_blocks, d + new_nblocks, val); + std::swap(d, this->m_bits); + for (std::size_t i = this->m_num_bits; + i < this->m_num_blocks * bits_per_block; ++i) + set_(i, value); + if (d != 0) + delete []d; + } + this->m_num_bits = num_bits; + this->m_num_blocks = this->calc_num_blocks(num_bits); + m_zero_unused_bits(); +} + +inline void dynamic_bitset:: +clear() +{ + if (this->m_bits != 0) { + delete this->m_bits; + this->m_bits = 0; + this->m_num_bits = 0; + this->m_num_blocks = 0; + } +} + + +inline void dynamic_bitset:: +push_back(bool bit) +{ + this->resize(this->size() + 1); + set_(this->size() - 1, bit); +} + +inline void dynamic_bitset:: +append(Block value) +{ + std::size_t old_size = size(); + resize(old_size + bits_per_block); + if (size() % bits_per_block == 0) + set_block_(this->m_num_blocks - 1, value); + else { + // G.P.S. to be optimized + for (std::size_t i = old_size; i < size(); ++i, value >>= 1) + set_(i, value & 1); + } +} + + +//----------------------------------------------------------------------------- +// bitset operations +inline dynamic_bitset& +dynamic_bitset::operator&=(const dynamic_bitset& rhs) +{ + AssertIf(size() != rhs.size()); + for (size_type i = 0; i < this->m_num_blocks; ++i) + this->m_bits[i] &= rhs.m_bits[i]; + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::operator|=(const dynamic_bitset& rhs) +{ + AssertIf(size() != rhs.size()); + for (size_type i = 0; i < this->m_num_blocks; ++i) + this->m_bits[i] |= rhs.m_bits[i]; + m_zero_unused_bits(); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::operator^=(const dynamic_bitset& rhs) +{ + AssertIf(size() != rhs.size()); + for (size_type i = 0; i < this->m_num_blocks; ++i) + this->m_bits[i] ^= rhs.m_bits[i]; + m_zero_unused_bits(); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::operator-=(const dynamic_bitset& rhs) +{ + AssertIf(size() != rhs.size()); + for (size_type i = 0; i < this->m_num_blocks; ++i) + this->m_bits[i] = this->m_bits[i] & ~rhs.m_bits[i]; + m_zero_unused_bits(); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::operator<<=(size_type n) +{ + if (n >= this->m_num_bits) + return reset(); + //else + if (n > 0) + { + size_type const last = this->m_num_blocks - 1; // m_num_blocks is >= 1 + size_type const div = n / bits_per_block; // div is <= last + size_type const r = n % bits_per_block; + + // PRE: div != 0 or r != 0 + + if (r != 0) { + + block_type const rs = bits_per_block - r; + + for (size_type i = last-div; i>0; --i) { + this->m_bits[i+div] = (this->m_bits[i] << r) | (this->m_bits[i-1] >> rs); + } + this->m_bits[div] = this->m_bits[0] << r; + + } + else { + for (size_type i = last-div; i>0; --i) { + this->m_bits[i+div] = this->m_bits[i]; + } + this->m_bits[div] = this->m_bits[0]; + } + + + // div blocks are zero filled at the less significant end + std::fill(this->m_bits, this->m_bits+div, static_cast<block_type>(0)); + + + } + + return *this; + + +} + + + + + + + +// NOTE: this assumes that within a single block bits are +// numbered from right to left. G.P.S. +// +// static Block offset(size_type bit) +// { return bit % bits_per_block; } +// +// +// In the implementation below the 'if (r != 0)' is logically +// unnecessary. It's there as an optimization only: in fact +// for r==0 the first branch becomes the second one with the +// b[last-div] = b[last] >> r; statement that does the work of +// the last iteration. +// +inline +dynamic_bitset & dynamic_bitset::operator>>=(size_type n) { + if (n >= this->m_num_bits) { + return reset(); + } + //else + if (n>0){ + + size_type const last = this->m_num_blocks - 1; // m_num_blocks is >= 1 + size_type const div = n / bits_per_block; // div is <= last + size_type const r = n % bits_per_block; + + // PRE: div != 0 or r != 0 + + if (r != 0) { + + block_type const ls = bits_per_block - r; + + for (size_type i = div; i < last; ++i) { + this->m_bits[i-div] = (this->m_bits[i] >> r) | (this->m_bits[i+1] << ls); + } + // r bits go to zero + this->m_bits[last-div] = this->m_bits[last] >> r; + } + + else { + for (size_type i = div; i <= last; ++i) { + this->m_bits[i-div] = this->m_bits[i]; + } + // note the '<=': the last iteration 'absorbs' + // this->m_bits[last-div] = this->m_bits[last] >> 0; + } + + + + // div blocks are zero filled at the most significant end + std::fill(this->m_bits+(this->m_num_blocks-div), this->m_bits+this->m_num_blocks, static_cast<block_type>(0)); + } + + return *this; +} + + + + + + + +inline dynamic_bitset +dynamic_bitset::operator<<(size_type n) const +{ + dynamic_bitset r(*this); + return r <<= n; +} + +inline dynamic_bitset +dynamic_bitset::operator>>(size_type n) const +{ + dynamic_bitset r(*this); + return r >>= n; +} + + +//----------------------------------------------------------------------------- +// basic bit operations + +inline dynamic_bitset& +dynamic_bitset::set(size_type pos, bool val) +{ + AssertIf(pos >= this->m_num_bits); + set_(pos, val); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::set() +{ + if (this->m_num_bits > 0) { + using namespace std; + memset(this->m_bits, ~0u, this->m_num_blocks * sizeof(this->m_bits[0])); + m_zero_unused_bits(); + } + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::reset(size_type pos) +{ + AssertIf(pos >= this->m_num_bits); + reset_(pos); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::reset() +{ + if (this->m_num_bits > 0) { + using namespace std; + memset(this->m_bits, 0, this->m_num_blocks * sizeof(this->m_bits[0])); + } + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::flip(size_type pos) +{ + AssertIf(pos >= this->m_num_bits); + this->m_bits[this->word(pos)] ^= this->mask1(pos); + return *this; +} + +inline dynamic_bitset& +dynamic_bitset::flip() +{ + for (size_type i = 0; i < this->m_num_blocks; ++i) + this->m_bits[i] = ~this->m_bits[i]; + m_zero_unused_bits(); + return *this; +} + +inline bool dynamic_bitset::test(size_type pos) const +{ + #if UNITY_EDITOR + if (pos < this->m_num_bits) + return test_(pos); + else + { + ErrorString("dynamic_bitset.test bit out of bounds"); + return false; + } + #else + AssertIf(pos >= this->m_num_bits); + return test_(pos); + #endif +} + +inline bool dynamic_bitset::any() const +{ + for (size_type i = 0; i < this->m_num_blocks; ++i) + if (this->m_bits[i]) + return 1; + return 0; +} + +inline bool dynamic_bitset::none() const +{ + return !any(); +} + +inline dynamic_bitset +dynamic_bitset::operator~() const +{ + dynamic_bitset b(*this); + b.flip(); + return b; +} + + +/* snipped: [gps] + +The following is the straightforward implementation of count(), which +we leave here in a comment for documentation purposes. + +template <typename Block, typename Allocator> +typename dynamic_bitset::size_type +dynamic_bitset::count() const +{ + size_type sum = 0; + for (size_type i = 0; i != this->m_num_bits; ++i) + if (test_(i)) + ++sum; + return sum; +} + +The actual algorithm used is based on using a lookup +table. + + + The basic idea of the method is to pick up X bits at a time + from the internal array of blocks and consider those bits as + the binary representation of a number N. Then, to use a table + of 1<<X elements where table[N] is the number of '1' digits + in the binary representation of N (i.e. in our X bits). + + Note that the table can be oversized (i.e. can even have more + than 1<<X elements; in that case only the first 1<<X will be + actually used) but it cannot be undersized. + In this implementation X is 8 (but can be easily changed: you + just have to change the definition of count<>::max_bits) and + the internal array of blocks is seen as an array of bytes: if + a byte has exactly 8 bits then it's enough to sum the value + of table[B] for each byte B. Otherwise 8 bits at a time are + 'extracted' from each byte by using another loop. As a further + efficiency consideration note that even if you have, let's say, + 32-bit chars the inner loop will not do 4 (i.e. 32/8) iterations, + unless you have at least one bit set in the highest 8 bits of the + byte. + + Note also that the outmost if/else is not necessary but is there + to help the optimizer (and one of the two branches is always dead + code). + + Aras: hardcoded table to be always max_bits=8. To help not so good compilers. + +*/ + + +inline dynamic_bitset::size_type +dynamic_bitset::count() const +{ + const byte_t * p = reinterpret_cast<const byte_t*>(this->m_bits); + const byte_t * past_end = p + this->m_num_blocks * sizeof(Block); + + size_type num = 0; + + while (p < past_end) { + num += bitcount<>::table[*p]; + ++p; + } + + return num; +} + + +//----------------------------------------------------------------------------- +// conversions + +// take as ref param instead? +template <typename CharT, typename Alloc> +void +to_string(const dynamic_bitset& b, + std::basic_string<CharT, Alloc>& s) +{ + s.assign(b.size(), '0'); + for (std::size_t i = 0; i < b.size(); ++i) + if (b.test(i)) // [G.P.S.] + s[b.size() - 1 - i] = '1'; +} + + +// Differently from to_string this function dumps out +// every bit of the internal representation (useful +// for debugging purposes) +// +template <typename CharT, typename Alloc> +void +dump_to_string(const dynamic_bitset& b, + std::basic_string<CharT, Alloc>& s) +{ + std::size_t const len = b.m_num_blocks * (dynamic_bitset::bits_per_block); + s.assign(len, '0'); + for (std::size_t i = 0; i != len; ++i) + if (b[i])// could use test_ here, but we have friend issues.-JGS + s[len - 1 - i] = '1'; +} + + + +template <typename BlockOutputIterator> +void +to_block_range(const dynamic_bitset& b, + BlockOutputIterator result) +{ + AssertIf(!(b.size() != 0 || b.num_blocks() == 0)); + std::copy (b.m_bits, b.m_bits + b.m_num_blocks, result); +} + +template <typename BlockIterator> +inline void +from_block_range(BlockIterator first, BlockIterator last, + dynamic_bitset& result) +{ + AssertIf(std::distance(first, last) != result.num_blocks()); + std::copy (first, last, result.m_bits); + result.m_zero_unused_bits (); +} + +inline dynamic_bitset::size_type +dynamic_bitset::size() const +{ + return this->m_num_bits; +} + +inline dynamic_bitset::size_type +dynamic_bitset::num_blocks() const +{ + return this->m_num_blocks; +} + +inline bool dynamic_bitset:: +is_subset_of(const dynamic_bitset& a) const +{ + AssertIf(this->size() != a.size()); + for (size_type i = 0; i < this->m_num_blocks; ++i) + if (this->m_bits[i] & ~a.m_bits[i]) + return false; + return true; +} + +inline bool dynamic_bitset:: +is_proper_subset_of(const dynamic_bitset& a) const +{ + AssertIf(this->size() != a.size()); + bool proper = false; + for (size_type i = 0; i < this->m_num_blocks; ++i) { + Block bt = this->m_bits[i], ba = a.m_bits[i]; + if (ba & ~bt) + proper = true; + if (bt & ~ba) + return false; + } + return proper; +} + +//----------------------------------------------------------------------------- +// comparison + +inline bool operator==(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + using namespace std; + return (a.m_num_bits == b.m_num_bits) && + ((a.m_num_bits == 0) || + !memcmp(a.m_bits, b.m_bits, a.m_num_blocks * sizeof(a.m_bits[0]))); +} + +inline bool operator!=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a == b); +} + +inline bool operator<(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + AssertIf(a.size() != b.size()); + typedef dynamic_bitset::size_type size_type; + + if (a.size() == 0) + return false; + + // Since we are storing the most significant bit + // at pos == size() - 1, we need to do the memcmp in reverse. + + // Compare a block at a time + for (size_type i = a.m_num_blocks - 1; i > 0; --i) + if (a.m_bits[i] < b.m_bits[i]) + return true; + else if (a.m_bits[i] > b.m_bits[i]) + return false; + + if (a.m_bits[0] < b.m_bits[0]) + return true; + else + return false; +} + +inline bool operator<=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a > b); +} + +inline bool operator>(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + AssertIf(a.size() != b.size()); + typedef dynamic_bitset::size_type size_type; + + if (a.size() == 0) + return false; + + // Since we are storing the most significant bit + // at pos == size() - 1, we need to do the memcmp in reverse. + + // Compare a block at a time + for (size_type i = a.m_num_blocks - 1; i > 0; --i) + if (a.m_bits[i] < b.m_bits[i]) + return false; + else if (a.m_bits[i] > b.m_bits[i]) + return true; + + if (a.m_bits[0] > b.m_bits[0]) + return true; + else + return false; +} + +inline bool operator>=(const dynamic_bitset& a, + const dynamic_bitset& b) +{ + return !(a < b); +} + +//----------------------------------------------------------------------------- +// bitset operations + +inline dynamic_bitset +operator&(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b &= y; +} + +inline dynamic_bitset +operator|(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b |= y; +} + +inline dynamic_bitset +operator^(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b ^= y; +} + +inline dynamic_bitset +operator-(const dynamic_bitset& x, + const dynamic_bitset& y) +{ + dynamic_bitset b(x); + return b -= y; +} + + +//----------------------------------------------------------------------------- +// private member functions + +inline void dynamic_bitset:: +set_(size_type bit) +{ + this->m_bits[this->word(bit)] |= this->mask1(bit); +} + +inline void dynamic_bitset:: +set_block_(size_type blocknum, Block value) +{ + this->m_bits[blocknum] = value; +} + +inline void dynamic_bitset:: +reset_(size_type b) +{ + this->m_bits[this->word(b)] &= this->mask0(b); +} + +inline bool dynamic_bitset::test_(size_type b) const +{ + return (this->m_bits[this->word(b)] & this->mask1(b)) != static_cast<Block>(0); +} + +inline bool dynamic_bitset::set_(size_type n, bool value) +{ + if (value) + set_(n); + else + reset_(n); + return value != static_cast<Block>(0); +} + + +// 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) +// +inline void dynamic_bitset::m_zero_unused_bits() +{ + AssertIf (this->m_num_blocks != this->calc_num_blocks(this->m_num_bits)); + + // if != 0 this is the number of bits used in the last block + const size_type used_bits = this->m_num_bits % bits_per_block; + + if (used_bits != 0) + this->m_bits[this->m_num_blocks - 1] &= ~(~static_cast<Block>(0) << used_bits); + +} + +#endif |