标签:
c++标准为处理二进制数值提供了两个工具:vector<bool>和bitset。
vector<bool>是对元素类型为bool的vector特化,它的内部并不真正存储bool值,而是以bit来压缩保存、使用代理技术来操作bit,造成的后果就是它很像容器,大多数情况下和标准容器一致,但它不是容器,不满足容器的定义。
bitset与vector<bool>类似,同样存储二进制位,但它的大小固定,而且比vector<bool>支持更多的位运算。
vector<bool>和bitset各有优缺点:vector<bool>可以动态增长,但不能方便地进行位运算;bitset则正好相反,可以方便地容纳的二进制位做位运算,但不能动态增长。
boost.dynamic_bitset的出现恰好填补了这两者之间的空白,它类似于标准库的bitset,提供丰富的位运算,同时长度又是动态变化的。
dynamic_bitset位于名字空间boost,为了使用dynamic_bitset组件,需要包含头文件<boost.dynamic_bitset.hpp>,即:
#include<boost/dynamic_bitset_hpp>
using namespace boost;
下面我给出部分源码的解析(只是个人的理解):
//============================================================================= // dynamic_bitset implementation //函数的实现 //----------------------------------------------------------------------------- // constructors, etc. template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>::dynamic_bitset(const Allocator& alloc) : m_bits(alloc), m_num_bits(0) { } template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>:: 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 <typename Block, typename Allocator> inline dynamic_bitset<Block, Allocator>:: dynamic_bitset(const dynamic_bitset& b) : m_bits(b.m_bits), m_num_bits(b.m_num_bits) { } template <typename Block, typename Allocator> inline dynamic_bitset<Block, Allocator>:: ~dynamic_bitset() { assert(m_check_invariants()); } template <typename Block, typename Allocator> inline void dynamic_bitset<Block, Allocator>:: swap(dynamic_bitset<Block, Allocator>& b) // no throw { std::swap(m_bits, b.m_bits); std::swap(m_num_bits, b.m_num_bits); } //赋值 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>:: operator=(const dynamic_bitset<Block, Allocator>& b) { m_bits = b.m_bits; m_num_bits = b.m_num_bits; return *this; } template <typename Block, typename Allocator> inline typename dynamic_bitset<Block, Allocator>::allocator_type dynamic_bitset<Block, Allocator>::get_allocator() const { return m_bits.get_allocator(); } //----------------------------------------------------------------------------- // size changing operations //num_bits:代表扩展多少位二进制 //vlaue为true是代表将每一位的值为都设为1 template <typename Block, typename Allocator> void dynamic_bitset<Block, Allocator>:: resize(size_type num_bits, bool value) // strong guarantee { //num_blocks()函数返回二进制为占用的Block数量 //size() / sizeof(Block)*8 + 1 //size()函数返回二进制的位数 const size_type old_num_blocks = num_blocks(); //required_blocks统计需要的Block数量 const size_type required_blocks = calc_num_blocks(num_bits); //根据value的真假,如果value为真时,拿1填充所有的位, //否则拿0填充 const block_type v = value? ~Block(0) : Block(0); //当需要的Block数量与原来的Block数量不相等时,进行扩展 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. //当value为1并且所要扩展的位数大于原来的位数 if (value && (num_bits > m_num_bits)) { // const block_width_type extra_bits = count_extra_bits(); if (extra_bits) { 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 <typename Block, typename Allocator> void dynamic_bitset<Block, Allocator>:: clear() // no throw { m_bits.clear(); m_num_bits = 0; } template <typename Block, typename Allocator> void dynamic_bitset<Block, Allocator>:: push_back(bool bit) { //获取比特位的个数 const size_type sz = size(); //扩展一位 resize(sz + 1); //位设置 set(sz, bit); } //把整数转换为二进制位全部追加到dynamic_bitset末尾(最高位) //它将把整数转换为一个Block再追加 template <typename Block, typename Allocator> void dynamic_bitset<Block, Allocator>:: append(Block value) // strong guarantee { const block_width_type r = count_extra_bits(); if (r == 0) { //没有空间时,调用push_back进行尾插 // the buffer is empty, or all blocks are filled m_bits.push_back(value); } else { //存在空间时 //调用push_back进行追加 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; assert(m_check_invariants()); } //----------------------------------------------------------------------------- // bitset operations //运算符的实现 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::operator&=(const dynamic_bitset& rhs) { //确保两个对象的二进制位数相同 assert(size() == rhs.size()); //num_block()为Block的块数 for (size_type i = 0; i < num_blocks(); ++i) m_bits[i] &= rhs.m_bits[i]; return *this; } //|=的实现 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::operator|=(const dynamic_bitset& rhs) { 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 <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::operator^=(const dynamic_bitset& rhs) { 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 <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::operator-=(const dynamic_bitset& rhs) { 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 <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::operator<<=(size_type n) { //m_num_bits:二进制的位数 //当左移的位数大于二进制本身的位数时,相当于将每一位都置为0 if (n >= m_num_bits) return reset(); //else //当n大于0并且小于二进制位数时 if (n > 0) { //num_blocks():统计Block的块数 size_type const last = num_blocks() - 1; // num_blocks() is >= 1 //bits_per_block:每一块所占的比特数 //div:移动的位数中占几个Block size_type const div = n / bits_per_block; // div is <= last //根据移动位数计算出二进制位的下标 //r == 0 说明移动的位数正好是Block的倍数,这时我们可以移动数组的元素 block_width_type const r = bit_index(n); block_type * const b = &m_bits[0]; if (r != 0) { //r!=0时,r正是n/Block所得的余数 block_width_type const 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 { //r == 0时,直接移动数组的元素 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 // 移出的用0填充 std::fill_n(b, div, static_cast<block_type>(0)); // zero out any 1 bit that flowed into the unused part // 将未使用的比特位置0 m_zero_unused_bits(); // thanks to Lester Gong } return *this; } // // NOTE: // see the comments to operator <<= // //右移和左移的原理是一样的 template <typename B, typename A> dynamic_bitset<B, A> & dynamic_bitset<B, A>::operator>>=(size_type n) { if (n >= m_num_bits) { return reset(); } //else if (n>0) { size_type const last = num_blocks() - 1; // num_blocks() is >= 1 size_type const div = n / bits_per_block; // div is <= last block_width_type const r = bit_index(n); block_type * const b = &m_bits[0]; if (r != 0) { block_width_type const 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(b + (num_blocks()-div), div, static_cast<block_type>(0)); } return *this; } //左移和右移 //创建临时对象调用<<= 、>>=,并将对象返回 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> dynamic_bitset<Block, Allocator>::operator<<(size_type n) const { dynamic_bitset r(*this); return r <<= n; } template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> dynamic_bitset<Block, Allocator>::operator>>(size_type n) const { dynamic_bitset r(*this); return r >>= n; } //----------------------------------------------------------------------------- // basic bit operations //将某一位设置为0或1操作 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::set(size_type pos, bool val) { assert(pos < m_num_bits); if (val) //val为真是进行置位操作 //根据pos获取Block的下标 m_bits[block_index(pos)] |= bit_mask(pos); else //否则进行清零操作 reset(pos); return *this; } //set()无参数时将二进制的所有位都置为1 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::set() { std::fill(m_bits.begin(), m_bits.end(), ~Block(0)); //将未使用的比特位清0 m_zero_unused_bits(); return *this; } //将某一位置清零操作 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::reset(size_type pos) { assert(pos < m_num_bits); #if defined __MWERKS__ && BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x // CodeWarrior 8 generates incorrect code when the &=~ is compiled, // use the |^ variation instead.. <grafik> m_bits[block_index(pos)] |= bit_mask(pos); m_bits[block_index(pos)] ^= bit_mask(pos); #else m_bits[block_index(pos)] &= ~bit_mask(pos); #endif return *this; } //将二进制的所有位都进行清零操作 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::reset() { std::fill(m_bits.begin(), m_bits.end(), Block(0)); return *this; } //将二进制进行翻转某一位操作 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::flip(size_type pos) { assert(pos < m_num_bits); m_bits[block_index(pos)] ^= bit_mask(pos); return *this; } //将二进制的所有位进行翻转操作 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator>& dynamic_bitset<Block, Allocator>::flip() { for (size_type i = 0; i < num_blocks(); ++i) m_bits[i] = ~m_bits[i]; //将未使用的比特位置0 m_zero_unused_bits(); return *this; } template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>::m_unchecked_test(size_type pos) const { //根据pos的值获得Block的下标,将该下标的元素与掩码相与 return (m_bits[block_index(pos)] & bit_mask(pos)) != 0; } //检测某一位为1或0 //为1返回真 template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>::test(size_type pos) const { assert(pos < m_num_bits); return m_unchecked_test(pos); } //如果二进制位中存在1时返回真 template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>::any() const { for (size_type i = 0; i < num_blocks(); ++i) if (m_bits[i]) return true; return false; } //与any()函数相反 //当二进制中存在0时返回真 template <typename Block, typename Allocator> inline bool dynamic_bitset<Block, Allocator>::none() const { return !any(); } //取反 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> dynamic_bitset<Block, Allocator>::operator~() const { //拷贝构造另一个对象 dynamic_bitset b(*this); //调用翻转函数 b.flip(); return b; } //统计二进制中1的个数 template <typename Block, typename Allocator> typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::count() const { using detail::dynamic_bitset_impl::table_width; using detail::dynamic_bitset_impl::access_by_bytes; using detail::dynamic_bitset_impl::access_by_blocks; using detail::dynamic_bitset_impl::value_to_type; #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 3) && (__GNUC_PATCHLEVEL__ == 3) // NOTE: Explicit qualification of "bits_per_block" // breaks compilation on gcc 4.3.3 enum { no_padding = bits_per_block == CHAR_BIT * sizeof(Block) }; #else // NOTE: Explicitly qualifying "bits_per_block" to workaround // regressions of gcc 3.4.x enum { no_padding = dynamic_bitset<Block, Allocator>::bits_per_block == CHAR_BIT * sizeof(Block) }; #endif enum { enough_table_width = table_width >= CHAR_BIT }; enum { mode = (no_padding && enough_table_width) ? access_by_bytes : access_by_blocks }; return do_count(m_bits.begin(), num_blocks(), Block(0), static_cast<value_to_type<(bool)mode> *>(0)); } //----------------------------------------------------------------------------- // conversions //转换函数 template <typename B, typename A, typename stringT> void to_string_helper(const dynamic_bitset<B, A> & 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<B, A>::size_type size_type; const size_type len = dump_all? dynamic_bitset<B, A>::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 <typename Block, typename Allocator, typename stringT> inline void to_string(const dynamic_bitset<Block, Allocator>& 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 <typename B, typename A, typename stringT> inline void dump_to_string(const dynamic_bitset<B, A>& b, stringT& s) { to_string_helper(b, s, true /* =dump_all*/); } template <typename Block, typename Allocator, typename BlockOutputIterator> inline void to_block_range(const dynamic_bitset<Block, Allocator>& 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 <typename Block, typename Allocator> unsigned long dynamic_bitset<Block, Allocator>:: 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_next(ulong_width - 1) != npos) throw 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 max_size = (std::min)(m_num_bits, static_cast<size_type>(ulong_width)); const size_type last_block = block_index( max_size - 1 ); assert((last_block * bits_per_block) < static_cast<size_type>(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<result_type>(m_bits[i]) << offset); } return result; } //返回二进制的位数 template <typename Block, typename Allocator> inline typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::size() const { return m_num_bits; } //返回二进制所占的块数 template <typename Block, typename Allocator> inline typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::num_blocks() const { return m_bits.size(); } template <typename Block, typename Allocator> inline typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::max_size() const { // 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 <typename Block, typename Allocator> inline bool dynamic_bitset<Block, Allocator>::empty() const { return size() == 0; } //检测一个对象是否为另一个对象的子集 //子集就是两个二进制对象一模一样 //例如 10010 和 10010 template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>:: is_subset_of(const dynamic_bitset<Block, Allocator>& a) const { //确保两个对象的二进制位数相同 assert(size() == a.size()); for (size_type i = 0; i < num_blocks(); ++i) //不为0说明两个对象不相同 if (m_bits[i] & ~a.m_bits[i]) return false; return true; } //检测一个对象是否为另一个对象的真子集 //例如 10101和 00101 template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>:: is_proper_subset_of(const dynamic_bitset<Block, Allocator>& a) const { //确保二进制的位数相同 assert(size() == a.size()); //确保两个对象的块数相同 assert(num_blocks() == a.num_blocks()); 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 <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>::intersects(const dynamic_bitset & b) const { //common_block:取两个对象中块数较小的数 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 // //从某一块开始寻找1的位置 template <typename Block, typename Allocator> typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::m_do_find_from(size_type first_block) const { size_type i = first_block; // skip null blocks // 跳过为0的块 while (i < num_blocks() && m_bits[i] == 0) ++i; //当i大于块数时,说明没找到 if (i >= num_blocks()) return npos; // not found //找到后返回位置 return i * bits_per_block + boost::lowest_bit(m_bits[i]); } //从最低位找二进制位1 template <typename Block, typename Allocator> typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::find_first() const { return m_do_find_from(0); } //从pos位置开始找下一个二进制位1 template <typename Block, typename Allocator> typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::find_next(size_type pos) const { //获取二进制位的个数 const size_type sz = size(); //当pos大于二进制位的个数或者二进制位的个数为0时 //返回 没找到 if (pos >= (sz-1) || sz == 0) return npos; ++pos; //根据pos的值获取块的下标 const size_type blk = block_index(pos); //根据pos的值获取二进制位的下标 const block_width_type ind = bit_index(pos); // mask out bits before pos //将pos所在的块和pos在块中的下标,将该块pos之前的二进制位都清零 //如果fore为1,说明存在1 //不为1时,说明该块不存在二进制位为1,从下一块开始找 const Block fore = m_bits[blk] & ( ~Block(0) << ind ); return fore? blk * bits_per_block + lowest_bit(fore) : m_do_find_from(blk + 1); } //----------------------------------------------------------------------------- // comparison //重载比较运算符(全局函数) //== 运算符 template <typename Block, typename Allocator> bool operator==(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { return (a.m_num_bits == b.m_num_bits) && (a.m_bits == b.m_bits); } //!= 运算符 template <typename Block, typename Allocator> inline bool operator!=(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { return !(a == b); } //< 运算符 template <typename Block, typename Allocator> bool operator<(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { //确保两个对象二进制的位数相同 assert(a.size() == b.size()); typedef typename dynamic_bitset<Block, Allocator>::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 comparisons in reverse. // //从高位开始判断,首次比较小的对象就返回真 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; } //相等时返回false return false; } //<= 运算符 template <typename Block, typename Allocator> inline bool operator<=(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { return !(a > b); } //> 运算符 template <typename Block, typename Allocator> inline bool operator>(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { return b < a; } //>= 运算符 template <typename Block, typename Allocator> inline bool operator>=(const dynamic_bitset<Block, Allocator>& a, const dynamic_bitset<Block, Allocator>& b) { return !(a < b); } //----------------------------------------------------------------------------- // stream operations //重载输出<< 运算符 #ifdef BOOST_OLD_IOSTREAMS template < typename Block, typename Alloc> std::ostream& operator<<(std::ostream& os, const dynamic_bitset<Block, Alloc>& b) { // NOTE: since this is aimed at "classic" iostreams, exception // masks on the stream are not supported. The library that // ships with gcc 2.95 has an exceptions() member function but // nothing is actually implemented; not even the class ios::failure. using namespace std; const ios::iostate ok = ios::goodbit; ios::iostate err = ok; if (os.opfx()) { //try typedef typename dynamic_bitset<Block, Alloc>::size_type bitsetsize_type; const bitsetsize_type sz = b.size(); std::streambuf * buf = os.rdbuf(); size_t npad = os.width() <= 0 // careful: os.width() is signed (and can be < 0) || (bitsetsize_type) os.width() <= sz? 0 : os.width() - sz; const char fill_char = os.fill(); const ios::fmtflags adjustfield = os.flags() & ios::adjustfield; // if needed fill at left; pad is decresed along the way if (adjustfield != ios::left) { for (; 0 < npad; --npad) if (fill_char != buf->sputc(fill_char)) { err |= ios::failbit; break; } } if (err == ok) { // output the bitset for (bitsetsize_type i = b.size(); 0 < i; --i) { const char dig = b.test(i-1)? '1' : '0'; if (EOF == buf->sputc(dig)) { err |= ios::failbit; break; } } } if (err == ok) { // if needed fill at right for (; 0 < npad; --npad) { if (fill_char != buf->sputc(fill_char)) { err |= ios::failbit; break; } } } os.osfx(); os.width(0); } // if opfx if(err != ok) os.setstate(err); // assume this does NOT throw return os; } #else template <typename Ch, typename Tr, typename Block, typename Alloc> std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& os, const dynamic_bitset<Block, Alloc>& b) { using namespace std; const ios_base::iostate ok = ios_base::goodbit; ios_base::iostate err = ok; typename basic_ostream<Ch, Tr>::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'); try { typedef typename dynamic_bitset<Block, Alloc>::size_type bitsetsize_type; typedef basic_streambuf<Ch, Tr> buffer_type; buffer_type * buf = os.rdbuf(); size_t npad = os.width() <= 0 // careful: os.width() is signed (and can be < 0) || (bitsetsize_type) os.width() <= b.size()? 0 : os.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 decresed 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 (bitsetsize_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); } catch (...) { // see std 27.6.1.1/4 bool rethrow = false; try { os.setstate(ios_base::failbit); } catch (...) { rethrow = true; } if (rethrow) throw; } } if(err != ok) os.setstate(err); // may throw exception return os; } #endif #ifdef BOOST_OLD_IOSTREAMS // A sentry-like class that calls isfx in its destructor. // "Necessary" because bit_appender::do_append may throw. class pseudo_sentry { std::istream & m_r; const bool m_ok; public: explicit pseudo_sentry(std::istream & r) : m_r(r), m_ok(r.ipfx(0)) { } ~pseudo_sentry() { m_r.isfx(); } operator bool() const { return m_ok; } }; //重载输入>>运算符 template <typename Block, typename Alloc> std::istream& operator>>(std::istream& is, dynamic_bitset<Block, Alloc>& b) { // Extractor for classic IO streams (libstdc++ < 3.0) // ----------------------------------------------------// // It's assumed that the stream buffer functions, and // the stream's setstate() _cannot_ throw. typedef dynamic_bitset<Block, Alloc> bitset_type; typedef typename bitset_type::size_type size_type; std::ios::iostate err = std::ios::goodbit; pseudo_sentry cerberos(is); // skips whitespaces if(cerberos) { b.clear(); const std::streamsize w = is.width(); const size_type limit = w > 0 && static_cast<size_type>(w) < b.max_size() ? w : b.max_size(); typename bitset_type::bit_appender appender(b); std::streambuf * buf = is.rdbuf(); for(int c = buf->sgetc(); appender.get_count() < limit; c = buf->snextc() ) { if (c == EOF) { err |= std::ios::eofbit; break; } else if (char(c) != '0' && char(c) != '1') break; // non digit character else { try { appender.do_append(char(c) == '1'); } catch(...) { is.setstate(std::ios::failbit); // assume this can't throw throw; } } } // for } is.width(0); if (b.size() == 0) err |= std::ios::failbit; if (err != std::ios::goodbit) is.setstate (err); // may throw return is; } #else // BOOST_OLD_IOSTREAMS template <typename Ch, typename Tr, typename Block, typename Alloc> std::basic_istream<Ch, Tr>& operator>>(std::basic_istream<Ch, Tr>& is, dynamic_bitset<Block, Alloc>& b) { using namespace std; typedef dynamic_bitset<Block, Alloc> bitset_type; typedef typename bitset_type::size_type size_type; const streamsize w = is.width(); const size_type limit = 0 < w && static_cast<size_type>(w) < b.max_size()? w : b.max_size(); ios_base::iostate err = ios_base::goodbit; typename basic_istream<Ch, Tr>::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(); try { typename bitset_type::bit_appender appender(b); basic_streambuf <Ch, Tr> * 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 } 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 try { is.setstate(ios_base::badbit); } catch(...) { rethrow = true; } if (rethrow) throw; } } is.width(0); if (b.size() == 0 /*|| !cerberos*/) err |= ios_base::failbit; if (err != ios_base::goodbit) is.setstate (err); // may throw return is; } #endif //----------------------------------------------------------------------------- // bitset operations(全局函数) //位比较函数 //按位与(求交集) template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> operator&(const dynamic_bitset<Block, Allocator>& x, const dynamic_bitset<Block, Allocator>& y) { //创建对象(拷贝构造) dynamic_bitset<Block, Allocator> b(x); //调用与等函数 return b &= y; } //按位或(求并集) template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> operator|(const dynamic_bitset<Block, Allocator>& x, const dynamic_bitset<Block, Allocator>& y) { dynamic_bitset<Block, Allocator> b(x); return b |= y; } //按位异或 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> operator^(const dynamic_bitset<Block, Allocator>& x, const dynamic_bitset<Block, Allocator>& y) { dynamic_bitset<Block, Allocator> b(x); return b ^= y; } //求差集 template <typename Block, typename Allocator> dynamic_bitset<Block, Allocator> operator-(const dynamic_bitset<Block, Allocator>& x, const dynamic_bitset<Block, Allocator>& y) { dynamic_bitset<Block, Allocator> b(x); return b -= y; } //----------------------------------------------------------------------------- // namespace scope swap //交换函数 template<typename Block, typename Allocator> inline void swap(dynamic_bitset<Block, Allocator>& left, dynamic_bitset<Block, Allocator>& right) // no throw { left.swap(right); } //----------------------------------------------------------------------------- // private (on conforming compilers) member functions //返回需要的Block数量 template <typename Block, typename Allocator> inline typename dynamic_bitset<Block, Allocator>::size_type dynamic_bitset<Block, Allocator>::calc_num_blocks(size_type num_bits) { //num_bit代表要扩展的位数 //bits_per_block代表每一个Block有几个比特 //例如int 有32个比特 return num_bits / bits_per_block + static_cast<int>( num_bits % bits_per_block != 0 ); } // gives a reference to the highest block //引用返回 template <typename Block, typename Allocator> inline Block& dynamic_bitset<Block, Allocator>::m_highest_block() { return const_cast<Block &> (static_cast<const dynamic_bitset *>(this)->m_highest_block()); } // gives a const-reference to the highest block //返回vector的最后一个元素(常引用返回) template <typename Block, typename Allocator> inline const Block& dynamic_bitset<Block, Allocator>::m_highest_block() const { assert(size() > 0 && num_blocks() > 0); return m_bits.back(); } // 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 <typename Block, typename Allocator> inline void dynamic_bitset<Block, Allocator>::m_zero_unused_bits() { //calc_num_block():返回Block的数量 assert (num_blocks() == calc_num_blocks(m_num_bits)); // if != 0 this is the number of bits used in the last block //count_extra_bits:判断二进制位是否为Block的倍数 size() / 每个块所占的比特数 const block_width_type extra_bits = count_extra_bits(); //当extra_bits不为0时说明二进制位数不是Block的倍数,存在未使用的比特位 //将未使用的比特置0 if (extra_bits != 0) m_highest_block() &= ~(~static_cast<Block>(0) << extra_bits); } // check class invariants // 检查是否越界 template <typename Block, typename Allocator> bool dynamic_bitset<Block, Allocator>::m_check_invariants() const { //count_extra_bits:判断二进制位是否为Block的倍数 size() / 每个块所占的比特数 const block_width_type extra_bits = count_extra_bits(); //当extra_bits不为0时说明二进制位数不是Block的倍数,存在未使用的比特位 if (extra_bits > 0) { //获取掩码 block_type const mask = (~static_cast<Block>(0) << extra_bits); //将高位与掩码相与,当不为0时返回false 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 #undef BOOST_BITSET_CHAR #endif // include guard
下面对于整个类的实现做一个简单的说明:
整个类的私有数据成员包括两个: (1)m_ bits (2)m_num_bits
(1)m_bits是一个vector<Block>的数组,其类型参数Block默认为unsigned long,代表m_bits其实就是一个数组,其每个元素的类型就是unsigned long
(2)m_num_bits:二进制的位数,
数组的每一个比特就是用来保存二进制位,所有的操作都是围绕这这个数组进行的。
下面对于该类的一些操作函数简单的说明:
(a)构造函数:
该类提供了多种构造方式:
构建空的对象。
使用二进制进行构造。
使用“01”字符串进行构造。
使用unsigned long 数进行构造
使用另一个对象进行拷贝构造。
注:dynamic_bitset内部按照由高到低的顺序存储二进制位,也就是说,第0个元素存储最低位。
(b)容器的操作:
resize():调整容器的大小,扩展或收缩都是允许的,如果是扩展,原有的二进制位保持不变,新增加的二进制位用指定值置位,如果是收缩,收缩后容器的二进制位保持不变,多余的位被抛弃。
push_back():向容器末尾追加一个值;
append():把整数转换位二进制位全部追加到末尾。
(c)比较操作与位运算
==、&= 、|=、-=;
&、|、^等
(d)访问元素:
test():检测第n位是否为1
any():二进制位中存在1返回true
none():二进制位中存在0返回true
count():统计二进制位为1的数量
set():将某一位或所有位置1或置0
reset():将某一位或所有位置0
flip():反转某一位或所有位
find_first():从第0位置开始查找,返回第一个为1的位置
find_next():从第pos位置开始查找,返回第一个为1的位置,找不到返回npos
(e)类型转换:
to_ulong():将二进制转换为unsigned long
to_string():将二进制转换为一个标准字符串
(f)集合操作:
is_subset_of():检测一个对象是否为另一个对象的子集
is_proper_subset_of():检测一个对象是否为另一个对象的真子集
并集、交集、差集
上述就是类的一些基本的操作,每个函数的实现也都进行了注释,希望对大家有帮助。。。。
标签:
原文地址:http://blog.csdn.net/ooooo12345re/article/details/51619961