Skip to content

Instantly share code, notes, and snippets.

@phoemur
Created April 27, 2018 01:27
Show Gist options
  • Save phoemur/a9f6f17cadccb70e7d516c4b92c9251e to your computer and use it in GitHub Desktop.
Save phoemur/a9f6f17cadccb70e7d516c4b92c9251e to your computer and use it in GitHub Desktop.
Dynamic Bitset in C++ implemented as a std::vector<bool>
#ifndef DYNAMIC_BITSET_HEADER
#define DYNAMIC_BITSET_HEADER
#include <algorithm>
#include <functional>
#include <iterator>
#include <numeric>
#include <stdexcept>
#include <string>
#include <sstream>
#include <type_traits>
#include <vector>
namespace Homebrew {
class DynBitSet : public std::vector<bool> { // Achtung !! No virtual destructor !!
public:
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value>, // only integral types
typename = std::enable_if_t<!std::is_same<std::decay_t<T>, DynBitSet>::value>> // don't pass self type here
DynBitSet(T num) // Allow implicit conversions
: std::vector<bool>(sizeof(T) << 3) // sizeof(T)*8
{
auto sz = this->size();
for (std::vector<bool>::size_type i=0; i<sz; ++i) {
this->operator[](i) = num >> i & 1;
}
}
explicit DynBitSet(const std::string& s)
: DynBitSet(std::stol(s)) {}
explicit DynBitSet(const char* s)
: DynBitSet(std::string(s)) {}
DynBitSet() : std::vector<bool>() {}
DynBitSet(const DynBitSet&) = default;
DynBitSet& operator=(const DynBitSet&) = default;
DynBitSet(DynBitSet&&) noexcept = default;
DynBitSet& operator=(DynBitSet&&) noexcept = default;
~DynBitSet() = default;
long to_long() const noexcept
{
return std::accumulate(this->rbegin(),
this->rend(),
0L,
[](long x, bool y) {return (x << 1) + y;});
}
std::string to_string() const
{
std::ostringstream ss;
std::copy(this->rbegin(), this->rend(), std::ostream_iterator<bool>(ss));
return ss.str();
}
bool test(std::size_t pos) const
{
if (pos < 0 || pos >= this->size())
throw std::out_of_range("Out of range access with index " + std::to_string(pos));
return this->operator[](pos);
}
std::size_t count() const noexcept
{
return std::accumulate(this->rbegin(),
this->rend(),
static_cast<std::size_t>(0));
}
DynBitSet& set() noexcept
{
std::fill(this->begin(), this->end(), true);
return *this;
}
DynBitSet& set(std::size_t pos, bool value = true)
{
if (pos < 0 || pos >= this->size())
throw std::out_of_range("Out of range access with index " + std::to_string(pos));
this->operator[](pos) = value;
return *this;
}
DynBitSet& reset() noexcept
{
std::fill(this->begin(), this->end(), false);
return *this;
}
DynBitSet& reset(std::size_t pos)
{
if (pos < 0 || pos >= this->size())
throw std::out_of_range("Out of range access with index " + std::to_string(pos));
this->operator[](pos) = false;
return *this;
}
DynBitSet& operator&=(const DynBitSet& other)
{
if (this->size() < other.size()) throw std::logic_error("First operand's size smaller than second's");
std::transform(other.begin(), other.end(),
this->begin(),
this->begin(),
std::bit_and<bool>());
return *this;
}
DynBitSet& operator|=(const DynBitSet& other)
{
if (this->size() < other.size()) throw std::logic_error("First operand's size smaller than second's");
std::transform(other.begin(), other.end(),
this->begin(),
this->begin(),
std::bit_or<bool>());
return *this;
}
DynBitSet& operator^=(const DynBitSet& other)
{
if (this->size() < other.size()) throw std::logic_error("First operand's size smaller than second's");
std::transform(other.begin(), other.end(),
this->begin(),
this->begin(),
std::bit_xor<bool>());
return *this;
}
DynBitSet operator~()
{
DynBitSet tmp (*this);
tmp.flip();
return tmp;
}
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value>>
DynBitSet& operator<<=(T num)
{
this->insert(this->begin(), num, 0);
this->erase(this->end() - num, this->end());
return *this;
}
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value>>
DynBitSet& operator>>=(T num)
{
this->resize(this->size()+num, 0);
this->erase(this->begin(), this->begin()+num);
return *this;
}
}; // class DynBitSet
bool operator==(const DynBitSet& lhs, const DynBitSet& rhs)
{
return lhs.to_long() == rhs.to_long();
}
bool operator!=(const DynBitSet& lhs, const DynBitSet& rhs) {return !(lhs == rhs);}
bool operator<(const DynBitSet& lhs, const DynBitSet& rhs)
{
return lhs.to_long() < rhs.to_long();
}
bool operator>(const DynBitSet& lhs, const DynBitSet& rhs) {return rhs < lhs;}
bool operator<=(const DynBitSet& lhs, const DynBitSet& rhs) {return !(lhs > rhs);}
bool operator>=(const DynBitSet& lhs, const DynBitSet& rhs) {return !(lhs < rhs);}
template<typename T>
DynBitSet operator^(const DynBitSet& lhs, const T& rhs)
{
DynBitSet tmp (lhs);
tmp ^= rhs;
return tmp;
}
template<typename T>
DynBitSet operator&(const DynBitSet& lhs, const T& rhs)
{
DynBitSet tmp (lhs);
tmp &= rhs;
return tmp;
}
template<typename T>
DynBitSet operator|(const DynBitSet& lhs, const T& rhs)
{
DynBitSet tmp (lhs);
tmp |= rhs;
return tmp;
}
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value>>
DynBitSet operator<<(const DynBitSet& lhs, T rhs)
{
DynBitSet tmp (lhs);
tmp <<= rhs;
return tmp;
}
DynBitSet operator<<(const DynBitSet& lhs, const DynBitSet& rhs)
{
return lhs << rhs.to_long();
}
template<typename T,
typename = std::enable_if_t<std::is_integral<T>::value>>
DynBitSet operator>>(const DynBitSet& lhs, T rhs)
{
DynBitSet tmp (lhs);
tmp >>= rhs;
return tmp;
}
DynBitSet operator>>(const DynBitSet& lhs, const DynBitSet& rhs)
{
return lhs >> rhs.to_long();
}
} // namespace Homebrew
#endif // DYNAMIC_BITSET_HEADER
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment