/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1995 - 1999 **/ /**********************************************************************/ /* FILE HISTORY: */ #define OEMRESOURCE #include "stdafx.h" #include #include #include #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 ; }