//
// List.cc
//
// List: A List class which holds objects of type Object.
//
// Part of the ht://Dig package
// Copyright (c) 1999-2004 The ht://Dig Group
// For copyright details, see the file COPYING in your distribution
// or the GNU Library General Public License (LGPL) version 2 or later
//
//
// $Id: List.cc,v 1.9 2004/05/28 13:15:21 lha Exp $
//
#ifdef HAVE_CONFIG_H
#include "htconfig.h"
#endif /* HAVE_CONFIG_H */
#include "List.h"
class listnode
{
public:
listnode *next;
Object *object;
};
//*********************************************************************
// List::List()
// Constructor
//
List::List()
{
head = tail = 0;
number = 0;
}
//*********************************************************************
// List::~List()
// Destructor
//
List::~List()
{
Destroy();
}
//*********************************************************************
// void List::Release()
// Release all the objects from our list.
//
void List::Release()
{
listnode *node;
while (head)
{
node = head;
head = head->next;
delete node;
}
head = tail = 0;
number = 0;
cursor.Clear();
}
//*********************************************************************
// void List::Destroy()
// Delete all the objects from our list.
//
void List::Destroy()
{
listnode *node;
while (head)
{
node = head;
head = head->next;
delete node->object;
delete node;
}
head = tail = 0;
number = 0;
cursor.Clear();
}
//*********************************************************************
// void List::Add(Object *object)
// Add an object to the list.
//
void List::Add(Object *object)
{
listnode *node = new listnode;
node->next = 0;
node->object = object;
if (tail)
{
tail->next = node;
tail = node;
}
else
{
head = tail = node;
}
number++;
}
//*********************************************************************
// void List::Insert(Object *object, int position)
// Add an object to the list.
//
void List::Insert(Object *object, int position)
{
listnode *node = new listnode;
node->next = 0;
node->object = object;
listnode *ln = head;
listnode *prev = 0;
for (int i = 0; i < position && ln; i++, ln = ln->next)
prev = ln;
if (!ln)
{
if (tail)
tail->next = node;
tail = node;
//
// The list is empty. This is a simple case, then.
//
if (!head)
head = node;
}
else
{
if (ln == head)
{
node->next = head;
head = node;
}
else
{
node->next = ln;
prev->next = node;
}
}
cursor.current_index = -1;
number++;
}
//*********************************************************************
// void List::Assign(Object *object, int position)
// Assign a new value to an index.
//
void List::Assign(Object *object, int position)
{
//
// First make sure that there is something there!
//
while (number < position + 1)
{
Add(0);
}
//
// Now find the listnode to put the new object in
//
listnode *temp = head;
for (int i = 0; temp && i < position; i++)
{
temp = temp->next;
}
cursor.current_index = -1;
delete temp->object;
temp->object = object;
}
//*********************************************************************
// int List::Remove(Object *object)
// Remove an object from the list.
//
int List::Remove(Object *object)
{
listnode *node = head;
listnode *prev = 0;
while (node)
{
if (node->object == object)
{
//
// Found it!
//
//
// If we are in the middle of a Get_Next() sequence, we need to
// fix up any problems with the current node.
//
if (cursor.current == node)
{
cursor.current = node->next;
}
if (head == tail)
{
head = tail = 0;
}
else if (head == node)
{
head = head->next;
}
else if (tail == node)
{
tail = prev;
tail->next = 0;
}
else
{
prev->next = node->next;
}
delete node;
number--;
cursor.current_index = -1;
return 1;
}
prev = node;
node = node->next;
}
return 0;
}
//*********************************************************************
//
int List::Remove(int position, int action /* = LIST_REMOVE_DESTROY */)
{
Object *o = List::operator[](position);
if(action == LIST_REMOVE_DESTROY) delete o;
return List::Remove(o);
}
//*********************************************************************
// Object *List::Get_Next()
// Return the next object in the list.
//
Object *List::Get_Next(ListCursor& cursor) const
{
listnode *temp = cursor.current;
if (cursor.current)
{
cursor.prev = cursor.current;
cursor.current = cursor.current->next;
if (cursor.current_index >= 0)
cursor.current_index++;
}
else
return 0;
return temp->object;
}
//*********************************************************************
// Object *List::Get_First()
// Return the first object in the list.
//
Object *List::Get_First()
{
if (head)
return head->object;
else
return 0;
}
//*********************************************************************
// int List::Index(Object *obj)
// Return the index of an object in the list.
//
int List::Index(Object *obj)
{
listnode *temp = head;
int index = 0;
while (temp && temp->object != obj)
{
temp = temp->next;
index++;
}
if (index >= number)
return -1;
else
return index;
}
//*********************************************************************
// Object *List::Next(Object *prev)
// Return the next object in the list. Using this, the list will
// appear as a circular list.
//
Object *List::Next(Object *prev)
{
listnode *node = head;
while (node)
{
if (node->object == prev)
{
node = node->next;
if (!node)
return head->object;
else
return node->object;
}
node = node->next;
}
return 0;
}
//*********************************************************************
// Object *List::Previous(Object *next)
// Return the next object in the list. Using this, the list will
// appear as a circular list.
//
Object *List::Previous(Object *next)
{
listnode *node = head;
listnode *prev = 0;
while (node)
{
if (node->object == next)
{
if (!prev)
return 0;
else
return prev->object;
}
prev = node;
node = node->next;
}
return 0;
}
//*********************************************************************
// Return the nth object in the list.
//
const Object *List::Nth(ListCursor& cursor, int n) const
{
if (n < 0 || n >= number)
return 0;
listnode *temp = head;
if (cursor.current_index == n)
return cursor.current->object;
if (cursor.current && cursor.current_index >= 0 && n == cursor.current_index + 1)
{
cursor.prev = cursor.current;
cursor.current = cursor.current->next;
if (!cursor.current)
{
cursor.current_index = -1;
return 0;
}
cursor.current_index = n;
return cursor.current->object;
}
for (int i = 0; temp && i < n; i++)
{
temp = temp->next;
}
if (temp)
{
cursor.current_index = n;
cursor.current = temp;
return temp->object;
}
else
return 0;
}
//*********************************************************************
// Object *List::Last()
// Return the last object inserted.
//
Object *List::Last()
{
if (tail)
{
return tail->object;
}
return 0;
}
//*********************************************************************
//
Object *List::Pop(int action /* = LIST_REMOVE_DESTROY */)
{
Object *o = 0;
listnode *ln = head;
listnode *prev = 0;
if (tail) {
if(action == LIST_REMOVE_DESTROY) {
delete tail->object;
} else {
o = tail->object;
}
if(head == tail) {
head = tail = 0;
} else {
for (int i = 0; ln != tail; i++, ln = ln->next)
prev = ln;
tail = prev;
tail->next = 0;
}
}
return o;
}
//*********************************************************************
// Object *List::Copy() const
// Return a deep copy of the list.
//
Object *List::Copy() const
{
List *list = new List;
ListCursor cursor;
Start_Get(cursor);
Object *obj;
while ((obj = Get_Next(cursor)))
{
list->Add(obj->Copy());
}
return list;
}
//*********************************************************************
// List &List::operator=(List &list)
// Return a deep copy of the list.
//
List &List::operator=(List &list)
{
Destroy();
list.Start_Get();
Object *obj;
while ((obj = list.Get_Next()))
{
Add(obj->Copy());
}
return *this;
}
//*********************************************************************
// void AppendList(List &list)
// Move contents of other list to the end of this list, and empty the
// other list.
//
void List::AppendList(List &list)
{
// Never mind an empty list or ourselves.
if (list.number == 0 || &list == this)
return;
// Correct our pointers in head and tail.
if (tail)
{
// Link in other list.
tail->next = list.head;
// Update members for added contents.
number += list.number;
tail = list.tail;
}
else
{
head = list.head;
tail = list.tail;
number = list.number;
}
// Clear others members to be an empty list.
list.head = list.tail = 0;
list.cursor.current = 0;
list.cursor.current_index = -1;
list.number = 0;
}