Bool向量实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bool向量实现相关的知识,希望对你有一定的参考价值。

有人可以告诉我这个向量实际上是如何工作的吗?特别是关于其operator=类的operator boolVecProxy以及主类的operator[]。我知道减少内存使用量是必需的。就像bool是1字节一样,使用此类,我们可以为每个元素将其减少7位。我猜想VecProxy需要分配每一位。

所以,这是代码:

template <>
class Vector<bool>
{
private:
    typedef unsigned char byte;
    size_t _size;
    size_t _capacity;
    size_t _byte_size;
    byte* _data;
public:
    Vector(size_t capacity = 0) : _size(0),
        _capacity(capacity),
        _byte_size(0),
        _data(nullptr)
    {
        if (capacity > 0)
        {
            _data = new byte[capacity / 8 + (capacity % 8 != 0)];
            if (!_data) throw "Out of memory";
        }
    }

    class VecProxy
    {
        size_t _idx;
        byte* _vec_ptr;
    public:
        VecProxy(size_t idx, byte* vecPtr) : _idx(idx), _vec_ptr(vecPtr) {}
        VecProxy& operator=(bool val)
        {
            size_t char_idx = _idx / 8;
            size_t bit_idx = _idx % 8;
            if (val)
                _vec_ptr[char_idx] |= 1 << bit_idx;
            else
                _vec_ptr[char_idx] &= ~(1 << bit_idx);
            return *this;
        }

        operator bool()
        {
            size_t char_idx = _idx / 8;
            size_t bit_idx = _idx % 8;
            return (_vec_ptr[char_idx] >> char_idx) & 0x01;
        }
    };

    VecProxy operator[](size_t idx)
    {
        if (idx >= _size) throw "Out of bounds";
        return VecProxy(idx, _data);
    }

    Vector& resize(size_t new_size)
    {
        _capacity = new_size;
        _size = _capacity < _size ? _capacity : _size;
        _byte_size = _size / 8 + (_size % 8 != 0);
        byte* tmp = new byte[_capacity / 8 + (_capacity % 8 != 0)];
        if (!tmp) throw "Out of memory";
        for (size_t i = 0; i < _byte_size; ++i)
            tmp[i] = _data[i];
        if (!_data)
            delete[] _data;
        _data = tmp;
    }

    Vector& push_back(bool val)
    {
        if (_size == _capacity)
        {
            if (_capacity < 10)
                resize(_capacity + 10);
            else
                resize(_capacity * 1.5);
        }
        VecProxy(_size++, _data) = val;
        return *this;
    }
};

我有template<>一定有点令人困惑。但是在.h文件的其他部分中放置了标准vector的主要实现。

所以,我想指定我的问题:

  1. operator=类的VecProxy中实际发生了什么?我对if感到非常困惑。
  2. returnoperator bool()语句不清楚。
  3. 但是我实际上知道了operator[]
答案

来自

像布尔值是1个字节,并且使用此类,我们可以将每个元素减少7位。

我们知道您了解每个位都有不同的含义,每个位代表一个不同的布尔值,然后将这些位一起打包在一起以节省空间。 为了再次获得布尔值,您必须找到正确的字节,然后找到该字节中的位。 _vec_ptr[char_idx]查找正确的字节。 1 << bit_idx产生将位隔离的bit mask

让我们更仔细地看一下VecProxyoperator=

VecProxy& operator=(bool val) { size_t char_idx = _idx / 8; // find byte index size_t bit_idx = _idx % 8; // find bit index if (val) // boolean is true, so bit must be set to 1 _vec_ptr[char_idx] |= 1 << bit_idx; else // boolean false, so bit must be set to 0 _vec_ptr[char_idx] &= ~(1 << bit_idx); return *this; }

让功能进一步拆分:

VecProxy& operator=(bool val) { size_t char_idx = _idx / 8; // find byte index size_t bit_idx = _idx % 8; // find bit index byte & loc = _vec_ptr[char_idx]; // reference to byte that must be updated byte mask = 1 << bit_idx; // mask isolating bit that must be updated if (val) // boolean is true, so bit must be set to 1 loc |= mask; else // boolean false, so bit must be set to 0 loc &= ~(mask); return *this; }

如果提供的boolval,则该位需要为1。这很简单,您只需在位掩码中进行“或”即可。说我们要第三位

00000100

我们有

10101010

应用或

10101010 OR 00000100 = 10101110

但是如果值是假的,我们需要将该位设置为零。我们不能使用OR来做到这一点,但是可以使用AND来做到这一点。不幸的是,如果您这样做微不足道,则会得到

11111111 AND 00000000 = 00000000

这没用。您想保留其他位。您需要反转遮罩

11111111 AND 11111011 = 11111011

这就是~运算符在loc &= ~(mask);中所做的工作>

事实证明,赋值运算符几乎是无用的。获得VecProxy的唯一方法是通过

VecProxy operator[](size_t idx)

并且它按值返回。它不能用于在Vector中设置一个位。您可以在代理中设置一点,仅此而已。此更改无法传播到Vector

myvec[42] = true;

未能编译,因为它将更新临时副本。

通过引用返回VecProxy,以便可以更新vector是不平凡的重写。

现在让我们看一下运算符bool

operator bool() { size_t char_idx = _idx / 8; size_t bit_idx = _idx % 8; return (_vec_ptr[char_idx] >> char_idx) & 0x01; }

此函数告诉您是否设置了此代理对象表示的位。它是如何做到的:我们找到带有_vec_ptr[char_idx]的字节,然后将整个字节移开,将感兴趣的位带到第一位,并屏蔽掉除了感兴趣的位以外的所有内容。如果该位置1,则返回true。 

说我们从]开始>

10101010

我们想要第三位:

10101010 >> 2 == 00101010

((注意!注意符号扩展!如果字节是无符号的,您将得到11101010以保持数字为负。在这里无关紧要,但是在其他情况下会得到您的帮助。)

现在我们使用掩码0x01(00000001)检查该位是否已设置。

00101010 & 00000001 = 00000000

C ++从那里处理它,将0转换为false的返回值

以上是关于Bool向量实现的主要内容,如果未能解决你的问题,请参考以下文章

引用向量的部分片段?

Operator '||' cannot be applied to operands of type 'bool?' and 'bool?'(代码片段

Operator '||' cannot be applied to operands of type 'bool?' and 'bool?'(代码片段

*** Bool 编码为数字属性列表片段。属性列表编码器

Segfault 使用 bool 类型的向量

Cg入门16:Fragment shader - 片段级光照