411 lines
7.4 KiB
C++
411 lines
7.4 KiB
C++
/*++
|
||
|
||
Copyright (c) 1999-2000 Microsoft Corporation
|
||
|
||
Module Name :
|
||
LstEntry.h
|
||
|
||
Abstract:
|
||
Declares CListEntry and other intrusive singly- and doubly-linked lists
|
||
|
||
Author:
|
||
George V. Reilly (GeorgeRe) 02-Mar-1999
|
||
|
||
Environment:
|
||
Win32 - User Mode
|
||
|
||
Project:
|
||
Internet Information Server RunTime Library
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#ifndef __LSTENTRY_H__
|
||
#define __LSTENTRY_H__
|
||
|
||
#ifndef __LOCKS_H__
|
||
# include <Locks.h>
|
||
#endif // !__LOCKS_H__
|
||
|
||
#ifndef LSTENTRY_LOCK
|
||
#ifdef LOCKS_KERNEL_MODE
|
||
#define LSTENTRY_LOCK CKSpinLock
|
||
#else // !LOCKS_KERNEL_MODE
|
||
#define LSTENTRY_LOCK CSpinLock
|
||
#endif // !LOCKS_KERNEL_MODE
|
||
#endif // !LSTENTRY_LOCK
|
||
|
||
// TODO:
|
||
// * Add STL-style iterators: begin(), end(), operator++(), etc
|
||
// * Templatize the lists, so that you can avoid the CONTAINING_RECORD goo
|
||
|
||
//--------------------------------------------------------------------
|
||
// CSingleListEntry: a node in a singly-linked list. Usually embedded
|
||
// within larger structures.
|
||
//--------------------------------------------------------------------
|
||
|
||
class CSingleListEntry
|
||
{
|
||
public:
|
||
CSingleListEntry* Next; // forward link
|
||
};
|
||
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// A non-threadsafe singly linked list
|
||
//--------------------------------------------------------------------
|
||
|
||
class IRTL_DLLEXP CSingleList
|
||
{
|
||
protected:
|
||
CSingleListEntry m_sleHead; // external head node
|
||
|
||
public:
|
||
CSingleList()
|
||
{
|
||
m_sleHead.Next = NULL;
|
||
}
|
||
|
||
~CSingleList()
|
||
{
|
||
IRTLASSERT(IsEmpty());
|
||
}
|
||
|
||
bool
|
||
IsEmpty() const
|
||
{
|
||
return m_sleHead.Next == NULL;
|
||
}
|
||
|
||
CSingleListEntry* const
|
||
Pop()
|
||
{
|
||
CSingleListEntry* psle = m_sleHead.Next;
|
||
|
||
if (psle != NULL)
|
||
m_sleHead.Next = psle->Next;
|
||
|
||
return psle;
|
||
}
|
||
|
||
void
|
||
Push(
|
||
CSingleListEntry* const psle)
|
||
{
|
||
psle->Next = m_sleHead.Next;
|
||
m_sleHead.Next = psle;
|
||
}
|
||
};
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// A threadsafe singly linked list
|
||
//--------------------------------------------------------------------
|
||
|
||
class IRTL_DLLEXP CLockedSingleList
|
||
{
|
||
protected:
|
||
LSTENTRY_LOCK m_lock;
|
||
CSingleList m_list;
|
||
|
||
public:
|
||
|
||
#ifdef LOCK_INSTRUMENTATION
|
||
CLockedSingleList()
|
||
: m_lock(NULL)
|
||
{}
|
||
#endif // LOCK_INSTRUMENTATION
|
||
|
||
void
|
||
Lock()
|
||
{
|
||
m_lock.WriteLock();
|
||
}
|
||
|
||
void
|
||
Unlock()
|
||
{
|
||
m_lock.WriteUnlock();
|
||
}
|
||
|
||
bool
|
||
IsLocked() const
|
||
{
|
||
return m_lock.IsWriteLocked();
|
||
}
|
||
|
||
bool
|
||
IsUnlocked() const
|
||
{
|
||
return m_lock.IsWriteUnlocked();
|
||
}
|
||
|
||
bool
|
||
IsEmpty() const
|
||
{
|
||
return m_list.IsEmpty();
|
||
}
|
||
|
||
CSingleListEntry* const
|
||
Pop()
|
||
{
|
||
Lock();
|
||
CSingleListEntry* const psle = m_list.Pop();
|
||
Unlock();
|
||
|
||
return psle;
|
||
}
|
||
|
||
void
|
||
Push(
|
||
CSingleListEntry* const psle)
|
||
{
|
||
Lock();
|
||
m_list.Push(psle);
|
||
Unlock();
|
||
}
|
||
};
|
||
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// CListEntry: a node in a circular doubly-linked list. Usually embedded
|
||
// within larger structures.
|
||
//--------------------------------------------------------------------
|
||
|
||
class CListEntry
|
||
{
|
||
public:
|
||
CListEntry* Flink; // forward link
|
||
CListEntry* Blink; // backward link
|
||
};
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// A non-threadsafe circular doubly linked list
|
||
//--------------------------------------------------------------------
|
||
|
||
class IRTL_DLLEXP CDoubleList
|
||
{
|
||
protected:
|
||
CListEntry m_leHead; // external head node
|
||
|
||
public:
|
||
CDoubleList()
|
||
{
|
||
m_leHead.Flink = m_leHead.Blink = &m_leHead;
|
||
}
|
||
|
||
~CDoubleList()
|
||
{
|
||
IRTLASSERT(m_leHead.Flink != NULL && m_leHead.Blink != NULL);
|
||
IRTLASSERT(IsEmpty());
|
||
}
|
||
|
||
bool
|
||
IsEmpty() const
|
||
{
|
||
return m_leHead.Flink == &m_leHead;
|
||
}
|
||
|
||
void
|
||
InsertHead(
|
||
CListEntry* const ple)
|
||
{
|
||
ple->Blink = &m_leHead;
|
||
ple->Flink = m_leHead.Flink;
|
||
ple->Flink->Blink = ple;
|
||
m_leHead.Flink = ple;
|
||
}
|
||
|
||
void
|
||
InsertTail(
|
||
CListEntry* const ple)
|
||
{
|
||
ple->Flink = &m_leHead;
|
||
ple->Blink = m_leHead.Blink;
|
||
ple->Blink->Flink = ple;
|
||
m_leHead.Blink = ple;
|
||
}
|
||
|
||
const CListEntry* const
|
||
HeadNode() const
|
||
{
|
||
return &m_leHead;
|
||
}
|
||
|
||
CListEntry* const
|
||
First() const
|
||
{
|
||
return m_leHead.Flink;
|
||
}
|
||
|
||
CListEntry* const
|
||
RemoveHead()
|
||
{
|
||
CListEntry* ple = First();
|
||
RemoveEntry(ple);
|
||
return ple;
|
||
}
|
||
|
||
CListEntry* const
|
||
Last() const
|
||
{
|
||
return m_leHead.Blink;
|
||
}
|
||
|
||
CListEntry* const
|
||
RemoveTail()
|
||
{
|
||
CListEntry* ple = Last();
|
||
RemoveEntry(ple);
|
||
return ple;
|
||
}
|
||
|
||
static void
|
||
RemoveEntry(
|
||
CListEntry* const ple)
|
||
{
|
||
CListEntry* const pleOldBlink = ple->Blink;
|
||
IRTLASSERT(pleOldBlink != NULL);
|
||
CListEntry* const pleOldFlink = ple->Flink;
|
||
IRTLASSERT(pleOldFlink != NULL);
|
||
|
||
pleOldBlink->Flink = pleOldFlink;
|
||
pleOldFlink->Blink = pleOldBlink;
|
||
}
|
||
};
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// A threadsafe circular doubly linked list
|
||
//--------------------------------------------------------------------
|
||
|
||
class IRTL_DLLEXP CLockedDoubleList
|
||
{
|
||
protected:
|
||
LSTENTRY_LOCK m_lock;
|
||
CDoubleList m_list;
|
||
|
||
public:
|
||
|
||
#ifdef LOCK_INSTRUMENTATION
|
||
CLockedDoubleList()
|
||
: m_lock(NULL)
|
||
{}
|
||
#endif // LOCK_INSTRUMENTATION
|
||
|
||
void
|
||
Lock()
|
||
{
|
||
m_lock.WriteLock();
|
||
}
|
||
|
||
void
|
||
Unlock()
|
||
{
|
||
m_lock.WriteUnlock();
|
||
}
|
||
|
||
bool
|
||
IsLocked() const
|
||
{
|
||
return m_lock.IsWriteLocked();
|
||
}
|
||
|
||
bool
|
||
IsUnlocked() const
|
||
{
|
||
return m_lock.IsWriteUnlocked();
|
||
}
|
||
|
||
bool
|
||
IsEmpty() const
|
||
{
|
||
return m_list.IsEmpty();
|
||
}
|
||
|
||
void
|
||
InsertHead(
|
||
CListEntry* const ple)
|
||
{
|
||
Lock();
|
||
m_list.InsertHead(ple);
|
||
Unlock();
|
||
}
|
||
|
||
void
|
||
InsertTail(
|
||
CListEntry* const ple)
|
||
{
|
||
Lock();
|
||
m_list.InsertTail(ple);
|
||
Unlock();
|
||
}
|
||
|
||
// not threadsafe
|
||
const CListEntry* const
|
||
HeadNode() const
|
||
{
|
||
return m_list.HeadNode();
|
||
}
|
||
|
||
// not threadsafe
|
||
CListEntry* const
|
||
First()
|
||
{
|
||
return m_list.First();
|
||
}
|
||
|
||
CListEntry* const
|
||
RemoveHead()
|
||
{
|
||
Lock();
|
||
CListEntry* const ple = m_list.RemoveHead();
|
||
Unlock();
|
||
return ple;
|
||
}
|
||
|
||
// not threadsafe
|
||
CListEntry* const
|
||
Last()
|
||
{
|
||
return m_list.Last();
|
||
}
|
||
|
||
CListEntry* const
|
||
RemoveTail()
|
||
{
|
||
Lock();
|
||
CListEntry* const ple = m_list.RemoveTail();
|
||
Unlock();
|
||
return ple;
|
||
}
|
||
|
||
void
|
||
RemoveEntry(
|
||
CListEntry* const ple)
|
||
{
|
||
Lock();
|
||
m_list.RemoveEntry(ple);
|
||
Unlock();
|
||
}
|
||
};
|
||
|
||
|
||
#ifndef CONTAINING_RECORD
|
||
//
|
||
// Calculate the address of the base of the structure given its type, and an
|
||
// address of a field within the structure.
|
||
//
|
||
|
||
#define CONTAINING_RECORD(address, type, field) \
|
||
((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field)))
|
||
|
||
#endif // !CONTAINING_RECORD
|
||
|
||
|
||
#endif // __LSTENTRY_H__
|