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.
386 lines
12 KiB
386 lines
12 KiB
//------------------------------------------------------------------------------------------
|
|
// list.cpp
|
|
//
|
|
// Routines to manage a singly-linked list of "things".
|
|
//
|
|
// A "ListElement" is allocated for each item to be put on the list; it is de-allocated
|
|
// when the item is removed. This means we don't need to keep a "next" pointer in every
|
|
// object we want to put on a list.
|
|
//
|
|
// NOTE: Mutual exclusion must be provided by the caller. If you want a synchronized
|
|
// list, you must use the routines in synchlist.cc.
|
|
//
|
|
//------------------------------------------------------------------------------------------
|
|
|
|
#include "list.hpp"
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// ListElement::ListElement
|
|
//
|
|
// Initialize a list element, so it can be added somewhere on a list.
|
|
//
|
|
// "itemPtr" is the item to be put on the list. It can be a pointer to anything.
|
|
// "sortKey" is the priority of the item, if any.
|
|
//------------------------------------------------------------------------------------------
|
|
ListElement::ListElement(void *itemPtr, int sortKey)
|
|
{
|
|
item = itemPtr;
|
|
key = sortKey;
|
|
next = NULL; // assume we'll put it at the end of the list
|
|
previous = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::List
|
|
//
|
|
// Initialize a list, empty to start with.
|
|
//
|
|
// Elements can now be added to the list.
|
|
//------------------------------------------------------------------------------------------
|
|
List::List()
|
|
{
|
|
first = last = iterator = NULL;
|
|
length = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::~List
|
|
//
|
|
// Prepare a list for deallocation. If the list still contains any ListElements,
|
|
// de-allocate them. However, note that we do *not* de-allocate the "items" on the
|
|
// list -- this module allocates and de-allocates the ListElements to keep track of
|
|
// each item, but a given item may be on multiple lists, so we can't de-allocate them here.
|
|
//------------------------------------------------------------------------------------------
|
|
List::~List()
|
|
{
|
|
Flush();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::Append
|
|
//
|
|
// Append an "item" to the end of the list.
|
|
//
|
|
// Allocate a ListElement to keep track of the item. If the list is empty, then this will
|
|
// be the only element. Otherwise, put it at the end.
|
|
//
|
|
// "item" is the thing to put on the list, it can be a pointer to anything.
|
|
//------------------------------------------------------------------------------------------
|
|
void List::Append(void *item)
|
|
{
|
|
ListElement *element = new ListElement(item, 0);
|
|
|
|
if (IsEmpty())
|
|
{
|
|
// list is empty
|
|
first = element;
|
|
last = element;
|
|
}
|
|
else
|
|
{
|
|
// else put it after last
|
|
last->next = element;
|
|
element->previous = last;
|
|
last = element;
|
|
}
|
|
length++;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::Prepend
|
|
//
|
|
// Put an "item" on the front of the list.
|
|
//
|
|
// Allocate a ListElement to keep track of the item. If the list is empty, then this will
|
|
// be the only element. Otherwise, put it at the beginning.
|
|
//
|
|
// "item" is the thing to put on the list, it can be a pointer to anything.
|
|
//------------------------------------------------------------------------------------------
|
|
void List::Prepend(void *item)
|
|
{
|
|
ListElement *element = new ListElement(item, 0);
|
|
|
|
if (IsEmpty())
|
|
{
|
|
// list is empty
|
|
first = element;
|
|
last = element;
|
|
}
|
|
else
|
|
{
|
|
// else put it before first
|
|
element->next = first;
|
|
first->previous = element;
|
|
first = element;
|
|
}
|
|
length++;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::Remove
|
|
//
|
|
// Remove the first "item" from the front of the list.
|
|
//
|
|
// Returns:
|
|
//
|
|
// Pointer to removed item, NULL if nothing on the list.
|
|
//------------------------------------------------------------------------------------------
|
|
void* List::Remove()
|
|
{
|
|
// Same as SortedRemove, but ignore the key
|
|
return SortedRemove(NULL);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::Flush
|
|
//
|
|
// Remove everything from the list.
|
|
//
|
|
//------------------------------------------------------------------------------------------
|
|
void List::Flush()
|
|
{
|
|
while (Remove() != NULL)
|
|
; // delete all the list elements
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::Mapcar
|
|
//
|
|
// Apply a function to each item on the list, by walking through
|
|
// the list, one element at a time.
|
|
//
|
|
// "func" is the procedure to apply to each element of the list.
|
|
//------------------------------------------------------------------------------------------
|
|
void List::Mapcar(VoidFunctionPtr func)
|
|
{
|
|
for (ListElement *ptr = first; ptr != NULL; ptr = ptr->next)
|
|
{
|
|
(*func)( ptr->item );
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::IsEmpty
|
|
//
|
|
// Returns TRUE if the list is empty (has no items).
|
|
//------------------------------------------------------------------------------------------
|
|
bool List::IsEmpty()
|
|
{
|
|
return (first == NULL);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::MoveFirst
|
|
//
|
|
// move to the first node in the list.
|
|
//
|
|
//------------------------------------------------------------------------------------------
|
|
void List::MoveFirst()
|
|
{
|
|
iterator = first;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::MoveNext
|
|
//
|
|
// move to the next state of the list.
|
|
//
|
|
//------------------------------------------------------------------------------------------
|
|
bool List::MoveNext()
|
|
{
|
|
if (iterator == NULL || iterator->next == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
iterator = iterator->next;
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::GetData
|
|
//
|
|
// get data of the current iterator.
|
|
//
|
|
//------------------------------------------------------------------------------------------
|
|
void* List::GetData()
|
|
{
|
|
// make sure iterator is set.
|
|
if (iterator == NULL)
|
|
return NULL;
|
|
|
|
// return the data.
|
|
return iterator->item;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::SortedInsert
|
|
//
|
|
// Insert an "item" into a list, so that the list elements are sorted in increasing order
|
|
// by "sortKey".
|
|
//
|
|
// Allocate a ListElement to keep track of the item. If the list is empty, then this will
|
|
// be the only element. Otherwise, walk through the list, one element at a time, to find
|
|
// where the new item should be placed.
|
|
//
|
|
// "item" is the thing to put on the list, it can be a pointer to anything.
|
|
// "sortKey" is the priority of the item.
|
|
//------------------------------------------------------------------------------------------
|
|
void List::SortedInsert(void *item, int sortKey)
|
|
{
|
|
ListElement *element = new ListElement(item, sortKey);
|
|
ListElement *ptr; // keep track
|
|
|
|
if (IsEmpty())
|
|
{
|
|
// if list is empty, put
|
|
first = element;
|
|
last = element;
|
|
}
|
|
else if (sortKey < first->key)
|
|
{
|
|
// item goes on front of list
|
|
element->next = first;
|
|
first->previous = element;
|
|
first = element;
|
|
}
|
|
else
|
|
{
|
|
// look for first elt in list bigger than item
|
|
for (ptr = first; ptr->next != NULL; ptr = ptr->next)
|
|
{
|
|
if (sortKey < ptr->next->key)
|
|
{
|
|
element->next = ptr->next;
|
|
element->previous = ptr;
|
|
ptr->next->previous = element;
|
|
ptr->next = element;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// item goes at end of list
|
|
last->next = element;
|
|
element->previous = last;
|
|
last = element;
|
|
}
|
|
length++;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::SortedRemove
|
|
//
|
|
// Remove the first "item" from the front of a sorted list.
|
|
//
|
|
// Returns:
|
|
//
|
|
// Pointer to removed item, NULL if nothing on the list. Sets *keyPtr to the priority value
|
|
// of the removed item (this is needed by interrupt.cc, for instance).
|
|
//
|
|
// "keyPtr" is a pointer to the location in which to store the priority of the removed item
|
|
//------------------------------------------------------------------------------------------
|
|
void* List::SortedRemove(int *keyPtr)
|
|
{
|
|
ListElement *element = first;
|
|
void *thing;
|
|
|
|
// if empty nothing to remove just return.
|
|
if (IsEmpty())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
thing = first->item;
|
|
if (first == last)
|
|
{
|
|
// list had one item, now has none
|
|
first = NULL;
|
|
last = NULL;
|
|
}
|
|
else
|
|
{
|
|
first = element->next;
|
|
if (first != NULL)
|
|
{
|
|
first->previous = NULL;
|
|
}
|
|
}
|
|
|
|
if (keyPtr != NULL)
|
|
{
|
|
*keyPtr = element->key;
|
|
}
|
|
delete element;
|
|
length--;
|
|
return thing;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::insertAfter
|
|
//
|
|
// insert a new item after this one
|
|
//------------------------------------------------------------------------------------------
|
|
void List::insertAfter(ListElement * listEl, void *item)
|
|
{
|
|
ListElement *newElement = new ListElement(item, 0);
|
|
newElement->next = listEl->next;
|
|
newElement->previous = listEl;
|
|
listEl->next = newElement;
|
|
|
|
if (last == listEl)
|
|
{
|
|
last = newElement;
|
|
}
|
|
|
|
length++;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::insertBefore
|
|
//
|
|
// insert a new item before this one
|
|
//------------------------------------------------------------------------------------------
|
|
void List::insertBefore(ListElement * listEl, void *item)
|
|
{
|
|
ListElement *newElement = new ListElement(item, 0);
|
|
newElement->next = listEl;
|
|
newElement->previous = listEl->previous;
|
|
listEl->previous = newElement;
|
|
|
|
if (first == listEl)
|
|
{
|
|
first = newElement;
|
|
}
|
|
|
|
length++;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------------------
|
|
// List::removeAt
|
|
//
|
|
// removes listEl from the list. Do not delete it from memory
|
|
//------------------------------------------------------------------------------------------
|
|
void List::removeAt(ListElement * listEl)
|
|
{
|
|
if(first != listEl)
|
|
{
|
|
(listEl->previous)->next = listEl->next;
|
|
}
|
|
else
|
|
{
|
|
first = listEl->next;
|
|
}
|
|
|
|
if(last != listEl)
|
|
{
|
|
(listEl->next)->previous = listEl->previous;
|
|
}
|
|
else
|
|
{
|
|
last = listEl->previous;
|
|
}
|
|
length --;
|
|
}
|