www.pudn.com > ReadingPeopleTracker-1.28.rar > List.h


/////////////////////////////////////////////////////////////////////////////////////////
//                                                                                     //
//  List.h                                                                             //
//                                                                                     //
//   A container class implementing a general (2-way) linked list of some type         //
//                                                                                     //
//   HISTORY: used to be ingeniously defined by amb using preprocessor directives      //
//            to avoid template problems of early template implementations in C++      //
//            compilers                                                                //
//                                                                                     //
//   template implementation by nts on Sat Nov 10 18:49:37 GMT 2001 from amb's list.h  //
//                                                                                     //
//   NB: our compiler does not support the `export' keyword fully yet so all code,     //
//        both interface and implementation, are contained in this .h file,            //
//                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////

#ifndef __LIST_H__
#define __LIST_H__

#include 
#include 

using namespace std;


namespace ReadingPeopleTracker
{

/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////    Interface   /////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////

//  List      used to be  list(type)  eg Profilelist
//  ListNode  used to be  item(type)  eg Profileitem

// the keyword 'export' is not implemented in GCC 2.95.x and will be ignored
template 
class ListNode   // used to be  class item(type)
{
public:
    type *dat;
    ListNode *prev;
    ListNode *next;
    
    ListNode ()
	{
	    bool this_is_recommended = false;
	    assert (this_is_recommended == true);  // do not use ListNode's copy constructor
	}
    
    ListNode (type *d, ListNode *p = NULL, ListNode *n = NULL)
	{
	    dat = d;
	    prev = p;
	    next = n;
	}
};

// the keyword 'export' is not implemented in GCC 2.95.x and will be ignored
template 
class List
{
public:
    ListNode *first;
    ListNode *last;
    unsigned int no_items;
    ListNode *current;
    
    List()
	{
	    first = last = current = NULL;
	    no_items = 0;
	}
    
    ~List()
	{
	    destroy_all();
	}
    
    List &operator= (List &original);
    List *duplicate();
    
    type *operator[](const unsigned int i) const;
    ListNode *find(type *item) const;
    
    type *add(type *new_item);
    type *add_a_copy(type *new_item);
    type *add()  { return add (new type); }
    
    void concat(List *l2);
    
    type *remove(ListNode *item);
    type *remove(type *item )  { return remove (find(item)); }
    type *remove(unsigned int i)  { return remove ((*this)[i]); }
    type *pop()  { return remove(last); }
    
    void destroy(ListNode *item);
    void destroy(type *item ) { destroy (find(item)); }
    void destroy(unsigned int i) { destroy ((*this)[i]); }
    
    void insert_before(ListNode *item, type *datum);
    void insert_at(unsigned int i, type *datum)
	{ insert_before((*this)[i], datum); }
    void insert_before(type *item, type *datum)
	{ insert_before(find(item), datum); }
    
    void delete_all();
    void destroy_all();
    
    void close();
    void open();
    
    ListNode *start()  { return current = first; }
    ListNode *forward()  { return current = current->next; }
    ListNode *back()  { return current = current->prev; }
    bool current_ok()  { return current != NULL; }
    
    type *get_current()  { return current->dat; }
    type *get_first()  { return first->dat; }
    type *get_last()  { return last->dat; }
    
