/*
								+----------------------------------+
								|                                  |
								|    ***  Bit array class   ***    |
								|                                  |
								|   Copyright © -tHE SWINe- 2005   |
								|                                  |
								|            BitArray.h            |
								|                                  |
								+----------------------------------+
*/

/**
 *	@file BitArray.h
 *	@author -tHE SWINe-
 *	@brief Simple and fast bit array class
 *
 *	@date 2007-03-15
 *
 *	passed code revision, improved to meet ÜberLame quality standards
 *
 *	now using unsigned integers for lengths instead of signed
 *
 *	made CBit owned by CBitArray (as was logical)
 *
 *	fixed hack in constant bit access using operator []
 *
 *	renamed CBitArray::Free() to CBitArray::Erase()
 *
 *	CBitArray::operator ==() now returns wheter arrays are equal (bool)
 *	instead of integer equality sign which is now returned by CBitArray::n_Compare()
 *
 *	added inequality comparison operators
 *
 *	removed most of non-operator functions (Set_Bit_High() and Set_Bit_Low()
 *	remains only for preformance purposes)
 *
 *	most stuff is now inline, the whole thing is significantly faster
 *
 *	@date 2007-06-26
 *
 *	fixed some bugs in array reallocation using CBitArray::Extend and
 *	in array copy operator CBitArray::operator =
 *
 *	@date 2007-03-04
 *
 *	changed integer types for more safety (now using uint32_t type as array
 *	base unit and unsigned long to store array length)
 *
 *	@date 2008-12-28
 *
 *	exposed internal data buffer for easier and faster serialization
 *
 *	fixed error which occured when copying bits from one array to another
 *	(CBit instances were copied, no array writes occured)
 *
 *	@date 2009-04-23
 *
 *	motivation for writing this file:
 *		std::vector<bool> is troublesome and generally two considered options are
 *			to erase (not deprecate) it, or rename it
 *		std::vector<bool> doesn't offer access to it's data buffer
 *		std::vector<bool> doesn't offer Set_Bit_Low() and Set_Bit_High() functions,
 *			therefore theoretically offers lower reachable performance
 *
 *	added CBitArray::n_Capacity(), CBitArray::Reserve() functions for more efficient
 *	(re)allocation
 *
 *	renamed CBitArray::CBit to CBitArray::CBitReference
 *
 *	added CBitArray::CBitReference::Raise() and CBitArray::CBitReference::Clear()
 *	functions for more efficient writes to individual bits (note
 *	CBitArray::CBitReference::operator =(bool) contains branch, not present
 *	in either of above functions)
 *
 *	@date 2009-10-26
 *
 *	added CBitReference::Invert(), CBitArray::Invert_Bit()
 *
 *	renamed CBitArray::Set_Bit_High() to CBitArray::Raise_Bit() and CBitArray::Set_Bit_Low()
 *	to CBitArray::Clear_Bit().
 *
 *	renamed CBitArray::Extend() to CBitArray::Resize().
 *
 *	changed CBitArray::n_Buffer_Size() to return size in bytes (to avoid crashing older code,
 *	renamed CBitArray::p_Buffer() to CBitArray::p_Get_Buffer(), CBitArray::FillBuffer() to
 *	CBitArray::Set_Buffer() and added size parameter, so older code had to be rewritten).
 *
 *	@todo implement CBitIterator (similar to CBitDifference, but allowing change of index,
 *		index difference and comparison)
 *	@todo write CBitArray::insert(), CBitArray::copy(), CBitArray::erase() and
 *		CBitArray::transform() (had those somewhere - investigate that), write optimized
 *		versions and test them extensively.
 *	@todo specify bit array storage type as CBitArray member (now using uint32_t), for
 *		experiments
 */

#ifndef __BIT_ARRAY_INCLUDED
#define __BIT_ARRAY_INCLUDED

#include "Integer.h"
#include "Buffer.h"

