#ifndef _xbARRAY_
#define _xbARRAY_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbArray
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<11/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbHEAP_
#	include "xbHeap.h"
#endif

#pragma warning(push)
#pragma warning(disable: 4311) //troncation de pointeur de 'wchar *' à 'xbNptr'

//Static array, size max = 16
template<class ta_Obj,int targArrSzMax = 16> class xbSArray
{
public:
	xbSArray()
	{
		m_sz = 0;
	}
	xbSArray(ta_Obj obj)
	{
		_init(1,obj);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2)
	{
		_init(2,obj,obj2);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3)
	{
		_init(3,obj,obj2,obj3);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4)
	{
		_init(4,obj,obj2,obj3,obj4);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5)
	{
		_init(5,obj,obj2,obj3,obj4,obj5);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6)
	{
		_init(6,obj,obj2,obj3,obj4,obj5,obj6);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7)
	{
		_init(7,obj,obj2,obj3,obj4,obj5,obj6,obj7);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8)
	{
		_init(8,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9)
	{
		_init(9,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10)
	{
		_init(10,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11)
	{
		_init(11,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12)
	{
		_init(12,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13)
	{
		_init(13,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14)
	{
		_init(14,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14,ta_Obj obj15)
	{
		_init(15,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14,obj15);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14,ta_Obj obj15,ta_Obj obj16)
	{
		_init(16,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14,obj16);
	}
	xbSArray(ta_Obj obj,const xbSArray<ta_Obj> &arr)
	{
		_init(1,obj);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,const xbSArray<ta_Obj> &arr)
	{
		_init(2,obj,obj2);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,const xbSArray<ta_Obj> &arr)
	{
		_init(3,obj,obj2,obj3);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,const xbSArray<ta_Obj> &arr)
	{
		_init(4,obj,obj2,obj3,obj4);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,const xbSArray<ta_Obj> &arr)
	{
		_init(5,obj,obj2,obj3,obj4,obj5);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,const xbSArray<ta_Obj> &arr)
	{
		_init(6,obj,obj2,obj3,obj4,obj5,obj6);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,const xbSArray<ta_Obj> &arr)
	{
		_init(7,obj,obj2,obj3,obj4,obj5,obj6,obj7);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,const xbSArray<ta_Obj> &arr)
	{
		_init(8,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,const xbSArray<ta_Obj> &arr)
	{
		_init(9,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,const xbSArray<ta_Obj> &arr)
	{
		_init(10,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,const xbSArray<ta_Obj> &arr)
	{
		_init(11,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,const xbSArray<ta_Obj> &arr)
	{
		_init(12,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,const xbSArray<ta_Obj> &arr)
	{
		_init(13,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14,const xbSArray<ta_Obj> &arr)
	{
		_init(14,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14,ta_Obj obj15,const xbSArray<ta_Obj> &arr)
	{
		_init(15,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14,obj15);
		Add(arr);
	}
	xbSArray(ta_Obj obj,ta_Obj obj2,ta_Obj obj3,ta_Obj obj4,ta_Obj obj5,ta_Obj obj6,ta_Obj obj7,ta_Obj obj8,ta_Obj obj9,ta_Obj obj10,ta_Obj obj11,ta_Obj obj12,ta_Obj obj13,ta_Obj obj14,ta_Obj obj15,ta_Obj obj16,const xbSArray<ta_Obj> &arr)
	{
		_init(16,obj,obj2,obj3,obj4,obj5,obj6,obj7,obj8,obj9,obj10,obj11,obj12,obj13,obj14,obj16);
		Add(arr);
	}
	void Init(const ta_Obj *pSrce,int sz)
	{
		if (sz < 0 || sz > targArrSzMax)
		{
			m_sz = 0;
			xbThrowEsysFmt("xbSArray()::Init(sz=%d, sz max=%d) : sz too big",
				sz,targArrSzMax);
		}
		ta_Obj *pDest = m_arr;
		m_sz = sz;
		while (sz > 0)
		{
			*(pDest++) = *(pSrce++);
			sz--;
		}
	}
	void Add(const ta_Obj *pSrce,int sz)
	{
		if (sz < 0 || sz+m_sz > targArrSzMax)
			xbThrowEsysFmt("xbSArray()::Add(sz=%d, cur sz=%d, sz max=%d) : sz too big",
				sz,m_sz,targArrSzMax);

		ta_Obj *pDest = m_arr + m_sz;
		m_sz += sz;
		while (sz > 0)
		{
			*(pDest++) = *(pSrce++);
			sz--;
		}
	}
	void Add(const xbSArray<ta_Obj> &arr)
	{
		Add(arr.Begin(),arr.Length);
	}
/*	void Add(const xbArray<ta_Obj> &arr)
	{
		Add(arr.Begin(),arr.Length);
	}*/

	ta_Obj &operator [] (int i)
	{
		if (i < 0 || i >= m_sz)
			xbThrowEargFmt("xbSArray.operator[](%d) failure, bad index (len=%d)",i,m_sz); 
		return m_arr[i];
	}
	const ta_Obj &operator [] (int i) const
	{
		if (i < 0 || i >= m_sz)
			xbThrowEargFmt("xbSArray.operator[](%d) const failure, bad index (len=%d)",i,m_sz); 
		return m_arr[i];
	}

	ta_Obj *Begin()
	{
		return m_sz?m_arr:NULL;
	}
	ta_Obj *End()
	{
		return m_sz?m_arr + m_sz:NULL;
	}
	const ta_Obj *Begin() const
	{
		return m_sz?m_arr:NULL;
	}
	const ta_Obj *End() const
	{
		return m_sz?m_arr + m_sz:NULL;
	}
	bool	IsEmpty() const
	{
		return m_sz == 0;
	}
	int		GetLength() const
	{
		return m_sz;
	}
	xbPropertyR(int,Length);
	ta_Obj &First(int i = 0)
	{
		if (i < 0 || i >= m_sz)
			xbThrowEargFmt("xbSArray.First(%d) failure, bad index (len=%d)",i,m_sz); 
		return m_arr[i];
	}
	const ta_Obj &First(int i = 0) const
	{
		if (i < 0 || i >= m_sz)
			xbThrowEargFmt("xbSArray.First(%d) const failure, bad index (len=%d)",i,m_sz); 
		return m_arr[i];
	}
	ta_Obj &Last(int i = 0)
	{
		int j = m_sz - i - 1;
		if (j < 0 || j >= m_sz)
			xbThrowEargFmt("xbSArray.First(%d) failure, bad index (len=%d)",i,m_sz); 
		return m_arr[j];
	}
	const ta_Obj &Last(int i = 0) const
	{
		int j = m_sz - i - 1;
		if (j < 0 || j >= m_sz)
			xbThrowEargFmt("xbSArray.First(%d) failure, bad index (len=%d)",i,m_sz); 
		return m_arr[j];
	}
protected:
	void _init(int sz,const ta_Obj obj,...)
	{
		Init(&obj,sz);
	}
	ta_Obj	m_arr[targArrSzMax];
	int		m_sz;
};


//MMM: CAUTION: Don't specify a class which take as member a pointer on itself ->
// if not after resize, insert, delete operations, array' objects will be corrupted. 
template<class ta_Obj,bool ta_bDelObj = true,bool ta_bAllocObj = true> 
	class xbArray
{
public:
	typedef xbArray<ta_Obj,ta_bDelObj,ta_bAllocObj> ta_self;

	xbArray()
	{
		m_pArr = NULL;
		m_nLen = 0;
#ifdef XDCBASE_X64
		m_nGrowBy = (128/sizeof(ta_Obj))<4?4:(128/sizeof(ta_Obj));
#else
		m_nGrowBy = (64/sizeof(ta_Obj))<4?4:(64/sizeof(ta_Obj));
#endif
	}
	~xbArray()
	{
		eProtect(Clear());
	}
	xbArray(const ta_self &arr)
	{
		m_pArr = NULL;
		m_nLen = 0;
#ifdef XDCBASE_X64
		m_nGrowBy = (128/sizeof(ta_Obj))<4?4:(128/sizeof(ta_Obj));
#else
		m_nGrowBy = (64/sizeof(ta_Obj))<4?4:(64/sizeof(ta_Obj));
#endif
		operator=(arr);
	}
	ta_Obj **DataPtr() {return (ta_Obj**)&m_pArr;}
	int *LengthPtr() {return &m_nLen;}
protected:
	class allocObj
	{
	public:
		allocObj() {};
		allocObj(const ta_Obj &obj) {m_Val = obj;};
		void operator=(const ta_Obj &obj) {m_Val = obj;}

		void *operator new(size_t sz, allocObj *ptr)
		{
			return (void*)ptr;
		}
		void operator delete(void *, allocObj *ptr) {};
		void operator delete(void *) {};

		operator ta_Obj&() {return m_Val;}
//	protected:
		ta_Obj	m_Val;
	};

public:
	xbArray &operator=(const ta_self &arr)
	{
		if (arr.IsEmpty())
		{
			Clear();
			return *this;
		}
		SetLength(arr.m_nLen);
		if (ta_bAllocObj)
		{
			allocObj	*pDest = m_pArr;
			allocObj	*pSrce = arr.m_pArr;
			for (int i = 0; i < m_nLen; i++,pDest++,pSrce++)
				*pDest = *pSrce;
		}
		else
		{
			::memcpy(m_pArr,arr.m_pArr,sizeof(allocObj) * m_nLen);
		}
		return *this;
	}


	ta_Obj &operator [] (int i)
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.operator[](%d) failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}
	const ta_Obj &operator [] (int i) const
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.operator[](%d) const failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}

	ta_Obj &GetAt(int i)
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.GetAt(%d) failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}
	const ta_Obj &GetAt(int i) const
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.GetAt(%d) failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}
	void SetAt(int i,const ta_Obj &val)
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.SetAt(%d,...) failure, bad index (len=%d)",i,m_nLen); 
		m_pArr[i] = val;
	}
	ta_Obj &First(int i = 0)
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.First(%d) failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}
	const ta_Obj &First(int i = 0) const
	{
		if (i < 0 || i >= m_nLen)
			xbThrowEargFmt("xbArray.First(%d) const failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[i];
	}
	ta_Obj &Last(int i = 0)
	{
		int j = m_nLen - i - 1;
		if (j < 0 || j >= m_nLen)
			xbThrowEargFmt("xbArray.Last(%d) failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[j];
	}
	const ta_Obj &Last(int i = 0) const
	{
		int j = m_nLen - i - 1;
		if (j < 0 || j >= m_nLen)
			xbThrowEargFmt("xbArray.Last(%d) const failure, bad index (len=%d)",i,m_nLen); 
		return m_pArr[j];
	}
	ta_Obj &unsafeGetAt(int i)
	{
		return m_pArr[i];
	}
	const ta_Obj &unsafeGetAt(int i) const
	{
		return m_pArr[i];
	}
	void unsafeSetAt(int i,const ta_Obj &val)
	{
		m_pArr[i] = val;
	}
	ta_Obj *Begin()
	{
		return (ta_Obj*)m_pArr;
	}
	ta_Obj *End()
	{
		if (IsEmpty()) return NULL;
		return (ta_Obj*)(m_pArr + m_nLen);
	}
	const ta_Obj *Begin() const
	{
		return (const ta_Obj*)m_pArr;
	}
	const ta_Obj *End() const
	{
		if (IsEmpty()) return NULL;
		return (const ta_Obj*)(m_pArr + m_nLen);
	}
	ta_Obj	*GetWritePtr(int len)
	{
		SetLength(len);
		return (ta_Obj*)m_pArr;
	}
	bool	IsEmpty() const
	{
		return m_pArr == NULL;
	}
	bool	IsValid() const
	{
		return m_pArr != NULL;
	}
	void Empty()
	{
		Clear();
	}
	virtual void Clear()
	{
		if (!m_pArr) return;
		if (ta_bDelObj)
		{
			allocObj	*ptr = m_pArr;
			for(int i = 0; i < m_nLen; i++, ptr++)
			{
				onDelete(ptr);
			}
		}
		allocObj	*ptr = m_pArr;
		m_pArr = NULL;
		m_nLen = 0;
		xbGlobalFree(ptr);
	}
	int GetGrowBy() const
	{
		return m_nGrowBy;
	}
	void SetGrowBy(int nGrowBy)
	{
		m_nGrowBy = nGrowBy;
	}
	xbPropertyRW(int,GrowBy);

	int		GetLength() const
	{
		return m_nLen; 
	}
	int		SetLength(int len)
	{
		if (len <= 0) 
		{
			xbRdbgAssert(len==0);
			Clear();
			return 0;
		}
		if (m_pArr && len == m_nLen) return len;
		allocObj *pArr;
		if (len < m_nLen)
		{
			if (!ta_bDelObj) m_nLen = len;
			else
			{
				xbAssert(m_pArr);
				pArr = m_pArr + m_nLen;
				while(m_nLen > len)
				{
					pArr--;
					m_nLen--;
					onDelete(pArr);
				}
			}
		}
		int newSize=(len+m_nGrowBy-1)/m_nGrowBy;
		if (newSize != (m_nLen+m_nGrowBy-1)/m_nGrowBy)
		{
			newSize *= m_nGrowBy;
			if (!m_pArr)
			{
				m_pArr = (allocObj*)xbGlobalAlloc(newSize * sizeof(allocObj)); 
			}
			else
			{
				m_pArr = (allocObj*)xbGlobalReAlloc(m_pArr,newSize * sizeof(allocObj));
			}
		}
		if (len > m_nLen)
		{
			if (ta_bAllocObj)
			{
				pArr = m_pArr + m_nLen;
				while(m_nLen < len)
				{
					new(pArr) allocObj();
					pArr++;
					m_nLen++;
				}
			}
			else
			{
				memset(m_pArr + m_nLen,0,(len - m_nLen) * sizeof(allocObj));
				m_nLen = len;
			}
		}
		return len;
	}

	int SetLength(int len,const ta_Obj &initObj)
	{
		if (len <= 0) 
		{
			xbRdbgAssert(len==0);
			Clear();
			return 0;
		}
		if (m_pArr && len == m_nLen) return len;
		allocObj *pArr;
		if (len < m_nLen)
		{
			if (!ta_bDelObj) m_nLen = len;
			else
			{
				xbAssert(m_pArr);
				pArr = m_pArr + m_nLen;
				while(m_nLen > len)
				{
					pArr--;
					m_nLen--;
					onDelete(pArr);
				}
			}
		}
		int newSize=(len+m_nGrowBy-1)/m_nGrowBy;
		if (newSize != (m_nLen+m_nGrowBy-1)/m_nGrowBy)
		{
			newSize *= m_nGrowBy;
			if (!m_pArr)
			{
				m_pArr = (allocObj*)xbGlobalAlloc(newSize * sizeof(allocObj)); 
			}
			else
			{
				m_pArr = (allocObj*)xbGlobalReAlloc(m_pArr,newSize * sizeof(allocObj)); 
			}
		}
		if (len > m_nLen)
		{
			pArr = m_pArr + m_nLen;
			while(m_nLen < len)
			{
				new(pArr) allocObj(initObj);
				pArr++;
				m_nLen++;
			}
		}
		return len;
	}
	xbPropertyRW(int,Length);


	int IncLength()
	{
		int len = m_nLen+1;
		int newSize=(len+m_nGrowBy-1)/m_nGrowBy;
		if (newSize != (m_nLen+m_nGrowBy-1)/m_nGrowBy)
		{
			newSize *= m_nGrowBy;
			if (!m_pArr)
			{
				m_pArr = (allocObj*)xbGlobalAlloc(newSize * sizeof(allocObj)); 
			}
			else
			{
				m_pArr = (allocObj*)xbGlobalReAlloc(m_pArr,newSize * sizeof(allocObj)); 
			}
		}
		if (ta_bAllocObj)
		{
			allocObj *pArr = m_pArr + m_nLen;
			new(pArr) allocObj();
		}
		else
		{
			memset(m_pArr + m_nLen,0,sizeof(allocObj));
		}
		return (m_nLen = len) - 1;
	}

	int	Add(const ta_Obj &obj)
	{
		int pos = IncLength();
		m_pArr[pos] = obj;
		return pos;
	}

	void Insert(int pos, const ta_Obj &obj)
	{
		if (pos < 0 || pos > m_nLen)
			xbThrowEargFmt("xbArray.Insert(%d,...) failure, bad index",pos);

		IncLength();
		if (ta_bDelObj) 
			onDelete(m_pArr + m_nLen - 1);
		if (m_nLen > pos + 1)
			::memmove(m_pArr + pos + 1,m_pArr + pos,sizeof(allocObj) * (m_nLen - pos - 1));
		if (ta_bAllocObj)
		{
			allocObj *ptr = m_pArr + pos;
			new(ptr) allocObj(obj);
		}
		else 
			m_pArr[pos] = obj;
	}

	void InsertLength(int pos, int lg)
	{
		if (lg <= 0)
			return;
		if (pos < 0 || pos > m_nLen)
			xbThrowEargFmt("xbArray.InsertLength(pos=%d,lg=%d) failure, bad index",pos,lg); 

		SetLength(lg + m_nLen);
		if (ta_bDelObj)
		{
			allocObj *ptr = m_pArr + m_nLen - lg;
			allocObj *pend = m_pArr + m_nLen;
			while(ptr < pend)
			{
				onDelete(ptr);
				ptr++;
			}
		}
		if (m_nLen > pos + lg)
			::memmove(m_pArr + pos + lg,m_pArr + pos,sizeof(allocObj) * (m_nLen - pos - lg));
		if (ta_bAllocObj)
		{
			allocObj *ptr = m_pArr + pos;
			allocObj *pend = ptr + lg;
			while(ptr < pend)
			{
				new(ptr) allocObj();
				ptr++;
			}
		}
		else 
		{
			memset(m_pArr + pos,0,sizeof(allocObj) * lg);
		}
	}

	void Delete(int pos)
	{
		if (pos < 0 || pos >= m_nLen)
			xbThrowEargFmt("xbArray.Delete(%d) failure, bad index (len=%d)",pos,m_nLen); 

		if (m_nLen <= 1)
		{
			Clear();
			return;
		}

		allocObj	*ptr = m_pArr + pos;
		if (ta_bDelObj) 
			onDelete(ptr);

		if (m_nLen > pos+1) 
			::memmove(ptr,ptr+1,sizeof(allocObj) * (m_nLen - pos - 1));
		m_nLen--;
		
		int newSize=(m_nLen+m_nGrowBy-1)/m_nGrowBy;
		if (newSize != (m_nLen+1+m_nGrowBy-1)/m_nGrowBy)
		{
			newSize *= m_nGrowBy;
			m_pArr = (allocObj*)xbGlobalReAlloc(m_pArr,newSize * sizeof(allocObj));
		}
	}
	void Delete(int pos, int cnt)
	{
		if (cnt <= 0) 
			return;
		if (pos < 0 || pos + cnt > m_nLen)
			xbThrowEargFmt("xbArray.Delete(%d,cnt=%d) failure, bad index (len=%d)",pos,cnt,m_nLen); 

		if (m_nLen <= cnt)
		{
			Clear();
			return;
		}
		if (ta_bDelObj) 
		{
			allocObj	*ptr = m_pArr + pos;
			for (int i = 0; i < cnt; i++)
			{
				onDelete(ptr);
				ptr++;
			}
		}
		allocObj	*ptr = m_pArr + pos;
		if (m_nLen > pos + cnt) 
			::memmove(ptr,ptr+cnt,sizeof(allocObj) * (m_nLen - pos - cnt));
		
		m_nLen-= cnt;
		
		int newSize=(m_nLen+m_nGrowBy-1)/m_nGrowBy;
		if (newSize != (m_nLen+cnt+m_nGrowBy-1)/m_nGrowBy)
		{
			newSize *= m_nGrowBy;
			m_pArr = (allocObj*)xbGlobalReAlloc(m_pArr,newSize * sizeof(allocObj));
		}
	}

	typedef int(__cdecl *SortCB)(const ta_Obj&,const ta_Obj&);

	void Sort(SortCB pSortCB)
	{
		if (!m_pArr) return;
		qsort(m_pArr,m_nLen,sizeof(allocObj),(int(__cdecl*)(const void *,const void *))pSortCB);
	}

	//rem: Template functions don't work in this case with vc 6.0 ...
	ta_Obj *SortedFind(const void *tofind,
		int (__cdecl *pFindCB)(const ta_Obj&,const void *),
		int *pPos = NULL)
	{
		if (!m_pArr) 
		{
			if (pPos) 
				*pPos = 0;
			return NULL;
		}
		LONG Cmp=1;
		allocObj *hi = m_pArr + m_nLen - 1;
		allocObj *lo = m_pArr,*ptr=m_pArr;
		while (lo <= hi)
		{
			ptr = lo + (((xbNptr(hi) - xbNptr(lo))/sizeof(allocObj)) / 2);
			Cmp = pFindCB(*ptr,tofind);
			if (Cmp > 0) hi = ptr - 1;
			else if (!Cmp) break;
			else lo = ptr + 1;
		}
	
		if (Cmp) 
		{
			if (pPos)
			{
				if (Cmp<0) 
					ptr++;
				*pPos = int((xbNptr(ptr) - xbNptr(m_pArr))/sizeof(allocObj));
			}
			return NULL;
		}
		if (pPos) 
			*pPos = int((xbNptr(ptr) - xbNptr(m_pArr))/sizeof(allocObj));

		return (ta_Obj*)ptr;
	}

	const ta_Obj *SortedFind(const void *tofind,
		int (__cdecl *pFindCB)(const ta_Obj&,const void *),
		int *pPos = NULL) const
	{
		if (!m_pArr) 
		{
			if (pPos) 
				*pPos = 0;
			return NULL;
		}
		LONG Cmp=1;
		allocObj *hi = m_pArr + m_nLen - 1;
		allocObj *lo = m_pArr,*ptr=m_pArr;
		while (lo <= hi)
		{
			ptr = lo + (((xbNptr(hi) - xbNptr(lo))/sizeof(allocObj)) / 2);
			Cmp = pFindCB(*ptr,tofind);
			if (Cmp > 0) hi = ptr - 1;
			else if (!Cmp) break;
			else lo = ptr + 1;
		}
	
		if (Cmp) 
		{
			if (pPos)
			{
				if (Cmp<0) 
					ptr++;
				*pPos = int((xbNptr(ptr) - xbNptr(m_pArr))/sizeof(allocObj));
			}
			return NULL;
		}
		if (pPos) 
			*pPos = int((xbNptr(ptr) - xbNptr(m_pArr))/sizeof(allocObj));

		return (ta_Obj*)ptr;
	}

	ta_Obj *Find(const void *tofind,
		int (__cdecl *pFindCB)(const ta_Obj&,const void *),int *pPos = NULL)
	{
		if (!m_pArr) 
		{
			if (pPos) 
				*pPos = 0;
			return NULL;
		}
		allocObj	*ptr = m_pArr;
		int			pos = 0;
		while(pos <= m_nLen)
		{
			if (pFindCB(*ptr,tofind) == 0) 
			{
				if (pPos) 
					*pPos = pos;
				return (ta_Obj*)ptr;
			}
			pos++;
			ptr++;
		}
		if (pPos) 
			*pPos = 0;
		return NULL;
	}

	const ta_Obj *Find(const void *tofind,
		int (__cdecl *pFindCB)(const ta_Obj&,const void *),int *pPos = NULL) const
	{
		if (!m_pArr) 
		{
			if (pPos) 
				*pPos = 0;
			return NULL;
		}
		allocObj	*ptr = m_pArr;
		int			pos = 0;
		while(pos <= m_nLen)
		{
			if (pFindCB(*ptr,tofind) == 0) 
			{
				if (pPos) 
					*pPos = pos;
				return (ta_Obj*)ptr;
			}
			pos++;
			ptr++;
		}
		if (pPos) 
			*pPos = 0;
		return NULL;
	}

	void Attach(ta_self *pArray)
	{
		Clear();
		m_pArr = pArray->m_pArr;
		m_nLen = pArray->m_nLen;
		pArray->m_pArr = NULL;
		pArray->m_nLen = 0;
	}
	void Detach(ta_self *pArray) //pArray could be NULL
	{
		if (pArray)
		{
			pArray->Clear();
			pArray->m_pArr = m_pArr;
			pArray->m_nLen = m_nLen;
		}
		m_pArr = NULL;
		m_nLen = 0;
	}
	void Attach(ta_Obj *pObj,int cObj)
	{
		Clear();
		m_pArr = (allocObj*)pObj;
		m_nLen = cObj;
	}
	ta_Obj *Detach(int *pcObj) //pcObj could be NULL
	{
		ta_Obj *pRet = (ta_Obj*)m_pArr;
		if (pcObj)
			*pcObj = m_nLen;
		m_pArr = NULL;
		m_nLen = 0;
		return pRet;
	}

protected:
	virtual void onDelete(allocObj *pObj)
	{
		delete pObj;
	}
	allocObj	*m_pArr;
	int			m_nLen;
	int			m_nGrowBy;
};

template<class ta_Obj,bool ta_bDelObj = true> class xbPtrArray
	:public xbArray<ta_Obj*,ta_bDelObj,false>
{
public:
	typedef xbPtrArray<ta_Obj,ta_bDelObj> ta_self;
	typedef xbArray<ta_Obj*,ta_bDelObj,false> ta_base;
	xbPtrArray()
	{
	}
	~xbPtrArray()
	{
		eProtect(Clear());
	}
	void ClearWithoutDelete()
	{
		if (!m_pArr) return;
		xbGlobalFree(m_pArr);
		m_pArr = NULL;
		m_nLen = 0;
	}
	void CopyPointersFrom(const xbPtrArray<ta_Obj,false> &arr)
	{
		ta_base::operator=((const ta_base &)arr);
	}
	void CopyPointersFrom(const xbPtrArray<ta_Obj,true> &arr)
	{
		ta_base::operator=((const ta_base &)arr);
	}
	void CopyObjetsFrom(const xbPtrArray<ta_Obj,false> &arr)
	{
		if (!ta_bDelObj)
			xbThrow xbEsys("xbPtrArray<ta_Obj,ta_bDelObj = false>::CopyObjetsFrom() forbidden when ta_bDelObj = false");
		if (arr.IsEmpty())
		{
			Clear();
			return;
		}
		SetLength(arr.m_nLen);
		allocObj	*pDest = m_pArr;
		allocObj	*pSrce = arr.m_pArr;
		for (int i = 0; i < m_nLen; i++,pDest++,pSrce++)
		{
			if (pSrce->m_Val)
				*pDest = new ta_Obj(*pSrce->m_Val);
			else *pDest = NULL;
		}
	}
	void CopyObjetsFrom(const xbPtrArray<ta_Obj,true> &arr)
	{
		if (!ta_bDelObj)
			xbThrow xbEsys("xbPtrArray<ta_Obj,ta_bDelObj = false>::CopyObjetsFrom() forbidden when ta_bDelObj = false");
		if (arr.IsEmpty())
		{
			Clear();
			return;
		}
		SetLength(arr.m_nLen);
		allocObj	*pDest = m_pArr;
		allocObj	*pSrce = arr.m_pArr;
		for (int i = 0; i < m_nLen; i++,pDest++,pSrce++)
		{
			if (pSrce->m_Val)
				*pDest = new ta_Obj(*pSrce->m_Val);
			else *pDest = NULL;
		}
	}
protected:
	virtual void onDelete(allocObj *pObj)
	{
		if (pObj->m_Val)
		{
			ta_Obj *pVal = pObj->m_Val;
			pObj->m_Val = NULL;
			delete pVal;
		}
	}
	xbPtrArray(const ta_self &arr)
	{
		m_pArr = NULL;
		m_nLen = 0;
		operator=(arr);
	}
	ta_self &operator=(const ta_self &arr)
	{
		ta_base::operator=(arr);
		return *this;
	}
	ta_self &operator=(const xbArray<ta_Obj*> &arr)
	{
		ta_base::operator=(arr);
		return *this;
	}
};

int	xbEXPORT xbSortLong(const long &nb1,const long &nb2);
int	xbEXPORT xbFindLong(const long &nb1,const void *pNb2);
int	xbEXPORT xbSortUlong(const ulong &nb1,const ulong &nb2);
int	xbEXPORT xbFindUlong(const ulong &nb1,const void *pNb2);
int	xbEXPORT xbSortInt64(const int64 &nb1,const int64 &nb2);
int	xbEXPORT xbFindInt64(const int64 &nb1,const void *pNb2);
int	xbEXPORT xbSortUint64(const uint64 &nb1,const uint64 &nb2);
int	xbEXPORT xbFindUint64(const uint64 &nb1,const void *pNb2);

#pragma warning(pop)

#endif
