/*++ Copyright (c) 1995 Microsoft Corporation Module Name: Abstract: map.hxx Author: Benjamin Leis (benl) 11/13/95 Revision History: --*/ #ifndef _MAP #define _MAP #define MAP_STACK_SIZE 40 //+--------------------------------------------------------------------------- // // Class: CMap () // // Purpose: // // Interface: CMap -- // ~CMap -- // Insert -- insert a key and item into map // Replace -- replaces a key's data or inserts it if is not in // the map already // Remove -- // Lookup -- // DeleteAll -- removes all the entries in the map and sets it to // empty // Lookup -- // Enum -- // DeleteNode -- // pRoot -- // // History: 12-05-1996 benl Created // 12-18-1997 benl modified // // Notes: works by copying values not be reference - so need constructors // / destructors // //---------------------------------------------------------------------------- template class CMapIter; template class CMap { public: friend CMapIter; CMap(void); ~CMap(void); void Insert(const T & tKey, const S & sItem); void Replace(const T & tkey, const S& sItem); BOOL Remove(const T & tKey); BOOL Lookup(const T & tKey, S & sItem) const; void DeleteAll(); // Second style of lookup S * Lookup(const T & tKey); CMapIter * Enum(); protected: class CNode { public: CNode(const T & t, const S & s) { tKey = t; sData = s; pLeft = NULL; pRight = NULL; bDeleted = FALSE; } CNode() { pLeft = NULL; pRight = NULL; bDeleted = FALSE; } CNode * pLeft; CNode * pRight; T tKey; S sData; BOOL bDeleted; }; void DeleteNode(CNode * pNode); CNode * pRoot; }; //+--------------------------------------------------------------------------- // // Class: CMapIter () // // Purpose: // // Interface: CMapIter -- // ~CMapIter -- // Next -- // _nodeStack -- // _iTop -- // _nodeDummy -- // // History: 2-13-1997 benl Created // // Notes: // //---------------------------------------------------------------------------- template class CMapIter { public: CMapIter ( CMap::CNode * pRoot); ~CMapIter(); BOOLEAN Next(T & t, S & s); private: //data CMap::CNode * _nodeStack[MAP_STACK_SIZE]; INT _iTop; CMap::CNode _nodeDummy; }; //+--------------------------------------------------------------------------- // // Member: CMapIter::CMapiter // // Synopsis: Constructor // // Arguments: [pRoot] -- // // Returns: // // History: 7-10-1997 benl Created // // Notes: called by CMap and given root to traverse // //---------------------------------------------------------------------------- template CMapIter::CMapIter(CMap::CNode * pRoot) { _iTop = 0; _nodeStack[_iTop] = pRoot; while (_nodeStack[_iTop]->pLeft != NULL) { // assert(_iTop < MAP_STACK_SIZE); _nodeStack[_iTop + 1] = _nodeStack[_iTop]->pLeft; _iTop++; } //add a dummy node at the bottom // assert(_iTop < MAP_STACK_SIZE); _nodeStack[_iTop + 1] = &_nodeDummy; _iTop++; } // ::CNode //+--------------------------------------------------------------------------- // // Member: ::~CMapIter // // Synopsis: // // Arguments: (none) // // Returns: // // History: 2-13-1997 benl Created // // Notes: // //---------------------------------------------------------------------------- template CMapIter::~CMapIter() { } //::~CMapIter //+--------------------------------------------------------------------------- // // Member: ::Next // // Synopsis: // // Arguments: [t] -- // [s] -- // // Returns: // // History: 2-13-1997 benl Created // // Notes: // //---------------------------------------------------------------------------- template BOOLEAN CMapIter::Next(T & t, S & s) { CMap::CNode * pTemp; if (_nodeStack[_iTop]->pRight != NULL) { //go to the leftmostest item below _nodeStack[_iTop] = _nodeStack[_iTop]->pRight; while (_nodeStack[_iTop]->pLeft != NULL) { // assert(_iTop < MAP_STACK_SIZE); _nodeStack[_iTop + 1] = _nodeStack[_iTop]->pLeft; _iTop++; } } else if (_iTop != 0) { // o.w backtrack up one level _iTop--; } else { //o.w we're done return FALSE; } //if current element is deleted recurse if (_nodeStack[_iTop]->bDeleted) { return Next(t, s); } else { t = _nodeStack[_iTop]->tKey; s = _nodeStack[_iTop]->sData; return TRUE; } } //::Next //+--------------------------------------------------------------------------- // // Member: CMap::CMap // // Synopsis: // // Arguments: (none) // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline CMap::CMap(void) { pRoot = NULL; } //::CMap //+--------------------------------------------------------------------------- // // Member: ::DeleteNode // // Synopsis: // // Arguments: [pNode] -- // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline void CMap::DeleteNode(CNode * pNode) { if (pNode != NULL) { DeleteNode(pNode->pLeft); DeleteNode(pNode->pRight); delete pNode; } } //::DeleteNode //+--------------------------------------------------------------------------- // // Member: ::~CMap // // Synopsis: // // Arguments: (none) // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline CMap::~CMap(void) { // printf("map destruct %x\n", this); DeleteAll(); } //::~CMap //+--------------------------------------------------------------------------- // // Member: ::Insert // // Synopsis: // // Arguments: [tKey] -- // [sData] -- // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline void CMap::Insert(const T & tKey, const S & sData) { CNode * pnodeTemp = pRoot; if (pRoot == NULL) pRoot = new CNode(tKey,sData); else { while (pnodeTemp != NULL) { if (pnodeTemp->tKey <= tKey) { if (pnodeTemp->pRight == NULL) { pnodeTemp->pRight = new CNode(tKey,sData); return; } else pnodeTemp = pnodeTemp->pRight; } else { if (pnodeTemp->pLeft == NULL) { pnodeTemp->pLeft = new CNode(tKey,sData); return; } else pnodeTemp = pnodeTemp->pLeft; } } //endwhile } //endif } //::Insert //+--------------------------------------------------------------------------- // // Member: ::Replace // // Synopsis: if the key exits replace its data with the new data // o.w just insert it // // Arguments: [tKey] -- the key to search for // [sData] -- the new data // // Returns: always succeeds // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline void CMap::Replace(const T & tKey, const S & sData) { CNode * pnodeTemp = pRoot; if (pRoot == NULL) { pRoot = new CNode(tKey,sData); } else { while (pnodeTemp != NULL) { //match - so replace its data if (pnodeTemp->tKey == tKey && !pnodeTemp->bDeleted) { pnodeTemp->sData = sData; return; } //recurse right else if (pnodeTemp->tKey < tKey) { if (NULL == pnodeTemp->pRight) { pnodeTemp->pRight = new CNode(tKey,sData); return; } else pnodeTemp = pnodeTemp->pRight; } //recurse left else { if (NULL == pnodeTemp->pLeft) { pnodeTemp->pLeft = new CNode(tKey,sData); return; } else pnodeTemp = pnodeTemp->pLeft; } } //endwhile } //endif } //::Replace //+--------------------------------------------------------------------------- // // Member: ::Remove // // Synopsis: // // Arguments: [tKey] -- // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline BOOL CMap::Remove(const T & tKey) { CNode * pnodeTemp = pRoot; CNode * pnodeParent = NULL; CNode * pnodeOrphan = NULL; if (pRoot == NULL) return FALSE; else { while (pnodeTemp != NULL) { if (pnodeTemp->tKey == tKey && (pnodeTemp->bDeleted == FALSE)) { if (pnodeParent == NULL) { // // deleting the root // if (pnodeTemp->pLeft != NULL) { pRoot = pnodeTemp->pLeft; pnodeOrphan = pnodeTemp->pRight; } else { pRoot = pnodeTemp->pRight; pnodeOrphan = pnodeTemp->pLeft; } } else { // // deleting an interor node // if (pnodeParent->pLeft == pnodeTemp) { pnodeParent->pLeft = pnodeTemp->pRight; pnodeOrphan = pnodeTemp->pLeft; } else { pnodeParent->pRight = pnodeTemp->pLeft; pnodeOrphan = pnodeTemp->pRight; } } delete pnodeTemp; // // re-insert the orphan // if (pnodeOrphan != NULL) { pnodeTemp = pRoot; while (pnodeTemp != NULL) { if (pnodeTemp->tKey <= pnodeOrphan->tKey) { if (pnodeTemp->pRight == NULL) { pnodeTemp->pRight = pnodeOrphan; break; } else pnodeTemp = pnodeTemp->pRight; } else { if (pnodeTemp->pLeft == NULL) { pnodeTemp->pLeft = pnodeOrphan; break; } else pnodeTemp = pnodeTemp->pLeft; } } //endwhile } return TRUE; } else if (pnodeTemp->tKey < tKey) { pnodeParent = pnodeTemp; pnodeTemp = pnodeTemp->pRight; } else { pnodeParent = pnodeTemp; pnodeTemp = pnodeTemp->pLeft; } } //endwhile } //endif return FALSE; } //::Remove //+--------------------------------------------------------------------------- // // Member: ::Lookup // // Synopsis: // // Arguments: [tKey] -- // [sItem] -- // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline BOOL CMap::Lookup(const T & tKey, S & sItem) const { CNode * pnodeTemp = pRoot; if (pRoot == NULL) return FALSE; else { while (pnodeTemp != NULL) { if (pnodeTemp->tKey == tKey && pnodeTemp->bDeleted == FALSE) { sItem = pnodeTemp->sData; return TRUE; } else if (pnodeTemp->tKey <= tKey) { pnodeTemp = pnodeTemp->pRight; } else { pnodeTemp = pnodeTemp->pLeft; } } //endwhile } //endif return FALSE; } //::Lookup //+--------------------------------------------------------------------------- // // Member: ::Lookup // // Synopsis: // // Arguments: [tKey] -- // // Returns: // // History: 12-05-1996 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline S * CMap::Lookup(const T & tKey) { CNode * pnodeTemp = pRoot; if (pRoot == NULL) return NULL; else { while (pnodeTemp != NULL) { if (pnodeTemp->tKey == tKey && pnodeTemp->bDeleted == FALSE) { return &(pnodeTemp->sData); } else if (pnodeTemp->tKey < tKey) { pnodeTemp = pnodeTemp->pRight; } else { pnodeTemp = pnodeTemp->pLeft; } } //endwhile } //endif return NULL; } //::Lookup //+--------------------------------------------------------------------------- // // Member: ::Enum // // Synopsis: returns the iterator // // Arguments: (none) // // Returns: iterator or null if map is empty // // History: 2-13-1997 benl Created // // Notes: // //---------------------------------------------------------------------------- template inline CMapIter * CMap::Enum() { if (pRoot) { return new CMapIter(pRoot); } else { return NULL; } } //::Enum //+--------------------------------------------------------------------------- // // Member: ::DeleteAll // // Synopsis: NonRecursive delete // // Arguments: (none) // // Returns: // // History: 12-18-1997 benl Created // // Notes: Cleans up the entire tree and sets it to empty // Does it nonrecursively but swiveling ptrs around // //---------------------------------------------------------------------------- template inline void CMap::DeleteAll() { CNode * pParent = 0; CNode * pNext = 0; CNode * pCurrent = pRoot; while (pCurrent) { //advance next to left and the set the left back to parent pNext = pCurrent->pLeft; pCurrent->pLeft = pParent; //If there is a left child move onto it //else if there is a right child move to it //o.w move up thru left ptr and delete current node if (pNext) { pParent = pCurrent; pCurrent = pNext; } else if (pCurrent->pRight) { pParent = pCurrent; pCurrent = pCurrent->pRight; pParent->pRight = 0; } else { //this is really a move up back the parent is now in pLeft pParent = pCurrent->pLeft; delete pCurrent; pCurrent = pParent; if (pCurrent) { pParent = pCurrent->pLeft; pCurrent->pLeft = 0; } } } pRoot = NULL; } // ::DeleteAll #endif