bitsetクラスを自作する

昨日勉強したbitsetクラスですが、題材としてとても面白そうだと思ったので自作してみることにしました。

テンプレートクラスとビット演算に慣れるという意味でもちょうど良いと思います。

#include <iostream>
#include <string>
using namespace std;

template<unsigned long SIZE>
class mybitset {
public:
    mybitset () { m_bit = 0; }
    mybitset (unsigned long bit) { m_bit = bit; }
    
    mybitset<SIZE>& set () {
        m_bit = (1 << SIZE) - 1;
        return *this;
    }
    
    mybitset<SIZE>& set (size_t pos,int val=1) {
        if ( SIZE <= pos ) {
            err();
        }
        if ( val ) {
            m_bit |= (1 << pos);
        }
        else {
            m_bit &= ~(1 << pos);
        }
        return *this;
    }
    
    mybitset<SIZE>& reset () {
        m_bit = 0;
        return *this;
    }
    
    mybitset<SIZE>& reset(size_t pos) {
        if ( SIZE <= pos ) {
            err();
        }
        return set(pos,0);
    }
    
    mybitset<SIZE>& flip() {
        m_bit = ~m_bit;
        m_bit &= (1 << SIZE) - 1;
        return *this;
    }
    
    mybitset<SIZE>& flip(size_t pos) {
        if ( SIZE <= pos ) {
            err();
        }
        set(pos,((*this)[pos] ? 0 : 1));
        return *this;
    }
    
    bool test(size_t pos) const {
        if ( SIZE <= pos ) {
            err();
        }
        return (m_bit & (1 << pos)) ? true : false;
    }
    
    bool operator[](size_t pos) const {
        return test(pos);
    }
    
    bool operator==(const mybitset<SIZE>& bs) const {
        return m_bit == bs.m_bit;
    }
    
    bool operator!=(const mybitset<SIZE>& bs) const {
        return m_bit != bs.m_bit;
    }
    
    mybitset<SIZE>& operator<<=(size_t shift) {
        m_bit <<= shift;
        m_bit &= (1 << SIZE) - 1;
        return *this;
    }
    
    mybitset<SIZE>& operator>>=(size_t shift) {
        m_bit >>= shift;
        m_bit &= (1 << SIZE) - 1;
        return *this;
    }
    
    mybitset<SIZE> operator<<(size_t shift) const {
        mybitset<SIZE> bs(m_bit);
        return bs <<= shift;
    }
    
    mybitset<SIZE> operator>>(size_t shift) const {
        mybitset<SIZE> bs(m_bit);
        return bs >>= shift;
    }
    
    mybitset<SIZE> operator~() const {
        mybitset<SIZE> bs(m_bit);
        return bs.flip();
    }
    
    size_t count () const {
        size_t cnt = 0;
        for(int i=0;i<SIZE;++i ) {
            if ( m_bit & (1 << i) ) {
                ++cnt;
            }
        }
        return cnt;
    }
    
    string to_string() const {
        string str;
        str.reserve(SIZE+1);
        for(int i=1;i<=SIZE;++i ) {
            str.append( (m_bit & (1 << (SIZE-i))) ? "1" : "0" );
        }
        return str;
    }
    
    unsigned long to_ulong () const {
        return m_bit;
    }
    
    bool any () const { return m_bit != 0; }
    bool none () const { return m_bit == 0; }
    unsigned long size () const { return SIZE; }
    
private:
    unsigned long m_bit;
    void err () const {
        // 取り合えず例外吐いておく
        throw("error");
    }
};

int main () {
    mybitset<8> bs;
    
    cout << bs.size() << endl;
    
    bs.set( 1 );
    bs.set( 2 );
    
    // どれか一つでもビットが立っていたら
    if ( bs.any() ) {
        // 立っているビットを確認する
        if ( bs[0] ) { cout << "bs[0] = ON" << endl; }
        if ( bs[1] ) { cout << "bs[1] = ON" << endl; }
        if ( bs[2] ) { cout << "bs[2] = ON" << endl; }
        if ( bs[3] ) { cout << "bs[3] = ON" << endl; }
        // test関数と[]演算子のオーバーロードは同じ
        if ( bs.test(0) ) { cout << "bs[0] = ON" << endl; }
        if ( bs.test(1) ) { cout << "bs[1] = ON" << endl; }
        if ( bs.test(2) ) { cout << "bs[2] = ON" << endl; }
        if ( bs.test(3) ) { cout << "bs[3] = ON" << endl; }
    }
    
    // ビットを文字列に変換する
    cout << "to_string = " << bs.to_string() << endl;
    
    // ビットが立っている数を数える
    cout << "count = " << bs.count() << endl;
    
    // ビットを反転する
    bs.flip();
    cout << "to_string = " << bs.to_string() << endl;
    
    // ビットを数値に変換する
    cout << "to_ulong = " << bs.to_ulong() << endl;
    
    // 1番目だけビットを反転する
    bs.flip(1);
    cout << "to_string = " << bs.to_string() << endl;
    
    // 4番目のビットだけを落とす
    bs.reset( 4 );
    cout << "to_string = " << bs.to_string() << endl;
    
    // 2ビット左へずらす
    bs = bs << 2;
    cout << "to_string = " << bs.to_string() << endl;
    
    // 2ビット右へずらす
    bs >>= 2;
    cout << "to_string = " << bs.to_string() << endl;
    
    // 引数なしsetは全ビットを立てる
    bs.set();
    cout << "to_string = " << bs.to_string() << endl;
    
    // 引数なしresetは全ビットを落とす
    bs.reset();
    cout << "to_string = " << bs.to_string() << endl;
    
    // ビットが一つも立っていなかったら
    if ( bs.none() ) {
        cout << "all bit OFF" << endl;
    }
    
    return 0;
}
$ main
8
bs[1] = ON
bs[2] = ON
bs[1] = ON
bs[2] = ON
to_string = 00000110
count = 2
to_string = 11111001
to_ulong = 249
to_string = 11111011
to_string = 11101011
to_string = 10101100
to_string = 00101011
to_string = 11111111
to_string = 00000000
all bit OFF

できました。

いくつかの演算子に関しては実装していません。

基本的なものに関しては大体実装できたと思います。

エラーの処理やテスト等はまだまだ適当なのでバグもあるかとは思いますが、とりあえずは満足ということで。