231 lines
5.8 KiB
C++
231 lines
5.8 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1994 - 1994.
|
||
|
//
|
||
|
// File: tblrowal.cxx
|
||
|
//
|
||
|
// Contents: The CTableRowAlloc class, used in allocation
|
||
|
// of table row data and checking of column bindings.
|
||
|
//
|
||
|
// Classes: CTableRowAlloc
|
||
|
//
|
||
|
// History: 27 Jun 1994 Alanw Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include "pch.cxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <tblrowal.hxx>
|
||
|
|
||
|
#include "tabledbg.hxx"
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTableRowAlloc::CTableRowAlloc, public
|
||
|
//
|
||
|
// Synopsis: Constructor for a row field allocator. Initializes
|
||
|
// max. width and other members.
|
||
|
//
|
||
|
// Arguments: [cbRow] - maximum size of the row. Can be zero if the
|
||
|
// row is to grow dynamically via the AllocOffset
|
||
|
// method.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//+-------------------------------------------------------------------------
|
||
|
|
||
|
CTableRowAlloc::CTableRowAlloc(unsigned cbRow) :
|
||
|
_maxRow( (USHORT)cbRow ),
|
||
|
_cbRow( sizeof(_aRowMap) ),
|
||
|
_iFirstFree(0)
|
||
|
{
|
||
|
|
||
|
RtlZeroMemory( _aRowMap, sizeof(_aRowMap) );
|
||
|
_pRowMap = _aRowMap;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTableRowAlloc::_IsLikelyFree
|
||
|
//
|
||
|
// Synopsis: Quickly checks to see if the given offset is likely to be
|
||
|
// free.
|
||
|
//
|
||
|
// Arguments: [iOffset] - Offset to test
|
||
|
// [cbData] - Length of the data needed.
|
||
|
//
|
||
|
// Returns: TRUE if that location is likely to be free.
|
||
|
// FALSE if it is guaranteed not to be a free candidate.
|
||
|
//
|
||
|
// History: 5-03-96 srikants Created
|
||
|
//
|
||
|
// Notes: This is a quick check to see if the location is likely to
|
||
|
// be free. Does not guarantee that it is free.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
inline BOOL CTableRowAlloc::_IsLikelyFree( unsigned iOffset, unsigned cbData )
|
||
|
{
|
||
|
if ( iOffset < _cbRow && _pRowMap[iOffset] != 0 )
|
||
|
return FALSE;
|
||
|
|
||
|
if (iOffset + cbData > _maxRow)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
inline unsigned AlignedOffset( unsigned offset, unsigned cbAlign )
|
||
|
{
|
||
|
Win4Assert( ( cbAlign & (cbAlign-1) ) == 0 );
|
||
|
return (offset + cbAlign-1) & ~(cbAlign-1);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTableRowAlloc::AllocOffset, public
|
||
|
//
|
||
|
// Synopsis: Allocate a row field. Return the offset in the row.
|
||
|
//
|
||
|
// Arguments: [cbData] - size of data field
|
||
|
// [cbAlign] - required alignment of field (may be zero
|
||
|
// if no alignment requirement)
|
||
|
// [fGrow] - TRUE if row can be grown
|
||
|
//
|
||
|
// Returns: USHORT - offset of allocted field. 0xFFFF if failed.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//+-------------------------------------------------------------------------
|
||
|
|
||
|
USHORT CTableRowAlloc::AllocOffset(
|
||
|
unsigned cbData,
|
||
|
unsigned cbAlign,
|
||
|
BOOL fGrow
|
||
|
) {
|
||
|
Win4Assert(cbAlign <= 16);
|
||
|
|
||
|
if (cbAlign == 0)
|
||
|
cbAlign = 1;
|
||
|
|
||
|
USHORT usSavedMax = _maxRow;
|
||
|
|
||
|
for ( unsigned i = AlignedOffset(_iFirstFree,cbAlign);
|
||
|
i < _cbRow;
|
||
|
i += cbAlign)
|
||
|
{
|
||
|
if (fGrow && (i + cbData) > _maxRow)
|
||
|
SetRowWidth(i + cbData);
|
||
|
if ( _IsLikelyFree(i, cbData) && ReserveRowSpace( i, cbData )) {
|
||
|
return (USHORT)i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fGrow)
|
||
|
{
|
||
|
SetRowWidth(i + cbData);
|
||
|
if (ReserveRowSpace( i, cbData )) {
|
||
|
return (USHORT)i;
|
||
|
}
|
||
|
SetRowWidth(usSavedMax);
|
||
|
}
|
||
|
return 0xFFFF;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CTableRowAlloc::ReserveRowSpace, public
|
||
|
//
|
||
|
// Synopsis: Reserve a row field in the allocation map.
|
||
|
//
|
||
|
// Arguments: [iOffset] - offset of field in row
|
||
|
// [cbData] - size of data field
|
||
|
//
|
||
|
// Returns: BOOL - TRUE if field could be reserved, FALSE otherwise
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//+-------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CTableRowAlloc::ReserveRowSpace(
|
||
|
unsigned iOffset,
|
||
|
unsigned cbData
|
||
|
) {
|
||
|
Win4Assert(cbData > 0);
|
||
|
|
||
|
if (iOffset + cbData > _maxRow) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (iOffset + cbData >= _cbRow) {
|
||
|
//
|
||
|
// Before growing the array, check to see if the reservation
|
||
|
// would fail anyway.
|
||
|
//
|
||
|
if (iOffset < _cbRow && _pRowMap[ iOffset ] != 0)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Need to allocate more space for the row map
|
||
|
//
|
||
|
unsigned cbNew = iOffset + max( cbData, CB_INIT );
|
||
|
BYTE* pNewMap = new BYTE [cbNew];
|
||
|
Win4Assert( _cbRow > 0 );
|
||
|
|
||
|
RtlCopyMemory(pNewMap, _pRowMap, _cbRow);
|
||
|
RtlZeroMemory((void *)&pNewMap[_cbRow], cbNew - _cbRow);
|
||
|
|
||
|
if ( _pRowMap != _aRowMap )
|
||
|
delete [] _pRowMap;
|
||
|
|
||
|
_pRowMap = pNewMap;
|
||
|
_cbRow = (USHORT)cbNew;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if any byte in the field has already been reserved.
|
||
|
//
|
||
|
for (unsigned i = 0; i < cbData; i++) {
|
||
|
if (_pRowMap[ iOffset + i ] != 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Reserve the requested field
|
||
|
//
|
||
|
for (i = 0; i < cbData; i++) {
|
||
|
_pRowMap[ iOffset + i ] = 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update the _iFirstFree if appropriate.
|
||
|
//
|
||
|
Win4Assert( _iFirstFree <= _cbRow );
|
||
|
|
||
|
if ( _iFirstFree == iOffset )
|
||
|
{
|
||
|
//
|
||
|
// Find the next free location
|
||
|
//
|
||
|
Win4Assert( i+iOffset == _iFirstFree+cbData );
|
||
|
Win4Assert( i == cbData );
|
||
|
|
||
|
for ( i += iOffset; i < _cbRow; i++ )
|
||
|
{
|
||
|
if ( !_IsInUse(i) )
|
||
|
break;
|
||
|
}
|
||
|
_iFirstFree = i;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|