STL 的 bitset 分析(二)

#-bitset #-STL

函数 _M_do_to_ulong 将 _M_w 表示的值转换成一个无符号长整数,函数要求 _M_w[0] 以上的字都是 0 ,否则抛出异常,如果 _M_w 中只有 _M_w[0] 所在的字不为 0 。则直接返回 _M_w[0] 表示的无符号长整数。

template<size_t _Nw>
unsigned long _Base_bitset<_Nw>::_M_do_to_ulong() const
{
  for (size_t __i = 1; __i < _Nw; ++__i) 
    if (_M_w[__i]) 
      __STL_THROW(overflow_error("bitset"));
  
  return _M_w[0];
}

函数 _M_do_find_first 查找从 _M_w 的最低位开始第一个为 1 的位。如果找到则返回找到的位置,否则返回形参提供的 __not_found(__not_found 不应为 __0 到 _Nw * __BIT_PER_WORD - 1 的数)。

函数从 _M_w[0] 开始逐个查找 _M_w 中的元素,如果找到一个不为 0 的元素,则说明第一个为 1 的位在这个字中,然后再从低字节到高字节逐个查找这个字的每个字节,如果找到一个不为 0 的字节,则说明第一个为 1 的位在这个字节中,最后根据该字节的值查找第一个为 1 的位在第几位。如果 _M_w 表示的值为 0 ,则最后返回 __not_found 。

template<size_t _Nw>
size_t _Base_bitset<_Nw>::_M_do_find_first(size_t __not_found) const 
{
  for ( size_t __i = 0; __i < _Nw; __i++ ) {
    _WordT __thisword = _M_w[__i];
    if ( __thisword != static_cast<_WordT>(0) ) {
      // find byte within word
      for ( size_t __j = 0; __j < sizeof(_WordT); __j++ ) {
	unsigned char __this_byte
	  = static_cast<unsigned char>(__thisword & (~(unsigned char)0));
	if ( __this_byte )
	  return __i*__BITS_PER_WORD + __j*CHAR_BIT +
	    _First_one<true>::_S_first_one[__this_byte];

	__thisword >>= CHAR_BIT;
      }
    }
  }
  // not found, so return an indication of failure.
  return __not_found;
}

函数 _M_do_find_next 查找第 __prev 位之后第一个为 1 的位。首先 prev++(下面的__prev 都是自增之后的 __prev),然后找到 __prev 位所在的字 _M_w[__i]。然后从 _M_w[__i] 的 _S_whichbyte(__prev) 字节开始到高字节,查找是否存在不为 0 的字节,如果存在,则说明从 __prev 开始第一个为 1 的位在当前字节,然后根据该字节的值查找该字节中第一个为 1 的位在该字节的第几位。如果从 __prev 所有的位都为 0 ,则返回 __not_found 。

template<size_t _Nw>
size_t
_Base_bitset<_Nw>::_M_do_find_next(size_t __prev, size_t __not_found) const
{
  // make bound inclusive
  ++__prev;

  // check out of bounds
  if ( __prev >= _Nw * __BITS_PER_WORD )
    return __not_found;

    // search first word
  size_t __i = _S_whichword(__prev);
  _WordT __thisword = _M_w[__i];

    // mask off bits below bound
  __thisword &= (~static_cast<_WordT>(0)) << _S_whichbit(__prev);

  if ( __thisword != static_cast<_WordT>(0) ) {
    // find byte within word
    // get first byte into place
    __thisword >>= _S_whichbyte(__prev) * CHAR_BIT;
    for ( size_t __j = _S_whichbyte(__prev); __j < sizeof(_WordT); __j++ ) {
      unsigned char __this_byte
	= static_cast<unsigned char>(__thisword & (~(unsigned char)0));
      if ( __this_byte )
	return __i*__BITS_PER_WORD + __j*CHAR_BIT +
	  _First_one<true>::_S_first_one[__this_byte];

      __thisword >>= CHAR_BIT;
    }
  }

  // check subsequent words
  __i++;
  for ( ; __i < _Nw; __i++ ) {
    _WordT __thisword = _M_w[__i];
    if ( __thisword != static_cast<_WordT>(0) ) {
      // find byte within word
      for ( size_t __j = 0; __j < sizeof(_WordT); __j++ ) {
	unsigned char __this_byte
	  = static_cast<unsigned char>(__thisword & (~(unsigned char)0));
	if ( __this_byte )
	  return __i*__BITS_PER_WORD + __j*CHAR_BIT +
	    _First_one<true>::_S_first_one[__this_byte];

	__thisword >>= CHAR_BIT;
      }
    }
  }

  // not found, so return an indication of failure.
  return __not_found;
} // end _M_do_find_next

_Base_bitset 有一个偏特化定义,但模板形参 _Nw 为 1 时,使用如下定义。_Nw 为 1 说明所有位只需要一个字的变量就能存储完毕了。其具体的定义和定义在整型变量上的位运算比较类似,不再详述。

