windows-nt/Source/XPSP1/NT/multimedia/media/audiosrv/list.h
2020-09-26 16:20:57 +08:00

327 lines
7.2 KiB
C++

//
// Lists have internal serialization so that most functions operate as atomic
// operations. However, the results of some functions are transient (i.e.
// immediately out-of-date) unless the caller explicitly locks the list using
// the Lock/Unlock methods. These functions are GetCount, GetHeadPosition,
// GetNext. Also, it is the caller's responsibility to serialize access to a
// POSITION. The internal serialization only ensures that two simultaneus
// AddTail calls will not make the list internally inconsistent, and nor will
// two simultaneous RemoveAt calls on _different_ POSITIONs.
//
// List elements with NULL object pointers are skipped by list iteration
// functions GetHeadPosition and GetNext.
//
typedef struct _CListElement {
struct _CListElement *Next;
struct _CListElement *Prev;
const void *Object;
} CListElement, *POSITION;
template <class TYPE, class ARG_TYPE> class CList {
public:
CList();
~CList();
POSITION AddHead(ARG_TYPE newElement);
POSITION AddTail(ARG_TYPE newElement);
TYPE GetAt(POSITION position);
int GetCount(void) const;
POSITION GetHeadPosition(void) const;
TYPE GetNext(POSITION& rPosition); // return *Position++
LONG Initialize(void);
POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
BOOL IsEmpty(void) const;
void Lock(void);
void MoveBefore(POSITION posTarget, POSITION posMove);
void RemoveAll(void);
void RemoveAt(POSITION position);
void SetAt(POSITION pos, ARG_TYPE newElement);
void Unlock(void);
private:
BOOL m_Initialized;
CRITICAL_SECTION m_CriticalSection;
int m_Count;
CListElement m_Sentinel;
};
template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::CList(void)
{
m_Initialized = FALSE;
m_Count = 0;
m_Sentinel.Next = &m_Sentinel;
m_Sentinel.Prev = &m_Sentinel;
m_Sentinel.Object = &m_Sentinel;
}
template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::~CList(void)
{
if (m_Initialized) {
RemoveAll();
ASSERT(m_Sentinel.Next = &m_Sentinel);
ASSERT(m_Sentinel.Prev = &m_Sentinel);
DeleteCriticalSection(&m_CriticalSection);
m_Initialized = FALSE;
}
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
{
POSITION pos;
ASSERT(m_Initialized);
pos = new CListElement;
if (pos) {
Lock();
pos->Next = m_Sentinel.Next;
pos->Prev = &m_Sentinel;
pos->Prev->Next = pos;
pos->Next->Prev = pos;
pos->Object = newElement;
m_Count++;
Unlock();
}
return pos;
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
{
POSITION pos;
ASSERT(m_Initialized);
pos = new CListElement;
if (pos) {
Lock();
pos->Next = &m_Sentinel;
pos->Prev = m_Sentinel.Prev;
pos->Prev->Next = pos;
pos->Next->Prev = pos;
pos->Object = newElement;
m_Count++;
Unlock();
}
return pos;
}
template<class TYPE, class ARG_TYPE>
TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION pos)
{
ASSERT(m_Initialized);
return (TYPE)pos->Object;
}
template<class TYPE, class ARG_TYPE>
int CList<TYPE, ARG_TYPE>::GetCount(void) const
{
ASSERT(m_Initialized);
return m_Count;
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition(void) const
{
POSITION pos;
ASSERT(m_Initialized);
pos = m_Sentinel.Next;
// Skip NULL elements
while (NULL == pos->Object) pos = pos->Next;
if (pos == &m_Sentinel) return NULL;
return pos;
}
template<class TYPE, class ARG_TYPE>
TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPos)
{
ASSERT(m_Initialized);
TYPE Object = (TYPE)rPos->Object;
rPos = rPos->Next;
// Skip NULL elements.
while (NULL == rPos->Object) rPos = rPos->Next;
if (rPos == &m_Sentinel) rPos = NULL;
return Object;
}
template<class TYPE, class ARG_TYPE>
LONG CList<TYPE, ARG_TYPE>::Initialize(void)
{
LONG result;
ASSERT(!m_Initialized);
__try {
InitializeCriticalSection(&m_CriticalSection);
result = NO_ERROR;
} __except(EXCEPTION_EXECUTE_HANDLER) {
result = ERROR_OUTOFMEMORY;
}
m_Initialized = (NO_ERROR == result);
return result;
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
{
ASSERT(m_Initialized);
if (position == NULL)
{
// insert after nothing -> head of the list
position = &m_Sentinel;
}
// Insert it after position
CListElement* newPos = new CListElement;
if (newPos)
{
Lock();
newPos->Next = position->Next;
newPos->Prev = position;
newPos->Next->Prev = newPos;
newPos->Prev->Next = newPos;
newPos->Object = newElement;
m_Count++;
Unlock();
}
return newPos;
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
{
ASSERT(m_Initialized);
if (position == NULL)
{
// insert before nothing -> tail of list
position = &m_Sentinel;
}
// Insert it before position
CListElement* newPos = new CListElement;
if (newPos)
{
Lock();
newPos->Next = position;
newPos->Prev = position->Prev;
newPos->Next->Prev = newPos;
newPos->Prev->Next = newPos;
newPos->Object = newElement;
m_Count++;
Unlock();
}
return newPos;
}
template<class TYPE, class ARG_TYPE>
BOOL CList<TYPE, ARG_TYPE>::IsEmpty(void) const
{
ASSERT(m_Initialized);
return (0 == m_Count);
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::Lock(void)
{
EnterCriticalSection(&m_CriticalSection);
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::MoveBefore(POSITION posTarget, POSITION posMove)
{
ASSERT(m_Initialized);
if (posTarget == posMove) return;
if (posTarget == NULL)
{
// Move before nothing -> tail of list
posTarget = &m_Sentinel;
}
// first remove from list
posMove->Prev->Next = posMove->Next;
posMove->Next->Prev = posMove->Prev;
// Move it before posTarget
posMove->Next = posTarget;
posMove->Prev = posTarget->Prev;
posMove->Next->Prev = posMove;
posMove->Prev->Next = posMove;
return;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::RemoveAll(void)
{
POSITION pos;
ASSERT(m_Initialized);
while (pos = GetHeadPosition()) RemoveAt(pos);
return;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION pos)
{
ASSERT(m_Initialized);
ASSERT(m_Count > 0);
Lock();
pos->Prev->Next = pos->Next;
pos->Next->Prev = pos->Prev;
m_Count--;
Unlock();
delete pos;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
{
ASSERT(m_Initialized);
ASSERT(m_Count > 0);
Lock();
pos->Object = newElement;
Unlock();
return;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::Unlock(void)
{
LeaveCriticalSection(&m_CriticalSection);
}