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.
314 lines
7.7 KiB
314 lines
7.7 KiB
/* (C) 1997 Microsoft Corp.
|
|
*
|
|
* file : SList.c
|
|
* authors : Christos Tsollis, Erik Mavrinac
|
|
*
|
|
* description: Implementation of list described in SList.h.
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "MCSMUX.h"
|
|
|
|
|
|
void SListInit(PSList pSL, unsigned NItems)
|
|
{
|
|
pSL->MaxEntries = NItems;
|
|
|
|
// Allocate the block of items (which, hopefully, will be the last one).
|
|
// NULL return value will be handled in the future.
|
|
pSL->Entries = (_SListNode *)Malloc(NItems * sizeof(_SListNode));
|
|
|
|
// Initialize the private member variables
|
|
pSL->NEntries = 0;
|
|
pSL->HeadOffset = 0;
|
|
pSL->CurrOffset = 0xFFFFFFFF;
|
|
}
|
|
|
|
|
|
|
|
void SListDestroy(PSList pSL)
|
|
{
|
|
if (pSL->Entries != NULL) {
|
|
Free(pSL->Entries);
|
|
pSL->Entries = NULL;
|
|
pSL->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.
|
|
|
|
if (pSL->Entries == NULL) {
|
|
// The list is empty; we try to allocate space anyway.
|
|
pSL->Entries = Malloc(pSL->MaxEntries * sizeof(_SListNode));
|
|
if (pSL->Entries == NULL)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
// 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->Entries;
|
|
pSL->Entries = Malloc(pSL->MaxEntries * 2 * sizeof(_SListNode));
|
|
if (pSL->Entries == NULL) {
|
|
// We failed; we have to return
|
|
pSL->Entries = OldEntries;
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy the old entries into the new array, starting from the head.
|
|
Temp = pSL->MaxEntries - pSL->HeadOffset;
|
|
MemCpy(pSL->Entries, OldEntries + pSL->HeadOffset, Temp * sizeof(_SListNode));
|
|
MemCpy(pSL->Entries + Temp, OldEntries, pSL->HeadOffset * sizeof(_SListNode));
|
|
|
|
// Free the old array of entries
|
|
Free(OldEntries);
|
|
|
|
// Set the instance variables
|
|
pSL->MaxEntries *= 2;
|
|
pSL->HeadOffset = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Append
|
|
* Inserts a value at the end of a list. Returns FALSE on error.
|
|
*/
|
|
|
|
BOOLEAN SListAppend(PSList pSL, unsigned NewKey, void *NewValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->Entries == NULL || pSL->NEntries >= pSL->MaxEntries)
|
|
if (!SListExpand(pSL))
|
|
return FALSE;
|
|
|
|
ASSERT(pSL->Entries != NULL);
|
|
ASSERT(pSL->NEntries < pSL->MaxEntries);
|
|
|
|
Temp = pSL->HeadOffset + pSL->NEntries;
|
|
if (Temp >= pSL->MaxEntries)
|
|
Temp -= pSL->MaxEntries;
|
|
pSL->Entries[Temp].Key = NewKey;
|
|
pSL->Entries[Temp].Value = NewValue;
|
|
pSL->NEntries++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Prepend
|
|
* Inserts a value at hte beginning of a list. Returns FALSE on error.
|
|
*/
|
|
|
|
BOOLEAN SListPrepend(PSList pSL, unsigned NewKey, void *NewValue)
|
|
{
|
|
if (pSL->Entries == NULL || pSL->NEntries >= pSL->MaxEntries)
|
|
if (!SListExpand(pSL))
|
|
return FALSE;
|
|
|
|
ASSERT(pSL->Entries != NULL);
|
|
ASSERT(pSL->NEntries < pSL->MaxEntries);
|
|
|
|
if (pSL->HeadOffset == 0)
|
|
pSL->HeadOffset = pSL->MaxEntries - 1;
|
|
else
|
|
pSL->HeadOffset--;
|
|
|
|
pSL->Entries[pSL->HeadOffset].Key = NewKey;
|
|
pSL->Entries[pSL->HeadOffset].Value = NewValue;
|
|
pSL->NEntries++;
|
|
|
|
// Reset iteration.
|
|
pSL->CurrOffset = 0xFFFFFFFF;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* 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, unsigned Key, void **pValue)
|
|
{
|
|
unsigned i, Temp, CurItem;
|
|
|
|
// Find Key in the list.
|
|
CurItem = pSL->HeadOffset;
|
|
for (i = 0; i < pSL->NEntries; i++) {
|
|
if (Key == pSL->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->Entries[CurItem].Value;
|
|
|
|
// Move the last item in the list into the open place.
|
|
Temp = pSL->HeadOffset + pSL->NEntries - 1;
|
|
if (Temp >= pSL->MaxEntries)
|
|
Temp -= pSL->MaxEntries;
|
|
pSL->Entries[CurItem] = pSL->Entries[Temp];
|
|
|
|
pSL->NEntries--;
|
|
pSL->CurrOffset = 0xFFFFFFFF; // Reset iteration.
|
|
return;
|
|
}
|
|
|
|
// Advance CurItem, wrapping at end of list.
|
|
CurItem++;
|
|
if (CurItem == pSL->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, unsigned *pKey, void **pValue)
|
|
{
|
|
if (pSL->NEntries < 1) {
|
|
*pKey = 0;
|
|
*pValue = NULL;
|
|
return;
|
|
}
|
|
|
|
// Reset iteration.
|
|
pSL->CurrOffset = 0xFFFFFFFF;
|
|
|
|
*pKey = (pSL->Entries + pSL->HeadOffset)->Key;
|
|
*pValue = (pSL->Entries + pSL->HeadOffset)->Value;
|
|
pSL->NEntries--;
|
|
pSL->HeadOffset++;
|
|
if (pSL->HeadOffset >= pSL->MaxEntries)
|
|
pSL->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, unsigned Key, void **pValue)
|
|
{
|
|
unsigned i, Temp;
|
|
_SListNode *pItem;
|
|
|
|
// Find Key in the list.
|
|
pItem = pSL->Entries + pSL->HeadOffset;
|
|
for (i = 0; i < pSL->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->Entries) >= pSL->MaxEntries)
|
|
pItem = pSL->Entries;
|
|
}
|
|
|
|
*pValue = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* RemoveLast
|
|
* Removes the value at the end of the lst and returns it. If the list is
|
|
* empty, returns zero.
|
|
*/
|
|
|
|
void SListRemoveLast(PSList pSL, unsigned *pKey, void **pValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->NEntries < 1) {
|
|
*pKey = 0;
|
|
*pValue = NULL;
|
|
return;
|
|
}
|
|
|
|
// Reset iteration.
|
|
pSL->CurrOffset = 0xFFFFFFFF;
|
|
|
|
pSL->NEntries--;
|
|
Temp = pSL->HeadOffset + pSL->NEntries - 1;
|
|
if (Temp >= pSL->MaxEntries)
|
|
Temp -= pSL->MaxEntries;
|
|
|
|
*pKey = (pSL->Entries + Temp)->Key;
|
|
*pValue = (pSL->Entries + Temp)->Value;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* 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, unsigned *pKey, void **pValue)
|
|
{
|
|
unsigned Temp;
|
|
|
|
if (pSL->NEntries < 1)
|
|
return FALSE;
|
|
|
|
if (pSL->CurrOffset == 0xFFFFFFFF) {
|
|
// Start from the beginning.
|
|
pSL->CurrOffset = 0;
|
|
}
|
|
else {
|
|
pSL->CurrOffset++;
|
|
if (pSL->CurrOffset >= pSL->NEntries) {
|
|
// Reset the iterator.
|
|
pSL->CurrOffset = 0xFFFFFFFF;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
Temp = pSL->CurrOffset + pSL->HeadOffset;
|
|
if (Temp >= pSL->MaxEntries)
|
|
Temp -= pSL->MaxEntries;
|
|
|
|
*pKey = pSL->Entries[Temp].Key;
|
|
*pValue = pSL->Entries[Temp].Value;
|
|
|
|
return TRUE;
|
|
}
|