    type *to_vector();
};

template 
ostream &operator<<(ostream &out_strm, const List &l);

template 
istream &operator>>(istream &in_strm, List &l);



/////////////////////////////////////////////////////////////////////////////////
//////////////////////////////    Implementation   //////////////////////////////
/////////////////////////////////////////////////////////////////////////////////


template 
List &List::operator= (List &original)
{
    destroy_all();  // make room for data
    
    ListNode *curr;
    
    for (curr = original.first; curr != NULL; curr = curr->next)
    {
	add_a_copy(curr->dat);
    }

    assert(no_items == original.no_items);
    
    current = NULL;

    return *this;
}


template 
List *List::duplicate()
{
    List *list_copy = new List;
    ListNode *curr;

    for (curr = first; curr != NULL; curr = curr->next)
	list_copy->add_a_copy(curr->dat);

    return list_copy;
}

template 
type *List::operator[] (const unsigned int i) const
{
    assert (i < no_items);

    unsigned int count;

    ListNode *curr = first;
    
    for (count = 0; count < i; count++)
	curr = curr->next;

    return curr->dat;
}

template 
ListNode *List::find(type *item_dat) const
{
    ListNode *curr = first;

    while ((curr != NULL) && (curr->dat != item_dat))
	curr = curr->next;

    return curr;
}

template 
type *List::add(type *new_item_dat)
{
    ListNode *new_item;
    if (no_items == 0)
    {
	assert (first == NULL);
	assert (last == NULL);
	new_item = new ListNode (new_item_dat, NULL, NULL);
	first = last = new_item;
	no_items = 1;
    }
    else
    {
	new_item = new ListNode (new_item_dat, last, NULL);
	last->next = new_item;
	no_items++;
	last = new_item;
    }
    return new_item->dat;
}

template 
type *List::add_a_copy(type *new_item_dat)
{
    type *copy_item_dat = new type;
    *copy_item_dat = *new_item_dat;
    return add(copy_item_dat);
}

template 
void List::concat(List *l2)
{
    if (no_items == 0)
    {
	assert(first == NULL);

	if (l2->no_items > 0)
	{
	    first = l2->first;
	    last = l2->last;
	    no_items = l2->no_items;
	}
	else
	    assert(l2->first == NULL);
    }
    else
    {
	assert(last->next == NULL);  // fails if close() was called or list error
    
	if (l2->no_items > 0)
	{
	    last->next = l2->first;
	    l2->first->prev = last;
	    last = l2->last;
	    no_items += l2->no_items;
	}
	else
	    assert(l2->first == NULL);
    }
    
    l2->first = l2->last = NULL;  // remove data from l2 list
    l2->no_items = 0;
}


template 
type *List::remove(ListNode *item)
{
    if (item == NULL)
	return NULL;

    type *rdat = item->dat;  // keep a pointer to return it

    if (no_items == 1)
    {
	assert (first == last);
	assert (item == first);
	
	delete item;
	first = last = current = NULL;
	no_items = 0;
	return rdat;
    }
    
    if (item->prev != NULL)
    {
	assert (item != first);
	item->prev->next = item->next;
    }
    
    if (item->next != NULL)
    {
	assert (item != last);
	item->next->prev = item->prev;
    } 

    if (item == first)
	first = item->next;

    if (item == last)
	last = item->prev;

    delete item;
    no_items--;
    return rdat;
}

template 
void List::destroy(ListNode *item)
{
    // let remove(...) remove and delete the item, keeping item->dat
    type *rdat = remove(item);  // keep a pointer to the data item->dat

    if (rdat != NULL)
	delete rdat;
}

template 
void List::insert_before(ListNode *item, type *datum)
{
    ListNode *new_item = new ListNode (datum, item->prev, item);
    if (item->prev != NULL) item->prev->next = new_item;
    if (item == first) first = new_item;
    item->prev = new_item;
    no_items++;
}

template 
void List::delete_all()
{
    while (no_items > 0)
	remove(last);

    first = last = current = NULL;
}

template 
void List::destroy_all()
{
    while (no_items > 0)
	destroy(last);

    first = last = current = NULL;
}

template 
void List::close()
{
    if (no_items > 0)
    {
	last->next = first;
	first->prev = last;
    }
}

template 
void List::open()
{
    if (no_items > 0)
    {
	last->next = first->prev = NULL;
    }
}

template 
type *List::to_vector()
{
    type *res = new type[no_items];
    ListNode *curr = first;

    for (unsigned int j = 0; j < no_items; j++)
    {
	res[j] = *(curr->dat);
	curr = curr->next;
    }

    return res;
}

template 
ostream &operator<<(ostream &out_strm, List &l)
{
    ListNode *curr = l.first;
    out_strm << "list_length = " << l.no_items << "\n";
    for (unsigned int j = 0; j < l.no_items; j++)
    {
	out_strm << (*(curr->dat)) << endl;
	curr = curr->next;
    }
    return out_strm;
}

template 
istream &operator>>(istream &in_strm, List &l)
{
    l.destroy_all();  // make room for data

    unsigned int nitems;
    char dummy [256];
    strcpy(dummy,"dummy");
    while ((in_strm.eof() == false) &&
	   ((strlen(dummy) == 0) ||
	    (strncmp(dummy, "list_length",12) != 0))) in_strm >> dummy;

    if (in_strm.eof() == false)
    {
	in_strm.ignore(256, '=');
	in_strm >> nitems;
	type *newdata;
	for (unsigned int j = 0; j < nitems; j++)
	{
	    newdata = new type;
	    in_strm >> (*newdata);
	    l.add(newdata);
	}
    }
    else
    {
	l.first = l.last = NULL;
	l.no_items = 0;
    }
    return in_strm;
}

} // namespace ReadingPeopleTracker

#endif