/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: list2.h,v 1.10.2.4 2000/03/05 04:57:36 justin Exp $
// $Revision: 1.10.2.4 $  $Author: justin $ $Date: 2000/03/05 04:57:36 $

//
//ScryMUD Server Code
//Copyright (C) 1998  Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// To contact the Author, Ben Greear:  greear@cyberhighway.net, (preferred)
//                                     greearb@agcs.com
//

// list.h -- Declarations for the list library

//  This templated list works only on pointers right now, it could, however
//  be changed to include ALL items easily.  There may be a few bugs left,
//  so be careful.  If you have any questions, write me at:  
//  greear@cyberhighway.net
//  Happy coding, Ben Greear


 
#ifndef BEN_List2_Include
#define BEN_List2_Include

#include <stdlib.h> 
#include <iostream.h>
#include <fstream.h>
#include <LogStream.h>
#include <string2.h>

#ifndef TRUE

#define TRUE 1
#define FALSE 0 

#endif

// The list keeps a buffer of cells that are accessing it currently.
// This is used to try to keep the cells in a sane state when a Node
// is removed from the list.  If more than 5 cells are in a list at
// a time, an error message will be thrown, but it still may work.
// I would strongly recomend not doing this if at all possible though!
#define NUMBER_OF_CONCURENT_CELLS 10
 

extern LogStream mudlog;
extern int core_dump(const char* msg); //misc2.cc
extern int __node_cnt;
extern int __list_cnt;
extern int __cell_cnt;

 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




template <class T> class Cell;

template <class T> class List {
protected:
   friend class Cell<T>;
      //
      // Cell is a safe pointer to a list node
   
   class Node {
   public:
      Node *prev;
      Node *next;
      T     item; // Node holds an item of parameterized type T

      Node() : prev(NULL), next(NULL) {
         __node_cnt++;
      }

      Node(const Node& rhs) : prev(rhs.prev), next(rhs.next) {
         item = rhs.item;
         __node_cnt++;
      }//copy constructor

      ~Node() {
         __node_cnt--;
      }
   };//Node

   virtual void handleLosingCell(Cell<T>& cll) {
      for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
         if (cll_list[i] && (cll_list[i]->node == cll.node) &&
            (cll_list[i] != &cll)) {
            cll_list[i]->next(); //increment it through the list.
            // Assume there will always at least be the header node.
         }//if
      }//for
   }//handleLosingCell

   virtual int handleRemoveCell(const Cell<T>& cll) {
      for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
         if (cll_list[i] == &cll) {
            cll_list[i] = NULL;
            return TRUE;
         }//if
      }//for

      mudlog << "List<> ERROR:  could not remove cell: " << (void*)(&cll)
             << " " << toString() << endl;

      //::core_dump("handleRemoveCell");
      return FALSE;
   }//handleRemoveCell      


   virtual int handleAddCell(Cell<T>& cll) {
      for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
         if (cll_list[i] == NULL) {
            cll_list[i] = &cll;
            return TRUE;
         }//if
      }//for
      
      mudlog << "List<> ERROR:  could not add cell: " << (void*)(&cll)
             << " " << toString() << endl;

      //::core_dump("handleAddCell");
      return FALSE;
   }//handleAddCell


   Node *header;
   int sz;
   Cell<T>* cll_list[NUMBER_OF_CONCURENT_CELLS];

