/* TMyArray.h - TMyArray template Copyright (c) 2005-2008 Chervov Dmitry This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include #define ARRAY_GROWBY 4 // if there is more than ARRAY_FREETHRESHOLD free array elements, then we're reallocating the array #define ARRAY_FREETHRESHOLD 16 template class TMyArray { public: TMyArray(); TMyArray(const TMyArray &A); ~TMyArray(); int GetSize() const; T* GetData() const; int AddElem(ARG_T pElem); int Add(const T *pItems, int nItems); void InsertElem(ARG_T pElem, int nInsertAt); void MoveElem(int nIndex, int nMoveTo); T& SetAtGrow(int nIndex); int Find(ARG_T pElem); // returns an index of the specified item, or -1 if the array doesn't contain the item int BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex = NULL); // returns an index of the specified item, or -1 if the array doesn't contain the item; // also it's possible to specify pIndex so that even if the array doesn't contain the item, the function will set *pIndex to a position where the item can be inserted; // CmpFunc must return -1, 0 and 1 depending whether pItem is lesser, equal or greater than needed; // BinarySearch() requires the array to be sorted in an ascending order void RemoveElem(int nIndex, int nItems = 1); void RemoveAll(); const T& operator[](int nIndex) const; T& operator[](int nIndex); TMyArray& operator=(const TMyArray &A); TMyArray& operator+=(const TMyArray &A); private: int SetAllocNum(int nNewAllocNum); T* pData; int nElemNum; int nAllocNum; }; template TMyArray::TMyArray() { nElemNum = 0; nAllocNum = 0; pData = NULL; } template TMyArray::TMyArray(const TMyArray &A)//: TMyArray() { nElemNum = 0; nAllocNum = 0; pData = NULL; *this = A; } template TMyArray::~TMyArray() { RemoveAll(); } template __forceinline int TMyArray::GetSize() const { return nElemNum; } template __forceinline T* TMyArray::GetData() const { return pData; } template __forceinline int TMyArray::SetAllocNum(int nNewAllocNum) { _ASSERT(nNewAllocNum >= nElemNum); T*pNewData = (nNewAllocNum) ? (T*)malloc(sizeof(T) * nNewAllocNum) : NULL; if (pData) { if (pNewData) { memcpy(pNewData, pData, sizeof(T) * nElemNum); } free(pData); } pData = pNewData; if (!pNewData) { nAllocNum = 0; return -1; // not enough memory? } else { nAllocNum = nNewAllocNum; return 0; // everything's ok } } template __forceinline int TMyArray::AddElem(ARG_T pElem) { if (nElemNum >= nAllocNum) { // reallocate memory to fit new element SetAllocNum(nAllocNum + GrowBy); } memset(pData + nElemNum, 0, sizeof(T)); pData[nElemNum] = pElem; return nElemNum++; } template __forceinline int TMyArray::Add(const T *pItems, int nItems) { if (nElemNum + nItems > nAllocNum) { // reallocate memory to fit new items SetAllocNum(nAllocNum + nElemNum + nItems - 1 - ((nElemNum + nItems - 1) % GrowBy) + GrowBy); } memset(pData + nElemNum, 0, sizeof(T) * nItems); int I; for (I = 0; I < nItems; I++) { pData[nElemNum++] = pItems[I]; } return nElemNum - nItems; // returns an index of the first item added } template __forceinline void TMyArray::InsertElem(ARG_T pElem, int nInsertAt) { _ASSERT(nInsertAt >= 0 && nInsertAt <= nElemNum); if (nElemNum >= nAllocNum) { // reallocate memory to fit new items SetAllocNum(nAllocNum + GrowBy); } memmove(pData + nInsertAt + 1, pData + nInsertAt, sizeof(T) * (nElemNum - nInsertAt)); memset(pData + nInsertAt, 0, sizeof(T)); pData[nInsertAt] = pElem; nElemNum++; } template __forceinline void TMyArray::MoveElem(int nIndex, int nMoveTo) { _ASSERT(nIndex >= 0 && nIndex < nElemNum && nMoveTo >= 0 && nMoveTo < nElemNum); if (nIndex == nMoveTo) { return; // nothing to do } char Elem[sizeof(T)]; memcpy(Elem, pData + nIndex, sizeof(T)); if (nIndex < nMoveTo) { memmove(pData + nIndex, pData + nIndex + 1, sizeof(T) * (nMoveTo - nIndex)); } else { memmove(pData + nMoveTo + 1, pData + nMoveTo, sizeof(T) * (nIndex - nMoveTo)); } memcpy(pData + nMoveTo, Elem, sizeof(T)); } template __forceinline T& TMyArray::SetAtGrow(int nIndex) { _ASSERT(nIndex >= 0); if (nIndex < nElemNum) { return pData[nIndex]; } if (nIndex >= nAllocNum) { if (SetAllocNum(nIndex - (nIndex % GrowBy) + GrowBy)) { // if there was an error nElemNum = 0; return *pData; } } memset(pData + nElemNum, 0, sizeof(T) * (nIndex - nElemNum + 1)); nElemNum = nIndex + 1; return pData[nIndex]; } template __forceinline int TMyArray::Find(ARG_T pElem) { int I; for (I = 0; I < nElemNum; I++) { if (pData[I] == pElem) { return I; } } return -1; } template __forceinline int TMyArray::BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex) { int L, R; int CmpResult; if (!nElemNum) { if (pIndex) { *pIndex = -1; } return -1; } for (L = 0, R = nElemNum; R - L > 1;) { int C = (L + R) >> 1; // rounds always to a lesser index if L + R is odd CmpResult = CmpFunc(pData[C], lParam); // usually, CmpFunc = pData[C] - lParam; i.e. CmpFunc > 0 when pData[C] is greater than necessary, < 0 when pData[C] is less, and = 0 when pData[C] is the item we search for if (CmpResult < 0) { L = C; } else if (CmpResult > 0) { R = C; } else { // CmpResult == 0 if (pIndex) { *pIndex = C; } return C; } } if (pIndex) { *pIndex = L; } CmpResult = CmpFunc(pData[L], lParam); if (!CmpResult) { return L; } if (CmpResult > 0) { // we don't need to check pData[R], as pData[R] > pData[L] > lParam, i.e. there are no suitable item in the array return -1; } // CmpResult < 0, we have to check pData[R] too if (pIndex) { *pIndex = R; } if (R >= nElemNum) { return -1; } return CmpFunc(pData[R], lParam) ? -1 : R; } template __forceinline void TMyArray::RemoveElem(int nIndex, int nItems) { _ASSERT(nIndex >= 0 && nIndex + nItems <= nElemNum); if (!nItems) { return; } // delete pData[nIndex]; // ~pData[nIndex]; int I; for (I = nIndex; I < nIndex + nItems; I++) { (pData + I)->~T(); } memmove(pData + nIndex, pData + nIndex + nItems, sizeof(T) * (nElemNum - nIndex - nItems)); nElemNum -= nItems; if (nAllocNum - nElemNum >= FreeThreshold) { SetAllocNum(nAllocNum - FreeThreshold); }/* else { memset(pData + nElemNum, 0, sizeof(T)); }*/ } template __forceinline void TMyArray::RemoveAll() { int I; for (I = 0; I < nElemNum; I++) { //delete pData[I]; (pData + I)->~T(); } nElemNum = 0; SetAllocNum(0); } template __forceinline const T& TMyArray::operator[](int nIndex) const { _ASSERT(nIndex >= 0 && nIndex < nElemNum); return pData[nIndex]; } template __forceinline T& TMyArray::operator[](int nIndex) { _ASSERT(nIndex >= 0 && nIndex < nElemNum); return pData[nIndex]; } template __forceinline TMyArray& TMyArray::operator=(const TMyArray &A) { RemoveAll(); int I; for (I = 0; I < A.GetSize(); I++) { AddElem(A[I]); } return *this; } template __forceinline TMyArray& TMyArray::operator+=(const TMyArray &A) { int I; for (I = 0; I < A.GetSize(); I++) { AddElem(A[I]); } return *this; } typedef TMyArray CHARARRAY;