位集Bitset的实现

本次带来Bitset模板库,除了跟标准库作全部兼容之外,还对C++14及以上版本环境进行了优化,可将对象声明为constexpr。

编译环境:C++11

源码:

#ifndef BITSET_H
#define BITSET_H

#include <iosfwd>
#include <string>

#if __cplusplus >= 201703L
#define CXX17_CONSTEXPR constexpr
#else 
#define CXX17_CONSTEXPR
#endif 

#if __cplusplus >= 201402L
#define CXX14_CONSTEXPR constexpr
#else 
#define CXX14_CONSTEXPR
#endif 

namespace _bitset_impl
{

template<typename _Tp, unsigned long _Bits>
struct MaxValue;

template<typename _Tp>
struct MaxValue<_Tp, 1>
{
    static constexpr _Tp value = 1;
};

template<typename _Tp, unsigned long _Bits>
struct MaxValue
{
    static constexpr _Tp value = MaxValue<_Tp, _Bits - 1>::value << 1 | 1;
};

template<typename _Tp, unsigned long _Top, unsigned long _Bottom>
struct Mask;

template<typename _Tp>
struct Mask<_Tp, 1, 1>
{
    static constexpr _Tp value = 1;
};

template<typename _Tp, unsigned long _Top, unsigned long _Bottom>
struct Mask
{
    static_assert(_Top >= _Bottom, "[_Top] cannot smaller than [_Bottom]");
    static_assert(_Bottom <= sizeof(_Tp) * 8, "[_Bottom] cannot greater than size of [_Tp]");

    static constexpr _Tp value = MaxValue<_Tp, _Top - _Bottom + 1>::value << _Bottom;
};

static CXX14_CONSTEXPR std::size_t BitMask(std::size_t __pos)
{ return 1 << __pos; } 

static CXX14_CONSTEXPR std::size_t BitMask(std::size_t __top, std::size_t __bottom)
{ 
    std::size_t __ret = 0;
    while(__top-- > __bottom)
    { __ret |= BitMask(__top); }
    return __ret;
} 

static CXX14_CONSTEXPR std::size_t BitCount(std::size_t __v)
{
    std::size_t __c = 0;
    while(__v != 0)
    {
        __v &= __v - 1;
        ++__c;
    }
    return __c;
}

}

template<unsigned long N>
class Bitset
{
public:
    static_assert(N > 0, "the number of bits must be greater than 0!!!");

    static constexpr std::size_t UNIT_SIZE = N / sizeof(std::size_t);
    static constexpr std::size_t BYTE_SIZE = N / sizeof(std::size_t) / 8 + static_cast<bool>(N % (sizeof(std::size_t) * 8));
    static constexpr std::size_t BIT_SIZE = sizeof(std::size_t) * 8;

    std::size_t _M_value[BYTE_SIZE] = {0};

    static CXX14_CONSTEXPR std::size_t _S_BitIndex(std::size_t __pos)
    { return __pos % (sizeof(std::size_t) * 8); }

    static CXX14_CONSTEXPR std::size_t _S_ByteIndex(std::size_t __pos)
    { return __pos / sizeof(std::size_t) / 8; }

public:
    class Reference;

public:
    CXX14_CONSTEXPR Bitset() {}
    CXX14_CONSTEXPR Bitset(char __v) : Bitset(static_cast<long long>(__v)) {}
    CXX14_CONSTEXPR Bitset(short __v) : Bitset(static_cast<long long>(__v)) {}
    CXX14_CONSTEXPR Bitset(int __v) : Bitset(static_cast<long long>(__v)) {}
    CXX14_CONSTEXPR Bitset(unsigned char __v) : Bitset(static_cast<unsigned long long>(__v)) {}
    CXX14_CONSTEXPR Bitset(unsigned short __v) : Bitset(static_cast<unsigned long long>(__v)) {}
    CXX14_CONSTEXPR Bitset(unsigned int __v) : Bitset(static_cast<unsigned long long>(__v)) {}

    CXX14_CONSTEXPR Bitset(long long __v)
    { _M_value[0] = __v; }

    CXX14_CONSTEXPR Bitset(unsigned long long __v)
    { _M_value[0] = __v; }

    template<std::size_t _Nb>
    CXX14_CONSTEXPR Bitset(const Bitset<_Nb> &__o)
    { this->operator=<_Nb>(__o); }

    CXX14_CONSTEXPR Bitset(const std::string &__s)
    {
        std::size_t __l = __s.size() > N ? N : __s.size();
        auto __it = __s.begin();
        for(std::size_t __i = 0; __i < __l; ++__i)
        { (*this)[__l - __i - 1] = *__it++ == '1'; }
    }

