/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@falcon.mercer.peachnet.edu
MUD++ development mailing list mudpp-list@spice.com
------------------------------------------------------------------------------
llist.h
*/
#ifndef LLIST_H
#define LLIST_H
template < class T >
class Node
{
public:
Node< T > *next;
T *obj;
Node()
: next(0), obj(0)
{
}
Node( T * x )
: next(0), obj(x)
{
}
~Node()
{
}
};
#define RDONLY 1
template < class T >
class LList
{
private:
Node< T > *head;
Node< T > *current;
unsigned char flags;
public:
LList()
: head(0), current(0), flags(0)
{
}
// Does node by node copy. This is so constructed objects
// that have list data will copy correctly.
LList( const LList & x );
~LList() { destroyList(); }
void destroyList();
// For creating a temp list to iterate with.
const LList & operator = ( const LList & );
// true copy, not read-only like assign operator
void copy( const LList & );
// Of course these members change the state of the object but
// for practical purposes they don't and we need const because
// iterating through a list is common thing to do for a const
// object. For example writing an object and its inventory to a
// file doesn't change object but you must iterate through
// inventory. This would not be required if I implemented LList
// iterators instead of my method off read-only copying of lists.
void next() const;
void reset() const { const_cast< LList * >(this)->current = head; }
void add( T * );
void addTop( T * );
void addAfterCurrent( T * );
void remove( T * );
T *remove();
T *peek() const;
T *peekNext() const;
};
// Does node by node copy. This is so constructed objects
// that have list data will copy correctly. Note that the
// actual object pointers still point to same address.
template < class T >
LList< T >::LList( const LList & x )
: head(0), current(0), flags(0)
{
Node< T > *node = x.head;
while( node )
{
add( node->obj );
node = node->next;
}
}
// Do read-only copy of a list. Items can't be added or removed
// from this list. It is only for iterating, etc. and is written
// specifically for this with the least overhead.
template < class T >
const LList< T > & LList< T >::operator = ( const LList & x )
{
if( &x != this )
{
destroyList();
head = x.head;
current = x.head;
flags |= RDONLY;
}
return *this;
}
template < class T >
void LList< T >::copy( const LList & x )
{
Node< T > *node = x.head;
if( &x != this )
{
destroyList();
while( node )
{
add( node->obj );
node = node->next;
}
}
}
template < class T >
inline void LList< T >::next() const
{
if( current )
{
const_cast< LList< T > * >(this)->current = current->next;
}
}
template < class T >
void LList< T >::destroyList()
{
// Make sure its not a copied list that was used for iterating
// which is just going out of scope.
if( !( flags & RDONLY ) )
{
if( head )
{
if( !current )
current = head;
for( ; head; head = current )
{
current = current->next;
delete head;
}
}
}
else
{
flags &= ~RDONLY; // clear read only bit
head = current = 0;
}
}
template < class T >
void LList< T >::addTop( T * obj )
{
if( !obj )
return;
else if( flags & RDONLY )
return; // need to bug this later
Node< T > *add = new Node< T >( obj );
add->next = head;
head = add;
if( ! current )
current = add;
}
template < class T >
void LList< T >::add( T * obj )
{
if( !obj )
return;
else if( flags & RDONLY )
return; // need to bug this later
Node< T > *add = new Node< T >( obj );
if( !head )
{
head = current = add;
return;
}
add->next = current;
if( head == current )
{
head = add;
current = add;
return;
}
Node< T > *tlast;
for( tlast = head; tlast->next; tlast = tlast->next )
{
if( tlast->next == current )
{
tlast->next = add;
break;
}
}
if( !tlast->next )
tlast->next = add;
current = add;
}
// Add a node after current node, used for sequential building
// of a list mostly.
template < class T >
void LList< T >::addAfterCurrent( T * obj )
{
if( !obj )
return;
else if( flags & RDONLY )
return; // need to bug this later
Node< T > *add = new Node< T >( obj );
if( !head )
{
head = current = add;
return;
}
else if( !current )
current = head;
add->next = current->next;
current->next = add;
}
template < class T >
void LList< T >::remove( T * obj )
{
if( !head )
return;
else if( flags & RDONLY )
return; // need to bug this later
Node< T > *rem;
Node< T > *tlast = 0;
if( head->obj == obj )
{
if( current == head )
current = head->next;
rem = head;
head = head->next;
delete rem;
return;
}
for( rem = head; rem; rem = rem->next )
{
if( rem->obj == obj )
{
if( rem == current )
{
current = current->next;
}
if( tlast )
tlast->next = rem->next;
delete rem;
return;
}
tlast = rem;
}
}
template < class T >
T *LList< T >::remove()
{
if( !head )
return 0;
else if( flags & RDONLY )
return 0; // need to bug this later
Node< T > *tlast;
Node< T > *rem = current;
if( !rem )
return 0;
else if( rem == head )
{
head = head->next;
current = current->next;
}
else
{
for( tlast = head; tlast->next; tlast = tlast->next )
{
if( tlast->next == rem )
{
tlast->next = rem->next;
break;
}
}
}
T *obj = rem->obj;
delete rem;
rem = tlast->next;
return obj;
}
template < class T >
T *LList< T >::peek() const
{
if( !current )
return 0;
return current->obj;
}
template < class T >
T *LList< T >::peekNext() const
{
if( !current || !current->next )
return 0;
return current->next->obj;
}
/* I decided to make LList a container-only class and remove
* code that deleted actual objects that it held as it could
* become buggy. (already caused some) - Fusion
template < class T >
void LList< T >::destroy()
{
if( !current )
return;
Node< T > *tlast;
Node< T > *rem = current;
for( tlast = head; tlast->next; tlast = tlast->next )
{
if( tlast->next == current )
{
tlast->next = current->next;
break;
}
}
delete rem->obj;
delete rem;
}
template < class T >
void LList< T >::destroy( T * obj )
{
if( !head )
return;
Node< T > *rem;
Node< T > *tlast = 0;
if( head->obj == obj )
{
if( current == head )
current = head->next;
rem = head;
head = head->next;
delete rem->obj;
delete rem;
return;
}
for( rem = head; rem; rem = rem->next )
{
if( rem->obj == obj )
{
if( rem == current )
current = current->next;
if( tlast )
tlast->next = rem->next;
delete rem->obj;
delete rem;
return;
}
tlast = rem;
}
}
*/
#endif