412 lines
10 KiB
C++
412 lines
10 KiB
C++
/*
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
|
|
compliance with the License. You may obtain a copy of the License
|
|
at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
|
|
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
|
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
|
|
|
|
See the Apache Version 2.0 License for specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
/*
|
|
* DrBList
|
|
*
|
|
* Declares a utility class for managing bi-linked listed
|
|
*/
|
|
|
|
#ifndef __DRYADBLIST_H__
|
|
#define __DRYADBLIST_H__
|
|
|
|
|
|
/*
|
|
* DrBListEntry
|
|
* The list entry class is intentionally opaque. Operations should always
|
|
* be done using the list object. The list entry class should be embedded
|
|
* in the object you want to store, and the DR_GET_CONTAINER macro
|
|
* used to map back to the actual object
|
|
*/
|
|
|
|
class DrBListEntry
|
|
{
|
|
public:
|
|
|
|
//Standard c'tor
|
|
inline DrBListEntry();
|
|
|
|
//Return TRUE if this entry is in a list.
|
|
//N.B. Remember to use the locking conventions of the list object!
|
|
inline BOOL IsInList();
|
|
|
|
//Remove this entry from whatever list its currently in
|
|
//N.B. Remember to use the locking conventions of the list object!
|
|
inline void Remove();
|
|
|
|
private:
|
|
friend class DrBList;
|
|
DrBListEntry * m_pNext, * m_pPrev;
|
|
};
|
|
|
|
/*
|
|
* DrBList
|
|
* Manages a bi-linked list of DrBListEntry's
|
|
*/
|
|
|
|
class DrBList
|
|
{
|
|
public:
|
|
|
|
/*
|
|
* Lifecycle Management
|
|
*/
|
|
|
|
//Standard c'tor
|
|
inline DrBList();
|
|
|
|
|
|
/*
|
|
* Inserting entries to list
|
|
*/
|
|
|
|
//Insert specified entry as head of list
|
|
//Asserts if pEntry is already in an existing list
|
|
inline void InsertAsHead(DrBListEntry * pEntry);
|
|
|
|
//Insert specified entry as tail of list
|
|
//Asserts if pEntry is already in an existing list
|
|
inline void InsertAsTail(DrBListEntry * pEntry);
|
|
|
|
//Insert pNewEntry as the next entry after pCurrentEntry
|
|
//Asserts if pNewEntry is already in an existing list
|
|
inline void InsertAsNext(DrBListEntry * pCurrentEntry, DrBListEntry * pNewEntry);
|
|
|
|
//Insert pNewEntry as the previoud entry before pCurrentEntry
|
|
//Asserts if pNewEntry is already in an existing list
|
|
inline void InsertAsPrev(DrBListEntry * pCurrentEntry, DrBListEntry * pNewEntry);
|
|
|
|
//Remove pEntry from a list and transition it to the head of this one
|
|
//pEntry can either be in this list or an unrelated one
|
|
//Asserts if pEntry is not already in an existing list
|
|
inline void TransitionToHead(DrBListEntry * pEntry);
|
|
|
|
//Remove pEntry from a list and transition it to the tail of this one
|
|
//pEntry can either be in this list or an unrelated one
|
|
//Asserts if pEntry is not already in an existing list
|
|
inline void TransitionToTail(DrBListEntry * pEntry);
|
|
|
|
//Remove all the entries from pList and transition them to the
|
|
//head of this one. pList must not be this list
|
|
inline void TransitionToHead(DrBList * pList);
|
|
|
|
//Remove all the entries from pList and transition them to the
|
|
//tail of this one. pList must not be this list
|
|
inline void TransitionToTail(DrBList * pList);
|
|
|
|
|
|
/*
|
|
* Removing entries from list
|
|
*/
|
|
|
|
//Remove entry from head of list and return it
|
|
//Returns NULL if list is empty
|
|
inline DrBListEntry * RemoveHead();
|
|
|
|
//Remove entry from tail of list and return it
|
|
//Returns NULL if list is empty
|
|
inline DrBListEntry * RemoveTail();
|
|
|
|
//Remove specified entry from list
|
|
inline DrBListEntry * Remove(DrBListEntry * pEntry);
|
|
|
|
|
|
/*
|
|
* Accessing entries in the list
|
|
*/
|
|
|
|
//Scan the list and if pEntry is found return it
|
|
//Returns NULL if pEntry is not found
|
|
inline DrBListEntry * Find(DrBListEntry * pEntry);
|
|
|
|
//Return the head entry in the list or NULL if list is empty
|
|
inline DrBListEntry * GetHead();
|
|
|
|
//Return the tail entry in the list or NULL if list is empty
|
|
inline DrBListEntry * GetTail();
|
|
|
|
//Return the next entry after pEntry, or NULL if pEntry is the tail
|
|
inline DrBListEntry * GetNext(DrBListEntry * pEntry);
|
|
|
|
//Return the previous entry before pEntry, or NULL if pEntry is the head
|
|
inline DrBListEntry * GetPrev(DrBListEntry * pEntry);
|
|
|
|
|
|
/*
|
|
* Retrieving state of list
|
|
*/
|
|
|
|
//Scan the list and count the total number of entries
|
|
inline DWORD CountLinks();
|
|
|
|
//Return TRUE if the list is empty
|
|
inline BOOL IsEmpty();
|
|
|
|
private:
|
|
|
|
DrBListEntry m_dummyEntry;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* Inline methods for DrBListEntry
|
|
*/
|
|
|
|
|
|
DrBListEntry::DrBListEntry()
|
|
{
|
|
m_pNext=this;
|
|
m_pPrev=this;
|
|
}
|
|
|
|
BOOL DrBListEntry::IsInList()
|
|
{
|
|
return (m_pNext!=this);
|
|
}
|
|
|
|
void DrBListEntry::Remove()
|
|
{
|
|
LogAssert(IsInList());
|
|
|
|
m_pNext->m_pPrev = m_pPrev;
|
|
m_pPrev->m_pNext = m_pNext;
|
|
m_pNext=this;
|
|
m_pPrev=this;
|
|
}
|
|
|
|
/*
|
|
* Inline methods for DrBList
|
|
*/
|
|
|
|
|
|
DrBList::DrBList()
|
|
{
|
|
//this space intentionally left blank
|
|
}
|
|
|
|
void DrBList::InsertAsHead(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry->IsInList()==FALSE);
|
|
|
|
pEntry->m_pNext=m_dummyEntry.m_pNext;
|
|
pEntry->m_pPrev=&m_dummyEntry;
|
|
m_dummyEntry.m_pNext->m_pPrev=pEntry;
|
|
m_dummyEntry.m_pNext=pEntry;
|
|
}
|
|
|
|
void DrBList::TransitionToHead(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry->IsInList());
|
|
|
|
//Pull entry from existing list
|
|
pEntry->m_pNext->m_pPrev = pEntry->m_pPrev;
|
|
pEntry->m_pPrev->m_pNext = pEntry->m_pNext;
|
|
//Insert into this list
|
|
pEntry->m_pNext=m_dummyEntry.m_pNext;
|
|
pEntry->m_pPrev=&m_dummyEntry;
|
|
m_dummyEntry.m_pNext->m_pPrev=pEntry;
|
|
m_dummyEntry.m_pNext=pEntry;
|
|
}
|
|
|
|
void DrBList::TransitionToHead(DrBList * pList)
|
|
{
|
|
LogAssert(pList != this);
|
|
|
|
if (!pList->IsEmpty())
|
|
{
|
|
DrBListEntry* otherHead = pList->GetHead();
|
|
DrBListEntry* otherTail = pList->GetTail();
|
|
otherTail->m_pNext=m_dummyEntry.m_pNext;
|
|
otherHead->m_pPrev=&m_dummyEntry;
|
|
m_dummyEntry.m_pNext->m_pPrev=otherTail;
|
|
m_dummyEntry.m_pNext=otherHead;
|
|
pList->m_dummyEntry.m_pNext=&(pList->m_dummyEntry);
|
|
pList->m_dummyEntry.m_pPrev=&(pList->m_dummyEntry);
|
|
}
|
|
}
|
|
|
|
void DrBList::InsertAsTail(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry->IsInList()==FALSE);
|
|
|
|
pEntry->m_pNext=&m_dummyEntry;
|
|
pEntry->m_pPrev=m_dummyEntry.m_pPrev;
|
|
m_dummyEntry.m_pPrev->m_pNext=pEntry;
|
|
m_dummyEntry.m_pPrev=pEntry;
|
|
}
|
|
|
|
void DrBList::TransitionToTail(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry->IsInList());
|
|
//Pull entry from existing list
|
|
pEntry->m_pNext->m_pPrev = pEntry->m_pPrev;
|
|
pEntry->m_pPrev->m_pNext = pEntry->m_pNext;
|
|
//Insert into this list
|
|
pEntry->m_pNext=&m_dummyEntry;
|
|
pEntry->m_pPrev=m_dummyEntry.m_pPrev;
|
|
m_dummyEntry.m_pPrev->m_pNext=pEntry;
|
|
m_dummyEntry.m_pPrev=pEntry;
|
|
}
|
|
|
|
//
|
|
// Append list to existing list's tail (uses m_dummyEntry to move links)
|
|
//
|
|
void DrBList::TransitionToTail(DrBList * pList)
|
|
{
|
|
LogAssert(pList != this);
|
|
|
|
if (!pList->IsEmpty())
|
|
{
|
|
DrBListEntry* otherHead = pList->GetHead();
|
|
DrBListEntry* otherTail = pList->GetTail();
|
|
|
|
//
|
|
// link tail's next and head's prev to placeholder's prev
|
|
//
|
|
otherTail->m_pNext=&m_dummyEntry;
|
|
otherHead->m_pPrev=m_dummyEntry.m_pPrev;
|
|
|
|
//
|
|
// Link placeholder's prev's next to head
|
|
//
|
|
m_dummyEntry.m_pPrev->m_pNext=otherHead;
|
|
|
|
//
|
|
// Link placeholder's prev to tail
|
|
//
|
|
m_dummyEntry.m_pPrev=otherTail;
|
|
|
|
//
|
|
// Update placeholder next and previous to self
|
|
//
|
|
pList->m_dummyEntry.m_pNext=&(pList->m_dummyEntry);
|
|
pList->m_dummyEntry.m_pPrev=&(pList->m_dummyEntry);
|
|
}
|
|
}
|
|
|
|
|
|
void DrBList::InsertAsNext(DrBListEntry * pCurrentEntry, DrBListEntry * pNewEntry)
|
|
{
|
|
LogAssert(pCurrentEntry->IsInList());
|
|
LogAssert(pNewEntry->IsInList()==FALSE);
|
|
|
|
pNewEntry->m_pNext=pCurrentEntry->m_pNext;
|
|
pNewEntry->m_pPrev=pCurrentEntry;
|
|
pCurrentEntry->m_pNext->m_pPrev=pNewEntry;
|
|
pCurrentEntry->m_pNext=pNewEntry;
|
|
}
|
|
|
|
void DrBList::InsertAsPrev(DrBListEntry * pCurrentEntry, DrBListEntry * pNewEntry)
|
|
{
|
|
LogAssert(pCurrentEntry->IsInList());
|
|
LogAssert(pNewEntry->IsInList()==FALSE);
|
|
|
|
pNewEntry->m_pNext=pCurrentEntry;
|
|
pNewEntry->m_pPrev=pCurrentEntry->m_pPrev;
|
|
pCurrentEntry->m_pPrev->m_pNext=pNewEntry;
|
|
pCurrentEntry->m_pPrev=pNewEntry;
|
|
}
|
|
|
|
DrBListEntry * DrBList::RemoveHead()
|
|
{
|
|
if (m_dummyEntry.m_pNext==&m_dummyEntry)
|
|
return NULL;
|
|
else
|
|
return Remove(m_dummyEntry.m_pNext);
|
|
}
|
|
|
|
DrBListEntry * DrBList::RemoveTail()
|
|
{
|
|
if (m_dummyEntry.m_pPrev==&m_dummyEntry)
|
|
return NULL;
|
|
else
|
|
return Remove(m_dummyEntry.m_pPrev);
|
|
}
|
|
|
|
DrBListEntry * DrBList::Remove(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry->IsInList());
|
|
LogAssert(pEntry!=&m_dummyEntry);
|
|
|
|
pEntry->m_pNext->m_pPrev = pEntry->m_pPrev;
|
|
pEntry->m_pPrev->m_pNext = pEntry->m_pNext;
|
|
pEntry->m_pNext=pEntry;
|
|
pEntry->m_pPrev=pEntry;
|
|
return pEntry;
|
|
}
|
|
|
|
|
|
DrBListEntry * DrBList::Find(DrBListEntry * pEntry)
|
|
{
|
|
LogAssert(pEntry);
|
|
DrBListEntry * pScan=m_dummyEntry.m_pNext;
|
|
while (pScan!=&m_dummyEntry)
|
|
{
|
|
if (pScan==pEntry)
|
|
return pEntry;
|
|
pScan=pScan->m_pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
DrBListEntry * DrBList::GetHead()
|
|
{
|
|
return (m_dummyEntry.m_pNext==&m_dummyEntry) ? NULL : m_dummyEntry.m_pNext;
|
|
}
|
|
|
|
DrBListEntry * DrBList::GetTail()
|
|
{
|
|
return (m_dummyEntry.m_pPrev==&m_dummyEntry) ? NULL : m_dummyEntry.m_pPrev;
|
|
}
|
|
|
|
DrBListEntry * DrBList::GetNext(DrBListEntry * pEntry)
|
|
{
|
|
return (pEntry->m_pNext==&m_dummyEntry) ? NULL : pEntry->m_pNext;
|
|
}
|
|
|
|
DrBListEntry * DrBList::GetPrev(DrBListEntry * pEntry)
|
|
{
|
|
return (pEntry->m_pPrev==&m_dummyEntry) ? NULL : pEntry->m_pPrev;
|
|
}
|
|
|
|
//
|
|
// Count the number of links in the list and return count
|
|
//
|
|
DWORD DrBList::CountLinks()
|
|
{
|
|
DWORD dwCount=0;
|
|
DrBListEntry * pScan=m_dummyEntry.m_pNext;
|
|
while (pScan!=&m_dummyEntry)
|
|
{
|
|
dwCount++;
|
|
pScan=pScan->m_pNext;
|
|
}
|
|
return dwCount;
|
|
}
|
|
|
|
BOOL DrBList::IsEmpty()
|
|
{
|
|
return (m_dummyEntry.m_pNext==&m_dummyEntry);
|
|
}
|
|
|
|
#endif //end if not defined __DRYADBLIST_H__
|