/*!**************************************************************************** @file PVRTArray.h @copyright Copyright (c) Imagination Technologies Limited. @brief Expanding array template class. Allows appending and direct access. Mixing access methods should be approached with caution. ******************************************************************************/ #ifndef __PVRTARRAY_H__ #define __PVRTARRAY_H__ #include "PVRTGlobal.h" #include "PVRTError.h" /****************************************************************************** ** Classes ******************************************************************************/ /*!*************************************************************************** @class CPVRTArray @brief Expanding array template class. *****************************************************************************/ template<typename T> class CPVRTArray { public: /*!*************************************************************************** @brief Blank constructor. Makes a default sized array. *****************************************************************************/ CPVRTArray() : m_uiSize(0), m_uiCapacity(GetDefaultSize()) { m_pArray = new T[m_uiCapacity]; } /*!*************************************************************************** @brief Constructor taking initial size of array in elements. @param[in] uiSize intial size of array *****************************************************************************/ CPVRTArray(const unsigned int uiSize) : m_uiSize(0), m_uiCapacity(uiSize) { _ASSERT(uiSize != 0); m_pArray = new T[uiSize]; } /*!*************************************************************************** @brief Copy constructor. @param[in] original the other dynamic array *****************************************************************************/ CPVRTArray(const CPVRTArray& original) : m_uiSize(original.m_uiSize), m_uiCapacity(original.m_uiCapacity) { m_pArray = new T[m_uiCapacity]; for(unsigned int i=0;i<m_uiSize;i++) { m_pArray[i]=original.m_pArray[i]; } } /*!*************************************************************************** @brief constructor from ordinary array. @param[in] pArray an ordinary array @param[in] uiSize number of elements passed *****************************************************************************/ CPVRTArray(const T* const pArray, const unsigned int uiSize) : m_uiSize(uiSize), m_uiCapacity(uiSize) { _ASSERT(uiSize != 0); m_pArray = new T[uiSize]; for(unsigned int i=0;i<m_uiSize;i++) { m_pArray[i]=pArray[i]; } } /*!*************************************************************************** @brief constructor from a capacity and initial value. @param[in] uiSize initial capacity @param[in] val value to populate with *****************************************************************************/ CPVRTArray(const unsigned int uiSize, const T& val) : m_uiSize(uiSize), m_uiCapacity(uiSize) { _ASSERT(uiSize != 0); m_pArray = new T[uiSize]; for(unsigned int uiIndex = 0; uiIndex < m_uiSize; ++uiIndex) { m_pArray[uiIndex] = val; } } /*!*************************************************************************** @brief Destructor. *****************************************************************************/ virtual ~CPVRTArray() { if(m_pArray) delete [] m_pArray; } /*!*************************************************************************** @brief Inserts an element into the array, expanding it if necessary. @param[in] pos The position to insert the new element at @param[in] addT The element to insert @return The index of the new item or -1 on failure. *****************************************************************************/ int Insert(const unsigned int pos, const T& addT) { unsigned int uiIndex = pos; if(pos >= m_uiSize) // Are we adding to the end uiIndex = Append(addT); else { unsigned int uiNewCapacity = 0; T* pArray = m_pArray; if(m_uiSize > m_uiCapacity) { uiNewCapacity = m_uiCapacity + 10; // Expand the array by 10. pArray = new T[uiNewCapacity]; // New Array if(!pArray) return -1; // Failed to allocate memory! // Copy the first half to the new array for(unsigned int i = 0; i < pos; ++i) { pArray[i] = m_pArray[i]; } } // Copy last half to the new array for(unsigned int i = m_uiSize; i > pos; --i) { pArray[i] = m_pArray[i - 1]; } // Insert our new element pArray[pos] = addT; uiIndex = pos; // Increase our size ++m_uiSize; // Switch pointers and free memory if needed if(pArray != m_pArray) { m_uiCapacity = uiNewCapacity; delete[] m_pArray; m_pArray = pArray; } } return uiIndex; } /*!*************************************************************************** @brief Appends an element to the end of the array, expanding it if necessary. @param[in] addT The element to append @return The index of the new item. *****************************************************************************/ unsigned int Append(const T& addT) { unsigned int uiIndex = Append(); m_pArray[uiIndex] = addT; return uiIndex; } /*!*************************************************************************** @brief Creates space for a new item, but doesn't add. Instead returns the index of the new item. @return The index of the new item. *****************************************************************************/ unsigned int Append() { unsigned int uiIndex = m_uiSize; SetCapacity(m_uiSize+1); m_uiSize++; return uiIndex; } /*!*************************************************************************** @brief Clears the array. *****************************************************************************/ void Clear() { m_uiSize = 0U; } /*!*************************************************************************** @brief Changes the array to the new size @param[in] uiSize New size of array *****************************************************************************/ EPVRTError Resize(const unsigned int uiSize) { EPVRTError err = SetCapacity(uiSize); if(err != PVR_SUCCESS) return err; m_uiSize = uiSize; return PVR_SUCCESS; } /*!*************************************************************************** @brief Expands array to new capacity @param[in] uiSize New capacity of array *****************************************************************************/ EPVRTError SetCapacity(const unsigned int uiSize) { if(uiSize <= m_uiCapacity) return PVR_SUCCESS; // nothing to be done unsigned int uiNewCapacity; if(uiSize < m_uiCapacity*2) { uiNewCapacity = m_uiCapacity*2; // Ignore the new size. Expand to twice the previous size. } else { uiNewCapacity = uiSize; } T* pNewArray = new T[uiNewCapacity]; // New Array if(!pNewArray) return PVR_FAIL; // Failed to allocate memory! // Copy source data to new array for(unsigned int i = 0; i < m_uiSize; ++i) { pNewArray[i] = m_pArray[i]; } // Switch pointers and free memory m_uiCapacity = uiNewCapacity; T* pOldArray = m_pArray; m_pArray = pNewArray; delete [] pOldArray; return PVR_SUCCESS; } /*!*************************************************************************** @fn Copy @brief A copy function. Will attempt to copy from other CPVRTArrays if this is possible. @param[in] other The CPVRTArray needing copied *****************************************************************************/ template<typename T2> void Copy(const CPVRTArray<T2>& other) { T* pNewArray = new T[other.GetCapacity()]; if(pNewArray) { // Copy data for(unsigned int i = 0; i < other.GetSize(); i++) { pNewArray[i] = other[i]; } // Free current array if(m_pArray) delete [] m_pArray; // Swap pointers m_pArray = pNewArray; m_uiCapacity = other.GetCapacity(); m_uiSize = other.GetSize(); } } /*!*************************************************************************** @brief assignment operator. @param[in] other The CPVRTArray needing copied *****************************************************************************/ CPVRTArray& operator=(const CPVRTArray<T>& other) { if(&other != this) Copy(other); return *this; } /*!*************************************************************************** @brief appends an existing CPVRTArray on to this one. @param[in] other the array to append. *****************************************************************************/ CPVRTArray& operator+=(const CPVRTArray<T>& other) { if(&other != this) { for(unsigned int uiIndex = 0; uiIndex < other.GetSize(); ++uiIndex) { Append(other[uiIndex]); } } return *this; } /*!*************************************************************************** @brief Indexed access into array. Note that this has no error checking whatsoever @param[in] uiIndex index of element in array @return the element indexed *****************************************************************************/ T& operator[](const unsigned int uiIndex) { _ASSERT(uiIndex < m_uiCapacity); return m_pArray[uiIndex]; } /*!*************************************************************************** @brief Indexed access into array. Note that this has no error checking whatsoever @param[in] uiIndex index of element in array @return The element indexed *****************************************************************************/ const T& operator[](const unsigned int uiIndex) const { _ASSERT(uiIndex < m_uiCapacity); return m_pArray[uiIndex]; } /*!*************************************************************************** @return Size of array @brief Gives current size of array/number of elements *****************************************************************************/ unsigned int GetSize() const { return m_uiSize; } /*!*************************************************************************** @brief Gives the default size of array/number of elements @return Default size of array *****************************************************************************/ static unsigned int GetDefaultSize() { return 16U; } /*!*************************************************************************** @brief Gives current allocated size of array/number of elements @return Capacity of array *****************************************************************************/ unsigned int GetCapacity() const { return m_uiCapacity; } /*!*************************************************************************** @brief Indicates whether the given object resides inside the array. @param[in] object The object to check in the array @return true if object is contained in this array. *****************************************************************************/ bool Contains(const T& object) const { for(unsigned int uiIndex = 0; uiIndex < m_uiSize; ++uiIndex) { if(m_pArray[uiIndex] == object) return true; } return false; } /*!*************************************************************************** @brief Attempts to find the object in the array and returns a pointer if it is found, or NULL if not found. The time taken is O(N). @param[in] object The object to check in the array @return Pointer to the found object or NULL. *****************************************************************************/ T* Find(const T& object) const { for(unsigned int uiIndex = 0; uiIndex < m_uiSize; ++uiIndex) { if(m_pArray[uiIndex] == object) return &m_pArray[uiIndex]; } return NULL; } /*!*************************************************************************** @brief Simple bubble-sort of the array. Pred should be an object that defines a bool operator(). @param[in] predicate The object which defines "bool operator()" *****************************************************************************/ template<class Pred> void Sort(Pred predicate) { bool bSwap; for(unsigned int i=0; i < m_uiSize; ++i) { bSwap = false; for(unsigned int j=0; j < m_uiSize-1; ++j) { if(predicate(m_pArray[j], m_pArray[j+1])) { PVRTswap(m_pArray[j], m_pArray[j+1]); bSwap = true; } } if(!bSwap) return; } } /*!*************************************************************************** @brief Removes an element from the array. @param[in] uiIndex The index to remove @return success or failure *****************************************************************************/ virtual EPVRTError Remove(unsigned int uiIndex) { _ASSERT(uiIndex < m_uiSize); if(m_uiSize == 0) return PVR_FAIL; if(uiIndex == m_uiSize-1) { return RemoveLast(); } m_uiSize--; // Copy the data. memmove will only work for built-in types. for(unsigned int uiNewIdx = uiIndex; uiNewIdx < m_uiSize; ++uiNewIdx) { m_pArray[uiNewIdx] = m_pArray[uiNewIdx+1]; } return PVR_SUCCESS; } /*!*************************************************************************** @brief Removes the last element. Simply decrements the size value @return success or failure *****************************************************************************/ virtual EPVRTError RemoveLast() { if(m_uiSize > 0) { m_uiSize--; return PVR_SUCCESS; } else { return PVR_FAIL; } } protected: unsigned int m_uiSize; /*!< Current size of contents of array */ unsigned int m_uiCapacity; /*!< Currently allocated size of array */ T *m_pArray; /*!< The actual array itself */ }; // note "this" is required for ISO standard, C++ and gcc complains otherwise // http://lists.apple.com/archives/Xcode-users//2005/Dec/msg00644.html /*!*************************************************************************** @class CPVRTArrayManagedPointers @brief Maintains an array of managed pointers. *****************************************************************************/ template<typename T> class CPVRTArrayManagedPointers : public CPVRTArray<T*> { public: /*!*************************************************************************** @brief Destructor. *****************************************************************************/ virtual ~CPVRTArrayManagedPointers() { if(this->m_pArray) { for(unsigned int i=0;i<this->m_uiSize;i++) { delete(this->m_pArray[i]); } } } /*!*************************************************************************** @brief Removes an element from the array. @param[in] uiIndex The index to remove. @return success or failure *****************************************************************************/ virtual EPVRTError Remove(unsigned int uiIndex) { _ASSERT(uiIndex < this->m_uiSize); if(this->m_uiSize == 0) return PVR_FAIL; if(uiIndex == this->m_uiSize-1) { return this->RemoveLast(); } unsigned int uiSize = (this->m_uiSize - (uiIndex+1)) * sizeof(T*); delete this->m_pArray[uiIndex]; memmove(this->m_pArray + uiIndex, this->m_pArray + (uiIndex+1), uiSize); this->m_uiSize--; return PVR_SUCCESS; } /*!*************************************************************************** @brief Removes the last element. Simply decrements the size value @return success or failure *****************************************************************************/ virtual EPVRTError RemoveLast() { if(this->m_uiSize > 0 && this->m_pArray) { delete this->m_pArray[this->m_uiSize-1]; this->m_uiSize--; return PVR_SUCCESS; } else { return PVR_FAIL; } } }; #endif // __PVRTARRAY_H__ /***************************************************************************** End of file (PVRTArray.h) *****************************************************************************/