/* Copyright (C) 2018 David Robillard Copyright (C) 2006-2007 Chris Hamilton This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef CHILBERT_FIXBITVEC_HPP #define CHILBERT_FIXBITVEC_HPP #include "chilbert/Operations.hpp" #include #include namespace chilbert { /* This must be an unsigned integer that is either 32 or 64 bits. Otherwise, there are places in the code that simply will not work. For speed, this should be the native word size. */ typedef uint64_t FBV_UINT; #define FBV_BITS 64 #define FBV1 ((FBV_UINT)1) #define FBV1S (~(FBV_UINT)0) #define FBVN1S(n) (n == FBV_BITS ? FBV1S : (FBV1 << n) - 1) class CFixBitVec { public: CFixBitVec(int bits = FBV_BITS) : m_rack{0} { assert(bits <= FBV_BITS); } /// Return the size in bits int size() const { return FBV_BITS; } /// Set all bits to one CFixBitVec& set() { m_rack = FBV1S; return *this; } /// Set all bits to zero CFixBitVec& reset() { m_rack = 0; return *this; } /// Return the value of the `index`th bit bool test(const int index) const { assert(0 <= index && index < FBV_BITS); return ((m_rack & (FBV1 << index)) > 0); } /// Set the `index`th bit to 1 CFixBitVec& set(const int index) { assert(0 <= index && index < FBV_BITS); m_rack |= ((FBV_UINT)1 << index); return *this; } /// Reset the `index`th bit to 0 CFixBitVec& reset(const int index) { assert(0 <= index && index < FBV_BITS); m_rack &= ~((FBV_UINT)1 << index); return *this; } /// Set the `index`th bit to `value` CFixBitVec& set(const int index, const bool value) { assert(0 <= index && index < FBV_BITS); m_rack ^= (-value ^ m_rack) & ((FBV_UINT)1 << index); return *this; } /// Flip the value of the `index`th bit CFixBitVec& flip(const int index) { assert(0 <= index && index < FBV_BITS); m_rack ^= (FBV1 << index); return *this; } bool operator==(const CFixBitVec& vec) const { return m_rack == vec.m_rack; } bool operator!=(const CFixBitVec& vec) const { return m_rack != vec.m_rack; } CFixBitVec& operator=(const FBV_UINT i) { m_rack = i; return *this; } CFixBitVec& operator&=(const CFixBitVec& vec) { m_rack &= vec.m_rack; return *this; } CFixBitVec operator&(const CFixBitVec& vec) const { CFixBitVec t(*this); t &= vec; return t; } CFixBitVec& operator|=(const CFixBitVec& vec) { m_rack |= vec.m_rack; return *this; } CFixBitVec operator|(const CFixBitVec& vec) const { CFixBitVec t(*this); t |= vec; return t; } CFixBitVec& operator^=(const CFixBitVec& vec) { m_rack ^= vec.m_rack; return *this; } CFixBitVec& operator^=(const FBV_UINT i) { m_rack ^= i; return *this; } CFixBitVec operator^(const CFixBitVec& vec) const { CFixBitVec t(*this); t ^= vec; return t; } CFixBitVec& operator<<=(const int bits) { m_rack <<= bits; return *this; } CFixBitVec operator<<(const int bits) const { CFixBitVec t(*this); t <<= bits; return t; } CFixBitVec& operator>>=(const int bits) { m_rack >>= bits; return *this; } CFixBitVec operator>>(const int bits) const { CFixBitVec t(*this); t >>= bits; return t; } /// Right-rotate the least significant `width` bits by `bits` positions CFixBitVec& rotr(const int bits, const int width) { assert(bits >= 0); assert(width > 0); assert(bits < width); m_rack &= FBVN1S(width); m_rack = (m_rack >> bits) | (m_rack << (width - bits)); m_rack &= FBVN1S(width); return *this; } /// Left-rotate the least significant `width` bits by `bits` positions CFixBitVec& rotl(int bits, int width) { assert(bits >= 0); assert(width > 0); assert(bits < width); m_rack &= FBVN1S(width); m_rack = (m_rack << bits) | (m_rack >> (width - bits)); m_rack &= FBVN1S(width); return *this; } /// Return true iff all bits are zero bool none() const { return m_rack == 0; } /// Return 1 + the index of the first set bit, or 0 if there are none int find_first() const { return chilbert::ffs(m_rack); } /// Flip all bits (one's complement) CFixBitVec& flip() { m_rack = ~m_rack; return *this; } /// Return the first rack FBV_UINT& rack() { return m_rack; } FBV_UINT rack() const { return m_rack; } /// Return a pointer to the racks FBV_UINT* racks() { return &m_rack; } const FBV_UINT* racks() const { return &m_rack; } /// Return the number of racks int rackCount() { return 1; } private: static_assert(8 * sizeof(FBV_UINT) == FBV_BITS, ""); static_assert((sizeof(FBV_UINT) == 4) || (sizeof(FBV_UINT) == 8), ""); FBV_UINT m_rack{}; }; template <> void grayCode(CFixBitVec& value) { value.rack() ^= (value.rack() >> 1); } template <> void grayCodeInv(CFixBitVec& value) { grayCodeInv(value.rack()); } } // namespace chilbert #endif