NachOS/code/threads/list.cc

332 lines
9.1 KiB
C++

// list.cc
//
// 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.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "list.h"
//----------------------------------------------------------------------
// 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, long long sortKey)
{
item = itemPtr;
key = sortKey;
next = NULL; // assume we'll put it at the end of the list
}
//----------------------------------------------------------------------
// List::List
// Initialize a list, empty to start with.
// Elements can now be added to the list.
//----------------------------------------------------------------------
List::List ()
{
first = last = NULL;
}
//----------------------------------------------------------------------
// 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 ()
{
while (Remove () != NULL)
; // delete all the list elements
}
//----------------------------------------------------------------------
// 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;
last = element;
}
}
//----------------------------------------------------------------------
// 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 = element;
}
}
//----------------------------------------------------------------------
// List::FirstItem
// Read item off the front of the list
//
// Returns:
// Pointer to first item, NULL if nothing on the list.
//----------------------------------------------------------------------
ListElement *
List::FirstElement ()
{
return first;
}
//----------------------------------------------------------------------
// 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 ()
{
return SortedRemove (NULL); // Same as SortedRemove, but ignore the key
}
//----------------------------------------------------------------------
// List::Remove
// Remove "item" off the list.
//----------------------------------------------------------------------
void
List::Remove (void *item)
{
ListElement **cur;
ListElement *prec = NULL, *next;
for (cur = &first; *cur; prec=*cur, cur = &(*cur)->next)
{
if ((*cur)->item == item)
{
if(*cur==last)
last = prec;
next = (*cur)->next;
delete *cur;
*cur = next;
return;
}
}
ASSERT(FALSE);
}
//----------------------------------------------------------------------
// List::Length
// Return the length of the list.
//----------------------------------------------------------------------
int
List::Length (void)
{
ListElement *cur;
int n = 0;
for (cur = first; cur; cur = cur->next)
n++;
return n;
}
//----------------------------------------------------------------------
// List::Mapcar
// Apply a function to each item on the list, by walking through
// the list, one element at a time.
//
// Unlike LISP, this mapcar does not return anything!
//
// "func" is the procedure to apply to each element of the list.
//----------------------------------------------------------------------
void
List::Mapcar (VoidFunctionPtr func)
{
ListElement *next;
for (ListElement * ptr = first; ptr != NULL; ptr = next)
{
next = ptr->next;
DEBUG ('l', "In mapcar, about to invoke %p(%p)\n", func, ptr->item);
(*func) (ptr->item);
}
}
//----------------------------------------------------------------------
// List::Mapcar
// Similar to the former, but also passes an addition argument to the
// function.
//----------------------------------------------------------------------
void
List::Mapcar (VoidFunctionPtr2 func, void *arg)
{
ListElement *next;
for (ListElement * ptr = first; ptr != NULL; ptr = next)
{
next = ptr->next;
DEBUG ('l', "In mapcar, about to invoke %p(%p)\n", func, ptr->item);
(*func) (ptr->item, arg);
}
}
//----------------------------------------------------------------------
// List::IsEmpty
// Returns TRUE if the list is empty (has no items).
//----------------------------------------------------------------------
bool
List::IsEmpty ()
{
if (first == NULL)
return TRUE;
else
return FALSE;
}
//----------------------------------------------------------------------
// 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, long long 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 = 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;
ptr->next = element;
return;
}
}
last->next = element; // item goes at end of list
last = element;
}
}
//----------------------------------------------------------------------
// 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 (long long *keyPtr)
{
ListElement *element = first;
void *thing;
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 (keyPtr != NULL)
*keyPtr = element->key;
delete element;
return thing;
}