/*  Metrowerks Standard Library  Version 4.0  1998 August 10  */

/*  $Date: 1998/12/04 23:58:21 $ 
 *  $Revision: 1.2 $ 
 *  $NoKeywords: $ 
 *
 *		Portions Copyright  1995-1998 Metrowerks, Inc.
 *		All rights reserved.
 */

/**
 **  bitset
 **/

#ifndef _BITSET
#define _BITSET

#include <mcompile.h>
#include <cstddef>
#include <climits>
#include <string>
#include <stdexcept>
#include <iosfwd>

#ifndef RC_INVOKED

#pragma options align=native
#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
	#pragma import on
#endif

#ifdef MSIPL_USING_NAMESPACE
	namespace std {
#endif

template<size_t N>
class bitset
{
public:
	// bit reference:
	class reference
	{
	public:
		reference& operator=(bool x) {v_.set(pos_, x); return *this;}
		reference& operator=(const reference& rhs) {v_.set(pos_, rhs); return *this;}
		bool operator~() const {return !v_.test(pos_);}
		operator bool() const {return v_.test(pos_);}
		reference& flip() {v_.flip(pos_); return *this;}
	private:
		bitset& v_;
		size_t pos_;

		reference(bitset& v, size_t pos) : v_(v), pos_(pos) {}

		friend class bitset;
	};

	// _lib.bitset.cons_ constructors:
	bitset();
	bitset(unsigned long val);

	// hh 980805 reverting to pre-member template code.
/*	#ifdef MSIPL_MEMBER_TEMPLATE  // hh 980713 Temporarily moved into class definition to support compiler
		template<class charT, class traits, class Allocator>
		bitset(const basic_string<charT,traits,Allocator>& str,
			typename basic_string<charT,traits,Allocator>::size_type pos = 0,
			typename basic_string<charT,traits,Allocator>::size_type n = basic_string<charT,traits,Allocator>::npos)
		{
			if (pos >= str.size())
				MSIPL_THROW_ME(out_of_range, "pos out of range of str in bitset constructor")
			if (n > str.size() - pos)
				n = str.size() - pos;
			if (n > N)
				n = N;
			{  // hh 980816 ARM/Standard neutral for-scoping
			for (size_t i = 0; i < nwords_; ++i)
				data_[i] = 0;
			}
			{  // hh 980816 ARM/Standard neutral for-scoping
			for (size_t i = 0; i < n; ++i)
			{
				char c = char(str[pos + n - 1 - i]);
				switch (c)
				{
				case '0':
					break;
				case '1':
					set(i);
					break;
				default:
					MSIPL_THROW_ME(invalid_argument, "str contains invalid characters in bitset constructor")
				}
			}
			}
		}
	#else */
		bitset(const string& str,
			typename string::size_type pos = 0,
			typename string::size_type n = string::npos)
		{
			if (pos >= str.size())
				MSIPL_THROW_ME(out_of_range, "pos out of range of str in bitset constructor")
			if (n > str.size() - pos)
				n = str.size() - pos;
			if (n > N)
				n = N;
			{  // hh 980816 ARM/Standard neutral for-scoping
			for (size_t i = 0; i < nwords_; ++i)
				data_[i] = 0;
			}
			{  // hh 980816 ARM/Standard neutral for-scoping
			for (size_t i = 0; i < n; ++i)
			{
				char c = char(str[pos + n - 1 - i]);
				switch (c)
				{
				case '0':
					break;
				case '1':
					set(i);
					break;
				default:
					MSIPL_THROW_ME(invalid_argument, "str contains invalid characters in bitset constructor")
				}
			}
			}
		}
//	#endif

	// _lib.bitset.members_ bitset operations:
	bitset<N>& operator&=(const bitset<N>& rhs);
	bitset<N>& operator|=(const bitset<N>& rhs);
	bitset<N>& operator^=(const bitset<N>& rhs);
	bitset<N>& operator<<=(size_t pos);
	bitset<N>& operator>>=(size_t pos);
	bitset<N>& set();
	bitset<N>& set(size_t pos, int val = true);
	bitset<N>& reset();
	bitset<N>& reset(size_t pos);
	bitset<N>  operator~() const;
	bitset<N>& flip();
	bitset<N>& flip(size_t pos);
	// element access:
	reference operator[](size_t pos);
	unsigned long to_ulong() const;

	// hh 980805 reverting to pre-member template code.
/*	#ifdef MSIPL_MEMBER_TEMPLATE  // hh 980713 Temporarily moved into class definition to support compiler
		template <class charT, class traits, class Allocator>
		basic_string<charT, traits, Allocator>
		to_string() const
		{
			basic_string<charT, traits, Allocator> result(N, charT('0'));
			for (size_t = 0; i < N; ++i)
				if (test(i))
					result[N-i-1] = charT('1');
			return result;
		}
	#else */
		string
		to_string() const
		{
			string result(N, '0');
			for (size_t i = 0; i < N; ++i)
				if (test(i))
					result[N-i-1] = '1';
			return result;
		}
//	#endif

	size_t count() const;
	size_t size()  const;
	bool operator==(const bitset<N>& rhs) const;
	bool operator!=(const bitset<N>& rhs) const;
	bool test(size_t pos) const;
	bool any() const;
	bool none() const;
	bitset<N> operator<<(size_t pos) const;
	bitset<N> operator>>(size_t pos) const;
private:
	static const size_t num_bits_word = CHAR_BIT*sizeof(unsigned long);
	static const size_t nwords_ = N == 0 ? 1 : (N-1) / num_bits_word + 1;
	static const unsigned long mask = (unsigned long)(-1) >> (unsigned long)(num_bits_word - N % num_bits_word);
	unsigned long data_[nwords_];

	size_t count1char(unsigned char flag) const;
	size_t count1long(unsigned long flag) const;
};

// _lib.bitset.operators_ bitset operations:

template <size_t N>
inline
bitset<N>
operator&(const bitset<N>& lhs, const bitset<N>& rhs)
{
	return bitset<N>(lhs) &= rhs;
}

template <size_t N>
inline
bitset<N>
operator|(const bitset<N>& lhs, const bitset<N>& rhs)
{
	return bitset<N>(lhs) |= rhs;
}

template <size_t N>
inline
bitset<N>
operator^(const bitset<N>& lhs, const bitset<N>& rhs)
{
	return bitset<N>(lhs) ^= rhs;
}

template <class charT, class traits, size_t N>
basic_istream<charT, traits>&
operator>>(basic_istream<charT, traits>& is, bitset<N>& rhs)
{
	istreambuf_iterator<charT> in(is);
	istreambuf_iterator<charT> end;
	int count = 0;
	string str;
	if (in != end)
	{
		while (count < N)
		{
			char c = char(*in);
			if (c == '0' || c == '1')
			{
				str += c;
				++count;
				if (++in == end)
				{
					is.setstate(ios_base::eofbit);
					break;
				}
			}
			else
				break;
		}
	}
	if (count == 0)
		is.setstate(ios_base::failbit);
	else
		rhs = bitset<N>(str);
	return is;
}

template <class charT, class traits, size_t N>
inline
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const bitset<N>& rhs)
{
	// hh 980805 reverting to pre-member template code.
//	#ifdef MSIPL_MEMBER_TEMPLATE
//		return os << rhs.to_string<charT, traits, allocator<charT> >();
//	#else
		return os << rhs.to_string();
//	#endif
}