public:

   static int getNodeCnt() { return __node_cnt; }
   static int getListCnt() { return __list_cnt; }
   static int getCellCnt() { return __cell_cnt; }

   List(const List<T> &L) : sz(L.sz) { //copy constructor
      //mudlog << "In List<T> copy constructor, (L.this: " << (void*)(&L)
      //       << "): " << L.toString() << "\n" << flush;
      __list_cnt++;

      header = new Node;
      memset(cll_list, 0, NUMBER_OF_CONCURENT_CELLS * sizeof(Cell<T>*));
      
      //for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
      //   cll_list[i] = NULL;
      //}


      if (!header) {
         //log("ERROR:  out of Memory: List2 constructor, exiting!\n");
         exit (101);
      }//if
      else {
         Cell<T> cll(L); 
         T ptr;

         header->item = (T)(NULL);
         header->next = header;
         header->prev = header;
  
         while ((ptr = cll.next())) { 
            append(ptr);
         }//while
      }//else

      //mudlog << "Done with List<T> copy constructor, L: " << L.toString()
      //       << "\n" << flush;
   } // copy constructor


   List(const T &Nil) : sz(0) {
      __list_cnt++;
      header = new Node;

      memset(cll_list, 0, NUMBER_OF_CONCURENT_CELLS * sizeof(Cell<T>*));
      
      //for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
      //   cll_list[i] = NULL;
      //}

      if (!header) { 
         //log("ERROR:  out of mem, list constructor, exiting!\n");
         exit (101);
      }//if
      else {
         header->item = Nil;
         header->next = header;
         header->prev = header;
      }//else

   } // constructor


   List() : sz(0) {
      __list_cnt++;
      header = new Node;

      memset(cll_list, 0, NUMBER_OF_CONCURENT_CELLS * sizeof(Cell<T>*));
      //for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
      //   cll_list[i] = NULL;
      //}

      if (!header) { 
         //log("ERROR:  out of mem, list constructor, exiting!\n");
         exit (101);
      }//if
      else {
         // header->item = (T)(NULL);
          header->item = (T)(0);
         header->next = header;
         header->prev = header;
      }//else

   } // constructor


   // Destructor for List<T> -- Destroy the list, linear
   // DOES NOT delete the items it points too.
   virtual ~List () { 
      __list_cnt--;

      for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
         if (cll_list[i]) {
            cll_list[i]->removeFromLst();
            cll_list[i] = NULL;
         }//if
      }//for

      this->clear();

      delete header;
   } //destructor 

   
   virtual List<T> &operator= (const List &L) {
 
      if (this != &L) { // Don't copy yourself
         this->clear();       
         sz = L.sz;

         Cell<T> cll(L);
         T datum; 

         while ((datum = cll.next())) {
            append(datum);
         }//for
      }//if

      return *this;
   }//assignment operator

                 /* functions */

   /*  CLEAR--   removes every node in a List (except the header node
       of course), DOES NOT delete data pointed to */
   virtual void clear() {
      Cell<T> cll(*this);
      T ptr = cll.next();
      while (ptr) {
         handleLosingCell(cll);
         ptr = cll.lose();
      }//while

      if (!header) {
         mudlog.log(ERROR, "ERROR:  HEADER NULL in Clear.\n");
      }//if
      sz = 0;
   }// clear

   virtual String toString() const {
      String retval(200);
      String tmp(50);

      Sprintf(retval, "this: %p  sz: %i  size: %i cells: ", this, sz, size());
      for (int i = 0; i<NUMBER_OF_CONCURENT_CELLS; i++) {
         Sprintf(tmp, "[%i] %p ", i, cll_list[i]);
         retval.Append(tmp);
      }//for

      return retval;
   }//toString

   /*  LOSEDATA  finds and cuts the node with the specified data in it out 
    *  of the list.  Removes only one instance of the data from the list.
    */
   virtual T loseData (const T& data) {
      Cell<T> cell(*this);
      T ldata;

      if (isEmpty()) {
         return (T)(0);
      }

      Assert((int)data);

      ldata = cell.next();
      while (ldata) {
         if (ldata == data) {
            handleLosingCell(cell);
            cell.lose();  //this WILL NOT delete the item pointed to.
            sz--;
            return ldata;
         }//if
         ldata = cell.next();
      }//while
      return (T)(0);
   }//LoseData

 
   // Substitute_Data //
   /* If it doesn't find the target data, it will insert anyway 
      (at the end).  It returns FALSE if no substitution was made,
      TRUE otherwise.  Does not delete what it replaced. */
   virtual int substituteData(const T& targ, const T& source, int j) {
      Cell<T> cell(*this);
      T ldata;
      int count = 0;

      while ((ldata = cell.next())) { 
         if (ldata == targ) {
            count++;
            if (count == j) {
               cell.node->item = source;
               return TRUE;
            }//if
         }//if
      }//while
      pushBack(source);
      return FALSE; //no substitution
   }//SubstituteData   


   virtual int haveData (const T& data) const {
      Cell<T> cell(*this);
      T ldata;
      
      while ((ldata = cell.next())) {
         if (ldata == data) {
            return TRUE;
         }//if
      }//while
      return FALSE;
   }//HaveData   

   virtual int dataCount(const T& data) const {
      Cell<T> cell(*this);
      T ldata;
      int retval = 0;
      
      while ((ldata = cell.next())) {
         if (ldata == data) {
            retval++;
         }//if
      }
      return retval;
   }//DataCount
 
   virtual void pushFront(const T& data) {
      prepend(data);
   }

   virtual void prepend(const T& data) {
      Cell<T> cell(*this);
      Assert((int)data);
      cell.insertAfter(data);
      sz++;
   }//push
 
   virtual void pushBack(const T& data) {
      append(data);
   }

   virtual void append(const T& data) {
      Cell<T> C(*this);
      Assert((int)data);
      C.insertBefore(data);
      sz++;
   }//put

   virtual void gainData(const T& data) {
      if (!haveData(data)) {
         append(data);
      }//if
   }//GainData

     
   /*  PULL--
       Returns the item contained at the BEGINNING of the list, it
       DOES delete the item from the list.  */
   virtual T popFront() {
      Cell<T> cll(*this);
      T ret = cll.next();
   
      if (ret) {
         handleLosingCell(cll);
         sz--;
         cll.lose();
      }//if
      return ret;
   }//Pull
 