__STL_TEMPLATE_NULL struct _Base_bitset<1> {
  typedef unsigned long _WordT;
  _WordT _M_w;

  _Base_bitset( void ) : _M_w(0) {}
  _Base_bitset(unsigned long __val) : _M_w(__val) {}

  static size_t _S_whichword( size_t __pos )
    { return __pos / __BITS_PER_WORD; }
  static size_t _S_whichbyte( size_t __pos )
    { return (__pos % __BITS_PER_WORD) / CHAR_BIT; }
  static size_t _S_whichbit( size_t __pos )
    {  return __pos % __BITS_PER_WORD; }
  static _WordT _S_maskbit( size_t __pos )
    { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); }

  _WordT& _M_getword(size_t)       { return _M_w; }
  _WordT  _M_getword(size_t) const { return _M_w; }

  _WordT& _M_hiword()       { return _M_w; }
  _WordT  _M_hiword() const { return _M_w; }

  void _M_do_and(const _Base_bitset<1>& __x) { _M_w &= __x._M_w; }
  void _M_do_or(const _Base_bitset<1>& __x)  { _M_w |= __x._M_w; }
  void _M_do_xor(const _Base_bitset<1>& __x) { _M_w ^= __x._M_w; }
  void _M_do_left_shift(size_t __shift)     { _M_w <<= __shift; }
  void _M_do_right_shift(size_t __shift)    { _M_w >>= __shift; }
  void _M_do_flip()                       { _M_w = ~_M_w; }
  void _M_do_set()                        { _M_w = ~static_cast<_WordT>(0); }
  void _M_do_reset()                      { _M_w = 0; }

  bool _M_is_equal(const _Base_bitset<1>& __x) const
    { return _M_w == __x._M_w; }
  bool _M_is_any() const
    { return _M_w != 0; }

  size_t _M_do_count() const {
    size_t __result = 0;
    const unsigned char* __byte_ptr = (const unsigned char*)&_M_w;
    const unsigned char* __end_ptr
      = ((const unsigned char*)&_M_w)+sizeof(_M_w);
    while ( __byte_ptr < __end_ptr ) {
      __result += _Bit_count<true>::_S_bit_count[*__byte_ptr];
      __byte_ptr++;
    }
    return __result;
  }

  unsigned long _M_do_to_ulong() const { return _M_w; }

  size_t _M_do_find_first(size_t __not_found) const;

  // find the next "on" bit that follows "prev"
  size_t _M_do_find_next(size_t __prev, size_t __not_found) const; 

};

_Sanitize 用来将 bitset 的中多余的位清 0 。因为 bitset 中的所有的位保存在基类定义 _M_w 中,_M_w 中总的位数是 __BIT_PER_WORD * _Nw,而实际需要的位数可能居于 __BIT_PER_WORD * _Nw - 1 到 __BIT_PER_WORD * _Nw 之间。_Sanitize 会将_M_w[_Nw - 1] 中多余的位置为 0 (多余的位处在高位)。模板形参 _Extraabits 表示多出的位数。函数 _M_do_sanitize 用来实现将多余位置 0 的操作。

template <size_t _Extrabits> struct _Sanitize {
  static void _M_do_sanitize(unsigned long& __val)
    { __val &= ~((~static_cast<unsigned long>(0)) << _Extrabits); }
};

_Sanitize 的一个偏特化定义,当 _Extrabits 为 0 时表示没有多余的位,此时 _M_do_sanitize 不做任何操作。

__STL_TEMPLATE_NULL struct _Sanitize<0> {
  static void _M_do_sanitize(unsigned long) {}
};

类模板 bitset 继承自 _Base_bitset<__BITSET_WORDS(_Nb)> 。其中 _Nb 表示 bitset 中一共有 _Nb 位。__BITSET_WORDS(_Nb) 表示 _Nb 位至少需要多少个字来进行存储,以便实例化 _Base_bitset 。

template<size_t _Nb>
class bitset : private _Base_bitset<__BITSET_WORDS(_Nb)>
{

内部定义了两个成员类型 _Base 和 _WordT 。

private:
  typedef _Base_bitset<__BITSET_WORDS(_Nb)> _Base;
  typedef unsigned long _WordT;

函数 _M_do_santize 用来将基类中 _M_w 的多余位置为 0 。调用 _Sanitize<_Nb % __BIT_PER_WORD> 类的静态函数 _M_do_sanitize 来实现。_M_hiword() 返回 _M_w 中最高位置的字(_M_w[__BITSET_WORD(_Nb) - 1])。

  void _M_do_sanitize() {
    _Sanitize<_Nb%__BITS_PER_WORD>::_M_do_sanitize(this->_M_hiword());
  }

bitset 中定义了一个嵌套类,它的作用有点类似于之前介绍的迭代器,通过 reference 的实例能够索引到 bitset 的某个位。reference 被设置为 bitset 的友元类。

