346 lines
14 KiB
C++
346 lines
14 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Contains a simple container class.
|
||
|
* \file IceContainer.cpp
|
||
|
* \author Pierre Terdiman
|
||
|
* \date February, 5, 2000
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Contains a list of 32-bits values.
|
||
|
* Use this class when you need to store an unknown number of values. The list is automatically
|
||
|
* resized and can contains 32-bits entities (dwords or floats)
|
||
|
*
|
||
|
* \class Container
|
||
|
* \author Pierre Terdiman
|
||
|
* \version 1.0
|
||
|
* \date 08.15.98
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// Precompiled Header
|
||
|
#include "Stdafx.h"
|
||
|
|
||
|
using namespace IceCore;
|
||
|
|
||
|
// Static members
|
||
|
#ifdef CONTAINER_STATS
|
||
|
udword Container::mNbContainers = 0;
|
||
|
udword Container::mUsedRam = 0;
|
||
|
#endif
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Constructor. No entries allocated there.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
mNbContainers++;
|
||
|
mUsedRam+=sizeof(Container);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Constructor. Also allocates a given number of entries.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
mNbContainers++;
|
||
|
mUsedRam+=sizeof(Container);
|
||
|
#endif
|
||
|
SetSize(size);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Copy constructor.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
mNbContainers++;
|
||
|
mUsedRam+=sizeof(Container);
|
||
|
#endif
|
||
|
*this = object;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Destructor. Frees everything and leaves.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container::~Container()
|
||
|
{
|
||
|
Empty();
|
||
|
#ifdef CONTAINER_STATS
|
||
|
mNbContainers--;
|
||
|
mUsedRam-=GetUsedRam();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Clears the container. All stored values are deleted, and it frees used ram.
|
||
|
* \see Reset()
|
||
|
* \return Self-Reference
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container& Container::Empty()
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
DELETEARRAY(mEntries);
|
||
|
mCurNbEntries = mMaxNbEntries = 0;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Resizes the container.
|
||
|
* \param needed [in] assume the container can be added at least "needed" values
|
||
|
* \return true if success.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::Resize(udword needed)
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
// Subtract previous amount of bytes
|
||
|
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
|
||
|
// Get more entries
|
||
|
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
|
||
|
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
|
||
|
|
||
|
// Get some bytes for new entries
|
||
|
udword* NewEntries = new udword[mMaxNbEntries];
|
||
|
CHECKALLOC(NewEntries);
|
||
|
|
||
|
#ifdef CONTAINER_STATS
|
||
|
// Add current amount of bytes
|
||
|
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
|
||
|
// Copy old data if needed
|
||
|
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||
|
|
||
|
// Delete old data
|
||
|
DELETEARRAY(mEntries);
|
||
|
|
||
|
// Assign new pointer
|
||
|
mEntries = NewEntries;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Sets the initial size of the container. If it already contains something, it's discarded.
|
||
|
* \param nb [in] Number of entries
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::SetSize(udword nb)
|
||
|
{
|
||
|
// Make sure it's empty
|
||
|
Empty();
|
||
|
|
||
|
// Checkings
|
||
|
if(!nb) return false;
|
||
|
|
||
|
// Initialize for nb entries
|
||
|
mMaxNbEntries = nb;
|
||
|
|
||
|
// Get some bytes for new entries
|
||
|
mEntries = new udword[mMaxNbEntries];
|
||
|
CHECKALLOC(mEntries);
|
||
|
|
||
|
#ifdef CONTAINER_STATS
|
||
|
// Add current amount of bytes
|
||
|
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Refits the container and get rid of unused bytes.
|
||
|
* \return true if success
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::Refit()
|
||
|
{
|
||
|
#ifdef CONTAINER_STATS
|
||
|
// Subtract previous amount of bytes
|
||
|
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
|
||
|
// Get just enough entries
|
||
|
mMaxNbEntries = mCurNbEntries;
|
||
|
if(!mMaxNbEntries) return false;
|
||
|
|
||
|
// Get just enough bytes
|
||
|
udword* NewEntries = new udword[mMaxNbEntries];
|
||
|
CHECKALLOC(NewEntries);
|
||
|
|
||
|
#ifdef CONTAINER_STATS
|
||
|
// Add current amount of bytes
|
||
|
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||
|
#endif
|
||
|
|
||
|
// Copy old data
|
||
|
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||
|
|
||
|
// Delete old data
|
||
|
DELETEARRAY(mEntries);
|
||
|
|
||
|
// Assign new pointer
|
||
|
mEntries = NewEntries;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Checks whether the container already contains a given value.
|
||
|
* \param entry [in] the value to look for in the container
|
||
|
* \param location [out] a possible pointer to store the entry location
|
||
|
* \see Add(udword entry)
|
||
|
* \see Add(float entry)
|
||
|
* \see Empty()
|
||
|
* \return true if the value has been found in the container, else false.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::Contains(udword entry, udword* location) const
|
||
|
{
|
||
|
// Look for the entry
|
||
|
for(udword i=0;i<mCurNbEntries;i++)
|
||
|
{
|
||
|
if(mEntries[i]==entry)
|
||
|
{
|
||
|
if(location) *location = i;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Deletes an entry. If the container contains such an entry, it's removed.
|
||
|
* \param entry [in] the value to delete.
|
||
|
* \return true if the value has been found in the container, else false.
|
||
|
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::Delete(udword entry)
|
||
|
{
|
||
|
// Look for the entry
|
||
|
for(udword i=0;i<mCurNbEntries;i++)
|
||
|
{
|
||
|
if(mEntries[i]==entry)
|
||
|
{
|
||
|
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
|
||
|
DeleteIndex(i);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
|
||
|
* \param entry [in] the value to delete.
|
||
|
* \return true if the value has been found in the container, else false.
|
||
|
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
bool Container::DeleteKeepingOrder(udword entry)
|
||
|
{
|
||
|
// Look for the entry
|
||
|
for(udword i=0;i<mCurNbEntries;i++)
|
||
|
{
|
||
|
if(mEntries[i]==entry)
|
||
|
{
|
||
|
// Entry has been found at index i.
|
||
|
// Shift entries to preserve order. You really should use a linked list instead.
|
||
|
mCurNbEntries--;
|
||
|
for(udword j=i;j<mCurNbEntries;j++)
|
||
|
{
|
||
|
mEntries[j] = mEntries[j+1];
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Gets the next entry, starting from input one.
|
||
|
* \param entry [in/out] On input, the entry to look for. On output, the next entry
|
||
|
* \param find_mode [in] wrap/clamp
|
||
|
* \return Self-Reference
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container& Container::FindNext(udword& entry, FindMode find_mode)
|
||
|
{
|
||
|
udword Location;
|
||
|
if(Contains(entry, &Location))
|
||
|
{
|
||
|
Location++;
|
||
|
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
|
||
|
entry = mEntries[Location];
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Gets the previous entry, starting from input one.
|
||
|
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
|
||
|
* \param find_mode [in] wrap/clamp
|
||
|
* \return Self-Reference
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
Container& Container::FindPrev(udword& entry, FindMode find_mode)
|
||
|
{
|
||
|
udword Location;
|
||
|
if(Contains(entry, &Location))
|
||
|
{
|
||
|
Location--;
|
||
|
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
|
||
|
entry = mEntries[Location];
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/**
|
||
|
* Gets the ram used by the container.
|
||
|
* \return the ram used in bytes.
|
||
|
*/
|
||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
udword Container::GetUsedRam() const
|
||
|
{
|
||
|
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
|
||
|
}
|
||
|
|
||
|
/*void Container::operator=(const Container& object)
|
||
|
{
|
||
|
SetSize(object.GetNbEntries());
|
||
|
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
|
||
|
mCurNbEntries = mMaxNbEntries;
|
||
|
}*/
|