folly BitIterator 的源码详解(上)

Folly BitIterator 源码详解

源起

在C++编程中咱们经常会用一个bit来存储boolean的true/false,将一个字节划分我8个bit,或者一个32位int划分为32个bit来使用,非常的自然,在其他一些相对高级的变成语言中处理相对会复杂的多,甚完全不能做到。利用一个字节来存储8个bool值,大幅度提升了数据存储的效率,而且甚至还能在一定程度上提升处理的效率。

然而,对于C++来说,毕竟是多个bit被合并存放到一个byte里面去了,如果要对某个bit进行操作,或者要对整个bit的数组进行遍历,如果自己写代码去实现,那么每次定位某个bit都需要首先定位到是哪个byte,然后定位到哪个byte里面的哪个bit,还是有些小麻烦的,而且容易出错。所以,folly为我们提供了一个工具模板类,BitIterator,将一个连续的内存块当做bit数组来进行遍历访问,来帮我解决这个小麻烦。譬如:

std::vector v;

  v.push_back(0x10);

  v.push_back(0x42);

 

我们定义了一个变量v,就是一个类型我int的vector数组。然后在数组里面存放了两个整型,而程序的本意是,存放了一个bit位0x0000004200000010ULL的bit数组。现在需要对这个bit数组进行遍历操作,那么用BitIteator可以这么写:

  using base_iterator = std::vector::iterator;

  std::for_each( folly::makeBitIterator( v.begin() ),

              folly::BitIterator< base_iterator >( v.end(), 0 ),

              []( auto bit ){

                           cout << bit << endl;

                        }

              );

以上代码套用标准stl中的for_each模板函数,对bit数组进行完整的遍历,并打印出每一个bit的值,就像普通的数组一样,非常方便。

 

当然甚至可以在遍历的过程中对其中的值进行修改,如:

    std::for_each( folly::makeBitIterator( v.begin() ),

                folly::BitIterator< std::vector::iterator >( v.end(), 0 ),

   1           []( auto bit ){

                         cout << bit << endl;

                         if( bit == 0 ) bit = 1; else bit = 0;

                     }

                );

 

在1这行代码这里的auto没有声明为auto&, 即bit不是左值引用类型,而是一个左值类型,而且也不允许声明为左值引用类型。

那么为什么可以使用bit=1就可以把bit数组中的值改掉了呢?实际上这个bit进行推导后,因为本身c++也没有所谓的bit类型,folly为他建了一个代理类型来对bit进行操控,这个代理类型的完整定义为:folly::bititerator_detail::BitReference。BitReference通过两个初始化构造函数的实参指向类某个int的某个bit,并且对=进行了重载,实现了对某个bit的=赋值操作。

另外为什么不能声明为左值引用类型呢,是因为在遍历的过程中,不像vector的*iter操作,返回的是一个当前元素的引用,因为bit数组无法引用,所以folly是通过创建当前bit的一个临时对象folly::bititerator_detail::BitReference来间接地指向这个bit的,而这个代理对象是一个典型的右值类型,所以不能用auto&。

 

BitIterator的使用就是这么简单,folly就是朴素地为咱们提供一个能够统一到标准STL进行容器容器的简单的接口封装。

你可能感兴趣的:(c++开发)