// ========================================================================== // Class Specification : COXFileWatchNotifier // ========================================================================== // Header file : OXFileWatchNotifier.h // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// // Properties: // NO Abstract class (does not have any objects) // YES Derived from CObject // NO Is a Cwnd. // NO Two stage creation (constructor & Create()) // NO Has a message map // NO Needs a resource // NO Persistent objects (saveable on disk) // NO Uses exceptions // ////////////////////////////////////////////////////////////////////////// // Desciption : // This class tread-safe collection assigning an unique ID to each object // Prerequisites (necessary conditions): ///////////////////////////////////////////////////////////////////////////// #ifndef __OXIDMANAGER_H__ #define __OXIDMANAGER_H__ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 #include "OXDllExt.h" #ifndef __AFXTEMPL_H__ #error Make sure is added to your StdAfx.h #endif #ifndef __AFXMT_H__ #error Make sure is added to your StdAfx.h #endif #define INITIAL_SIZE 10 #define GROW_BY 5 template class COXIDManager : public CObject { // Data members ------------------------------------------------------------- public: protected: CArray m_arObjs; // Array of the elements CUIntArray m_arFreeIDs; // not assigned ID int m_nLastUsedSlot; // last used index in m_arObjs CCriticalSection m_crsecGuard; private: // Member functions --------------------------------------------------------- public: COXIDManager(); // Standard for serialization // --- In : // --- Out : // --- Returns : // --- Effect : Constructs the object COXIDManager(int nSize, int nGrowBy); // --- In : nSize: initial number of expected Elements // nGrowBy: value for correcting the size of the array whet it grows // --- Out : // --- Returns : // --- Effect : Constructs the object UINT AddItem(ClassType* pObj); // --- In : pObj: the object to be added // --- Out : // --- Returns : the ID of the object // --- Effect : adds pObj to the ID-Manager and returns a unique ID ClassType* GetItemPtr(UINT nID) ; // --- In : nID: the ID of the requested object // --- Out : // --- Returns : a pointer to the object or NULL if the ID is not valid // --- Effect : returns a pointer to the object identified by nID ClassType* RemoveItem(UINT nID); // --- In : nID: the ID of the object to be removed // --- Out : // --- Returns : a pointer to the object or NULL if the ID is not valid // --- Effect : returns a pointer to the object identified by nID and // removes the object from the Manager. // Note: Does not delete the Object ! void RemoveAll (); // --- In : // --- Out : // --- Returns : // --- Effect : removes all OBJ from the Manager. // Note: Does not delete the Objects ! void DeleteAll (); // --- In : // --- Out : // --- Returns : // --- Effect : Removes all Objects and deletes them int GetHeadPosition() ; // --- In : // --- Out : // --- Returns : the ID of first slot that is not empty // --- Effect : returns first slot (for iteration) ClassType* GetNext(int& nPos) ; // --- In : nPos: the ID of the current slot // --- Out : nPos: the ID of the next non empty slot // --- Returns : a pointer to the object at the current slot // --- Effect : returns object at slot nPos and calculates next nPos UINT ItemCount(); // --- In : // --- Out : // --- Returns : the number if items in the IDManager // --- Effect : determines the number of items virtual ~COXIDManager(); // --- In : // --- Out : // --- Returns : // --- Effect : Object destructor #ifdef _DEBUG virtual void AssertValid() ; // --- In : // --- Out : // --- Returns : // --- Effect : AssertValid performs a validity check on this object // by checking its internal state. // In the Debug version of the library, AssertValid may assert and // thus terminate the program. virtual void Dump(CDumpContext& dc) ; // --- In : dc : The diagnostic dump context for dumping, usually afxDump. // --- Out : // --- Returns : // --- Effect : Dumps the contents of the object to a CDumpContext object. // It provides diagnostic services for yourself and // other users of your class. #endif protected: BOOL _IsIDFree (UINT nSearchID, int& nFoundSlot) ; BOOL _IsIDFree (UINT nSearchID) ; private: }; // Data members ------------------------------------------------------------- // public: // protected: // CArray m_arObjs // --- Array of the elements // CUIntArray m_arFreeIDs; // --- not assigned ID // int m_nLastUsedSlot; // --- last used index in m_arObjs // CCriticalSection m_crsecGuard; // --- synchronization object // protected: // Member functions --------------------------------------------------------- // public: template COXIDManager::COXIDManager() { m_arObjs.SetSize(INITIAL_SIZE, GROW_BY); m_nLastUsedSlot = -1; //no slot in use } template COXIDManager::COXIDManager(int nSize, int nGrowBy) { m_arObjs.SetSize(nSize, nGrowBy); m_nLastUsedSlot = -1; //no slot in use } template COXIDManager::~COXIDManager() { // remove all objects from the arrays DeleteAll(); } // ---- public services ----------------------------------- template UINT COXIDManager::AddItem (ClassType* pObj) { UINT nID; // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); // use ID from the FreeID-Array if possible if (m_arFreeIDs.GetUpperBound() >= 0) { //get last element and shorten array by one element nID = (UINT) m_arFreeIDs[m_arFreeIDs.GetUpperBound()]; m_arFreeIDs.RemoveAt(m_arFreeIDs.GetUpperBound()); m_arFreeIDs.FreeExtra(); //because IDs in Free-Array are always < m_nLastUsedSlot, //wo do not have to correct the m_nLastUsedSlot value m_arObjs.SetAt(nID, pObj); } else { // set object to m_nLastUsedSlot+1 m_nLastUsedSlot++; nID = m_nLastUsedSlot; m_arObjs.SetAtGrow(nID, pObj); } return nID; // return the used array-slot } template ClassType* COXIDManager::GetItemPtr (UINT nID) { // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); //if ID is valid, return Object. Otherwise return NULL if ( ((int)nID) >= 0 && ((int)nID) <= m_nLastUsedSlot && !_IsIDFree (nID) ) { return m_arObjs[nID]; } return NULL; } template ClassType* COXIDManager::RemoveItem (UINT nID) { ASSERT( ((int)nID) >= 0 && ((int)nID) <= (int)m_nLastUsedSlot); ASSERT( !_IsIDFree(nID)); // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); ClassType* pObj; pObj = m_arObjs[nID]; // check if element is the last one, if so shrink array if (nID == (UINT)m_nLastUsedSlot) { m_arObjs.RemoveAt(nID); m_nLastUsedSlot--; //find the last used slot using FreeID-Array int nFreeID; while (_IsIDFree(m_nLastUsedSlot, nFreeID)) { m_nLastUsedSlot--; m_arFreeIDs.RemoveAt(nFreeID); } } else { // remove and save free ID m_arObjs[nID] = NULL; m_arFreeIDs.Add(nID); } // Free Memory if Size > UsedSlot * 1.2 if (m_arObjs.GetSize() > ((m_nLastUsedSlot+1) * 1.2)) { m_arObjs.SetSize((int)((m_nLastUsedSlot+1) * 1.2), (int)((m_nLastUsedSlot+1) * 0.2)); m_arObjs.FreeExtra(); } return pObj; } template void COXIDManager::RemoveAll() { // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); m_arObjs.RemoveAll(); m_arObjs.SetSize(INITIAL_SIZE, GROW_BY); m_arObjs.FreeExtra(); m_arFreeIDs.RemoveAll(); m_arFreeIDs.FreeExtra(); m_nLastUsedSlot = -1; //no slot in use } template void COXIDManager::DeleteAll() { // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); for (int i=0; i <= m_nLastUsedSlot; i++) { if (m_arObjs[i] != NULL) { ASSERT_VALID(m_arObjs[i]); delete m_arObjs[i]; } } m_arObjs.RemoveAll(); m_arObjs.SetSize(INITIAL_SIZE, GROW_BY); m_arObjs.FreeExtra(); m_arFreeIDs.RemoveAll(); m_arFreeIDs.FreeExtra(); m_nLastUsedSlot = -1; //no slot in use } template int COXIDManager::GetHeadPosition() { // GetHeadPosition should be used similar to the service of // MFC-Lists. // So NULL is emty!! // +++++ Position == Slot+1 +++++ // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); int nID = 0; while (_IsIDFree(nID)) nID++; nID = (nID > m_nLastUsedSlot) ? NULL : nID+1; return nID; } template ClassType* COXIDManager::GetNext(int& nPos) { nPos--; //see comment in GetHeadPosition ASSERT(nPos >= 0 && nPos <= m_nLastUsedSlot); // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); ClassType* pObj = GetItemPtr(nPos); //find next used ID nPos++; while (_IsIDFree(nPos)) nPos++; nPos = (nPos > m_nLastUsedSlot) ? NULL : nPos+1; return pObj; } template UINT COXIDManager::ItemCount() { return m_nLastUsedSlot-m_arFreeIDs.GetUpperBound(); } // ---- diagnostics --------------------------------------- #ifdef _DEBUG template void COXIDManager::AssertValid() { // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); CObject::AssertValid(); //checks if all Elemets are valid for (int i=0; i <= m_arObjs.GetUpperBound(); i++) { if (m_arObjs[i] != NULL) { ASSERT_VALID(m_arObjs[i]); } } } template void COXIDManager::Dump(CDumpContext& dc) { // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); CObject::Dump(dc); dc << _T("\nNumber of elements: "); dc << m_nLastUsedSlot-m_arFreeIDs.GetUpperBound() << _T("\n"); if (dc.GetDepth() > 0) { int nPos; nPos = GetHeadPosition(); while (nPos != 0) { dc << _T("\tID: ") << nPos; dc << _T("\t Element: "); GetNext(nPos)->Dump(dc); } } } #endif // _DEBUG // protected: template BOOL COXIDManager::_IsIDFree (UINT nSearchID, int& nFoundSlot) // --- In : nSearchID: the ID to be checked // --- Out : nFoundSlot: the position of the ID // --- Returns : TRUE if the ID is free // --- Effect : searchs for nSearchID in the Free-ID Array. // If so, nFoundSlot returns the index from the slot. { int i; // Synchronization CSingleLock lockObj( &m_crsecGuard); lockObj.Lock(); for ( i=0; i <= m_arFreeIDs.GetUpperBound(); i++) { if (m_arFreeIDs[i] == nSearchID) { nFoundSlot = i; return TRUE; } } return FALSE; } template BOOL COXIDManager::_IsIDFree (UINT nSearchID) // --- In : nSearchID: the ID to be checked // --- Out : // --- Returns : TRUE if the ID is free // --- Effect : searchs for nSearchID in the Free-ID Array. { // searchs for nSearchID in the Free-ID Array. int i; return _IsIDFree(nSearchID, i); } // private: #endif // __OXIDMANAGER_H__