You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
8.2 KiB
308 lines
8.2 KiB
/* (C) 1997-1999 Microsoft Corp.
|
|
*
|
|
* file : SList.c
|
|
* authors : Christos Tsollis, Erik Mavrinac
|
|
*
|
|
* description: Implementation of list described in SList.h.
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "mcsimpl.h"
|
|
|
|
|
|
void SListInit(PSList pSL, unsigned NItems)
|
|
{
|
|
// Initialize the private member variables. Use preallocated array for
|
|
// initial node array.
|
|
pSL->Hdr.NEntries = 0;
|
|
pSL->Hdr.MaxEntries = SListDefaultNumEntries;
|
|
pSL->Hdr.HeadOffset = 0;
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF;
|
|
pSL->Hdr.Entries = pSL->InitialList;
|
|
}
|
|
|
|
|
|
|
|
void SListDestroy(PSList pSL)
|
|
{
|
|
// Only free if we have a pool-allocated array.
|
|
if (pSL->Hdr.Entries != pSL->InitialList) {
|
|
ExFreePool(pSL->Hdr.Entries);
|
|
pSL->Hdr.Entries = pSL->InitialList;
|
|
pSL->Hdr.MaxEntries = SListDefaultNumEntries;
|
|
}
|
|
pSL->Hdr.NEntries = 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Expand
|
|
* Private function to double the storage of the SList. Returns FALSE on
|
|
* error.
|
|
*/
|
|
static BOOLEAN SListExpand(PSList pSL)
|
|
{
|
|
unsigned Temp;
|
|
_SListNode *OldEntries; // Keeps a copy of the old array of values.
|
|
|
|
ASSERT(pSL->Hdr.Entries != NULL);
|
|
|
|
// The current array of entries is full, so we need to allocate a bigger
|
|
// one. The new array has twice the size of the old one.
|
|
OldEntries = pSL->Hdr.Entries;
|
|
pSL->Hdr.Entries = ExAllocatePoolWithTag(PagedPool, pSL->Hdr.MaxEntries *
|
|
2 * sizeof(_SListNode), MCS_POOL_TAG);
|
|
if (pSL->Hdr.Entries == NULL) {
|
|
// We failed; we have to return
|
|
pSL->Hdr.Entries = OldEntries;
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy the old entries into the new array, starting from the head.
|
|
Temp = pSL->Hdr.MaxEntries - pSL->Hdr.HeadOffset;
|
|
memcpy(pSL->Hdr.Entries, OldEntries + pSL->Hdr.HeadOffset, Temp *
|
|
sizeof(_SListNode));
|
|
memcpy(pSL->Hdr.Entries + Temp, OldEntries, pSL->Hdr.HeadOffset *
|
|
sizeof(_SListNode));
|
|
|
|
// Free the old array of entries if not the initial array.
|
|
if (OldEntries != pSL->InitialList)
|
|
ExFreePool(OldEntries);
|
|
|
|
// Set the instance variables
|
|
pSL->Hdr.MaxEntries *= 2;
|
|
pSL->Hdr.HeadOffset = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Append
|
|
* Inserts a value at the end of a list. Returns FALSE on error.
|
|
*/
|
|
BOOLEAN SListAppend(PSList pSL, UINT_PTR NewKey, void *NewValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->Hdr.NEntries < pSL->Hdr.MaxEntries ||
|
|
(pSL->Hdr.NEntries >= pSL->Hdr.MaxEntries && SListExpand(pSL))) {
|
|
Temp = pSL->Hdr.HeadOffset + pSL->Hdr.NEntries;
|
|
if (Temp >= pSL->Hdr.MaxEntries)
|
|
Temp -= pSL->Hdr.MaxEntries;
|
|
pSL->Hdr.Entries[Temp].Key = NewKey;
|
|
pSL->Hdr.Entries[Temp].Value = NewValue;
|
|
pSL->Hdr.NEntries++;
|
|
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef NotUsed
|
|
/*
|
|
* Prepend
|
|
* Inserts a value at the beginning of a list. Returns FALSE on error.
|
|
*/
|
|
BOOLEAN SListPrepend(PSList pSL, UINT_PTR NewKey, void *NewValue)
|
|
{
|
|
if (pSL->Hdr.NEntries >= pSL->Hdr.MaxEntries)
|
|
if (!SListExpand(pSL))
|
|
return FALSE;
|
|
|
|
ASSERT(pSL->Hdr.Entries != NULL);
|
|
ASSERT(pSL->Hdr.NEntries < pSL->Hdr.MaxEntries);
|
|
|
|
if (pSL->Hdr.HeadOffset == 0)
|
|
pSL->Hdr.HeadOffset = pSL->Hdr.MaxEntries - 1;
|
|
else
|
|
pSL->Hdr.HeadOffset--;
|
|
|
|
pSL->Hdr.Entries[pSL->Hdr.HeadOffset].Key = NewKey;
|
|
pSL->Hdr.Entries[pSL->Hdr.HeadOffset].Value = NewValue;
|
|
pSL->Hdr.NEntries++;
|
|
|
|
// Reset iteration.
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF;
|
|
|
|
return TRUE;
|
|
}
|
|
#endif // NotUsed
|
|
|
|
|
|
|
|
/*
|
|
* Remove
|
|
* Removes a value from the list, returning the value in *pValue. Returns
|
|
* NULL in *pValue if the key does not exist. pValue can be NULL.
|
|
*/
|
|
void SListRemove(PSList pSL, UINT_PTR Key, void **pValue)
|
|
{
|
|
unsigned i, Temp, CurItem;
|
|
|
|
// Find Key in the list.
|
|
CurItem = pSL->Hdr.HeadOffset;
|
|
for (i = 0; i < pSL->Hdr.NEntries; i++) {
|
|
if (Key == pSL->Hdr.Entries[CurItem].Key) {
|
|
// Found it; now move the last value in the list into its place.
|
|
// (Remember we aren't trying to preserve ordering here.)
|
|
if (pValue != NULL)
|
|
*pValue = pSL->Hdr.Entries[CurItem].Value;
|
|
|
|
// Move the last item in the list into the open place.
|
|
Temp = pSL->Hdr.HeadOffset + pSL->Hdr.NEntries - 1;
|
|
if (Temp >= pSL->Hdr.MaxEntries)
|
|
Temp -= pSL->Hdr.MaxEntries;
|
|
pSL->Hdr.Entries[CurItem] = pSL->Hdr.Entries[Temp];
|
|
|
|
pSL->Hdr.NEntries--;
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF; // Reset iteration.
|
|
return;
|
|
}
|
|
|
|
// Advance CurItem, wrapping at end of list.
|
|
CurItem++;
|
|
if (CurItem == pSL->Hdr.MaxEntries)
|
|
CurItem = 0;
|
|
}
|
|
|
|
if (pValue != NULL)
|
|
*pValue = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* RemoveFirst
|
|
* Reads and removes the 1st item from the list. Returns the value removed,
|
|
* or zero if the list is empty.
|
|
*/
|
|
void SListRemoveFirst(PSList pSL, UINT_PTR *pKey, void **pValue)
|
|
{
|
|
if (pSL->Hdr.NEntries < 1) {
|
|
*pKey = 0;
|
|
*pValue = NULL;
|
|
return;
|
|
}
|
|
|
|
// Reset iteration.
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF;
|
|
|
|
*pKey = (pSL->Hdr.Entries + pSL->Hdr.HeadOffset)->Key;
|
|
*pValue = (pSL->Hdr.Entries + pSL->Hdr.HeadOffset)->Value;
|
|
pSL->Hdr.NEntries--;
|
|
pSL->Hdr.HeadOffset++;
|
|
if (pSL->Hdr.HeadOffset >= pSL->Hdr.MaxEntries)
|
|
pSL->Hdr.HeadOffset = 0;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* GetByKey
|
|
* Searches the list and returns in *pValue the value corresponding to the
|
|
* given key. If the key is not present, returns FALSE and NULL in
|
|
* *pValue. If key is found, reurns nonzero.
|
|
*/
|
|
BOOLEAN SListGetByKey(PSList pSL, UINT_PTR Key, void **pValue)
|
|
{
|
|
unsigned i, Temp;
|
|
_SListNode *pItem;
|
|
|
|
// Find Key in the list.
|
|
pItem = pSL->Hdr.Entries + pSL->Hdr.HeadOffset;
|
|
for (i = 0; i < pSL->Hdr.NEntries; i++) {
|
|
if (Key == pItem->Key) {
|
|
// Found it; set *pValue and return.
|
|
*pValue = pItem->Value;
|
|
return TRUE;
|
|
}
|
|
|
|
// Advance pItem, wrapping at end of list.
|
|
pItem++;
|
|
if ((unsigned)(pItem - pSL->Hdr.Entries) >= pSL->Hdr.MaxEntries)
|
|
pItem = pSL->Hdr.Entries;
|
|
}
|
|
|
|
*pValue = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
#ifdef NotUsed
|
|
/*
|
|
* RemoveLast
|
|
* Removes the value at the end of the lst and returns it. If the list is
|
|
* empty, returns zero.
|
|
*/
|
|
void SListRemoveLast(PSList pSL, UINT_PTR *pKey, void **pValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->Hdr.NEntries < 1) {
|
|
*pKey = 0;
|
|
*pValue = NULL;
|
|
return;
|
|
}
|
|
|
|
// Reset iteration.
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF;
|
|
|
|
pSL->Hdr.NEntries--;
|
|
Temp = pSL->Hdr.HeadOffset + pSL->Hdr.NEntries - 1;
|
|
if (Temp >= pSL->Hdr.MaxEntries)
|
|
Temp -= pSL->Hdr.MaxEntries;
|
|
|
|
*pKey = (pSL->Hdr.Entries + Temp)->Key;
|
|
*pValue = (pSL->Hdr.Entries + Temp)->Value;
|
|
}
|
|
#endif // NotUsed
|
|
|
|
|
|
|
|
/*
|
|
* Iterate
|
|
* Iterates through the items of a list. CurrOffset is used as a current
|
|
* iteration pointer, so this function can be called in a loop. Returns
|
|
* FALSE if the iteration has completed, nonzero if the iteration continues
|
|
* (and *pKey is valid).
|
|
*/
|
|
BOOLEAN SListIterate(PSList pSL, UINT_PTR *pKey, void **pValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->Hdr.NEntries >= 1) {
|
|
if (pSL->Hdr.CurrOffset != 0xFFFFFFFF) {
|
|
pSL->Hdr.CurrOffset++;
|
|
if (pSL->Hdr.CurrOffset >= pSL->Hdr.NEntries) {
|
|
// Reset the iterator.
|
|
pSL->Hdr.CurrOffset = 0xFFFFFFFF;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// Start from the beginning.
|
|
pSL->Hdr.CurrOffset = 0;
|
|
}
|
|
|
|
Temp = pSL->Hdr.CurrOffset + pSL->Hdr.HeadOffset;
|
|
if (Temp >= pSL->Hdr.MaxEntries)
|
|
Temp -= pSL->Hdr.MaxEntries;
|
|
|
|
*pKey = pSL->Hdr.Entries[Temp].Key;
|
|
*pValue = pSL->Hdr.Entries[Temp].Value;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|