/********************************************************************** Filename : GArrayPaged.h Content : Created : Authors : Maxim Shemanarev Copyright : (c) 2001-2008 Scaleform Corp. All Rights Reserved. Licensees may use this file in accordance with the valid Scaleform Commercial License Agreement provided with the software. This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE. **********************************************************************/ #ifndef INC_GArrayPaged_H #define INC_GArrayPaged_H #include "GAllocator.h" // ***** GConstructorPagedPOD // // A modification of GConstructorPOD with paged construction/destruction // Used to avoid possible run-time overhead for POD types. //------------------------------------------------------------------------ template class GConstructorPagedPOD : public GConstructorPOD { public: static void ConstructArrayPaged(T**, UPInt, UPInt, UPInt, UPInt) {} static void DestructArrayPaged (T**, UPInt, UPInt, UPInt, UPInt) {} }; // ***** GConstructorPagedMov // // Correct C++ paged construction and destruction //------------------------------------------------------------------------ template class GConstructorPagedMov : public GConstructorMov { public: static void ConstructArrayPaged(T** pages, UPInt start, UPInt end, UPInt pageShift, UPInt pageMask) { for (UPInt i = start; i < end; ++i) { GConstructorMov::Construct(pages[i >> pageShift] + (i & pageMask)); } } static void DestructArrayPaged(T** pages, UPInt start, UPInt end, UPInt pageShift, UPInt pageMask) { for (UPInt i = end; i > start; --i) { GConstructorMov::Destruct(pages[(i-1) >> pageShift] + ((i-1) & pageMask)); } } }; // ***** GAllocatorPaged* // // Simple wraps as specialized allocators //------------------------------------------------------------------------ template struct GAllocatorPagedGH_POD : GAllocatorBaseGH, GConstructorPagedPOD {}; template struct GAllocatorPagedGH : GAllocatorBaseGH, GConstructorPagedMov {}; template struct GAllocatorPagedLH_POD : GAllocatorBaseLH, GConstructorPagedPOD {}; template struct GAllocatorPagedLH : GAllocatorBaseLH, GConstructorPagedMov {}; // ***** GArrayPagedBase // // A simple class template to store data similar to std::deque // It doesn't reallocate memory but instead, uses pages of data of size // of (1 << PageSh), that is, power of two. The data is NOT contiguous in memory, // so the only valid access methods are operator [], At(), ValueAt(), Front(), Back() // The container guarantees the persistence of elements' addresses in memory, // so the elements can be used in intrusive linked lists. // // Reallocs occur only when the pool of pointers to pages needs // to be extended (happens very rarely). You can control the increment // value by PtrPoolInc. // //------------------- // The code of this class template was taken from the Anti-Grain Geometry // Project and modified for the use by Scaleform. // Permission to use without restrictions is hereby granted to // Scaleform Corp. by the author of Anti-Grain Geometry Project. //------------------------------------------------------------------------ template class GArrayPagedBase { public: enum PageConsts { PageShift = PageSh, PageSize = 1 << PageShift, PageMask = PageSize - 1 }; typedef GArrayPagedBase SelfType; typedef T ValueType; typedef Allocator AllocatorType; ~GArrayPagedBase() { ClearAndRelease(); } GArrayPagedBase() : Size(0), NumPages(0), MaxPages(0), Pages(0) {} void ClearAndRelease() { if(NumPages) { T** blk = Pages + NumPages - 1; UPInt freeCount = Size & PageMask; while(NumPages--) { Allocator::DestructArray(*blk, freeCount); Allocator::Free(*blk); freeCount = PageSize; --blk; } Allocator::Free(Pages); } Size = NumPages = MaxPages = 0; Pages = 0; } void Clear() { Allocator::DestructArrayPaged(Pages, 0, Size, PageShift, PageMask); Size = 0; } void PushBack(const T& val) { Allocator::Construct(acquireDataPtr(), val); ++Size; } bool PushBackSafe(const T& val) { T* p = acquireDataPtrSafe(); if (!p) return false; Allocator::Construct(p, val); ++Size; return true; } template void PushBackAlt(const S& val) { Allocator::ConstructAlt(acquireDataPtr(), val); ++Size; } void PopBack() { if(Size) { Allocator::Destruct(&At(Size - 1)); --Size; } } UPInt GetCapacity() const { return NumPages << PageShift; } UPInt GetNumBytes() const { return GetCapacity() * sizeof(T) + MaxPages * sizeof(T*); } void Reserve(UPInt newCapacity) { if(newCapacity > GetCapacity()) { UPInt newNumPages = (newCapacity + PageMask) >> PageShift; for(UPInt i = NumPages; i < newNumPages; ++i) allocatePage(i); } } void Resize(UPInt newSize) { if(newSize > Size) { UPInt newNumPages = (newSize + PageMask) >> PageShift; for(UPInt i = NumPages; i < newNumPages; ++i) allocatePage(i); Allocator::ConstructArrayPaged(Pages, Size, newSize, PageShift, PageMask); Size = newSize; return; } if(newSize < Size) { Allocator::DestructArrayPaged(Pages, newSize, Size, PageShift, PageMask); Size = newSize; } } void CutAt(UPInt newSize) { if(newSize < Size) { Allocator::DestructArrayPaged(Pages, newSize, Size, PageShift, PageMask); Size = newSize; } } void InsertAt(UPInt pos, const T& val) { if(pos >= Size) { PushBack(val); } else { Allocator::Construct(acquireDataPtr()); ++Size; UPInt i; // TBD: Optimize page copying for(i = Size-1; i > pos; --i) { At(i) = At(i - 1); } At(pos) = val; } } void RemoveAt(UPInt pos) { if(Size) { // TBD: Optimize page copying for(++pos; pos < Size; pos++) { At(pos-1) = At(pos); } Allocator::Destruct(&At(Size - 1)); --Size; } } UPInt GetSize() const { return Size; } const T& operator [] (UPInt i) const { return Pages[i >> PageShift][i & PageMask]; } T& operator [] (UPInt i) { return Pages[i >> PageShift][i & PageMask]; } const T& At(UPInt i) const { return Pages[i >> PageShift][i & PageMask]; } T& At(UPInt i) { return Pages[i >> PageShift][i & PageMask]; } T ValueAt(UPInt i) const { return Pages[i >> PageShift][i & PageMask]; } const T& Front() const { return Pages[0][0]; } T& Front() { return Pages[0][0]; } const T& Back() const { return At(Size - 1); } T& Back() { return At(Size - 1); } private: // Copying is prohibited GArrayPagedBase(const SelfType&); const SelfType& operator = (const SelfType&); void allocatePage(UPInt nb) { if(nb >= MaxPages) { if(Pages) { Pages = (T**)Allocator::Realloc( Pages, (MaxPages + PtrPoolInc) * sizeof(T*), __FILE__, __LINE__); } else { Pages = (T**)Allocator::Alloc( this, PtrPoolInc * sizeof(T*), __FILE__, __LINE__); } MaxPages += PtrPoolInc; } Pages[nb] = (T*)Allocator::Alloc(this, PageSize * sizeof(T), __FILE__, __LINE__); NumPages++; } GINLINE T* acquireDataPtr() { UPInt np = Size >> PageShift; if(np >= NumPages) { allocatePage(np); } return Pages[np] + (Size & PageMask); } bool allocatePageSafe(UPInt nb) { if(nb >= MaxPages) { T** newPages; if(Pages) { newPages = (T**)Allocator::Realloc( Pages, (MaxPages + PtrPoolInc) * sizeof(T*), __FILE__, __LINE__); } else { newPages = (T**)Allocator::Alloc( this, PtrPoolInc * sizeof(T*), __FILE__, __LINE__); } if (!newPages) return false; Pages = newPages; MaxPages += PtrPoolInc; } Pages[nb] = (T*)Allocator::Alloc(this, PageSize * sizeof(T), __FILE__, __LINE__); if (!Pages[nb]) return false; NumPages++; return true; } GINLINE T* acquireDataPtrSafe() { UPInt np = Size >> PageShift; if(np >= NumPages) { if (!allocatePageSafe(np)) return NULL; } return Pages[np] + (Size & PageMask); } UPInt Size; UPInt NumPages; UPInt MaxPages; T** Pages; }; // ***** GArrayPagedPOD // // General purpose paged array for objects that DOES NOT require // construction/destruction. Constructors and destructors are not called! // Global heap is in use. //------------------------------------------------------------------------ template class GArrayPagedPOD : public GArrayPagedBase > { public: typedef GArrayPagedPOD SelfType; typedef T ValueType; typedef GAllocatorPagedGH_POD AllocatorType; }; // ***** GArrayPaged // // General purpose paged array for objects that require // explicit construction/destruction. // Global heap is in use. //------------------------------------------------------------------------ template class GArrayPaged : public GArrayPagedBase > { public: typedef GArrayPaged SelfType; typedef T ValueType; typedef GAllocatorPagedGH AllocatorType; }; // ***** GArrayPagedLH_POD // // General purpose paged array for objects that require // explicit construction/destruction. // Local heap is in use. //------------------------------------------------------------------------ template class GArrayPagedLH_POD : public GArrayPagedBase > { public: typedef GArrayPagedLH_POD SelfType; typedef T ValueType; typedef GAllocatorPagedLH_POD AllocatorType; }; // ***** GArrayPagedLH // // General purpose paged array for objects that DOES NOT require // construction/destruction. Constructors and destructors are not called! // Local heap is in use. //------------------------------------------------------------------------ template class GArrayPagedLH : public GArrayPagedBase > { public: typedef GArrayPagedLH SelfType; typedef T ValueType; typedef GAllocatorPagedLH AllocatorType; }; #endif