    CXX14_CONSTEXPR bool any() const 
    {
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        {
            if(_M_value[__i])
            { return true; }
        }
        return false;
    }

    CXX14_CONSTEXPR bool none() const 
    { return !any(); }

    CXX14_CONSTEXPR bool all() const 
    {
        constexpr std::size_t __m = _bitset_impl::Mask<std::size_t, sizeof(std::size_t) - 1, 1>::value;
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        {
            if(_M_value[__i] & __m != __m)
            { return false; }
        }
        return true;
    }

    CXX14_CONSTEXPR std::size_t count() const 
    {
        std::size_t __c = 0;
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        { __c += _bitset_impl::BitCount(_M_value[__i]); }
        return __c;
    }

    CXX14_CONSTEXPR Bitset& flip()
    {
        if CXX17_CONSTEXPR (N % sizeof(std::size_t) == 0)
        { _M_value[BYTE_SIZE - 1] = ~_M_value[BYTE_SIZE - 1]; }
        else 
        {
            constexpr std::size_t __m = _bitset_impl::Mask<std::size_t, N % sizeof(std::size_t) - 1, 1>::value;
            _M_value[BYTE_SIZE - 1] ^= __m;
        }
        for(std::size_t __i = 0; __i < BYTE_SIZE - 1; ++__i)
        { _M_value[__i] = ~_M_value[__i]; }
        return *this;
    }

    CXX14_CONSTEXPR bool operator[](std::size_t __pos) const 
    { return (_M_value[_S_ByteIndex(__pos)] & _bitset_impl::BitMask(_S_BitIndex(__pos))) != 0; }

    Reference operator[](std::size_t __pos)
    { return Reference(&_M_value[0], __pos); }

    std::string to_string() const 
    {
        std::string __ret(N, 0);
        for(std::size_t __i = 0; __i < N; ++__i)
        { __ret[N - __i - 1] = (*this)[__i] ? '1' : '0'; }
        return __ret;
    }

    friend std::ostream& operator<<(std::ostream &__os, const Bitset &__v)
    { return __os << __v.to_string(); }

    CXX14_CONSTEXPR Bitset<N> operator~() const 
    {
        Bitset<N> __ret;
        constexpr std::size_t __l = N % (sizeof(std::size_t) * 8);
        constexpr std::size_t __m = _bitset_impl::Mask<std::size_t, __l, 0>::value;
        for(std::size_t __i = 0; __i < BYTE_SIZE - 1; ++__i)
        { __ret._M_value[__i] = ~_M_value[__i]; }
        __ret._M_value[BYTE_SIZE - 1] = _M_value[BYTE_SIZE - 1] ^ __m;
        return __ret;
    }

    CXX14_CONSTEXPR Bitset<N>& operator|=(const Bitset<N> &__o)
    {
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        { _M_value[__i] |= __o._M_value[__i]; }
        return *this;
    }

    CXX14_CONSTEXPR Bitset<N>& operator&=(const Bitset<N> &__o)
    {
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        { _M_value[__i] &= __o._M_value[__i]; }
        return *this;
    }

    CXX14_CONSTEXPR Bitset<N>& operator^=(const Bitset<N> &__o)
    {
        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        { _M_value[__i] ^= __o._M_value[__i]; }
        return *this;
    }

    CXX14_CONSTEXPR Bitset<N>& operator<<=(std::size_t __c)
    {
        using namespace _bitset_impl;

        for(std::size_t __i = BYTE_SIZE; __i > 0; --__i)
        {
            std::size_t __index = __i - 1;
            if(__c >= BIT_SIZE)
            {
                _M_value[__index] = 0;
                __c -= BIT_SIZE;
            }
            else 
            {
                __c = BIT_SIZE - __c;

                std::size_t __tmp = 0;
                if(__index > 0)
                { __tmp = _M_value[__index - 1] & BitMask(BIT_SIZE, __c); }
                _M_value[__index] <<= BIT_SIZE - __c;
                _M_value[__index] |= __tmp >> __c;
            }
        }
        return *this;
    }

    CXX14_CONSTEXPR Bitset<N>& operator>>=(std::size_t __c)
    {
        using namespace _bitset_impl;

        for(std::size_t __i = 0; __i < BYTE_SIZE; ++__i)
        {
            if(__c >= BIT_SIZE)
            {
                _M_value[__i] = 0;
                __c -= BIT_SIZE;
            }
            else 
            {
                __c = BIT_SIZE - __c;

                std::size_t __tmp = 0;
                if(__i < BYTE_SIZE - 1)
                { __tmp = _M_value[__i + 1] & BitMask(BIT_SIZE - __c, 0); }
                _M_value[__i] >>= BIT_SIZE - __c;
                _M_value[__i] |= __tmp << __c;
            }
        }
        return *this;
    }

