601 lines
12 KiB
C++
601 lines
12 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1995 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#define OEMRESOURCE
|
|
#include "stdafx.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <memory.h>
|
|
#include <ctype.h>
|
|
|
|
#include "objplus.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
CObjHelper :: CObjHelper ()
|
|
: m_ctor_err( 0 ),
|
|
m_api_err( 0 ),
|
|
m_b_dirty( FALSE ),
|
|
m_time_created( ::GetCurrentTime() )
|
|
{
|
|
}
|
|
|
|
|
|
void CObjHelper :: ReportError ( LONG errInConstruction )
|
|
{
|
|
Trace1("CObjectPlus construction failure, error = %d", errInConstruction);
|
|
m_ctor_err = errInConstruction ;
|
|
}
|
|
|
|
LONG CObjHelper :: SetApiErr ( LONG errApi )
|
|
{
|
|
return m_api_err = errApi ;
|
|
}
|
|
|
|
void CObjHelper :: AssertValid () const
|
|
{
|
|
ASSERT( QueryError() == 0 ) ;
|
|
}
|
|
|
|
BOOL CObjHelper :: IsValid () const
|
|
{
|
|
return QueryError() == 0 ;
|
|
}
|
|
|
|
DWORD CObjHelper :: QueryAge () const
|
|
{
|
|
DWORD dwTime = ::GetCurrentTime(),
|
|
dwDiff ;
|
|
if ( dwTime < m_time_created )
|
|
{
|
|
dwDiff = dwTime + (((DWORD) -1) - (m_time_created - 1)) ;
|
|
}
|
|
else
|
|
{
|
|
dwDiff = dwTime - m_time_created ;
|
|
}
|
|
|
|
return dwDiff ;
|
|
}
|
|
|
|
|
|
// Constructor of extended object
|
|
CObjectPlus :: CObjectPlus ()
|
|
{
|
|
}
|
|
|
|
// Compare one object with another: default implementation
|
|
// orders objects by creation time. Return -1, 0 or 1.
|
|
|
|
int CObjectPlus :: Compare ( const CObjectPlus * pob ) const
|
|
{
|
|
return QueryCreationTime() < pob->QueryCreationTime()
|
|
? -1
|
|
: QueryCreationTime() != pob->QueryCreationTime() ;
|
|
}
|
|
|
|
CObListIter :: CObListIter ( const CObOwnedList & obList )
|
|
: m_obList( obList )
|
|
{
|
|
Reset() ;
|
|
}
|
|
|
|
void CObListIter :: Reset ()
|
|
{
|
|
m_pos = m_obList.GetCount() ? m_obList.GetHeadPosition() : NULL ;
|
|
}
|
|
|
|
CObject * CObListIter :: Next ()
|
|
{
|
|
return m_pos == NULL
|
|
? NULL
|
|
: m_obList.GetNext( m_pos ) ;
|
|
}
|
|
|
|
//
|
|
// Subclass of CObList whose default behavior is to destroy
|
|
// its contents during its own destruction
|
|
//
|
|
CObOwnedList :: CObOwnedList ( int nBlockSize )
|
|
: CObList( nBlockSize ),
|
|
m_b_owned( TRUE )
|
|
{
|
|
}
|
|
|
|
CObOwnedList :: ~ CObOwnedList ()
|
|
{
|
|
RemoveAll() ;
|
|
}
|
|
|
|
void CObOwnedList :: RemoveAll ()
|
|
{
|
|
if ( m_b_owned )
|
|
{
|
|
//
|
|
// Remove and discard all the objects
|
|
//
|
|
while ( ! IsEmpty() )
|
|
{
|
|
CObject * pob = RemoveHead() ;
|
|
delete pob ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Just remove the object pointers
|
|
CObList::RemoveAll() ;
|
|
}
|
|
}
|
|
|
|
CObject * CObOwnedList :: Index ( int index )
|
|
{
|
|
CObListIter oli( *this ) ;
|
|
|
|
CObject * pob ;
|
|
|
|
for ( int i = 0 ; (pob = oli.Next()) && i++ < index ; ) ;
|
|
|
|
return pob ;
|
|
}
|
|
|
|
CObject * CObOwnedList :: RemoveIndex ( int index )
|
|
{
|
|
POSITION pos ;
|
|
CObListIter oli( *this ) ;
|
|
int i ;
|
|
CObject * pob ;
|
|
|
|
for ( i = 0, pos = oli.QueryPosition() ;
|
|
(pob = oli.Next()) && i < index ;
|
|
i++, pos = oli.QueryPosition() ) ;
|
|
|
|
if ( pob && i == index )
|
|
{
|
|
RemoveAt( pos ) ;
|
|
}
|
|
else
|
|
{
|
|
pob = NULL ;
|
|
}
|
|
return pob ;
|
|
}
|
|
|
|
// Remove the first (and hopefully only) occurrence of an object
|
|
// pointer from this list.
|
|
BOOL CObOwnedList :: Remove ( CObject * pob )
|
|
{
|
|
POSITION pos = Find( pob ) ;
|
|
|
|
if ( pos == NULL )
|
|
return FALSE ;
|
|
|
|
RemoveAt( pos ) ;
|
|
return TRUE ;
|
|
}
|
|
|
|
// Set all elements to dirty or clean. Return TRUE if
|
|
// any element was dirty.
|
|
BOOL CObOwnedList :: SetAll ( BOOL bDirty )
|
|
{
|
|
int cDirtyItems = 0 ;
|
|
CObListIter oli( *this ) ;
|
|
CObjectPlus * pob ;
|
|
|
|
while ( pob = (CObjectPlus *) oli.Next() )
|
|
{
|
|
cDirtyItems += pob->IsDirty() ;
|
|
pob->SetDirty( bDirty ) ;
|
|
}
|
|
SetDirty( bDirty );
|
|
|
|
return cDirtyItems > 0 ;
|
|
}
|
|
|
|
|
|
int CObOwnedList :: FindElement ( CObject * pobSought ) const
|
|
{
|
|
CObListIter oli( *this ) ;
|
|
CObject * pob ;
|
|
|
|
for ( int i = 0 ;
|
|
(pob = oli.Next()) && pob != pobSought ;
|
|
i++ ) ;
|
|
|
|
return pob ? i : -1 ;
|
|
}
|
|
|
|
// Override of CObList::AddTail() to control exception handling.
|
|
// Returns NULL if addition fails.
|
|
|
|
POSITION CObOwnedList :: AddTail (
|
|
CObjectPlus * pobj,
|
|
BOOL bThrowException )
|
|
{
|
|
POSITION pos = NULL ;
|
|
|
|
// Catch only memory exceptions.
|
|
TRY
|
|
{
|
|
pos = CObList::AddTail( pobj ) ;
|
|
}
|
|
CATCH( CMemoryException, e )
|
|
{
|
|
pos = NULL ;
|
|
}
|
|
END_CATCH
|
|
|
|
if ( pos == NULL && bThrowException )
|
|
{
|
|
// CObList::AddTail() threw an exception. Echo it.
|
|
AfxThrowMemoryException() ;
|
|
}
|
|
return pos ;
|
|
}
|
|
|
|
|
|
typedef struct
|
|
{
|
|
CObjectPlus * pObj ; // Pointer to object to be sorted
|
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pFunc ; // Pointer to ordering function
|
|
} CBOWNEDLIST_SORT_HELPER ;
|
|
|
|
// This static member function is used to quick sort an array of structures
|
|
// as declared above. Each element contains the object pointer and a
|
|
// pointer to the object's member function to be invoked for comparison.
|
|
|
|
//int CDECL CObOwnedList :: SortHelper (
|
|
int _cdecl CObOwnedList :: SortHelper (
|
|
const void * pa,
|
|
const void * pb
|
|
)
|
|
{
|
|
CBOWNEDLIST_SORT_HELPER
|
|
* pHelp1 = (CBOWNEDLIST_SORT_HELPER *) pa,
|
|
* pHelp2 = (CBOWNEDLIST_SORT_HELPER *) pb ;
|
|
|
|
return (pHelp1->pObj->*pHelp1->pFunc)( pHelp2->pObj ) ;
|
|
}
|
|
|
|
// Sort the list by recreating it entirely.
|
|
|
|
LONG CObOwnedList :: Sort ( CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc )
|
|
{
|
|
LONG err = 0 ;
|
|
int cItems = (int)GetCount() ;
|
|
|
|
if ( cItems < 2 )
|
|
return NO_ERROR ;
|
|
|
|
CObListIter obli( *this ) ;
|
|
CObjectPlus * pObNext ;
|
|
BOOL bOwned = SetOwnership( FALSE ) ;
|
|
int i ;
|
|
|
|
CBOWNEDLIST_SORT_HELPER * paSortHelpers = NULL ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
// Allocate the helper array
|
|
paSortHelpers = new CBOWNEDLIST_SORT_HELPER[ cItems ] ;
|
|
|
|
/// Fill the helper array.
|
|
for ( i = 0 ; pObNext = (CObjectPlus *) obli.Next() ; i++ )
|
|
{
|
|
paSortHelpers[i].pFunc = pOrderFunc ;
|
|
paSortHelpers[i].pObj = pObNext ;
|
|
}
|
|
|
|
// Release all object pointer references. Note that we
|
|
// forced "owned" to FALSE above.
|
|
RemoveAll() ;
|
|
|
|
ASSERT( GetCount() == 0 ) ;
|
|
|
|
// Sort the helper array
|
|
::qsort( (void *) paSortHelpers,
|
|
cItems,
|
|
sizeof paSortHelpers[0],
|
|
SortHelper ) ;
|
|
|
|
// Refill the list from the helper array.
|
|
for ( i = 0 ; i < cItems ; i++ )
|
|
{
|
|
AddTail( paSortHelpers[i].pObj ) ;
|
|
}
|
|
|
|
ASSERT( GetCount() == cItems ) ;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
// Delete the working array
|
|
delete [] paSortHelpers ;
|
|
|
|
// Restore the object ownership state
|
|
SetOwnership( bOwned ) ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
//
|
|
// Subclass of CObArray whose default behavior is to destroy
|
|
// its contents during its own destruction
|
|
//
|
|
CObOwnedArray :: CObOwnedArray ()
|
|
: CObArray(),
|
|
m_b_owned( TRUE )
|
|
{
|
|
}
|
|
|
|
CObOwnedArray :: ~ CObOwnedArray ()
|
|
{
|
|
RemoveAll() ;
|
|
}
|
|
|
|
void CObOwnedArray :: RemoveAll ()
|
|
{
|
|
if ( m_b_owned )
|
|
{
|
|
int i, nElements;
|
|
|
|
nElements = (int)GetSize();
|
|
for (i = 0; i < nElements; ++i)
|
|
{
|
|
delete (CObject *)GetAt(i) ;
|
|
}
|
|
}
|
|
//
|
|
// Just remove the object pointers
|
|
//
|
|
CObArray::RemoveAll() ;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CObOwnedArray :: RemoveAt (
|
|
int nIndex,
|
|
int nCount
|
|
)
|
|
{
|
|
for (int i = 0; i < nCount; ++i)
|
|
{
|
|
delete (CObject *)GetAt(nIndex) ;
|
|
}
|
|
|
|
CObArray::RemoveAt(nIndex, nCount);
|
|
}
|
|
|
|
|
|
//
|
|
// Set all elements to dirty or clean. Return TRUE if
|
|
// any element was dirty.
|
|
//
|
|
BOOL
|
|
CObOwnedArray :: SetAll (
|
|
BOOL bDirty
|
|
)
|
|
{
|
|
int cDirtyItems = 0 ;
|
|
CObjectPlus * pob ;
|
|
int i;
|
|
|
|
int nElements = (int)GetSize();
|
|
|
|
for (i = 0; i < nElements; ++i)
|
|
{
|
|
pob = (CObjectPlus *)GetAt(i);
|
|
cDirtyItems += pob->IsDirty() ;
|
|
pob->SetDirty( bDirty ) ;
|
|
}
|
|
|
|
SetDirty( bDirty );
|
|
|
|
return cDirtyItems > 0 ;
|
|
}
|
|
|
|
|
|
int
|
|
CObOwnedArray :: FindElement (
|
|
CObject * pobSought
|
|
) const
|
|
{
|
|
CObject * pob ;
|
|
int i;
|
|
int nElements = (int)GetSize();
|
|
|
|
for ( i = 0, pob = NULL; i < nElements && pob != pobSought; ++i)
|
|
{
|
|
pob = (CObject *)GetAt(i);
|
|
}
|
|
|
|
return i < nElements ? i : -1 ;
|
|
}
|
|
|
|
void
|
|
CObOwnedArray :: Swap(
|
|
int nIndx1,
|
|
int nIndx2
|
|
)
|
|
{
|
|
CObject * pTmp = GetAt(nIndx1);
|
|
SetAt(nIndx1, GetAt(nIndx2));
|
|
SetAt(nIndx2, pTmp);
|
|
}
|
|
|
|
//
|
|
// This sort is pretty slow. Why?
|
|
//
|
|
|
|
void
|
|
CObOwnedArray :: QuickSort(
|
|
int nLow,
|
|
int nHigh,
|
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc
|
|
)
|
|
{
|
|
int nUp, nDown;
|
|
CObjectPlus * pBreak;
|
|
|
|
if (nLow < nHigh)
|
|
{
|
|
if((nHigh - nLow) == 1)
|
|
{
|
|
if (((CObjectPlus *)GetAt(nLow)->*pOrderFunc)((CObjectPlus *)GetAt(nHigh)) > 0)
|
|
{
|
|
Swap(nLow, nHigh);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pBreak = (CObjectPlus *)GetAt(nHigh);
|
|
do
|
|
{
|
|
nUp = nLow;
|
|
nDown = nHigh;
|
|
while(nUp < nDown && ((CObjectPlus *)GetAt(nUp)->*pOrderFunc)(pBreak) <= 0)
|
|
{
|
|
++nUp;
|
|
}
|
|
while(nDown > nUp && ((CObjectPlus *)GetAt(nDown)->*pOrderFunc)(pBreak) >= 0)
|
|
{
|
|
--nDown;
|
|
}
|
|
if (nUp < nDown)
|
|
{
|
|
Swap(nUp, nDown);
|
|
}
|
|
} while (nUp < nDown);
|
|
|
|
Swap(nUp, nHigh);
|
|
if ((nUp - nLow) < (nHigh - nUp) )
|
|
{
|
|
QuickSort(nLow, nUp - 1, pOrderFunc);
|
|
QuickSort(nUp + 1, nHigh, pOrderFunc);
|
|
}
|
|
else
|
|
{
|
|
QuickSort(nUp + 1, nHigh, pOrderFunc);
|
|
QuickSort(nLow, nUp - 1, pOrderFunc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
LONG
|
|
CObOwnedArray :: Sort (
|
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc
|
|
)
|
|
{
|
|
LONG err = 0 ;
|
|
int cItems = GetSize() ;
|
|
|
|
if ( cItems < 2 )
|
|
{
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
QuickSort(0, GetUpperBound(), pOrderFunc);
|
|
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
CObjectPlus * pObj ; // Pointer to object to be sorted
|
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pFunc ; // Pointer to ordering function
|
|
} CBOWNEDARRAY_SORT_HELPER ;
|
|
|
|
// This static member function is used to quick sort an array of structures
|
|
// as declared above. Each element contains the object pointer and a
|
|
// pointer to the object's member function to be invoked for comparison.
|
|
|
|
//int CDECL CObOwnedArray :: SortHelper (
|
|
int _cdecl CObOwnedArray :: SortHelper (
|
|
const void * pa,
|
|
const void * pb
|
|
)
|
|
{
|
|
CBOWNEDARRAY_SORT_HELPER
|
|
* pHelp1 = (CBOWNEDARRAY_SORT_HELPER *) pa,
|
|
* pHelp2 = (CBOWNEDARRAY_SORT_HELPER *) pb ;
|
|
|
|
return (pHelp1->pObj->*pHelp1->pFunc)( pHelp2->pObj ) ;
|
|
}
|
|
|
|
// Sort the list by recreating it entirely.
|
|
|
|
LONG
|
|
CObOwnedArray :: Sort (
|
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc
|
|
)
|
|
{
|
|
LONG err = 0 ;
|
|
int cItems = (int)GetSize() ;
|
|
|
|
if ( cItems < 2 )
|
|
{
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
CObjectPlus * pObNext ;
|
|
BOOL bOwned = SetOwnership( FALSE ) ;
|
|
int i ;
|
|
|
|
CBOWNEDARRAY_SORT_HELPER * paSortHelpers = NULL ;
|
|
|
|
CATCH_MEM_EXCEPTION
|
|
{
|
|
// Allocate the helper array
|
|
paSortHelpers = new CBOWNEDARRAY_SORT_HELPER[ cItems ] ;
|
|
|
|
/// Fill the helper array.
|
|
for ( i = 0 ; i < cItems ; ++i )
|
|
{
|
|
pObNext = (CObjectPlus *) GetAt(i);
|
|
paSortHelpers[i].pFunc = pOrderFunc ;
|
|
paSortHelpers[i].pObj = pObNext ;
|
|
}
|
|
|
|
// Release all object pointer references. Note that we
|
|
// forced "owned" to FALSE above.
|
|
RemoveAll() ;
|
|
|
|
ASSERT( GetSize() == 0 ) ;
|
|
|
|
// Sort the helper array
|
|
::qsort( (void *) paSortHelpers,
|
|
cItems,
|
|
sizeof paSortHelpers[0],
|
|
SortHelper ) ;
|
|
|
|
// Refill the list from the helper array.
|
|
for ( i = 0 ; i < cItems ; i++ )
|
|
{
|
|
Add( paSortHelpers[i].pObj ) ;
|
|
}
|
|
|
|
ASSERT( GetSize() == cItems ) ;
|
|
}
|
|
END_MEM_EXCEPTION(err)
|
|
|
|
// Delete the working array
|
|
delete [] paSortHelpers ;
|
|
|
|
// Restore the object ownership state
|
|
SetOwnership( bOwned ) ;
|
|
|
|
return err ;
|
|
}
|