/*  DRAG--
    Returns the item contained at the END of the list, it
    DOES delete the item from the list.  */
   virtual T popBack() {
      Cell<T> cll(*this);
      T ret = cll.prev();
      if (ret) {
         handleLosingCell(cll);
         sz--;
         cll.lose();
      }//if
      return ret;
   }//Drag


   virtual int insertAt(int posn, T& val) {
      Cell<T> cll(*this);
      int i = 0;

      if (!val)
         return FALSE;

      sz++;
      T ptr;
      while ((ptr = cll.next())) {
         if (i == posn) {
            cll.insertBefore(val);
            return TRUE;
         }
         i++;
      }//while
      
      cll.insertBefore(val);
      return TRUE;
   }//insertAt

   virtual T removeAt(int posn) {
      Cell<T> cll(*this);
      int i = 0;

      if (i < 0)
         return (T)(0);

      T ptr;
      while ((ptr = cll.next())) {
         if (i == posn) {
            handleLosingCell(cll);
            cll.lose();
            sz--;
            return ptr;
         }
         i++;
      }//while
      return (T)(0);
   }//removeAt

   virtual T elementAt(int index) const {
      Cell<T> cll(*this);
      int i = 0;

      if (index < 0)
         return (T)(0);

      T ptr;
      while ((ptr = cll.next())) {
         if (i == index) {
            return ptr;
         }
         i++;
      }//while
      return (T)(0);
   }//elementAt

   /*  FRONT--
       Returns the item contained at the BEGINNING of the list, it
       DOES NOT delete the item from the list.  */
   virtual T peekRear() const {
      return header->prev->item; 
   }//

   virtual T peekBack() const {
      return peekRear();
   }//

   virtual T peekFront() const {
      return header->next->item; 
   }//top
 

   /*  HEAD--  Make cll point to the head of the list. */
   virtual void head(Cell<T>& cll) {
      if (cll.isInList(this)) {
         cll.node = header;
      }
      else {
         cll.clear(); //important, removes it from it's previous list.
         cll.node = header;
         cll.in_lst = (List<T>*)(this);
         handleAddCell(cll);
      }//else
   }//head

   virtual int assign(Cell<T>& cll, const T& data) {
      Assert(cll.isInList(this));
      cll.assign(data);
      return TRUE;
   }//Assign

   virtual void insertBefore(Cell<T>& cll, const T& data) {
      Assert(cll.isInList(this));
      sz++;
      cll.insertBefore(data);
   }//insertBefore

   virtual void insertAfter(Cell<T>& cll, const T& data) {
      Assert(cll.isInList(this));
      sz++;
      cll.insertAfter(data);
   }//insertBefore

   virtual T lose(Cell<T>& cll) {
      if (cll.node != header) {
         Assert(cll.isInList(this));
         handleLosingCell(cll);
         sz--;
         return cll.lose();
      }//if
      else {
         mudlog << "ERROR:  Trying to lose header, this: " << this
                << " Cell<T>: " << (void*)(&cll) << endl;
         Assert(0); //Dump core, need to debug this.
         return (T)(0);
      }//else
   }//insertBefore

   virtual int isEmpty() const {
      Assert((int)header);
      return (header->next == header);
   }//IsEmpty

   /*  size--  Returns the number of cells contained in a List.  */
   virtual int size() const {
      class List<T>::Node* node_ptr = header->next;
      int count = 0;
   
      while (node_ptr != header) {
         count++;
         node_ptr = node_ptr->next;
      }//while

      // Leave this in for a while till we're sure it's debugged!!
      if (count != sz) {
         mudlog << "ERROR: sz: " << sz << " does not match calculated size: "
                << count << endl;
      }
      return count;
   }//sz

   virtual int Assert(const int boolean_val) const {
      if (!boolean_val)
         ::core_dump((const char*)("List2.h"));
      return TRUE;
   }

   friend void clear_ptr_list(List<T> &L);  //DOES delete the data
   friend void Put(const T& val, List<T> &L);
   friend T Top(const List<T> &L);
   friend int IsEmpty(const List<T> &L);
   friend int HaveData(const T& val, const List<T>& L);
};

// A few of these are back wards compatable hacks

template <class T> int HaveData(const T& val, const List<T>& L) {
   return L.haveData(val);
}

template <class T> int IsEmpty(const List<T>& L) {
   return L.isEmpty();
}

template <class T> T Top(const List<T>& L) {
   return L.peekFront();
}

//on the end of the list
template <class T> void Put(const T& val, List<T>& L) {
   L.append(val);
}

