Dryad/DryadVertex/VertexHost/system/classlib/include/DrBList.h

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__