673 lines
16 KiB
C++
673 lines
16 KiB
C++
/*++
|
|
|
|
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 T, class S> class CMapIter;
|
|
|
|
template <class T, class S> class CMap {
|
|
public:
|
|
friend CMapIter<T,S>;
|
|
|
|
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<T,S> * 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 T, class S> class CMapIter {
|
|
public:
|
|
CMapIter ( CMap<T,S>::CNode * pRoot);
|
|
~CMapIter();
|
|
|
|
BOOLEAN Next(T & t, S & s);
|
|
|
|
private:
|
|
//data
|
|
CMap<T,S>::CNode * _nodeStack[MAP_STACK_SIZE];
|
|
INT _iTop;
|
|
CMap<T,S>::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 <class T, class S>
|
|
CMapIter<T,S>::CMapIter(CMap<T,S>::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 <class T, class S>
|
|
CMapIter<T,S>::~CMapIter()
|
|
{
|
|
} //::~CMapIter
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::Next
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [t] --
|
|
// [s] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 2-13-1997 benl Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <class T, class S>
|
|
BOOLEAN CMapIter<T,S>::Next(T & t, S & s)
|
|
{
|
|
CMap<T,S>::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<class T, class S>
|
|
inline CMap<T,S>::CMap(void)
|
|
{
|
|
pRoot = NULL;
|
|
} //::CMap
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::DeleteNode
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pNode] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 12-05-1996 benl Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, class S>
|
|
inline void CMap<T,S>::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<class T, class S>
|
|
inline CMap<T,S>::~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<class T, class S>
|
|
inline void CMap<T,S>::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<class T, class S>
|
|
inline void CMap<T,S>::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<class T, class S>
|
|
inline BOOL CMap<T,S>::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<class T, class S>
|
|
inline BOOL CMap<T,S>::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<class T, class S>
|
|
inline S * CMap<T,S>::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<class T, class S>
|
|
inline CMapIter<T,S> * CMap<T,S>::Enum()
|
|
{
|
|
if (pRoot) {
|
|
return new CMapIter<T,S>(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 <class T, class S>
|
|
inline void CMap<T,S>::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
|