/**
 *	@brief simple bit-array implementation
 *
 *	This is bit array implementation, similar to std::vector<bool>, but
 *	exposing some more of the implementation, so it's theoretically faster.
 *	This also allows accessing it's internal buffer contents.
 *
 */
class CBitArray : private TBuffer {
protected:
	/**
	 *	@class log2
	 *	@brief simple base-2 logarithm template
	 *	@todo maybe it's defined elsewhere
	 */
	template <unsigned int n> class log2 {
	public:
		enum { value = log2<n / 2> :: value + 1 };
	};
	/** @brief simple base-2 logarithm template, specialized for n = 1 case */
	template <> class log2<1> {
	public:
		enum { value = 0 };
	};
	/** @brief simple base-2 logarithm template, specialized for n = 0 case */
	template <> class log2<0> {
	public:
		enum { value = 0 };
	};

public:
	/** type for bit array size */
#ifdef __LARGE_BIT_ARRAY__
#ifndef __LARGE_BUFFER__
#error "error: __LARGE_BUFFER__ not defined, while __LARGE_BIT_ARRAY__ is defined"
#endif //__LARGE_BUFFER__
	typedef uint64_t size_t;
#else //__LARGE_BIT_ARRAY__
	typedef ::size_t size_t;
#endif //__LARGE_BIT_ARRAY__

	typedef size_t index_t; /**< type for bit array indices */
	typedef size_t offset_t; /**< type for bit array iterator difference (note this should be unsigned) */

	typedef uint32_t _NativeInt; /**< internal type to store bit array */

	/**
	 *	@brief precalculated constants for bit indexing arithmetic
	 */
	enum {
		unit_SizeBytes = sizeof(_NativeInt), /**< size of internal type, in bytes (4) */
		unit_SizeBits = unit_SizeBytes * 8, /**< size of internal type, in bits (32) */
		index_Shift = log2<unit_SizeBits>::value, /**< bit index shift (5) */
		index_Mask = unit_SizeBits - 1 /**< bit index mask (0x1f) */
	};

public:
	/**
	 *	@brief writable bit reference class
	 *
	 *	This is kind of pointer which points to a single bit
	 *	in the array, enabling it to be read or written.
	 *
	 *	@note Note this bit reference gets invalidated on bit array resize!
	 */
	class CBitReference {
	private:
		_NativeInt &m_r_array;
		_NativeInt m_n_mask;

	public:
		/**
		 *	@brief creates reference to a bit
		 *
		 *	Default constructor; creates reference to a bit with zero-based index
		 *	n_index in bit array p_array (doesn't check array bounds).
		 *
		 *	@param[in,out] r_array is integer from bit array, containing the bit to be referenced
		 *	@param[in] n_mask is bit mask
		 */
		inline CBitReference(_NativeInt &r_array, _NativeInt n_mask)
			:m_r_array(r_array), m_n_mask(n_mask)
		{}

		/**
		 *	@brief writes b_value to bit in the array
		 *
		 *	Writes boolean value b_value to bit in the array, referenced by this
		 *	object, and returns the written value.
		 *
		 *	@param[in] b_value is boolean value to be written
		 *
		 *	@return Returns b_value
		 */
		inline bool operator =(bool b_value)
		{
			if(b_value)
				m_r_array |= m_n_mask;
			else
				m_r_array &= ~m_n_mask;
			return b_value;
		}

		/**
		 *	@brief writes value of r_bit to bit in the array
		 *
		 *	Writes value of r_bit to bit in the array, referenced by this
		 *	object, and returns the written value.
		 *
		 *	@param[in] r_bit is reference to a bit containing value to be written
		 *
		 *	@return Returns value of r_bit
		 */
		inline bool operator =(const CBitReference &r_bit)
		{
			return *this = bool(r_bit);
		}

		/**
		 *	@brief writes a '1' to this bit
		 *
		 *	This effectively does the same as "bit = true", but operator =() in fact contains
		 *	a branch to decide wheter to clear the bit (use logical and), or raise the bit
		 *	(use logical ot). Using this function can lead to small speed improvement.
		 *
		 *	@note In case speed is critical, it might be more appropriate to use
		 *		CBitArray::Raise_Bit()
		 */
		inline void Raise()
		{
			m_r_array |= m_n_mask;
		}

