You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
12 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
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 3 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, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef hsBiExpander_inc
#define hsBiExpander_inc
#include "hsMemory.h"
#include "hsTemplates.h"
///////////////////////////////////////////////////////////////////////////////
////////////// Expander ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T> class hsExpander {
private:
Int32 fNumPost;
Int32 fNumPostAlloc;
T* fArray;
Int32 fGrowBy; // default = 0, to double
Int32 fMinSize; // default = 1, min == 1
Int32 fCurrent;
hsExpander(const hsExpander& x); // make it passed as ref or pointer
void IExpand(int newSize);
public:
enum { kMissingIndex = -1 };
hsExpander(Int32 minSize = 1, Int32 growBy = 0);
virtual ~hsExpander();
hsExpander<T>& operator=(const hsExpander<T>&orig) { return Copy(orig); }
hsExpander<T>& Copy(const hsExpander<T>& orig);
void SetCount(int cnt) { if( cnt >= fNumPostAlloc )IExpand(cnt); fNumPost = cnt; }
Int32 GetCount() const { return fNumPost; }
hsBool Empty() const { return GetCount() == 0; }
const T& Get(Int32 index) const;
Int32 Get(Int32 index, Int32 count, T data[]) const;
Int32 Find(const T&) const; // returns kMissingIndex if not found
void SetArray(T* a, Int32 cnt);
T* GetArray() { return fArray; }
T& operator[]( Int32 index );
Int32 Append(const T&); // returns t's index
T* Append();
Int32 Push(const T& t) { return Append(t); }
T* Push() { return Append(); }
T* Top() { return fNumPost ? fArray + fNumPost-1 : nil; }
Int32 Pop(T* t); // returns count of remaining
Int32 Pop();
void Reset(); // clears out everything
T& Head() { return fArray[0]; }
T& Tail() { return fArray[fNumPost-1]; }
T& Current() { return fArray[fCurrent]; }
void First();
void Last();
void Plus() { ++fCurrent; }
hsBool More() { return (fCurrent < fNumPost); }
};
template <class T>
hsExpander<T>& hsExpander<T>::Copy(const hsExpander<T>& orig)
{
SetCount(orig.GetCount());
int i;
for( i = 0; i < GetCount(); i++ )
fArray[i] = orig.fArray[i];
return *this;
}
template <class T>
void hsExpander<T>::SetArray(T* a, Int32 cnt)
{
delete [] fArray;
if( a )
fArray = a;
fNumPost = fNumPostAlloc = cnt;
}
template <class T>
void hsExpander<T>::IExpand(int newSize)
{
Int32 newPostAlloc = fNumPostAlloc;
if( !newPostAlloc )
newPostAlloc++;
while( newPostAlloc <= newSize )
newPostAlloc = fGrowBy ? newPostAlloc + fGrowBy : newPostAlloc << 1;
T* newArray = TRACKED_NEW T[newPostAlloc];
int i;
for( i = 0; i < fNumPost; i++ )
newArray[i] = fArray[i];
delete [] (fArray);
fArray = newArray;
fNumPostAlloc = newPostAlloc;
}
template <class T>
hsExpander<T>::hsExpander(Int32 minSize, Int32 growBy)
{
hsThrowIfBadParam(minSize < 0);
hsThrowIfBadParam(growBy < 0);
fMinSize = minSize+1;
fGrowBy = growBy;
fArray = TRACKED_NEW T[fMinSize];
fNumPostAlloc = fMinSize;
fNumPost = 0;
}
template <class T>
hsExpander<T>::~hsExpander()
{
delete [] fArray;
}
template <class T>
void hsExpander<T>::First()
{
fCurrent = 0;
}
template <class T>
void hsExpander<T>::Last()
{
fCurrent = fNumPost-1;
}
template <class T>
T& hsExpander<T>::operator[]( Int32 index )
{
hsDebugCode(hsThrowIfBadParam((index < 0)||(index >= fNumPost));)
return fArray[index];
}
template <class T>
const T& hsExpander<T>::Get( Int32 index ) const
{
hsDebugCode(hsThrowIfBadParam((index < 0)||(index >= fNumPost));)
return fArray[index];
}
template <class T>
Int32 hsExpander<T>::Get(Int32 index, Int32 count, T data[]) const
{
if( count > 0 )
{ hsThrowIfNilParam(data);
hsThrowIfBadParam((index < 0)||(index >= fNumPost));
if (index + count > fNumPost)
count = fNumPost - index;
for (int i = 0; i < count; i++)
data[i] = fArray[i + index];
}
return count;
}
template <class T>
Int32 hsExpander<T>::Find(const T& obj) const
{
for (int i = 0; i < fNumPost; i++)
if (fArray[i] == obj)
return i;
return kMissingIndex;
}
template <class T>
Int32 hsExpander<T>::Append(const T& obj)
{
hsAssert(!(fNumPost >= fNumPostAlloc), "Must be less");
if( fNumPost == fNumPostAlloc-1 )
IExpand(fNumPostAlloc);
fArray[fNumPost] = obj;
return fNumPost++;
}
template <class T>
T* hsExpander<T>::Append()
{
hsAssert(!(fNumPost >= fNumPostAlloc), "Must be less");
if( fNumPost == fNumPostAlloc-1 )
IExpand(fNumPostAlloc);
return fArray + fNumPost++;
}
template <class T>
Int32 hsExpander<T>::Pop(T*t)
{
hsThrowIfBadParam(Empty());
--fNumPost;
if( t )
*t = fArray[fNumPost];
return GetCount();
}
template <class T>
Int32 hsExpander<T>::Pop()
{
hsThrowIfBadParam(Empty());
--fNumPost;
return GetCount();
}
template <class T>
void hsExpander<T>::Reset()
{
fNumPost = 0;
}
///////////////////////////////////////////////////////////////////////////////
////////////// BiExpander /////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T> class hsBiExpander {
private:
Int32 fNumPre;
Int32 fNumPost;
Int32 fNumPreAlloc;
Int32 fNumPostAlloc;
T* fArray;
Int32 fGrowBy; // default = 0, to double
Int32 fMinSize; // default = 1, min == 1
Int32 fCurrent;
hsBiExpander<T>& operator=(const hsBiExpander<T>&); // don't allow assignment
hsBiExpander(const hsBiExpander<T>&); // make it passed as ref or pointer
void IExpand(int newSize, hsBool towardEnd = true);
public:
enum { kMissingIndex = -1 };
hsBiExpander(Int32 minSize = 1, Int32 growBy = 0);
virtual ~hsBiExpander();
Int32 GetFirst() const { return -fNumPre; }
Int32 GetCount() const { return fNumPre + fNumPost; }
hsBool Empty() const { return GetCount() == 0; }
const T& Get(Int32 index) const;
Int32 Get(Int32 index, Int32 count, T data[]) const;
Int32 Find(const T&) const; // returns kMissingIndex if not found
void SetArray(T* a, Int32 cnt, Int32 numPre=0);
T** GetArray() { return fArray - fNumPre; }
T& operator[]( Int32 index );
T* Append(); // returns t's index
T* Push(); // returns t's index
Int32 Append(const T&); // returns t's index
Int32 Push(const T&); // returns t's index
Int32 Pop(T*t = nil) { return PopHead(t); } // returns count of remaining
Int32 PopHead(T*t = nil); // returns count of remaining
Int32 PopTail(T*t = nil); // returns count of remaining
void Reset(); // clears out everything
T& Head() { return fArray[-fNumPre]; }
T& Tail() { return fArray[fNumPost-1]; }
T& Current() { return fArray[fCurrent]; }
void First();
void Last();
void Plus() { ++fCurrent; }
void Minus() { --fCurrent; }
hsBool More() { return (fCurrent < fNumPost)&&(fCurrent >= -fNumPre); }
};
template <class T>
void hsBiExpander<T>::SetArray(T* a, Int32 cnt, Int32 numPre)
{
if( !numPre )
Reset();
else
{
fNumPreAlloc = fNumPre = numPre;
fNumPostAlloc = fNumPost = cnt - numPre;
fArray = a + numPre;
}
}
template <class T>
void hsBiExpander<T>::IExpand(int newSize, hsBool towardEnd)
{
Int32 newPreAlloc = fNumPreAlloc;
Int32 newPostAlloc = fNumPostAlloc;
if( towardEnd )
{
if( !newPostAlloc )
newPostAlloc++;
while( newPostAlloc <= newSize )
newPostAlloc = fGrowBy ? newPostAlloc + fGrowBy : newPostAlloc << 1;
}
else
{
if( !newPreAlloc )
newPreAlloc++;
while( newPreAlloc <= newSize )
newPreAlloc = fGrowBy ? newPreAlloc + fGrowBy : newPreAlloc << 1;
}
T* newArray = TRACKED_NEW T[newPreAlloc + newPostAlloc];
newArray += newPreAlloc;
int i;
for( i = -fNumPre; i < fNumPost; i++ )
newArray[i] = fArray[i];
// HSMemory::BlockMove(fArray-fNumPre, newArray-fNumPre,
// (fNumPre+fNumPost)*sizeof(*fArray));
delete [] (fArray-fNumPreAlloc);
fArray = newArray;
fNumPreAlloc = newPreAlloc;
fNumPostAlloc = newPostAlloc;
}
template <class T>
hsBiExpander<T>::hsBiExpander(Int32 minSize, Int32 growBy)
{
hsThrowIfBadParam(minSize < 0);
hsThrowIfBadParam(growBy < 0);
fMinSize = minSize+1;
fGrowBy = growBy;
fArray = TRACKED_NEW T[fMinSize << 1];
fNumPreAlloc = fNumPostAlloc = fMinSize;
fArray += fNumPreAlloc;
fNumPre = fNumPost = 0;
}
template <class T>
hsBiExpander<T>::~hsBiExpander()
{
delete [] (fArray - fNumPreAlloc);
}
template <class T>
void hsBiExpander<T>::First()
{
fCurrent = -fNumPre;
}
template <class T>
void hsBiExpander<T>::Last()
{
fCurrent = fNumPost-1;
}
template <class T>
T& hsBiExpander<T>::operator[]( Int32 index )
{
hsDebugCode(hsThrowIfBadParam((index < -fNumPre)||(index >= fNumPost));)
return fArray[index];
}
template <class T>
const T& hsBiExpander<T>::Get( Int32 index ) const
{
hsDebugCode(hsThrowIfBadParam((index < -fNumPre)||(index >= fNumPost));)
return fArray[index];
}
template <class T>
Int32 hsBiExpander<T>::Get(Int32 index, Int32 count, T data[]) const
{
if( count > 0 )
{ hsThrowIfNilParam(data);
hsThrowIfBadParam((index < -fNumPre)||(index >= fNumPost));
if (index + count > fNumPost)
count = fNumPost - index;
for (int i = 0; i < count; i++)
data[i] = fArray[i + index];
}
return count;
}
template <class T>
Int32 hsBiExpander<T>::Find(const T& obj) const
{
for (int i = -fNumPre; i < fNumPost; i++)
if (fArray[i] == obj)
return i;
return kMissingIndex;
}
template <class T>
T* hsBiExpander<T>::Append()
{
hsAssert(!(fNumPost >= fNumPostAlloc), "Must be less");
if( fNumPost == fNumPostAlloc-1 )
IExpand(fNumPostAlloc, true);
return fArray + fNumPost++;
}
template <class T>
T* hsBiExpander<T>::Push()
{
hsAssert(!(fNumPre >= fNumPreAlloc), "Must be less");
if( ++fNumPre == fNumPreAlloc )
IExpand(fNumPreAlloc, false);
return fArray - fNumPre;
}
template <class T>
Int32 hsBiExpander<T>::Append(const T& obj)
{
hsAssert(!(fNumPost >= fNumPostAlloc), "Must be less");
if( fNumPost == fNumPostAlloc-1 )
IExpand(fNumPostAlloc, true);
fArray[fNumPost] = obj;
return fNumPost++;
}
template <class T>
Int32 hsBiExpander<T>::Push(const T& obj)
{
hsAssert(!(fNumPre >= fNumPreAlloc), "Must be less");
if( ++fNumPre == fNumPreAlloc )
IExpand(fNumPreAlloc, false);
fArray[-fNumPre] = obj;
return -fNumPre;
}
template <class T>
Int32 hsBiExpander<T>::PopHead(T*t)
{
hsThrowIfBadParam(Empty());
if( t )
*t = fArray[-fNumPre];
--fNumPre;
return GetCount();
}
template <class T>
Int32 hsBiExpander<T>::PopTail(T*t)
{
hsThrowIfBadParam(Empty());
--fNumPost;
if( t )
*t = fArray[fNumPost];
return GetCount();
}
template <class T>
void hsBiExpander<T>::Reset()
{
fNumPre = fNumPost = 0;
}
#endif // hsBiExpander_inc