//+------------------------------------------------------------------------- // // 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 #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; }