C++标准为处理二进制数值提供了两个工具:vector<bool>和bitset.
vector<bool> 是对元素类型为bool的vector特化,它内部并不真正存储bool值而是以bit来压缩保存,使用代理技术来操作bit,造成的后果就是它很像容器,大多数情况下的行为与标准容器一样,但它不是容器,不满足容器的定义。
bitset与vector<bool> 类似,同样存储二进制,但它的的大小固定,而且比vector<bool>支持更多的位运算。
两者的优缺点:vector<bool>可以动态增长,但不能方便地进行位运算;bitset则可以方便地对容纳的二进制位做位运算,但是不能动态的增长。
boost.dynamic_bitset 的出现恰好填补了这两者之间的空白,它类似标准库的bitset,提供丰富的位运算,同时长度又是动态可变的。

类摘要

template <typename Block, typename Allocator>
class dynamic_bitset
{
public:
    explicit dynamic_bitset();/// 构造函数
    dynamic_bitset(const dynamic_bitset& b);
    /// 基本操作
    void  swap(dynamic_bitset& b);
    void  resize(size_type num_bit, bool value = false);
    void  clear();
    void  push_back(bool bit);
    void  apend(Block block);
    ///  操作符重载
    bool operator[](size_type pos)const; 
    dynamic_bitset& operator&=(const dynamic_bitset& b);
    dynamic_bitset& operator|=(const dynamic_bitset& b);
    ...
    /// 
    dynamic_bitset&  set();
    dynamic_bitset&  reset();
    dynamic_bitset&  filp();
    /// 测试
    bool test(size_type n) const;
    bool any() const;
    bool none() const;
    dynamic_bitset operator~()const;
    size_type count() const;
    /// 转型到 ulong
    unsigned long to_ulong() cosnt;
    /// 容量操作
    size_type  size()const;
    size_type  num_blocks() const;
    size_type  max_size() const;
    bool       empty() const;
    /// 集合操作
    bool  is_subset_of(const dynamic_bitset& a)const;
    bool  is_proper_subset_of(const dynamic_bitset& a)const;
    /// 查找元素
    size_type  find_first()const;
    size_type  find_next(size_type pos) const;
};
dynamic_bitset 几乎与std::bitset相同,包括接口和行为,唯一的区别是:dynamic_bitset的大小是在构造函数中又参数决定的,而且运行时时动态可变的。
注意:与vecor<bool>和bitset一样,dynamic_bitset不符合标准容器的定义,不是严格意义样的容器,不提供迭代器的支持。

创建与赋值

dynamic_bitset的第一个模板参数Block指示dynamic_bitset以什么整数类型存储二进制位,必须是一个无符号整数,默认是unsigned long。第二个参数Allocator是类内部使用的内存分配器,默认是std::allocator<Block>。   
 - 不带参数的构造函数创建一个大小为0的dynamic_bitset对象
 - 传入参数制定dynamic_bitset的大小并赋初值,像标准容易一样
 - 从另一个dynamic_bitset拷贝构造
 - 从 01 字符串构造(与std::bitset一样都要求是std::string字符串)
 dynamic_bitset<> db1;        /// 空的dynamic_bitset 对象
    dynamic_bitset<> db2(10);    /// 创建一个大小为10的对象
    dynamic_bitset<> db3(0x16,    
    BOOST_BINARY(10101));       //注意这里,使用了boost宏 BOOST_BINARY 构造一个编译期的二进制数
    dynamic_bitset<> db4(string("0100"));  ///字符串构造
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;
    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl; /// operator[]

容器操作

dynamic_bitset 可以使用resize()成员函数在运行时调整容器的大小,扩展或者收缩都是允许的,并且可以用true/false或者1/0指定扩展后新元素的默认值。
如果是扩展,那么原来有的二进制位保持不变,新增的二进制位被指为指定的值:如果是收缩,那么收缩后容量的二进制位保持不变,多余的二进制位被抛弃,此时设置新元素的默认值是无意义的。
    dynamic_bitset<> db;///空的dynamic_bitset对象

    db.resize(10, true);///扩展为10个二进制,全部为1
    cout << db << endl; /// 1111111111

    db.resize(5);       /// 缩小容量为5个二进制
    cout << db << endl; /// 11111

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();    /// 清空 效率比resize效率高
        assert(db.empty()&& db.size()==0);

    }
    /// dynamic_bitset 使用Block来存储二进制位,因此,size()函数不能
    /// 反映dynamic_bitset所占用的内存大小。
    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true); /// 实际上是项二进制最高位添加
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));/// 实际上是项二进制最高位添加
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl; //0000000000000000000000000000010101001
    }

位运算与比较运算

与vector<bool>相似,dynamic_bitset也运用了代理技术,重载了operator[], operator|等操作符,因此可以像普通数字一样访问其中的二进制位,而且能对二进制或者整个容器做任意位运算,当然吹不能做加减乘除
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;  ///按位与运算
    db1[1] ^= 1;  ///按位异或运算
    cout << db1 << endl;/// 1000

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;///1101
    cout << (db1 | db2) << endl;///1101

访问元素

除了使用operator[]直接访问容器内的元素外,dynamic—bitset还有个成员函数用于测试或者重置二进制位。
1.test()函数检测第n位是否为1
2.如果容器中存在二进制位1,那么any()返回true
3.如果容器中不存在二进制位1,那么none()返回true
4.count()函数统计容器中所有值为1的元素数量
5.set()函数可以置全部或者特定的位置的值为0或者1
6.reset()可以置全部或者特定的位置的值为0
7.flip()可以反转全部或者特定的位置的值
8.find_first()从0位置开始查找,返回第一个值为1的位置
9.find_next(pos)从第pos位置开始差值,返回第一个值为1的位置,如果查找不到,返回npos.

“`
dynamic_bitset<> db(4, BOOST_BINARY(0101));

assert(db.test(0) && !db.test(1));
assert(db.any() && !db.none());
assert(db.count() == 2);  ///值为1 的个数

{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    db.flip(); /// 反转
    assert(db.to_ulong() == BOOST_BINARY(1010));

    db.set();
    assert(!db.none());

    db.reset();
    assert(!db.any() );

    db.set(1, 1);
    assert(db.count() == 1);

}

{
    dynamic_bitset<> db(5, BOOST_BINARY(00101));

    auto pos = db.find_first();
    assert(pos == 0);

    pos = db.find_next(pos);
    assert(pos == 2);

}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