STL源码阅读(九)

STL源码阅读(九)(SGI STL v3.3)

limits (<limits>)

提供编译时算术类型变量的属性信息。

valarray (<valarray>)

数值数组类

// valarray的元素选择类
class slice {
 ...
private:
  size_t _M_start;  // 起始元素的位置 
  size_t _M_length; // 元素的个数
  size_t _M_stride; // 元素之间的步长
 ...
}
// slice作为角标号的帮助类
template <class _Tp>
class slice_array {
  friend class valarray<_Tp>;
public:
  typedef _Tp value_type;
 ...
  slice          _M_slice;  // 下标
  valarray<_Tp>& _M_array;  // 数值数组
 ...

// 定义了=、*=、/=、%=、+=、-=、^=、&=、|=、<<=、>>=,算术、逻辑与移位操作
// 操作都是在指定的角标处的元素上进行运算的,看一小段源码即可明白
void operator=(const valarray<value_type>& __x) const {
    size_t __index = _M_slice.start();
    for (size_t __i = 0;
         __i < _M_slice.size();
         ++__i, __index += _M_slice.stride()) // 对于赋值数组__x是以1为角标步长的
      _M_array[__index] = __x[__i];
}
}
// valarray的元素选择类,可以选择多组(形成多维数组)
class gslice {
private:
  size_t _M_start;  // 起始元素下标
  valarray<size_t> _M_lengths;  // 每一维的元素个数
  valarray<size_t> _M_strides;  // 定义每一维元素之间的步长
 ...
}
template <class _Tp>
class gslice_array {
  friend class valarray<_Tp>;
public:
  typedef _Tp value_type;
 ...
  gslice                _M_gslice;  // 下标
  valarray<value_type>& _M_array;   // 数值数组
 ...
}

// 所定义的操作符类似于slice_array,只不过前者是多维的
// 在有效的下标处进行操作
template <class _Tp>
class mask_array {
  friend class valarray<_Tp>;
public:
  typedef _Tp value_type;
 ...
  valarray<bool> _M_mask;
  valarray<_Tp>& _M_array;
 ...
}
// 在指定的一些下标处进行操作
template <class _Tp>
class indirect_array {
  friend class valarray<_Tp>;
public:
  typedef _Tp value_type;
 ...
  valarray<size_t> _M_addr;
  valarray<_Tp>&   _M_array;
 ...
}
// valarray基类
template <class _Tp> 
struct _Valarray_base {
 ...
    _Tp*   _M_first;    // 指向数组的指针,分配的是一段连续内存
    size_t _M_size;     // 数组大小
 ...
    // 使用malloc和free来分配、释放内存
}

template <class _Tp> 
class valarray : private _Valarray_base<_Tp> {
 ...
  friend class gslice;

public:
    typedef _Tp value_type;
    // 注意标量赋值是将所有元素赋为同一个值
   valarray& operator=(const value_type& __x) {
     fill_n(this->_M_first, this->_M_size, __x);
     return *this;
   }

    // 注意resize会先释放原内存,然后再分配__n*sizeof(value_type)
    // 大小的内存,并以__x初始化每个元素
  void resize(size_t __n, value_type __x = value_type()) {
    destroy(this->_M_first, this->_M_first + this->_M_size);
    this->_Valarray_base<_Tp>::_M_deallocate();
    this->_Valarray_base<_Tp>::_M_allocate(__n);
    uninitialized_fill_n(this->_M_first, this->_M_size, __x);
  }
 ...
}

// 注意operator*是按照对应元素相乘的,不是向量乘。其它算术操作同理
template <class _Tp> inline valarray<_Tp> operator*(const valarray<_Tp>& __x,
                               const valarray<_Tp>& __y) {
  typedef typename valarray<_Tp>::_NoInit _NoInit;
  valarray<_Tp> __tmp(__x.size(), _NoInit());
  for (size_t __i = 0; __i < __x.size(); ++__i)
    __tmp[__i] = __x[__i] * __y[__i];
  return __tmp;
}

// 返回一个新的数值数组,它的元素是原数组平移n(正值向左,负值向右)后的元素的副本
template <class _Tp>
valarray<_Tp> valarray<_Tp>::shift(int __n) const
{
  valarray<_Tp> __tmp(this->size());

  if (__n >= 0) {
    if (__n < this->size())
      copy(this->_M_first + __n, this->_M_first + this->size(),
           __tmp._M_first);
  }
  else {
    if (-__n < this->size())
      copy(this->_M_first, this->_M_first + this->size() + __n,
           __tmp._M_first - __n);
  }
  return __tmp;
}

// 循环平移数组元素
template <class _Tp>
valarray<_Tp> valarray<_Tp>::cshift(int __m) const
{
  valarray<_Tp> __tmp(this->size());

  // Reduce __m to an equivalent number in the range [0, size()).  We
  // have to be careful with negative numbers, since the sign of a % b
  // is unspecified when a < 0.
  long __n = __m;
  if (this->size() < numeric_limits<long>::max())
    __n %= long(this->size());
  if (__n < 0)
    __n += this->size();

  copy(this->_M_first,       this->_M_first + __n,
       __tmp._M_first + (this->size() - __n));
  copy(this->_M_first + __n, this->_M_first + this->size(),
       __tmp._M_first);

  return __tmp;
}

参考资料

  1. sgi STL
  2. cppreference.com
posted @ 2016-08-06 20:28  corfox  阅读(145)  评论(0编辑  收藏  举报