Files
GTASource/rage/scaleform/Src/GKernel/GArrayPaged.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

463 lines
12 KiB
C++

/**********************************************************************
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 T>
class GConstructorPagedPOD : public GConstructorPOD<T>
{
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 T>
class GConstructorPagedMov : public GConstructorMov<T>
{
public:
static void ConstructArrayPaged(T** pages, UPInt start, UPInt end, UPInt pageShift, UPInt pageMask)
{
for (UPInt i = start; i < end; ++i)
{
GConstructorMov<T>::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<T>::Destruct(pages[(i-1) >> pageShift] + ((i-1) & pageMask));
}
}
};
// ***** GAllocatorPaged*
//
// Simple wraps as specialized allocators
//------------------------------------------------------------------------
template<class T, int SID> struct GAllocatorPagedGH_POD : GAllocatorBaseGH<SID>, GConstructorPagedPOD<T> {};
template<class T, int SID> struct GAllocatorPagedGH : GAllocatorBaseGH<SID>, GConstructorPagedMov<T> {};
template<class T, int SID> struct GAllocatorPagedLH_POD : GAllocatorBaseLH<SID>, GConstructorPagedPOD<T> {};
template<class T, int SID> struct GAllocatorPagedLH : GAllocatorBaseLH<SID>, GConstructorPagedMov<T> {};
// ***** 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 T, int PageSh, int PtrPoolInc, class Allocator>
class GArrayPagedBase
{
public:
enum PageConsts
{
PageShift = PageSh,
PageSize = 1 << PageShift,
PageMask = PageSize - 1
};
typedef GArrayPagedBase<T, PageSh, PtrPoolInc, Allocator> 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<class S>
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 T, int PageSh=6, int PtrPoolInc=64, int SID=GStat_Default_Mem>
class GArrayPagedPOD :
public GArrayPagedBase<T, PageSh, PtrPoolInc, GAllocatorPagedGH_POD<T, SID> >
{
public:
typedef GArrayPagedPOD<T, PageSh, PtrPoolInc, SID> SelfType;
typedef T ValueType;
typedef GAllocatorPagedGH_POD<T, SID> AllocatorType;
};
// ***** GArrayPaged
//
// General purpose paged array for objects that require
// explicit construction/destruction.
// Global heap is in use.
//------------------------------------------------------------------------
template<class T, int PageSh=6, int PtrPoolInc=64, int SID=GStat_Default_Mem>
class GArrayPaged :
public GArrayPagedBase<T, PageSh, PtrPoolInc, GAllocatorPagedGH<T, SID> >
{
public:
typedef GArrayPaged<T, PageSh, PtrPoolInc, SID> SelfType;
typedef T ValueType;
typedef GAllocatorPagedGH<T, SID> AllocatorType;
};
// ***** GArrayPagedLH_POD
//
// General purpose paged array for objects that require
// explicit construction/destruction.
// Local heap is in use.
//------------------------------------------------------------------------
template<class T, int PageSh=6, int PtrPoolInc=64, int SID=GStat_Default_Mem>
class GArrayPagedLH_POD :
public GArrayPagedBase<T, PageSh, PtrPoolInc, GAllocatorPagedLH_POD<T, SID> >
{
public:
typedef GArrayPagedLH_POD<T, PageSh, PtrPoolInc, SID> SelfType;
typedef T ValueType;
typedef GAllocatorPagedLH_POD<T, SID> 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 T, int PageSh=6, int PtrPoolInc=64, int SID=GStat_Default_Mem>
class GArrayPagedLH :
public GArrayPagedBase<T, PageSh, PtrPoolInc, GAllocatorPagedLH<T, SID> >
{
public:
typedef GArrayPagedLH<T, PageSh, PtrPoolInc, SID> SelfType;
typedef T ValueType;
typedef GAllocatorPagedLH<T, SID> AllocatorType;
};
#endif