// Implementation

template<size_t N>
bitset<N>::bitset()
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] = 0;
}

template<size_t N>
bitset<N>::bitset(unsigned long val)
{
	if (N < num_bits_word)
		val &= mask;
	data_[0] = val;
	for (size_t i = 1; i < nwords_; ++i)
		data_[i] = 0;
}

template<size_t N>
bitset<N>&
bitset<N>::operator&=(const bitset<N>& rhs)
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] &= rhs.data_[i];
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::operator|=(const bitset<N>& rhs)
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] |= rhs.data_[i];
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::operator^=(const bitset<N>& rhs)
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] ^= rhs.data_[i];
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::operator<<=(size_t pos)
{
	long offset = long(pos / num_bits_word);
	if (offset > 0)
	{
		long i = long(nwords_ - 1);
		for (; i-offset >= 0; --i)
			data_[i] = data_[i-offset];
		for (; i >= 0; --i)
			data_[i] = 0;
	}
	unsigned long rshift = num_bits_word - pos % num_bits_word;
	unsigned long lshift = pos % num_bits_word;
	for (size_t i = nwords_ - 1; i > 0; --i)
	{
		data_[i] <<= lshift;
		data_[i] |= data_[i-1] >> rshift;
	}
	data_[0] <<= lshift;
	if (mask)
		data_[nwords_-1] &= mask;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::operator>>=(size_t pos)
{
	long offset = long(pos / num_bits_word);
	if (offset > 0)
	{
		long i = 0;
		for (; i+offset < nwords_; ++i)
			data_[i] = data_[i+offset];
		for (; i < nwords_; ++i)
			data_[i] = 0;
	}
	unsigned long rshift = pos % num_bits_word;
	unsigned long lshift = num_bits_word - pos % num_bits_word;
	for (size_t i = 0; i < nwords_-1; ++i)
	{
		data_[i] >>= rshift;
		data_[i] |= data_[i+1] << lshift;
	}
	data_[nwords_-1] >>= rshift;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::set()
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] = (unsigned long)(-1);
	if (mask)
		data_[nwords_-1] &= mask;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::set(size_t pos, int val)
{
	if (pos >= N)
		MSIPL_THROW_ME(out_of_range, "index out of range of bitset::set")
	size_t word = pos / num_bits_word;
	unsigned long bitmask = (unsigned long)1 << pos % num_bits_word;
	if (val)
		data_[word] |= bitmask;
	else
		data_[word] &= ~bitmask;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::reset()
{
	for (size_t i = 0; i < nwords_; ++i)
		data_[i] = 0;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::reset(size_t pos)
{
	if (pos >= N)
		MSIPL_THROW_ME(out_of_range, "index out of range of bitset::reset")
	size_t word = pos / num_bits_word;
	unsigned long bitmask = (unsigned long)1 << pos % num_bits_word;
	data_[word] &= ~bitmask;
	return *this;
}

template<size_t N>
inline
bitset<N>
bitset<N>::operator~() const
{
	return bitset<N>(*this).flip();
}

template<size_t N>
bitset<N>&
bitset<N>::flip()
{
	for (int i = 0; i < nwords_; ++i)
		data_[i] = ~data_[i];
	if (mask)
		data_[nwords_-1] &= mask;
	return *this;
}

template<size_t N>
bitset<N>&
bitset<N>::flip(size_t pos)
{
	if (pos >= N)
		MSIPL_THROW_ME(out_of_range, "index out of range of bitset::flip")
	size_t word = pos / num_bits_word;
	unsigned long bitmask = (unsigned long)1 << pos % num_bits_word;
	unsigned long& bits = data_[word];
	if (bits & bitmask)
		bits &= ~bitmask;
	else
		bits |= bitmask;
	return *this;
}

template<size_t N>
inline
bitset<N>::reference
bitset<N>::operator[](size_t pos)
{
	return reference(*this, pos);
}

template<size_t N>
unsigned long
bitset<N>::to_ulong() const
{
	for (size_t i = 1; i < nwords_; ++i)
		if (data_[i] != 0)
			MSIPL_THROW_ME(overflow_error, "bitset::to_ulong overflow")
	return data_[0];
}

template<size_t N>
size_t
bitset<N>::count1char(unsigned char flag) const
{
	if (flag == 0)
		return 0;
	size_t count = 0;
	unsigned char char_mask = 1;
	for (int i = 0; i < CHAR_BIT; ++i, char_mask <<= 1)
		if (flag & char_mask)
			++count;
	return count;
}

template<size_t N>
size_t
bitset<N>::count1long(unsigned long flag) const
{
	if (flag == 0)
		return 0;
	size_t count = 0;
	unsigned long char_mask = (unsigned long)(-1) >> (unsigned long)(num_bits_word - CHAR_BIT);
	unsigned long shift = 0;
	for (int i = 0; i < sizeof(unsigned long); ++i)
	{
		count += count1char((unsigned char)((flag & char_mask) >> shift));
		char_mask <<= CHAR_BIT;
		shift += CHAR_BIT;
	}
	return count;
}

template<size_t N>
size_t
bitset<N>::count() const
{
	size_t count = 0;
	for (size_t i = 0; i < nwords_; ++i)
		count += count1long(data_[i]);
	return count;
}

template<size_t N>
inline
size_t
bitset<N>::size() const
{
	return N;
}

template<size_t N>
bool
bitset<N>::operator==(const bitset<N>& rhs) const
{
	for (size_t i = 0; i < nwords_; ++i)
		if (data_[i] != rhs.data_[i])
			return false;
	return true;
}

template<size_t N>
bool
bitset<N>::operator!=(const bitset<N>& rhs) const
{
	for (size_t i = 0; i < nwords_; ++i)
		if (data_[i] != rhs.data_[i])
			return true;
	return false;
}

template<size_t N>
bool
bitset<N>::test(size_t pos) const
{
	if (pos >= N)
		MSIPL_THROW_ME(out_of_range, "index out of range of bitset::test")
	size_t word = pos / num_bits_word;
	unsigned long bitmask = (unsigned long)1 << pos % num_bits_word;
	return bool(data_[word] & bitmask);
}

template<size_t N>
bool
bitset<N>::any() const
{
	for (size_t i = 0; i < nwords_; ++i)
		if (data_[i])
			return true;
	return false;
}

template<size_t N>
bool
bitset<N>::none() const
{
	for (size_t i = 0; i < nwords_; ++i)
		if (data_[i])
			return false;
	return true;
}

template<size_t N>
inline
bitset<N>
bitset<N>::operator<<(size_t pos) const
{
	return bitset<N>(*this) <<= pos;
}

template<size_t N>
inline
bitset<N>
bitset<N>::operator>>(size_t pos) const
{
	return bitset<N>(*this) >>= pos;
}

#ifdef MSIPL_USING_NAMESPACE
	} // namespace std
#endif

#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__)
	#pragma import reset
#endif
#pragma options align=reset

#endif // RC_INVOKED

#endif

// hh 980509 rewritten
// hh 980713 Temporarily moved member templates into class definition to support compiler
// hh 980805 reverting to pre-member template code.
// hh 980816 ARM/Standard neutral for-scoping
// hh 980902 #ifdef'd out exception code when ndef MSIPL_EXCEPT
