本次带来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;
}
运行结果: