List Handling in SSLIB 

This document covers methods and data members common to the list classes,
PhysExtentList (PEL), LogExtentList (LEL), and DirList (DL).  
In brief, they are:

class <SomeKindaList> {  
// Data Members
  private:    
    allocError_;
  public:     
    RWSlist xlist_;             // public because RW wouldn't compile private

// Methods
  private: 
    copy( thisKindaList, err );
    free();
  public:
    <constructors>              // After calling, call error()
    operator=( thisKindaList ); // After calling, call error()
    error();
    nullPointersError();
    at( i, err );
    append( listEntry, err );   
    concat( xEL, err );         // In PEL and LEL.  Not in DL.
    remove( i, err );           // In PEL and LEL.  Not in DL.
    numExtents();               // In PEL and LEL only.  Compare w/DL::entries()
    entries();                  // In DL only.
    isEmpty();                  // In DL only.
};

DATA MEMBERS -- PRIVATE

+ allocError_

The allocation error is set when a call to operator new() fails.  Note that
some platforms (like ours, g++ on HP-UX) won't trap new() and just abend.
allocError_ is set by the copy constructor and operator=() methods.  Use error()
to get the value of allocError_.


DATA MEMBERS -- PUBLIC

+ xlist_  

Our lists are based on RogueWave's generic singly-linked lists, RWGSlist.  
The underlying list structure is public because 
it had to be to compile and to give
the careful programmer access to the RogueWave Slist methods.  The RW lists
are implemented as a set of pointers to objects in the list.

METHODS -- PRIVATE

+ copy( thisKindaList, err );

copy() makes a deep copy of the list, meaning it allocates space for new 
copies of the objects in the input list and then copies them.  The current
list, *this, is first cleared and then replaced by a copy of the input list.
If copy() errors out, *this will have zero entries.  copy() is called 
by the copy constructor and operator=().  copy() does nothing if you ask
it to copy itself, e.g., (*this).copy(*this, err).  Errors returned include
error_No_free_store if new() fails and error_Null_pointer if the input
list contains a null pointer.  See nullPointersError() for more info on 
this error.

+ free();

free() does a deep delete of the contents of the list.  free() is called by
the destructor and clear().

METHODS -- PUBLIC

+ Constructors

  default constructor.    
    PhysExtentList(); 
    LogExtentList(); 
    DirList();

    You don't really need to check the error() after calling the default
    constructor, since it always sets the allocError_ to error_None.
    It's just an easier rule of thumb to remember always check error() after
    calling the constructor.

  copy constructor.
    PhysExtentList( const PhysExtentList & );
    LogExtentList( const LogExtentList & );
    DirList( const DirList & );

    The copy constructor calls copy( inputList, allocError_ ); and thus sets
    the allocError_ state member.  So call error() afterwards. 

  special constructors for specific lists.
    LEL has one that builds a list from an ADTable, and DL has one that 
    builds a list of one element from a DirEntry.  Since these both allocate
    heap memory, remember to call error() afterwards.

+ operator=()
    Calls copy() and sets allocError_ to the returned error.  Use error()
    after.

+ error()
    Returns the value of allocError_. 

+ nullPointersError()
    The underlying structure of the list is an ordered set of pointers to 
    entry objects.  Our methods assume that there are no null pointers in 
    the list, rather that all pointers in the list point to valid objects. 
    Thus copy() might return an error_Null_pointer.  So might print().
    You can use nullPointersError() to check for this error condition
    separately.  By the way, the only way the list can be corrupt is if
    a programmer deletes one of the RWSlist pointers using operator delete().
    Note that public access to the RWSlist is granted through the class 
    data member xlist_ and through the iterator classes (which directly 
    return the list pointers).

+ at(i, err)
    Returns a pointer to the element in the list at position i.  Similar to 
    operator[i] but allows us to return errors, including 
    error_Index_out_of_bounds and error_Null_pointer.  Indices start at 0.

+ append(listEntry, err)
    Makes a copy of the input argument and appends it to this list.  A list
    entry is the kind of object the list contains, like a PhysExtent, LogExtent,
    or DirEntry.

+ concat(EL, err)   // In PEL and LEL only  
    Concatenates two lists.  That is, it appends the input list onto this list.
    This method exists in PEL and LEL, but not in DL.

+ remove(i, err)    // In PEL and LEL only
    Removes element i from the list.  
    This method exists in PEL and LEL, but not in DL.
    
+ numExtents()      // In PEL and LEL only
  entries()         // In DL only
    Returns the number of entries (i.e., extents or DirEntries) in the list.

+ isEmpty()         // In DL only
    Returns true if the number of entries in the list is zero.
    This method exists in DL only.


ListIterators
   Certain list classes such as DirList, PhysExtentList, and LogExtentList
   have associated list iterators.  These are based on the RogueWave
   RWGSlistIterator.  Iterators are useful when traversing a list, especially
   when you want to maintain more than one traversal pointer.

   An iterator is like a pointer to an item in the list, called the current
   item.  You use methods to return that pointer, advance it, and reset it.  
   You also have various tests to tell you if you are at the start or end 
   of the list.

   Be careful.  When you get a pointer to an item in a list, if you call
   delete on the pointer, you will leave a hole in the list object.  Don't
   do this because we assume in many places that there are no such holes.
   In general, the toolkit list classes either have methods to remove
   contained items or are designed so that you have to destroy them all
   at once.  

The iter classes are: DirListIter, PhysExtentListIter, and LogExtentListIter.
Their methods look like those below, where XListIter is used as a generic form.

// XListIter()
// XListIter( XList )
//      Constructs an iterator.  
//      NOTE:  Initially the current item is undefined.
//      You need to use operator()() or next() to get to the first item.
//      Or use operator++().
// ~XListIter()
//      Destructs the iterator object.
// operator()()
//      Advances the iterator to the next item and returns a pointer to it.  
//      Returns nil if at end of the list.
// next()
//      Advances the iterator to the next item.  Returns FALSE if there
//      is no next item (i.e., at End of List).  Note that this method
//      does not return a pointer to the item.
// operator++()
//      Like next(), advances the iterator but doesn't check for end of list.  
//      Returns void.
// atFirst()
//      Returns TRUE if current item is first element.  Else returns
//      FALSE.  Example:  After 'reset(); next();' atFirst() is True. 
// atLast()
//      Returns TRUE if current item is last element.  
// key()
//      Returns a ptr to the current item.  Returns NULL if at 
//      end of list.  Returns NULL if you use key() right after 
//      the constructor.
// reset()
//      Resets the iterator to its initial state.  
//      NOTE:  You need to use operator()() or next() to get to the first item.