template <class T> void clear_ptr_list(List<T>& L) {
   while (!L.isEmpty()) {
      delete L.popFront();
   }//while
}//


 
///************************************************************************///
///*************************  Cell  ***************************************///
///************************************************************************///
 
template <class T> class Cell {
private:

   // Before implementing this, think out the case where one cell is in
   // a list, and is coppied.  The list doesn't know of the new cell.
   // This can be fixed if it proves needed. --BEN
   Cell<T>& operator=(const Cell<T>& src);

   // Same issue with this guy.
   Cell (const Cell<T>& src);// :
      //node(src.node), in_lst(src.in_lst) {
      //__cell_cnt++; 
      //in_lst->handleAddCell(*this);
   //}//constructor


protected:
   friend class List<T>;

   List<T>::Node *node;
   List<T>* in_lst;

   virtual void insertBefore (const T& data) {
      Assert((int)node);
      List<T>::Node *N = new List<T>::Node; 
      if (!N) {
         mudlog.log(ERROR, "ERROR, out of Memory trying to allocate a cell.\n");
         exit (101);
      }//if
      N->item = data;
      N->prev = node->prev;
      N->next = node;
      node->prev->next = N;
      node->prev = N;
   }// insert before

   virtual int assign(const T& data) {
      Assert(node && data);
      node->item = data;
      return TRUE;
   }//Assign


   /*  INSTERT_AFTER-- Insert an item into a list after a given cell. */
   virtual void insertAfter(const T& data) {
      Assert((int)node);
      List<T>::Node *N = new List<T>::Node; 
      N->item = data;
      N->prev = node;
      N->next = node->next;
      node->next = N;
      N->next->prev = N;
   }// insert after
 
   /*  LOSE   Deletes a node, sets cell equal to next cell,  
       returns what the new cell contains.  Can only be called by
       List<>, and that takes care of keeping other Cell<> iterators
       cleaned up. */
   virtual T lose() {
      class List<T>::Node* node_ptr = node;    
      
      node->prev->next = node->next;
      node->next->prev = node->prev;
      
      node = node->next;
      if (node_ptr->item)
         delete node_ptr;
      return node->item;
   }// Lose

   virtual void removeFromLst() {
      in_lst = NULL;
   }

public:
   
   // Constructors
   //
   Cell () { node = NULL; __cell_cnt++; in_lst = NULL; }

   Cell (const List<T>& L) : node(L.header) {
      __cell_cnt++;
      in_lst = (List<T>*)(&L);
      in_lst->handleAddCell(*this);
   }//constructor

   virtual ~Cell() {
      __cell_cnt--;
      clear(); //this is important, allows the list to clean *this up.
   }//destructor

   virtual void clear() {
      if (in_lst) {
         in_lst->handleRemoveCell(*this);
         in_lst = NULL;
      }//if
   }

   int Assert(const int boolean_val) const {
      if (!boolean_val) {
         ::core_dump("Cell<T>");
         return FALSE;
      }
      else
         return TRUE;
   }//Assert

   /*  NEXT--  next(cell)  
       This function sets "cell" equal to the next cell in the list and
       returns this cell's item.  */
   T next() {
      node = node->next;
      return node->item;
   }//next

/*  PREV--   prev(cell)  
    This function sets "cell" equal to the previous cell in the list
    and returns the new cell's item.  */
   T prev() {
      node = node->prev;
      return node->item;
   }//prev
 

   /*  ITEM-- returns the data stored in the target cell, the cell
       is NOT changed. */
   T item () const { return node->item; }//item
 
   List<T>* getInList() { return in_lst; }

   int isInList(List<T>* lst) const { return (in_lst == lst); }

};


template <class T> class SortedPtrList : public List<T> {
public:
   SortedPtrList() : List<T>() { }
   SortedPtrList(const List<T> &L) : List<T>(L) { }
   SortedPtrList(const T &Nil) : List<T>(Nil) { }

   void insertSorted(T val) {
      Cell<T> cll(*this);
      T ptr;
      while ((ptr = cll.next())) {
         if (*val < *ptr) {
            insertBefore(cll, val);
            return;
         }//if
      }//while
      insertBefore(cll, val);
   }//insertSorted
};//SortedPtrList


template <class T> class SortedValList : public List<T> {
public:
   SortedValList() : List<T>() { }
   SortedValList(const List<T> &L) : List<T>(L) { }
   SortedValList(const T &Nil) : List<T>(Nil) { }

   void insertSorted(T& val) {
      Cell<T> cll(*this);
      T ptr;
      while ((ptr = cll.next())) {
         if (val < ptr) {
            insertBefore(cll, val);
            return;
         }//if
      }//while
      insertBefore(cll, val);
   }//insertSorted
};//SortedValList


#endif