//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * ビットセットヘッダ
 * @author Junpee
 */

#ifndef BIT_SET_H_
#define BIT_SET_H_

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * ビットセット
 *
 * テンプレートの型にu_char, u_short, u_int等を使用してください。
 * このクラスは継承しないで下さい。
 */
template <typename Type>
class BitSet{
public:
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	BitSet() : bits_(0){}

	/**
	 * コンストラクタ
	 * @param bits ビット列
	 */
	BitSet(const Type& bits) : bits_(bits){}

	/**
	 * デストラクタ
	 */
	~BitSet(){}

	//--------------------------------------------------------------------------
	/**
	 * 長さの取得
	 * @return 長さ
	 */
	int getLength() const{ return sizeof(Type) * 8; }

	/**
	 * クリア
	 */
	void clear(){ bits_ = 0; }

	//--------------------------------------------------------------------------
	/**
	 * ビット列の設定
	 * @param bits ビット列
	 */
	void setBits(Type bits){ bits_ = bits; }

	/**
	 * ビット列の取得
	 * @return ビット列
	 */
	Type getBits() const{ return bits_; }

	//--------------------------------------------------------------------------
	// 全ビットに対する操作
	//--------------------------------------------------------------------------
	/**
	 * 補数
	 * @return ビットセット
	 */
	const BitSet& not(){
		bits_ = ~bits_;
		return (*this);
	}

	/**
	 * 全てのビットをONにする
	 * @return ビットセット
	 */
	const BitSet& onAllBits(){
		bits_ = 0;
		bits_ = ~bits_;
		return (*this);
	}

	/**
	 * 全てのビットをOFFにする
	 * @return ビットセット
	 */
	const BitSet& offAllBits(){
		bits_ = 0;
		return (*this);
	}

	/**
	 * 全てのビットを設定する
	 * @param flag trueならビットをONにします
	 * @return ビットセット
	 */
	const BitSet& setAllBits(bool flag){
		if(flag){ onAllBits(); }
		else{ offAllBits(); }
		return (*this);
	}

	//--------------------------------------------------------------------------
	// ビットセットによるビット操作
	//--------------------------------------------------------------------------
	/**
	 * 論理積
	 * @param bitSet 論理積をとるビットセット
	 * @return ビットセット
	 */
	const BitSet& and(const BitSet& bitSet){
		bits_ &= bitSet.bits_;
		return (*this);
	}

	/**
	 * 論理和
	 * @param bitSet 論理和をとるビットセット
	 * @return ビットセット
	 */
	const BitSet& or(const BitSet& bitSet){
		bits_ |= bitSet.bits_;
		return (*this);
	}

	/**
	 * 排他的論理和
	 * @param bitSet 排他的論理和をとるビットセット
	 * @return ビットセット
	 */
	const BitSet& xor(const BitSet& bitSet){
		bits_ ^= bitSet.bits_;
		return (*this);
	}

	/**
	 * ビットをONにする
	 * @param bitSet 設定するビットセット
	 * @return ビットセット
	 */
	const BitSet& onBit(const BitSet& bitSet){
		bits_ |= bitSet.bits_;
		return (*this);
	}

	/**
	 * ビットをOFFにする
	 * @param bitSet 設定するビットセット
	 * @return ビットセット
	 */
	const BitSet& offBit(const BitSet& bitSet){
		bits_ &= (~bitSet.bits_);
		return (*this);
	}

	/**
	 * ビットの設定
	 * @param bitSet ビットを設定するビットセット
	 * @param flag trueならビットをONにします
	 * @return ビットセット
	 */
	const BitSet& setBit(const BitSet& bitSet, bool flag){
		if(flag){ onBit(bitSet); }
		else{ offBit(bitSet); }
		return (*this);
	}

	/**
	 * ビットの取得
	 * @param bitSet ビットを取得するビットセット
	 * @return ビットがすべてONならばtrue
	 */
	bool getBit(const BitSet& bitSet) const{
		return ((bits_ & bitSet.bits_) == bitSet.bits_);
	}

	//--------------------------------------------------------------------------
	// ビット列によるビット操作
	//--------------------------------------------------------------------------
	/**
	 * 論理積
	 * @param bits 論理積をとるビット列
	 * @return ビットセット
	 */
	const BitSet& and(Type bits){
		bits_ &= bits;
		return (*this);
	}

	/**
	 * 論理和
	 * @param bits 論理和をとるビット列
	 * @return ビットセット
	 */
	const BitSet& or(Type bits){
		bits_ |= bits;
		return (*this);
	}

	/**
	 * 排他的論理和
	 * @param bits 排他的論理和をとるビット列
	 * @return ビットセット
	 */
	const BitSet& xor(Type bits){
		bits_ ^= bits;
		return (*this);
	}

	/**
	 * ビットをONにする
	 * @param bits 設定するビット列
	 * @return ビットセット
	 */
	const BitSet& onBit(Type bits){
		bits_ |= bits;
		return (*this);
	}

	/**
	 * ビットをOFFにする
	 * @param bits 設定するビット列
	 * @return ビットセット
	 */
	const BitSet& offBit(Type bits){
		bits_ &= (~bits);
		return (*this);
	}

	/**
	 * ビットの設定
	 * @param bits ビットを設定するビット列
	 * @param flag trueならビットをONにします
	 * @return ビットセット
	 */
	const BitSet& setBit(Type bits, bool flag){
		if(flag){ onBit(bits); }
		else{ offBit(bits); }
		return (*this);
	}

	/**
	 * ビットの取得
	 * @param bits ビットを取得するビット列
	 * @return ビットがすべてONならばtrue
	 */
	bool getBit(Type bits) const{
		return ((bits_ & bits) == bits);
	}

	//--------------------------------------------------------------------------
	// インデックスによるビット操作
	//--------------------------------------------------------------------------
	/**
	 * インデックスビットをONにする
	 * @param index ビットのインデックス
	 */
	const BitSet& onIndexedBit(int index){
		Assert((index >= 0) && (index < getLength()));
		bits_ |= (0x1 << index);
		return (*this);
	}

	/**
	 * インデックスビットをOFFにする
	 * @param index ビットのインデックス
	 */
	const BitSet& offIndexedBit(int index){
		Assert((index >= 0) && (index < getLength()));
		bits_ &= (~(0x1 << index));
		return (*this);
	}

	/**
	 * インデックスビットの設定
	 * @param index ビットのインデックス
	 * @param flag trueならビットをONにします
	 */
	const BitSet& setIndexedBit(int index, bool flag){
		if(flag){ onIndexedBit(index); }
		else{ offIndexedBit(index); }
		return (*this);
	}

	/**
	 * インデックスビットの取得
	 * @param index ビットのインデックス
	 * @return インデックスのビットが立っていればtrue
	 */
	bool getIndexedBit(int index) const{
		Assert((index >= 0) && (index < getLength()));
		return ((bits_ & (0x1 << index)) != 0);
	}

	//--------------------------------------------------------------------------
	/**
	 * 文字列への変換
	 * @return 文字列
	 */
	String toString() const{
		String result;
		for(int i = getLength() - 1; i >= 0; i--){
			if(getIndexedBit(i)){ result += "1"; }
			else{ result += "0"; }
		}
		return result;
	}

private:
	//--------------------------------------------------------------------------
	// ビット列
	Type bits_;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of BIT_SET_H_
//------------------------------------------------------------------------------