		/**
		 *	@brief writes a '0' to this bit
		 *
		 *	This effectively does the same as "bit = false", but operator =() in fact contains
		 *	a branch to decide wheter to clear the bit (use logical and), or raise the bit
		 *	(use logical ot). Using this function can lead to small speed improvement.
		 *
		 *	@note In case speed is critical, it might be more appropriate to use
		 *		CBitArray::Clear_Bit()
		 */
		inline void Clear()
		{
			m_r_array &= ~m_n_mask;
		}

		/**
		 *	@brief inverts the bit
		 *
		 *	This effectively does the same as "bit = !bit", but operator =() in fact contains
		 *	a branch to decide wheter to clear the bit (use logical and), or raise the bit
		 *	(use logical ot). Using this function can lead to small speed improvement.
		 *
		 *	@note In case speed is critical, it might be more appropriate to use
		 *		CBitArray::Invert_Bit()
		 */
		inline void Invert()
		{
			m_r_array ^= m_n_mask;
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if bits are equal, false otherwise.
		 */
		inline bool operator ==(bool b_value)
		{
			return bool(*this) == b_value;
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if this bit is zero, while b_value is true, false otherwise.
		 */
		inline bool operator <(bool b_value) const
		{
			return !bool(*this) && b_value;
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if this bit is one, while b_value is false, false otherwise.
		 */
		inline bool operator >(bool b_value) const
		{
			return bool(*this) && !b_value;
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if this <= r_bit, false otherwise.
		 */
		inline bool operator <=(bool b_value) const
		{
			return !(*this > b_value);
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if this >= r_bit, false otherwise.
		 */
		inline bool operator >=(bool b_value) const
		{
			return !(*this < b_value);
		}

		/**
		 *	@brief bit comparison operator
		 *
		 *	Compares values of two bits (does not compare
		 *		array and index, compares referenced value).
		 *
		 *	@param[in] b_value is reference value to be compared to
		 *
		 *	@return Returns true if this != r_bit, false otherwise.
		 */
		inline bool operator !=(bool b_value) const
		{
			return !(*this == b_value);
		}

		/**
		 *	@brief gets value of the referenced bit
		 *
		 *	@return Returns value of bit in referenced array.
		 */
		inline operator bool() const
		{
			return (m_r_array & m_n_mask) != 0;
		}
	};

private:
	size_t m_n_used_bits;

public:
	/**
	 *	@brief default constructor
	 *
	 *	Default constructor; initializes an empty array.
	 */
	inline CBitArray()
		:m_n_used_bits(0)
	{}

	/**
	 *	@brief constructor with array length specifier
	 *
	 *	Constructor; allocates array to size n_length_bits bits. In case
	 *	there's not enough memory, array length will be zero.
	 *
	 *	@param[in] n_length_bits is required array length, in bits
	 *
	 *	@note Call n_Size() to find out if there was enough memory.
	 */
	CBitArray(size_t n_length_bits);

	/**
	 *	@brief allocates array to specified lenght
	 *
	 *	Allocates array to lenght n_length bits, original contents
	 *	are erased (use Extend() if required).
	 *
	 *	@param[in] n_length_bits is required lenght, in bits
	 *
	 *	@return Returns true on success, false on failure (not enough memory).
	 */
	bool Alloc(size_t n_length_bits);

	/**
	 *	@brief resizes the array
	 *
	 *	Resizes array to total lenght n_length_bits bits, original data are
	 *	kept intact, except when new size is smaller than original size
	 *	(last bits are thrown away).
	 *
	 *	@param[in] n_length_bits is required array length in bits
	 *
	 *	@return Returns true on success, false on failure (not enough memory).
	 *
	 *	@note This doesn't work as std::vector's resize and does not increase
	 *		capacity in powers-of-two steps, so inserting bits in a loop is O(n2),
	 *		not O(n log n).
	 *	@note Extending to array capacity (or less) always succeeds, buffer isn't
	 *		reallocated.
	 */
	bool Resize(size_t n_length_bits);

	/**
	 *	@brief reserves space for additional bits
	 *
	 *	Extends internal buffer to accomodate at least n_length_bits bits in total,
	 *		but does not change array length (as Extend() does).
	 *
	 *	@param[in] n_length_bits is desired array capacity in bits
	 *
	 *	@return Returns true on success, false on failure (not enough memory).
	 *
	 *	@note This doesn't work as std::vector's resize and does not increase
	 *		capacity in powers-of-two steps, so inserting bits in a loop is O(n2),
	 *		not O(n log n).
	 *	@note Has no effect in case n_length is less or equal to current capacity.
	 */
	bool Reserve(size_t n_length_bits);

	/**
	 *	@brief erases array
	 *
	 *	Erases the array, frees internal buffers (capacity will be zero, use
	 *		Extend() with n_length = 0 to avoid that).
	 */
	void Erase();

	/**
	 *	@brief swaps two arrays
	 *
	 *	Swaps this array with r_t_other, no reallocations are made (beware swapping
	 *		two arrays, allocated in different threads!).
	 *
	 *	@param[in,out] r_other is the other array to swap with
	 *
	 */
	void Swap(CBitArray &r_other);

	/**
	 *	@brief gets length of array in @c bits
	 *
	 *	@return Returns length of array in @c bits.
	 */
	inline size_t n_Length() const
	{
		return m_n_used_bits;
	}

	/**
	 *	@brief gets length of array in @c bits
	 *
	 *	@return Returns length of array in @c bits.
	 *
	 *	@note This is only alias to n_Length().
	 */
	inline size_t n_Size() const
	{
		return n_Length(); // bug-proof
	}

	/**
	 *	@brief gets array capacity in bits
	 *
	 *	Gets capacity, the maximal length of array (in bits) without reallocating.
	 *
	 *	@return Returns array capacity in bits.
	 */
	inline size_t n_Capacity() const
	{
		return TBuffer::n_Size() * 8;
	}

	/**
	 *	@brief bit access operator
	 *
	 *	Bit access operator for reading / writing bits.
	 *
	 *	@param[in] n_index is zero-based bit index
	 *
	 *	@return Returns reference to bit with zero-based index n_index
	 *
	 *	@note References are invalidated when reallocating!
	 */
	inline CBitReference operator [](size_t n_index)
	{
		return CBitReference(p_Data()[n_Index(n_index)], n_Mask(n_index));
	}

	/**
	 *	@brief bit access operator
	 *
	 *	Read-only bit access operator.
	 *
	 *	@param[in] n_index is zero-based bit index
	 *
	 *	@return Returns value of bit with zero-based index n_index
	 */
	inline bool operator [](size_t n_index) const
	{
		return (p_Data()[n_Index(n_index)] >> n_Shift(n_index)) & 1;
	}

	/**
	 *	@brief set all bits in array to boolean
	 *
	 *	Sets all bits in array to b_value.
	 *
	 *	@param[in] b_value is boolean value to set all bits to.
	 *
	 *	@return Returns b_value (to allow for multiple assignment).
	 *
	 *	@remarks Although this basically contains two different code paths, for setting
	 *		array to all ones and to all zeros, it is quite efficient (in contrast with
	 *		setting individual bits, for which CBitReference::Raise() and
	 *		CBitReference::Clear() have superior performance to CBitReference::operator =())
	 */
	bool operator =(bool b_value);

	/**
	 *	@brief inverts all bits in the array
	 */
	void Invert();

	/**
	 *	@brief copy-operator
	 *
	 *	Copies contents of r_array to this array.
	 *
	 *	@param[in] r_array is source array
	 *
	 *	@return Returns true if there was enough memory and array was
	 *		successfully copied, otherwise false.
	 */
	bool operator =(const CBitArray &r_array);

	/**
	 *	@brief array concatenation
	 *
	 *	Appends contents of r_array to the end of this array.
	 *
	 *	@param[in] r_array is bit array to be appended
	 *
	 *	@return Returns true in case there was enough memory and arrays
	 *		were concatenated, otherwise false.
	 *
	 *	@note This is optimized to copy array in larger units than bits
	 *		(in case destination array is word-aligned, it copies them in words).
	 *		Generally it requires 16 times less operations than copying
	 *		bit by bit.
	 */
	bool operator +=(const CBitArray &r_array);

	/**
	 *	@brief array to boolean comparison
	 *
	 *	Compares all bits in the array to b_value.
	 *
	 *	@param[in] b_value is comparison reference value
	 *
	 *	@return Returns true in case all bits in array are equal to b_value, otherwise false.
	 *	@return Always returns true for an empty array.
	 */
	bool operator ==(bool b_value) const;

	/**
	 *	@brief array to array comparison
	 *
	 *	Compares all bits in the array to bits in the other array.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true in case array lengths and contents are equal, otherwise false.
	 */
	bool operator ==(const CBitArray &r_array) const;

	/**
	 *	@brief array to array comparison
	 *
	 *	Two-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true if this < r_array, otherwise false .
	 */
	inline bool operator <(const CBitArray &r_array) const;

	/**
	 *	@brief array to array comparison
	 *
	 *	Two-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true if this > r_array, otherwise false .
	 */
	inline bool operator >(const CBitArray &r_array) const
	{
		return r_array < *this; // operator <() is faster than n_Compare
	}

	/**
	 *	@brief array to array comparison
	 *
	 *	Two-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true if this >= r_array, otherwise false .
	 */
	inline bool operator >=(const CBitArray &r_array) const
	{
		return !(*this < r_array); // operator <() is faster than n_Compare
	}

	/**
	 *	@brief array to array comparison
	 *
	 *	Two-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true if this <= r_array, otherwise false .
	 */
	inline bool operator <=(const CBitArray &r_array) const
	{
		return !(r_array < *this); // operator <() is faster than n_Compare
	}

	/**
	 *	@brief array to array comparison
	 *
	 *	Two-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns true if this != r_array, otherwise false .
	 */
	inline bool operator !=(const CBitArray &r_array) const
	{
		return !(*this == r_array); // operator ==() is faster than n_Compare
	}

	/**
	 *	@brief array to array comparison
	 *
	 *	Three-way array to array comparison in strcmp()-like fashion. Compares
	 *	bits in natural order, first different bit decides, in case all bits
	 *	up to length of shorter array are equal, compares lengths.
	 *
	 *	@param[in] r_array is the other array to compare to
	 *
	 *	@return Returns 1 if this > r_array, 0 if this == r_array or -1 if this < r_array.
	 */
	int n_Compare(const CBitArray &r_array) const;

	/**
	 *	@brief fast bit write function
	 *
	 *	Raises (writes 1 to) bit with zero-based index n_index
	 *
	 *	@param n_index is zero-based index of bit to be raised
	 *
	 *	@note This is faster (and resulting code is probably a bit smaller), than if using
	 *		<tt>array[n_index].Raise()</tt> (not to mention <tt>array[n_index] = true</tt>).
	 */
	inline void Raise_Bit(size_t n_index)
	{
		p_Data()[n_Index(n_index)] |= n_Mask(n_index);
	}

	/**
	 *	@brief fast bit write function
	 *
	 *	Clears (writes 0 to) bit with zero-based index n_index
	 *
	 *	@param n_index is zero-based index of bit to be cleared
	 *
	 *	@note This is faster (and resulting code is probably a bit smaller), than if using
	 *		<tt>array[n_index].Raise()</tt> (not to mention <tt>array[n_index] = false</tt>).
	 */
	inline void Clear_Bit(size_t n_index)
	{
		p_Data()[n_Index(n_index)] &= ~n_Mask(n_index);
	}

	/**
	 *	@brief fast bit inversion function
	 *
	 *	Inverts (negates boolean value of) bit with zero-based index n_index
	 *
	 *	@param n_index is zero-based index of bit to be inverted
	 *
	 *	@note This is faster (and resulting code is probably a bit smaller), than if using
	 *		<tt>array[n_index].Invert()</tt> (not to mention
	 *		<tt>array[n_index] = !array[n_index]</tt>).
	 */
	inline void Invert_Bit(size_t n_index)
	{
		p_Data()[n_Index(n_index)] ^= n_Mask(n_index);
	}

	/**
	 *	@brief gets internal buffer size
	 *
	 *	@return Returns (used) size of internal data buffer, in bytes.
	 *
	 *	@note Returned size may be rounded up to nearest greater multiple of four,
	 *		it is really wrong idea trying to save those (up to three) bytes by
	 *		cutting them off. For example, if array is 1 bit long, only a single byte
	 *		would be needed to store it, but in case array is internally stored in
	 *		integers, that one bit is stored in the fourth byte of the array (endianness),
	 *		so cutting it off means losing that bit.
	 */
	inline size_t n_Buffer_Size() const
	{
		return n_UnitsUsed() * unit_SizeBytes;
		// can't align to less bits, because of endiannes
	}

	/**
	 *	@brief gets internal data buffer
	 *
	 *	@return Returns const pointer to internal data buffer.
	 *
	 *	@note The buffer is n_Buffer_Size() bytes long.
	 */
	inline const void *p_Get_Buffer() const
	{
		return TBuffer::p_Data();
	}

	/**
	 *	@brief gets internal data buffer
	 *
	 *	@return Returns pointer to internal data buffer.
	 *
	 *	@note The buffer is n_Buffer_Size() bytes long.
	 */
	inline void *p_Get_Buffer()
	{
		return TBuffer::p_Data();
	}

	/**
	 *	@brief copies internal data buffer
	 *
	 *	Fills p_data with data from intrernal buffer
	 *
	 *	@param p_data is pointer to destination buffer, it must be allocated
	 *		to n_Buffer_Size() bytes
	 *	@param n_size is size of p_data array, in bytes (for parameter validation only)
	 */
	void Get_Buffer(size_t n_size, void *p_data) const;

	/**
	 *	@brief fills internal data buffer
	 *
	 *	Fills data buffer with data from p_data.
	 *
	 *	@param p_data is pointer to source data, it must contain n_Buffer_Size() bytes
	 *	@param n_size is size of p_data array, in bytes (for parameter validation only)
	 */
	void Set_Buffer(size_t n_size, const void *p_data);

	/**
	 *	@brief writes array to a file
	 *
	 *	Writes an array to opened file p_fr.
	 *
	 *	@param[in] p_fw is opened file pointer (should be opened for writing in binary mode).
	 *
	 *	@return Returns true if successful, otherwise false.
	 *
	 *	@deprecated Use p_Get_Buffer() instead.
	 */
	bool Store(FILE *p_fw) const;

	/**
	 *	@brief loads array from a file
	 *
	 *	Loads an array from opened file p_fr.
	 *
	 *	@param[in] p_fr is opened file pointer (should be opened for reading in binary mode).
	 *
	 *	@return Returns true if successful, otherwise false.
	 *
	 *	@deprecated Use p_Get_Buffer() instead.
	 */
	bool Load(FILE *p_fr);

	/**
	 *	@brief gets maximal bit array size
	 *
	 *	@return Returns the greatest size possible, in bits, the array can be allocated to.
	 */
	static size_t n_Max_Size()
	{
		return size_t(CMaxIntValue<size_t>::result());
	}

private:
	/**
	 *	@return returns pointer to data buffer in native integer units
	 */
	inline _NativeInt *p_Data()
	{
		return (_NativeInt*)TBuffer::p_Data();
	}

	/**
	 *	@return returns const pointer to data buffer in native integer units
	 */
	inline const _NativeInt *p_Data() const
	{
		return (_NativeInt*)TBuffer::p_Data();
	}

	/**
	 *	@return returns index of native integer, containing bit with zero-based index n_index
	 */
	static inline index_t n_Index(index_t n_index)
	{
		return n_index >> index_Shift;
	}

	/**
	 *	@return returns bit-shift inside native integer to get bit with zero-based index n_index
	 */
	static inline int n_Shift(index_t n_index)
	{
		return n_index & index_Mask;
	}

	/**
	 *	@return returns bit-shift inside native integer to get bit with zero-based index n_index
	 */
	static inline _NativeInt n_Mask(index_t n_index)
	{
		return _NativeInt(1) << n_Shift(n_index);
	}

	/**
	 *	@return returns number of data buffer elements, including last one in case it's used partialy
	 */
	inline size_t n_UnitsUsed() const
	{
		return n_WholeUnitsUsed() + ((b_LastUnitUsedPartialy())? 1 : 0); // doesn't overflow this way
	}

	/**
	 *	@return returns number of data buffer elements, including last one in case it's used partialy
	 */
	static inline size_t n_UnitsUsed(size_t n_bits_used)
	{
		return n_WholeUnitsUsed(n_bits_used) +
			((b_LastUnitUsedPartialy(n_bits_used))? 1 : 0); // doesn't overflow this way
	}

	/**
	 *	@return returns number of data buffer elements where all bits are used
	 */
	inline size_t n_WholeUnitsUsed() const
	{
		return m_n_used_bits >> index_Shift;
	}

	/**
	 *	@return returns number of data buffer elements where all bits are used
	 */
	static inline size_t n_WholeUnitsUsed(size_t n_bits_used)
	{
		return n_bits_used >> index_Shift;
	}

	/**
	 *	@return returns true in case the last used buffer elements isn't fully used
	 *		(only some of it's bits are used), otherwise returns false
	 *	@note this implies n_WholeUnitsUsed() == n_UnitsUsed() - 1
	 */
	inline bool b_LastUnitUsedPartialy() const
	{
		return (m_n_used_bits & index_Mask) != 0;
	}

	/**
	 *	@return returns true in case the last used buffer elements isn't fully used
	 *		(only some of it's bits are used), otherwise returns false
	 *	@note this implies n_WholeUnitsUsed(n_bits_used) == n_UnitsUsed(n_bits_used) - 1
	 */
	static inline bool b_LastUnitUsedPartialy(size_t n_bits_used)
	{
		return (n_bits_used & index_Mask) != 0;
	}

	/**
	 *	@return returns valid bit mask for the last buffer element
	 *	@note this returns 0 in case b_LastUnitUsedPartialy() is false
	 */
	inline _NativeInt n_LastUnitMask() const
	{
		return _NativeInt(1) << ((m_n_used_bits & index_Mask) - 1);
	}

	/**
	 *	@return returns valid bit mask for the last buffer element
	 *	@note this returns 0 in case b_LastUnitUsedPartialy() is false
	 */
	static inline _NativeInt n_LastUnitMask(size_t n_bits_used)
	{
		return _NativeInt(1) << ((n_bits_used & index_Mask) - 1);
	}
};

/**
 *	@brief global ::swap specialization
 *
 *	Overrides global ::swap to swap bits two CBitArray::CBitReference
 *		points to, instead of swapping their contents.
 *
 *	@param[in,out] a is the first bit reference to be swapped
 *	@param[in,out] b is the other bit reference to be swapped
 */
inline void swap(CBitArray::CBitReference a, CBitArray::CBitReference b)
{
	bool b_temp = a;
	a = b;
	b = b_temp;
}

namespace std {
/**
 *	@brief std::swap specialization
 *
 *	Overrides std::swap to swap bits two CBitArray::CBitReference
 *		points to, instead of swapping their contents.
 *
 *	@param[in,out] a is the first bit reference to be swapped
 *	@param[in,out] b is the other bit reference to be swapped
 */
inline void swap(CBitArray::CBitReference a, CBitArray::CBitReference b)
{
	bool b_temp = a;
	a = b;
	b = b_temp;
}
};

#endif //__BIT_ARRAY_INCLUDED
