BitSet
前几天干了一件比较无聊的事儿——抄了一遍C++ STL bitset的源代码,把不懂的宏定义去掉了,发现(暂时)还能用,嘿嘿。
#ifndef BITSET_H #define BITSET_H #include <string> #include <stdexcept> #include <iostream> template <size_t Bits> class BitSet { public: typedef bool element_type; typedef unsigned int Type; class Reference { friend class BitSet<Bits>; public: ~Reference() {} Reference& operator=(bool val) { p->set(pos, val); return *this; } Reference& operator=(const Reference& bitRef) { p->set(pos, bool(bitRef)); return *this; } Reference& flip() { p->flip(pos); return *this; } bool operator~() const { return !p->test(pos); } operator bool() const { return p->test(pos); } private: Reference() : p(0), pos(0) {} Reference(BitSet<Bits>& bitSet, size_t pos) : p(&bitSet), pos(pos) {} BitSet<Bits> *p; size_t pos; }; bool at(size_t pos) const { return test(pos); } Reference at(size_t pos) { return Reference(*this, pos); } bool operator[](size_t pos) const { return test(pos); } Reference operator[](size_t pos) { return Reference(*this, pos); } BitSet() { tidy(); } BitSet(unsigned long long val) { tidy(); for (size_t pos = 0; val != 0 && pos < Bits; val >>= 1, ++pos) { if (val & 1) set(pos); } } BitSet(const std::string& str, std::string::size_type pos = 0, std::string::size_type count = std::string::npos, char e0 = '0', char e1 = '1') { construct(str, pos, count, e0, e1); } BitSet(const char *ptr, std::string::size_type count = std::string::npos, char e0 = '0', char e1 = '1') { construct(count == std::string::npos ? std::string(ptr) : std::string(ptr, count), 0, count, e0, e1); } void construct(const std::string& str, std::string::size_type pos, std::string::size_type count, char e0, char e1) { std::string::size_type num; if (str.size() < pos) xran(); if (str.size() - pos < count) count = str.size() - pos; if (Bits < count) count = Bits; tidy(); for (pos += count, num = 0; num < count; ++num) { if (str[--pos] == e1) set(num); else if (str[pos] != e0) xinv(); } } BitSet<Bits>& operator&=(const BitSet<Bits>& right) { for (ptrdiff_t pos = Words; 0 <= pos; --pos) { array[pos] &= right.getWord(pos); } return *this; } BitSet<Bits>& operator|=(const BitSet<Bits>& right) { for (ptrdiff_t pos = Words; 0 <= pos; --pos) { array[pos] |= right.getWord(pos); } return *this; } BitSet<Bits>& operator^=(const BitSet<Bits>& right) { for (ptrdiff_t pos = Words; 0 <= pos; --pos) { array[pos] ^= right.getWord(pos); } return *this; } BitSet<Bits>& operator<<=(size_t pos) { const ptrdiff_t wordShift = (ptrdiff_t)(pos / BitsPerWord); if (wordShift != 0) { for (ptrdiff_t wpos = Words; 0 <= wpos; --wpos) array[wpos] = (wordShift <= wpos ? array[wpos - wordShift] : 0); } if ((pos %= BitsPerWord) != 0) { // 0 < pos < BitsPerWord, shift by bits for (ptrdiff_t wpos = Words; 0 < wpos; --wpos) array[wpos] = (Type)((array[wpos] << pos) | (array[wpos - 1]) >> (BitsPerWord - pos)); array[0] <<= pos; } trim(); return *this; } BitSet<Bits>& operator>>=(size_t pos) { const ptrdiff_t wordShift = (ptrdiff_t)(pos / BitsPerWord); if (wordShift != 0) { for (ptrdiff_t wpos = 0; wpos <= Words; ++wpos) array[wpos] = (wordShift <= Words - wpos ? array[wpos + wordShift] : 0); } if ((pos %= BitsPerWord) != 0) { for (ptrdiff_t wpos = 0; wpos < Words; ++wpos) array[wpos] = (Type)((array[wpos] >> pos) | (array[wpos + 1] << (BitsPerWord - pos))); array[Words] >>= pos; } return *this; } BitSet<Bits>& set() { tidy((Type)~0); return *this; } BitSet<Bits>& set(size_t pos, bool val = true) { if (Bits <= pos) xran(); if (val) array[pos / BitsPerWord] |= (Type)1 << pos % BitsPerWord; else array[pos / BitsPerWord] &= ~((Type)1 << pos % BitsPerWord); return *this; } BitSet<Bits>& reset() { tidy(); return *this; } BitSet<Bits>& reset(size_t pos) { return set(pos, false); } BitSet<Bits>& operator~() const { return BitSet<Bits>(*this).flip(); } BitSet<Bits>& flip() { for (ptrdiff_t pos = Words; 0 <= pos; --pos) array[pos] = (Type)~array[pos]; trim(); return *this; } BitSet<Bits>& flip(size_t pos) { if (Bits <= pos) xran(); array[pos / BitsPerWord] ^= (Type)1 << pos % BitsPerWord; return *this; } unsigned long to_ulong() const { unsigned long long val = to_ullong(); unsigned long ans = (unsigned long)val; if (ans != val) xofllo(); return ans; } unsigned long long to_ullong() const { ptrdiff_t pos = Words; for (; (ptrdiff_t)(sizeof(unsigned long long) / sizeof(Type)) <= pos; --pos) { if (array[pos] != 0) xofllo(); } unsigned long long val = array[pos]; while (0 <= --pos) val = ((val << (BitsPerWord - 1)) << 1) | array[pos]; return val; } std::string to_string(char e0 = '0', char e1 = '1') const { std::string str; str.reserve(Bits); std::string::size_type pos = Bits; while (0 < pos) { if (test(--pos)) str += e1; else str += e0; } return str; } size_t count() const { const char *const BitsPerByte = "\0\1\1\2\1\2\2\3\1\2\2\3\2\3\3\4" "\1\2\2\3\2\3\3\4\2\3\3\4\3\4\4\5" "\1\2\2\3\2\3\3\4\2\3\3\4\3\4\4\5" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\1\2\2\3\2\3\3\4\2\3\3\4\3\4\4\5" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\3\4\4\5\4\5\5\6\4\5\5\6\5\6\6\7" "\1\2\2\3\2\3\3\4\2\3\3\4\3\4\4\5" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\3\4\4\5\4\5\5\6\4\5\5\6\5\6\6\7" "\2\3\3\4\3\4\4\5\3\4\4\5\4\5\5\6" "\3\4\4\5\4\5\5\6\4\5\5\6\5\6\6\7" "\3\4\4\5\4\5\5\6\4\5\5\6\5\6\6\7" "\4\5\5\6\5\6\6\7\5\6\6\7\6\7\7\x8"; const unsigned char *ptr = (const unsigned char *)(const void *)array; const unsigned char *const end = ptr + sizeof(array); size_t val = 0; for (; ptr != end; ++ptr) val += BitsPerByte[*ptr]; return val; } size_t size() const { return Bits; } bool operator==(const BitSet<Bits>& right) const { for (ptrdiff_t pos = Words; 0 <= pos; --pos) { if (array[pos] != right.getWord(pos)) return false; } return true; } bool operator!=(const BitSet<Bits>& right) const { return !(*this == right); } bool test(size_t pos) const { if (Bits < pos) xran(); return (array[pos / BitsPerWord] & ((Type)1 << pos % BitsPerWord)) != 0; } bool any() const { for (ptrdiff_t pos = Words; 0 <= pos; --pos) { if (array[pos] != 0) return true; } return false; } bool none() const { return !any(); } bool all() const { return count() == size(); } BitSet<Bits> operator<<(size_t pos) const { return BitSet<Bits>(*this) <<= pos; } BitSet<Bits> operator>>(size_t pos) const { return BitSet<Bits>(*this) >>= pos; } Type getWord(size_t pos) const { return array[pos]; } private: static const ptrdiff_t BitsPerWord = (ptrdiff_t)(CHAR_BIT * sizeof(Type)); static const ptrdiff_t Words = (ptrdiff_t)(Bits == 0 ? 0 : (Bits - 1) / BitsPerWord); void tidy(Type val = 0) { for (ptrdiff_t pos = Words; 0 <= pos; --pos) array[pos] = val; if (val != 0) trim(); } void trim() { if (Bits % BitsPerWord != 0) array[Words] &= ((Type)1 << Bits % BitsPerWord) - 1; } void xinv() const { throw std::invalid_argument("invalid BitSet<N> char"); } void xofllo() const { throw std::overflow_error("BitSet<N> overflow"); } void xran() const { throw std::out_of_range("invalid BitSet<N> position"); } Type array[Words + 1]; }; template<size_t Bits> BitSet<Bits> operator&(const BitSet<Bits>& left, const BitSet<Bits>& right) { BitSet<Bits> ans = left; return ans &= right; } template<size_t Bits> BitSet<Bits> operator|(const BitSet<Bits>& left, const BitSet<Bits>& right) { BitSet<Bits> ans = left; return ans |= right; } template<size_t Bits> BitSet<Bits> operator^(const BitSet<Bits>& left, const BitSet<Bits>& right) { BitSet<Bits> ans = left; return ans ^= right; } template<size_t Bits> std::ostream& operator<<(std::ostream& os, const BitSet<Bits>& right) { return os << right.to_string(); } template<size_t Bits> std::istream& operator>>(std::istream& is, BitSet<Bits>& right) { char e1 = '1'; char e0 = '0'; std::ios_base::iostate state = std::ios_base::goodbit; bool changed = false; std::string str; const std::istream::sentry ok(is); if (ok) { try { int meta = is.rdbuf()->sgetc(); for (size_t count = right.size(); 0 < count; meta = is.rdbuf()->snextc(), --count) { char c; if (meta == EOF) { state |= std::ios_base::eofbit; break; } else if ((c = (char)meta) != e0 && c != e1) break; else if (str.max_size() <= str.size()) { state |= std::ios_base::failbit; break; } else { if (c == e1) str.append(1, '1'); else str.append(1, '0'); changed = true; } } } catch (...) { is.setstate(std::ios_base::badbit, true); } } if (!changed) state |= std::ios_base::failbit; is.setstate(state); right = BitSet<Bits>(str); return is; } #endif