|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: tblalloc.hxx
//
// Contents: Memory allocation wrappers for large tables
//
// Classes: PVarAllocator - protocol for variable data allocators
// PFixedAllocator - protocol for fixed and variable alloctors
// PFixedVarAllocator - protocol for fixed and variable alloctors
// CVarBufferAllocator - simple allocation from a buffer
// CFixedVarBufferAllocator - fixed/var allocation from a buffer
// CWindowDataAllocator - data allocator for window var data
// CFixedVarAllocator - data allocator for fixed and var pieces
//
// Functions: TblPageAlloc - Allocate page-alligned memory
// TblPageRealloc - re-allocate page-alligned memory
// TblPageDealloc - deallocate page-alligned memory
// TblPageGrowSize - suggest a new size for page-alligned memory
//
// Notes: TODO - There is no means to limit growth of data segments.
// How will memory allocation targets be maintained?
// Does there need to be some means of signalling
// between the memory allocators and their consumers?
//
// History: 14 Mar 1994 AlanW Created
//
//--------------------------------------------------------------------------
#pragma once
#ifdef DISPLAY_INCLUDES
#pragma message( "#include <" __FILE__ ">..." )
#endif
#include <pmalloc.hxx>
typedef ULONG_PTR TBL_OFF;
//
// Signature structure (for debugging primarily)
//
struct TBL_PAGE_SIGNATURE { ULONG ulSig; ULONG cbSize; PVOID pbAddr; PVOID pCaller; // pad to paragraph for convenience
};
//
// Signature values; all start with the string 'tbl'
//
const ULONG TBL_SIG_COMPRESSED = 0x436c6274; // 'tblC'
const ULONG TBL_SIG_ROWDATA = 0x526c6274; // 'tblR'
const ULONG TBL_SIG_VARDATA = 0x566c6274; // 'tblV'
const unsigned cbTblAllocAlignment = sizeof( double );
inline DWORD _RoundUpToChunk( DWORD x, DWORD chunksize ) { return (x + chunksize - 1) & ~(chunksize - 1); }
//
// Minimum size and incremental growth constants
//
const ULONG TBL_PAGE_ALLOC_MIN = 4096;
const ULONG TBL_PAGE_MASK = (TBL_PAGE_ALLOC_MIN - 1);
const ULONG TBL_PAGE_ALLOC_INCR = 32768;
//
// Maximum size of a growable data segment
//
const ULONG TBL_PAGE_MAX_SEGMENT_SIZE = 64 * 1024;
//+-------------------------------------------------------------------------
//
// Function: TblPageAlloc, public
//
// Synopsis: Allocate page-alligned memory
//
// Effects: The memory allocation counter is incremented.
// rcbSizeNeeded is adjusted on return to indicate the
// size of the allocated memory.
//
// Arguments: [rcbSizeNeeded] - required size of memory area
// [rcbPageAllocTracker] - memory allocation counter
// [ulSig] - signature of the memory (optional)
//
// Returns: PVOID - pointer to the allocated memory. NULL if
// allocation failure.
//
// Notes: rcbSizeNeeded is set to the minimum required size
// needed. TblPageGrowSize can be called to suggest
// a new size for an existing memory region.
//
// If ulSig is non-zero, the beginning of the allocated
// block is initialized with a signature block which
// identifies the caller, and which gives the size of the
// memory block. In this case, the returned pointer is
// advanced beyond the signature block.
//
//--------------------------------------------------------------------------
PVOID TblPageAlloc( ULONG& rcbSizeNeeded, ULONG& rcbPageAllocTracker, ULONG const ulSig = 0 );
//+-------------------------------------------------------------------------
//
// Function: TblPageRealloc, public
//
// Synopsis: Re-allocate page-alligned memory
//
// Effects: The memory allocation counter is incremented.
// Memory is committed or decommitted to the required size.
//
// Arguments: [rcbSizeNeeded] - required size of memory area
// [rcbPageAllocTracker] - memory allocation counter
// [cbNewSize] - required size of memory area
// [cbOldSize] - current size of memory area
//
// Returns: PVOID - pointer to the allocated memory. NULL if
// allocation failure.
//
// Notes: cbOldSize need not be supplied if the memory area
// begins with a signature block. In this case, the
// pbMem passed in should point to beyond the signature
// block, and the cbNewSize should not include the size
// of the signature block.
//
//--------------------------------------------------------------------------
PVOID TblPageRealloc( PVOID pbMem, ULONG& rcbPageAllocTracker, ULONG cbNewSize, ULONG cbOldSize );
//+-------------------------------------------------------------------------
//
// Function: TblPageDealloc, public
//
// Synopsis: Deallocate page-alligned memory
//
// Effects: The memory allocation counter is decremented
//
// Arguments: [pbMem] - pointer to the memory to be deallocated
// [rcbPageAllocTracker] - memory allocation counter
//
// Requires: memory to be deallocated must have previously been
// allocated by TblPageAlloc.
//
// Returns: nothing
//
// Notes:
//
//--------------------------------------------------------------------------
void TblPageDealloc( PVOID pbMem, ULONG& rcbPageAllocTracker, ULONG cbSize = 0 );
//+-------------------------------------------------------------------------
//
// Function: TblPageGrowSize, inline
//
// Synopsis: Suggest a new size for memory growth
//
// Arguments: [cbCurrentSize] - current allocation size
// [fSigned] - TRUE iff mem. block will include signature
//
// Returns: ULONG - size to be input to TblPageAlloc
//
// Notes:
//
//--------------------------------------------------------------------------
inline ULONG TblPageGrowSize( ULONG cbCurrentSize, ULONG const fSigned = FALSE ) { if (cbCurrentSize == 0) { return (ULONG)(fSigned ? TBL_PAGE_ALLOC_MIN - sizeof (TBL_PAGE_SIGNATURE): TBL_PAGE_ALLOC_MIN); }
ULONG cbSize = cbCurrentSize; if (fSigned) { cbSize += sizeof (TBL_PAGE_SIGNATURE); }
if (cbSize < TBL_PAGE_ALLOC_INCR) { cbSize *= 2; } else { cbSize += TBL_PAGE_ALLOC_INCR; }
// Round to page size
cbSize = _RoundUpToChunk( cbSize, TBL_PAGE_ALLOC_MIN );
if (fSigned) cbSize -= sizeof (TBL_PAGE_SIGNATURE); return cbSize; }
//+-------------------------------------------------------------------------
//
// Class: PFixedAllocator
//
// Purpose: Base class for fixed data allocator
//
//--------------------------------------------------------------------------
class PFixedAllocator { public: // Allocate a piece of fixed memory.
virtual PVOID AllocFixed() = 0;
// Return the size of the allocation unit
virtual size_t FixedWidth() const = 0;
// Return the base address of the reserved area
virtual BYTE* BufferAddr() const = 0;
// Return the size of the reserved area
virtual size_t GetReservedSize() const = 0;
virtual void ReInit( BOOL fVarOffsets, size_t cbReserved, void * pvBuf, ULONG cbBuf ) { Win4Assert(!"Never called"); } };
//+-------------------------------------------------------------------------
//
// Class: PFixedVarAllocator
//
// Purpose: Base class for fixed/variable data allocator
//
//--------------------------------------------------------------------------
class PFixedVarAllocator: public PVarAllocator, public PFixedAllocator { };
//+-------------------------------------------------------------------------
//
// Class: CVarBufferAllocator
//
// Purpose: Simple data allocator for byte buffer allocation.
//
// Notes: This allocator just carves pieces out of a data
// buffer and hands them out.
//
//--------------------------------------------------------------------------
class CVarBufferAllocator : public PVarAllocator { public: CVarBufferAllocator (PVOID pBuf, size_t cbBuf) : _pBuf( (BYTE *)pBuf), _pBaseAddr( (BYTE *)pBuf ), _cbBuf( cbBuf ) { }
// Allocate a piece of memory.
PVOID Allocate(ULONG cbNeeded);
// Free a previously allocated piece of memory (can't in a buffer).
void Free(PVOID pMem) { return; }
// Return whether OffsetToPointer has non-null effect
BOOL IsBasedMemory(void) { return _pBaseAddr != 0; }
// Convert a pointer offset to a pointer.
PVOID OffsetToPointer(TBL_OFF oBuf) { return _pBaseAddr + oBuf; }
// Convert a pointer to a pointer offset.
TBL_OFF PointerToOffset(PVOID pBuf) { return (BYTE *)pBuf - _pBaseAddr; }
// Set base address for OffsetToPointer and PointerToOffset
void SetBase(BYTE* pbBase) { _pBaseAddr = pbBase; }
protected: BYTE* _pBuf; // Buffer base
BYTE* _pBaseAddr; // Bias for addresses
size_t _cbBuf; // Available space in _pBuf
};
//+-------------------------------------------------------------------------
//
// Member: CVarBufferAllocator::Allocate, inline
//
// Synopsis: Allocates a piece of data out of a memory buffer
//
// Effects: updates _pBuf and _cbBuf
//
// Arguments: [cbNeeded] - number of byes of memory needed
//
// Returns: PVOID - a pointer to the allocated memory
//
// Signals: Throws E_OUTOFMEMORY if not enough memory is available.
//
// Notes:
//
//--------------------------------------------------------------------------
inline PVOID CVarBufferAllocator::Allocate( ULONG cbNeeded ) { BYTE* pRetBuf; if (cbNeeded <= _cbBuf) { pRetBuf = _pBuf; _pBuf += cbNeeded; _cbBuf -= cbNeeded; } else { QUIETTHROW( CException(E_OUTOFMEMORY) ); } return pRetBuf; }
//+-------------------------------------------------------------------------
//
// Class: CFixedVarBufferAllocator
//
// Purpose: fixed/var data allocator for byte buffer allocation.
//
// Notes: This allocator just carves pieces out of a data
// buffer and hands them out. It supports both fixed
// and variable data allocation, growing variable data
// downward from the end of the buffer.
//
//--------------------------------------------------------------------------
class CFixedVarBufferAllocator : public PFixedVarAllocator { public: CFixedVarBufferAllocator (PVOID pBuf, ULONG_PTR ulOffsetFixup, size_t cbBuf, size_t cbFixed, size_t cbReserved = 0) : _pBufferAddr( (BYTE *)pBuf ), _pBaseOffset( (BYTE *)pBuf ), _ulOffsetFixup( ulOffsetFixup ), _pFixedBuf( (BYTE *)pBuf + cbReserved), _pVarBuf( (BYTE *)pBuf + cbBuf), _cbReserved( cbReserved ), _cbFixed( cbFixed ) { // make the variable allocations 8-byte aligned
while ( ( (ULONG_PTR) _pVarBuf ) & ( cbTblAllocAlignment - 1 ) ) _pVarBuf--; }
// Allocate a piece of fixed memory.
PVOID AllocFixed();
// Allocate a piece of variable memory.
PVOID Allocate(ULONG cbNeeded);
// Free a previously allocated piece of memory (can't in a buffer).
void Free(PVOID pMem) {}
// Return whether OffsetToPointer has non-null effect
BOOL IsBasedMemory(void) { return _pBaseOffset != 0; }
// Convert a pointer offset to a pointer.
PVOID OffsetToPointer(TBL_OFF oBuf) { return oBuf - _ulOffsetFixup + _pBaseOffset; }
// Convert a pointer to a pointer offset.
TBL_OFF PointerToOffset(PVOID pBuf) { return (BYTE *) pBuf - _pBaseOffset + _ulOffsetFixup; }
// Set base address for OffsetToPointer and PointerToOffset
void SetBase(BYTE* pbBase) { _pBaseOffset = pbBase; }
// Return size of fixed data records
size_t FixedWidth() const { return _cbFixed; }
// Return the size of the reserved area
size_t GetReservedSize() const { return _cbReserved; }
// Return the base address of the reserved area
BYTE* BufferAddr() const { return _pBufferAddr; }
protected: size_t _FreeSpace() { return (size_t)(_pVarBuf - _pFixedBuf); }
BYTE* _pBufferAddr; // Buffer base
BYTE* _pBaseOffset; // Buffer base for offset calculations
ULONG_PTR _ulOffsetFixup; // Client's version of the buffer base
BYTE* _pFixedBuf; // Buffer pointer for next fixed alloc.
BYTE* _pVarBuf; // Buffer pointer for next variable alloc.
size_t _cbFixed; // Size of fixed allocations
size_t _cbReserved; // Size of reserved area
};
//+-------------------------------------------------------------------------
//
// Member: CFixedVarBufferAllocator::AllocFixed, inline
//
// Synopsis: Allocates a piece of fixed data out of a memory buffer
//
// Effects: updates _pFixedBuf
//
// Arguments: [cbNeeded] - number of byes of memory needed
//
// Returns: PVOID - a pointer to the allocated memory
//
// Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
// is available.
//
//--------------------------------------------------------------------------
inline PVOID CFixedVarBufferAllocator::AllocFixed() { BYTE* pRetBuf = _pFixedBuf;
if (_cbFixed <= _FreeSpace()) _pFixedBuf += _cbFixed; else QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
return pRetBuf; }
//+-------------------------------------------------------------------------
//
// Member: CFixedVarBufferAllocator::Allocate, inline
//
// Synopsis: Allocates a piece of data out of a memory buffer
//
// Effects: updates _pVarBuf
//
// Arguments: [cbNeeded] - number of byes of memory needed
//
// Returns: PVOID - a pointer to the allocated memory
//
// Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
// is available.
//
//--------------------------------------------------------------------------
inline PVOID CFixedVarBufferAllocator::Allocate( ULONG cbNeeded ) { // align to 8 byte boundry -- a little wasteful?
cbNeeded = _RoundUpToChunk( cbNeeded, cbTblAllocAlignment );
if (cbNeeded <= _FreeSpace()) _pVarBuf -= cbNeeded; else QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
return _pVarBuf; }
//+-------------------------------------------------------------------------
//
// Class: CWindowDataAllocator
//
// Purpose: Data allocator for window variable data
//
// Interface: PVarAllocator
//
// Notes: This allocator manages a pool of pages as a simple
// heap.
//
// Data allocated out of the variable data space will
// be stored internally as offsets, so that the data may
// be moved around without need for adjusting pointers.
//
//--------------------------------------------------------------------------
class CWindowDataAllocator: public PVarAllocator {
friend class CFixedVarAllocator; // for access to CHeapHeader
//
// Heap header used to record sizes of allocated and
// freed memory.
//
struct CHeapHeader {
USHORT cbSize; // size of this memory block
USHORT cbPrev; // size of preceeding mem. block
// the size of this struct needs to be 8-byte aligned.
ULONG _dummy;
// Flags or'ed with cbSize or cbPrev
enum EHeapFlags { HeapFree = 1, HeapEnd = 2, HEAP_FLAGS = 3 // HeapFree | HeapEnd
};
USHORT Size(void) { return cbSize & ~HEAP_FLAGS; } BOOL IsFree(void) { return cbSize & HeapFree; } BOOL IsFirst(void) { return (cbPrev & HeapEnd) != 0; } BOOL IsLast(void) { return (cbSize & HeapEnd) != 0; } CHeapHeader* Next(void) { return IsLast() ? 0 : (CHeapHeader*) (((BYTE *) this) + Size()); } CHeapHeader* Prev(void) { return IsFirst() ? 0 : (CHeapHeader*) (((BYTE *) this) - (cbPrev & ~HEAP_FLAGS)); } };
//
// Header used on each segment of arena to link them together
// and provide for offset mapping.
//
struct CSegmentHeader { CSegmentHeader* pNextSegment; // linked list to other segments
ULONG oBaseOffset; // assigned offset for first memory
ULONG cbSize; ULONG cbFree; // Free space in segment
};
public: CWindowDataAllocator (ULONG* pcbPageTracker = &_cbPageTracker) : _cbTotal( 0 ), _pBaseAddr( 0 ), _pcbPageUsed( pcbPageTracker ), _oNextOffset( sizeof (TBL_PAGE_SIGNATURE )) { }
CWindowDataAllocator (PVOID pBuf, size_t cbBuf, CHeapHeader* pHeap = NULL, ULONG* pcbPageTracker = &_cbPageTracker ) : _cbTotal( 0 ), _pBaseAddr( 0 ), _pcbPageUsed( pcbPageTracker ), _oNextOffset( sizeof (TBL_PAGE_SIGNATURE )) { _SetArena(pBuf, cbBuf, pHeap, sizeof(TBL_PAGE_SIGNATURE)); }
~CWindowDataAllocator();
// Allocate a piece of memory.
PVOID Allocate(ULONG cbNeeded);
// Free a previously allocated piece of memory.
void Free(PVOID pMem);
// Return whether OffsetToPointer has non-null effect
BOOL IsBasedMemory(void) { return TRUE; }
// Convert a pointer offset to a pointer.
PVOID OffsetToPointer(TBL_OFF oBuf);
// Convert a pointer to a pointer offset.
TBL_OFF PointerToOffset(PVOID pBuf);
// Set base address for OffsetToPointer and PointerToOffset
void SetBase(BYTE* pbBase);
#if CIDBG
void WalkHeap(void (pfnReport)(PVOID pb, USHORT cb, USHORT f)); #endif
private: // Set the limits of the allocation area.
void _SetArena( PVOID pBufBase, size_t cbBuf, CHeapHeader* pHeap = NULL, ULONG oBuf = 0); PVOID _SplitHeap(CSegmentHeader* pSegHdr, CHeapHeader* pThisHeap, size_t cbNeeded);
CSegmentHeader* _pBaseAddr; // pointer to first segment in arena
ULONG _oNextOffset; // next offset value to be assigned
size_t _cbTotal; // total size of allocation area
ULONG* _pcbPageUsed; // page usage tracking variable
static ULONG _cbPageTracker; // default page tracker
};
//+-------------------------------------------------------------------------
//
// Class: CFixedVarAllocator
//
// Purpose: The ultimate data allocator. Supports fixed and
// variable memory allocations from the same segment.
// Automatically grows both fixed and variable allocations
// automatically.
// When memory usage grows beyond 1 page, fixed and
// variable allocations will be taken from separate
// segments.
//
//--------------------------------------------------------------------------
class CFixedVarAllocator: public PFixedVarAllocator { public: CFixedVarAllocator (BOOL fGrowInitially, BOOL fVarOffsets, size_t cbDataWidth, size_t cbReserved = 0) : _fVarOffsets( fVarOffsets ), _pbBaseAddr( NULL ), _pbLastAddrPlusOne( NULL ), _pbBuf( NULL ), _cbBuf( 0 ), _cbReserved( cbReserved ), _cbDataWidth( cbDataWidth ), _VarAllocator( NULL ), _cbPageUsed( 0 ), _cbTotal( 0 ), _fDidReInit( FALSE ) { if ( fGrowInitially ) _GrowData(); }
~CFixedVarAllocator ( );
void ReInit( BOOL fVarOffsets, size_t cbReserved, void * pvBuf, ULONG cbBuf ) { Win4Assert( ! _fDidReInit ); Win4Assert( 0 == _pbBaseAddr ); Win4Assert( 0 == _VarAllocator );
_cbPageUsed = cbBuf; _cbReserved = cbReserved; _fVarOffsets = fVarOffsets; _pbBaseAddr = (BYTE *) pvBuf; _pbLastAddrPlusOne = _pbBaseAddr + _cbBuf; _fDidReInit = TRUE; }
// Allocate a piece of fixed memory.
PVOID AllocFixed() { Win4Assert( ! _fDidReInit ); BYTE* pRetBuf;
if (_pbBaseAddr == NULL) _GrowData();
if ( _cbDataWidth <= FreeSpace() ) { pRetBuf = _pbBuf; _pbBuf += _cbDataWidth; return pRetBuf; }
if (_cbDataWidth > FreeSpace() ) { if (_cbTotal != _cbBuf) _SplitData(TRUE); else _GrowData(); }
if ( _cbDataWidth <= FreeSpace() ) { pRetBuf = _pbBuf; _pbBuf += _cbDataWidth; } else { Win4Assert( !"unexpected out of memory" ); } return pRetBuf; }
// Return the size of the allocation unit
size_t FixedWidth() const { return _cbDataWidth; }
// Return the base address of the reserved area
BYTE* BufferAddr() const { return _pbBaseAddr; }
// Return the size of the reserved area
size_t GetReservedSize() const { return _cbReserved; }
// Convert an offset to a pointer
BYTE* FixedPointer( TBL_OFF obData ) const { return _pbBaseAddr+obData; }
// Convert an offset to a pointer
TBL_OFF FixedOffset( BYTE* pbData ) const { return pbData - _pbBaseAddr; }
// Return the base address of the allocation area
BYTE* FirstRow() const { return _pbBaseAddr + _cbReserved; }
// Set the size of the allocation unit
VOID SetRowSize(size_t cbDataWidth) { _cbDataWidth = cbDataWidth; }
// Set the size of the reserved area
VOID SetReservedSize(size_t cbReserved) { _cbReserved = cbReserved; if (_pbBaseAddr == NULL) _pbBuf = _pbBaseAddr + cbReserved; }
// Resize the fixed portion of the buffer
void ResizeAndInitFixed( size_t cbDataWidth, ULONG cItems );
// Get a buffer for the specified number of fixed size allocations
void * AllocMultipleFixed( ULONG cItems );
// Allocate a piece of variable memory.
PVOID Allocate(ULONG cbNeeded);
// Free a previously allocated piece of memory.
void Free(PVOID pMem);
// Return whether OffsetToPointer has non-null effect
BOOL IsBasedMemory(void) { return _fVarOffsets; }
// Set base address for OffsetToPointer and PointerToOffset
void SetBase(BYTE* pbBase) { if (pbBase == 0) _fVarOffsets = FALSE; else Win4Assert( !"CFixedVarAllocator::SetBase not supported" ); }
// Convert a pointer offset to a pointer.
PVOID OffsetToPointer(TBL_OFF oBuf) { if (_fVarOffsets) { if (_VarAllocator) return _VarAllocator->OffsetToPointer(oBuf); else if ( _fDidReInit ) return _pbBaseAddr + oBuf; else return _pbBaseAddr + oBuf - sizeof (TBL_PAGE_SIGNATURE); } else { return (PVOID) oBuf; } }
// Convert a pointer to a pointer offset. Bias it so the offset
// adds easily with a page address.
TBL_OFF PointerToOffset(PVOID pBuf) { if (_fVarOffsets) { if (_VarAllocator) return _VarAllocator->PointerToOffset(pBuf); else if ( _fDidReInit ) return (BYTE *) pBuf - _pbBaseAddr; else return ((BYTE *)pBuf - _pbBaseAddr) + sizeof (TBL_PAGE_SIGNATURE); } else { return (TBL_OFF) pBuf; } }
// Return free space in buffer
size_t FreeSpace() const { return (_cbBuf - (UINT)(_pbBuf - _pbBaseAddr)); }
// Return total memory used
ULONG MemUsed( void ) { return _cbPageUsed; }
#if CIDBG
CWindowDataAllocator* VarAllocator(void) { return _VarAllocator; } #endif
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf); #endif
protected: size_t _cbTotal; // Total allocated size of _pbBaseAddr
ULONG _cbPageUsed; // Total memory used
private: void _GrowData(size_t cbNeeded = 0); void _SplitData(BOOL fMoveFixedData); CWindowDataAllocator* _VarAllocator; // Var data allocator after split
BOOL _fVarOffsets; // offsets != pointers for var allocations
BOOL _fDidReInit; // hence the allocator is read-only and
// has one buffer for fixed & variable data
BYTE* _pbBaseAddr; // Bias for addresses
BYTE* _pbLastAddrPlusOne; // First byte past allocated memory
BYTE* _pbBuf; // Buffer base
size_t _cbBuf; // Available space in _pbBaseAddr
size_t _cbDataWidth; // Size of each allocated piece of memory
size_t _cbReserved; // Size of reserved area
};
class CFixedVarTableWindowAllocator: public PFixedVarAllocator { enum { cbFixedIncrement = 4096, cbVariableIncrement = 8192 };
public: CFixedVarTableWindowAllocator() : _cbFixedSize(0), _cbFixedUsed(0), _iCurVar(0), _cbVarUsed(0) {}
~CFixedVarTableWindowAllocator() { for ( unsigned i = 0; i < _aVariableBufs.Count(); i++ ) delete _aVariableBufs[i]; }
PVOID AllocFixed() { Win4Assert( _cbFixedSize <= cbFixedIncrement );
if ( ( _cbFixedSize + _cbFixedUsed ) > _aFixed.Count() ) _aFixed.ReSize( _aFixed.Count() + cbFixedIncrement );
void *pv = _aFixed.Get() + _cbFixedUsed; _cbFixedUsed += _cbFixedSize; return pv; }
size_t FixedWidth() const { return _cbFixedSize; }
BYTE * BufferAddr() const { return _aFixed.Get(); }
size_t GetReservedSize() const { return 0; }
void ReInit( BOOL fVarOffsets, size_t cbReserved, void * pvBuf, ULONG cbBuf ) { Win4Assert(!"Never called"); }
PVOID Allocate(ULONG cbNeeded) { cbNeeded = _RoundUpToChunk( cbNeeded, sizeof( double ) );
Win4Assert( cbNeeded <= cbVariableIncrement );
if ( 0 == _aVariableBufs.Count() ) { XArray<BYTE> xTmp( cbVariableIncrement ); _aVariableBufs[0] = xTmp.Get(); xTmp.Acquire(); } else if ( ( cbNeeded + _cbVarUsed ) > cbVariableIncrement ) { _iCurVar = _aVariableBufs.Count(); XArray<BYTE> xTmp( cbVariableIncrement ); _aVariableBufs[_aVariableBufs.Count()] = xTmp.Get(); xTmp.Acquire(); _cbVarUsed = 0; }
void * pv = _aVariableBufs[_iCurVar] + _cbVarUsed; _cbVarUsed += cbNeeded; return pv; }
void Free(PVOID pMem) { Win4Assert( !"not called" ); }
BOOL IsBasedMemory(void) { return FALSE; }
PVOID OffsetToPointer(TBL_OFF oBuf) { return (PVOID) oBuf; }
TBL_OFF PointerToOffset(PVOID pBuf) { return (TBL_OFF) pBuf; }
void SetBase(BYTE* pbBase) {}
VOID SetRowSize(size_t cbDataWidth) { _cbFixedSize = cbDataWidth; }
BYTE * FixedPointer( TBL_OFF obData ) { return _aFixed.Get()+obData; }
TBL_OFF FixedOffset( BYTE* pbData ) { return pbData - _aFixed.Get(); }
ULONG MemUsed() { return _cbFixedUsed + _aVariableBufs.Count() * cbVariableIncrement; }
BYTE * FirstRow() const { return _aFixed.Get(); }
private: size_t _cbFixedSize; size_t _cbFixedUsed; XArray<BYTE> _aFixed;
unsigned _iCurVar; unsigned _cbVarUsed; CDynArrayInPlace<BYTE *> _aVariableBufs; };
|