    CXX14_CONSTEXPR Bitset<N> operator<<(std::size_t __c) const
    {
        Bitset<N> __ret(*this);
        __ret <<= __c;
        return __ret;
    }

    CXX14_CONSTEXPR Bitset<N> operator>>(std::size_t __c) const
    {
        Bitset<N> __ret(*this);
        __ret >>= __c;
        return __ret;
    }

    CXX14_CONSTEXPR Bitset<N> operator&(const Bitset<N> &__o) const
    {
        Bitset<N> __ret(*this);
        __ret &= __o;
        return __ret;
    }

    CXX14_CONSTEXPR Bitset<N> operator|(const Bitset<N> &__o) const
    {
        Bitset<N> __ret(*this);
        __ret |= __o;
        return __ret;
    }

    CXX14_CONSTEXPR Bitset<N> operator^(const Bitset<N> &__o) const
    {
        Bitset<N> __ret(*this);
        __ret ^= __o;
        return __ret;
    }

    template<std::size_t _Nb>
    CXX14_CONSTEXPR Bitset<N>& operator=(const Bitset<_Nb> &__o)
    {
        constexpr std::size_t __m = _Nb > N ? N : _Nb;
        CXX14_CONSTEXPR std::size_t __mb = _S_ByteIndex(__m);
        for(std::size_t __i = 0; __i < __mb; ++__i)
        { _M_value[__i] = __o._M_value[__i]; }

        if CXX17_CONSTEXPR (N > _Nb)
        {
            for(std::size_t __i = __mb; __i < BYTE_SIZE; ++__i)
            { _M_value[__i] = 0; }
        }
        return *this;
    }

    template<std::size_t _Nb>
    CXX14_CONSTEXPR bool operator==(const Bitset<_Nb> &__o) const
    {
        constexpr std::size_t __m = _Nb > N ? N : _Nb;
        if CXX17_CONSTEXPR (_Nb > N)
        {
            for(std::size_t __i = __o.BYTE_SIZE; __i > N; --__i)
            { 
                if(__o._M_value[__i - 1] != 0)
                { return false; }
            }
        }
        else 
        {
            for(std::size_t __i = BYTE_SIZE; __i > _Nb; --__i)
            { 
                if(_M_value[__i - 1] != 0)
                { return false; }
            }
        }
        for(std::size_t __i = 0; __i < __m; ++__i)
        {
            if(_M_value[__i] != __o._M_value[__i])
            { return false; }
        }
        return true;
    }

    CXX14_CONSTEXPR unsigned long to_ulong() const 
    { return static_cast<unsigned long>(_M_value[0]); }

    CXX14_CONSTEXPR unsigned long long to_ullong() const 
    { return static_cast<unsigned long long>(_M_value[0]); }

public:
    class Reference
    {
    private:
        friend class Bitset;

        std::size_t *_M_value;
        std::size_t _M_pos;

        Reference() {}

        Reference(std::size_t *__v, std::size_t __pos)
         : _M_value(&__v[_S_ByteIndex(__pos)]), _M_pos(_S_BitIndex(__pos)) { }

    public: 
        ~Reference() {}

        Reference& operator=(bool __v)
        {
            if(__v)
            { *_M_value |= _bitset_impl::BitMask(_M_pos); }
            else 
            { *_M_value &= ~_bitset_impl::BitMask(_M_pos); }
            return *this;
        }

        Reference& operator=(const Reference &__r)
        {
            if(__r)
            { *_M_value |= _bitset_impl::BitMask(_M_pos); }
            else 
            { *_M_value &= ~_bitset_impl::BitMask(_M_pos); }
            return *this;
        }

        operator bool() const
        { return *_M_value & _bitset_impl::BitMask(_M_pos); }

        Reference& flip()
        {
            *_M_value ^= _bitset_impl::BitMask(_M_pos);
            return *this;
        }
    };
};

#endif // BITSET_H

应用constexpr的测试代码:

#include <iostream>

int main()
{
    constexpr Bitset<24> e(8 + 16);
    std::cout << e << std::endl;
    std::cout << (e << 2) << std::endl;
    std::cout << (e >> 3) << std::endl;
    std::cout << (e ^ 2) << std::endl;
    std::cout << (~e) << std::endl;
    return 0;
}

运行结果:

猜你喜欢

转载自blog.csdn.net/qq811299838/article/details/110413210