  class reference;
  friend class reference;

reference 类中将 bitset 也设置成了友元类,同时 reference 中定义了两个成员变量,其中 _M_wp 用来指向 bitset 中 _M_w 的中的某个字,_M_pos 用来表示当前 reference 在索引 _M_wp 指向的字中哪一个位。

    friend class bitset;

    _WordT *_M_wp;
    size_t _M_bpos;

构造函数通过一个 bitset 的实例来初始化当前 _M_wp ,用给定值 __pos 来初始化 _M_pos。

    reference( bitset& __b, size_t __pos ) {
      _M_wp = &__b._M_getword(__pos);
      _M_bpos = _Base::_S_whichbit(__pos);
    }

函数 operator= 用 __x 来对当前 reference 索引的位进行赋值,如果 __x 为 true 则将 _M_wp 指向的字中的第 _M_pos 位置为 1。否则将该位置为 0。

    reference& operator=(bool __x) {
      if ( __x )
	*_M_wp |= _Base::_S_maskbit(_M_bpos);
      else
	*_M_wp &= ~_Base::_S_maskbit(_M_bpos);

      return *this;
    }

函数 operator= 用一个 reference 的实例 __j 中的内容赋值给当前 reference。如果 __j 中 _M_wp 非空,而且 __j 中 _M_wp 的第 __j._M_pos 位为 1,则将当前 reference 中 _M_wp 指向的字中的第 _M_pos 位置为 1 。否则将该位置为 0 。

    reference& operator=(const reference& __j) {
      if ( (*(__j._M_wp) & _Base::_S_maskbit(__j._M_bpos)) )
	*_M_wp |= _Base::_S_maskbit(_M_bpos);
      else
	*_M_wp &= ~_Base::_S_maskbit(_M_bpos);

      return *this;
    }

函数 operator~() 取当前 reference 索引的位的反。如果 _M_wp 非空,判断 _M_wp 指向的字中的第 _M_pos 位是否为 1 。如果为 1 则返回 false(即 0)。否则返回 true(即 1 ),如果 _M_wp 为空,返回 1

    bool operator~() const
      { return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) == 0; }

函数 operator() 取当前 reference 索引的位的值。如果 _M_wp 非空,判断 _M_wp 指向的字中的第 _M_pos 位是否为 1 。如果为 1 则返回 true(即 1),否则返回 false(即 0)。如果 _M_wp 为空,返回 0 。

    operator bool() const
      { return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; }

函数 flip 用来将 reference 索引的位取反,前面的两个函数只是返回了需要的值,但没有对当前 reference 索引的位进行更改,但 flip 函数会改变当前 reference 索引的位。函数将 _M_wp 所指向的字与一个第 _M_pos 位为 1 ,其他位为 0 的字进行异或,达到将 _M_wp 所指向的字中的第 _M_pos 位取反的目的。

    reference& flip() {
      *_M_wp ^= _Base::_S_maskbit(_M_bpos);
      return *this;
    }

第一个构造函数为空构造函数,第二个构造函数用一个给定的无符号长整数 __val 来对当前 bitset 进行初始化。初始化列表中调用基类的构造函数,用来初始化基类的 _M_w,函数体中调用 _M_do_sanitize() 函数将多余的位置为 0 。

  bitset() {}
  bitset(unsigned long __val) : _Base_bitset<__BITSET_WORDS(_Nb)>(__val) 
    { _M_do_sanitize(); }

构造函数中用字符串 __s 中第 __pos 位以后的内容对当前 bitet 进行初始化,要求 __s 中第 __pos 位以后的内容只有字符 0 或者字符 1 。

  template<class _CharT, class _Traits, class _Alloc>
  explicit bitset(const basic_string<_CharT, _Traits, _Alloc>& __s,
		  size_t __pos = 0)
    : _Base() 
  {
    if (__pos > __s.size()) 
      __STL_THROW(out_of_range("bitset"));
    _M_copy_from_string(__s, __pos,
			basic_string<_CharT, _Traits, _Alloc>::npos);
  }

构造函数中用字符串 __s 中第 __pos 位以后的 __n 个字符对当前 bitset 进行初始化。要求 __s 中第 __pos 为以后的 __n 个字符中只能出现字符 0 或者字符 1。

  template<class _CharT, class _Traits, class _Alloc>
  bitset(const basic_string<_CharT, _Traits, _Alloc>& __s,
	 size_t __pos,
	 size_t __n)
    : _Base() 
  {
    if (__pos > __s.size()) 
      __STL_THROW(out_of_range("bitset"));
    _M_copy_from_string(__s, __pos, __n);
  }

STL 的 bitset 分析(一)</br> STL 的 bitset 分析(二)</br> STL 的 bitset 分析(三)</br> STL 的 bitset 分析(四)</br>