/* ....[@@@..[@@@..............[@.................. 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