Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

list.H

Go to the documentation of this file.
00001 /*
00002  * Copyright 2000, Brown University, Providence, RI.
00003  * 
00004  *                         All Rights Reserved
00005  * 
00006  * Permission to use, copy, modify, and distribute this software and its
00007  * documentation for any purpose other than its incorporation into a
00008  * commercial product is hereby granted without fee, provided that the
00009  * above copyright notice appear in all copies and that both that
00010  * copyright notice and this permission notice appear in supporting
00011  * documentation, and that the name of Brown University not be used in
00012  * advertising or publicity pertaining to distribution of the software
00013  * without specific, written prior permission.
00014  * 
00015  * BROWN UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
00016  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
00017  * PARTICULAR PURPOSE.  IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE FOR
00018  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00020  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00021  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  */
00023 #ifndef GLUE_LIST_H
00024 #define GLUE_LIST_H
00025 
00026 #include <stdlib.h>  // for qsort
00027 #include "std/dllimpexp.H"
00028 #include "std/config.H"
00029 #include "std/error.H"
00030 
00031 extern "C" {
00032 typedef int (* compare_func_t) (const void *, const void *);
00033 }
00034 
00035 static const int BAD_IND = -999;
00036 
00037 //----------------------------------------------
00038 //
00039 //  ARRAY:
00040 //      Templated array-based list. It resizes
00041 //  itself as necessary. Constructor lets you
00042 //  specify the expected size.
00043 //
00044 //----------------------------------------------
00045 #define cARRAY const ARRAY
00046 template <class T>
00047 class ARRAY {
00048  protected:
00049    T      *_array;      // pointer to the data
00050    int     _num;        // number of elements in the array
00051    int     _max;        // max elements for currently allocated array
00052    int     _unique;
00053 
00054    // needed by LIST (below -- ARRAY of REFptrs): 
00055    virtual void clear_ele  (int)        {}
00056    virtual void clear_range(int, int)   {}
00057    void  append_ele(const T& el) {
00058          // append element
00059          if (_num == _max) realloc();
00060          _array[_num++] = el;
00061    }
00062 
00063  public:
00064    // ******** MANAGERS ********
00065    ARRAY(int m=0) : _array(0), _num(0), _max(m > 0 ? m : 0), _unique(0) {
00066       if (_max) _array = new T[_max];
00067    }
00068    ARRAY(cARRAY<T>& l) : _array(0), _num(0), _max(0), _unique(0) { *this = l; }
00069    ARRAY(const T &e) : _array(0), _num(0), _max(0), _unique(0) { ARRAY<T> l;
00070                                                                  l += e;
00071                                  *this = l; }
00072    virtual ~ARRAY() { clear(); delete [] _array;}
00073 
00074    // ******** ACCESSORS/CONVENIENCE ********
00075    int          num()              const { return _num; }
00076    bool         empty()            const { return (_num<=0); }
00077    bool         valid_index(int k) const { return (k>=0 && k<_num); }
00078    void         set_unique()             { _unique = 1; }
00079 
00080    const T*     array()            const { return _array; }
00081    T*           array()                  { return _array; }
00082    T&           operator [](int j)       { return _array[j]; }
00083    T&           last()                   { if (empty())
00084                                               err_msg("ARRAY::last-list empty");
00085                                            return _array[_num-1]; }
00086    const T& operator [](int j)     const { return _array[j]; }
00087    const T&           last()       const { if (empty())
00088                                               err_msg("ARRAY::last-list empty");
00089                                            return _array[_num-1]; }
00090 
00091    // ******** MEMORY MANAGEMENT ********
00092 
00093    void clear() { clear_range(0,_num); _num=0; }
00094    virtual void truncate(int n) {
00095       if (valid_index(n)) {
00096          clear_range(n,_num);
00097          _num = n;
00098       } else err_msg("ARRAY::truncate: bad index %d", n);
00099    }
00100 
00101    // realloc() is called automatically as necessary
00102    // when the array runs out of room, or explicitly
00103    // when it's known that the array will shortly need
00104    // to contain a given number of elements. new_max
00105    // tells how large the array should be -- if the
00106    // array is already that large nothing happens.
00107    // otherwise, the array is reallocated and its elements
00108    // are copied to the new array. if new_max == 0, this
00109    // is interpreted as a request that _max should be
00110    // doubled. the exception is when _max is also 0
00111    // (meaning the array itself is null), in which case
00112    // _max is set to 1 and the array is allocated to
00113    // hold a single element.
00114    virtual void realloc(int new_max=0) {
00115        if (new_max && new_max <= _max)
00116           return;
00117        _max = (new_max == 0) ? (_max ? _max*2 : 1) : new_max;
00118        T *tmp = new T [_max];
00119        if (tmp == 0)
00120           err_sys("ARRAY: realloc failed");
00121        for (int i=0; i<_num; i++) {
00122           tmp[i] = _array[i];
00123           clear_ele(i);
00124        }
00125        delete [] _array;
00126        _array = tmp;
00127    }
00128 
00129    // ******** CONTAINMENT ********
00130    int get_index(const T &el) const {
00131       // return index of element
00132       // or BAD_IND if element is not found:
00133       for (int k = _num-1; k >= 0; k--)
00134          if (_array[k] == el)
00135             return k;
00136       return BAD_IND;
00137    }
00138    bool contains(const T &el) const { return get_index(el) != BAD_IND; }
00139 
00140    // ******** ADDING ********
00141    void operator += (const T& el) {
00142       if (_unique)
00143           add_uniquely(el);
00144       else
00145           append_ele(el);
00146    }
00147 
00148    // append (same as +=):
00149    void add (const T& p) { *this += p; }     
00150 
00151    // add to front:
00152    void push(const T& p) {
00153       insert(0,1);
00154       _array[0] = p;
00155    } 
00156    
00157    bool add_uniquely(const T& el) {
00158       // add element only if it isn't already there:
00159       int ret=0;
00160       if (get_index(el) == BAD_IND) {
00161          append_ele(el);
00162          ret = 1;
00163       }
00164       return ret;
00165    }
00166 
00167    // XXX - is this used??
00168    void insert(int ind, int num) {
00169       // open up a gap of uninitialized elements
00170       // in the array, starting at index 'ind',
00171       // extending for 'num' elements.
00172       // 
00173       // presumably these elements then 
00174       // get assigned directly.
00175       if (_num+num >= _max) 
00176          realloc(_max+num);
00177       _num += num;
00178       for (int i = _num-1; i>=ind+num; i--)
00179          _array[i] = _array[i-num];
00180    }
00181 
00182    // ******** REMOVING ********
00183    bool remove(int k) {
00184       // remove element k
00185       // return 1 on success, 0 on failure:
00186       if (valid_index(k)) {
00187          // replace element k with last element and shorten list:
00188          _array[k] = _array[--_num];
00189          clear_ele(_num);
00190          return 1;
00191       } else if (k != BAD_IND) {
00192          err_msg("ARRAY::remove: invalid index %d", k);
00193          return 0;
00194       } else return 0; // assume the call to get_index() failed
00195    }
00196    
00197    // search for given element, remove it:
00198 
00199    void operator -= (cARRAY<T> &l)        { for (int i=0; i < l.num(); i++)
00200                                                *this -= l[i]; }
00201 
00202    bool operator -= (const T &el)         { return remove(get_index(el)); }
00203    bool          rem(const T &p)          { return (*this -= p); }
00204                 
00205    T pop() {
00206       // delete last element in list and return it:
00207       T tmp = last();
00208       remove(_num-1);
00209       return tmp;
00210    }
00211 
00212    // ******** ARRAY OPERATORS ********
00213    ARRAY<T>& operator =(cARRAY<T>& l) {
00214       // assignment operator:
00215       if (&l == this)  // don't do anything if rhs already is lhs
00216          return *this;
00217       clear();
00218       if(!l.empty()) {
00219          realloc(l._num);
00220          for (int i=0; i<l._num; i++)
00221             *this += l[i];
00222       }
00223       return *this;
00224    }
00225    ARRAY<T>& operator +=(cARRAY<T>& l) {
00226       // concatenation operator:
00227       if(!l.empty()) {
00228          realloc(_num + l._num);
00229          for (int i=0; i<l._num; i++)
00230             *this += l[i];
00231       }
00232       return *this;
00233    }
00234    bool operator ==(const ARRAY<T> &c) const {
00235        if (num() != c.num())
00236           return 0;
00237        for (int i = 0; i < num(); i++) {
00238           // Use !(x == y) because == should be available and != may not be
00239           if (!((*this)[i] == c[i]))
00240              return 0;
00241        }
00242        return 1;
00243    }
00244 
00245    // ******** REORDERING ********
00246    void reverse() {
00247       for (int i=0, j=_num-1; i<j; ++i, --j) {
00248          // swap causes potential conflicts, so we do this instead...
00249          T tmp     = _array[i];
00250          _array[i] = _array[j];
00251          _array[j] = tmp;
00252       }
00253    }
00254    virtual void sort(compare_func_t compare) {
00255       qsort(_array, _num, sizeof(T), compare);
00256    }
00257 };
00258 
00259 
00260 
00261 //----------------------------------------------
00262 //
00263 //  LIST:
00264 //
00265 //      same as ARRAY, but assumes the templated
00266 //      type T is derived from a REFptr, and calls
00267 //      Clear() on ref pointers as needed.
00268 //
00269 //----------------------------------------------
00270 #define cLIST const LIST
00271 template <class T>
00272 class LIST : public ARRAY<T> {
00273  protected:
00274    virtual void clear_ele  (int i)          { _array[i].Clear(); }
00275    virtual void clear_range(int i, int j)   { for (int k=i; k < j; k++)
00276                                                  clear_ele(k); }
00277  public:
00278    LIST(int m=0)     : ARRAY<T>(m) {}
00279    LIST(cLIST<T>& l) : ARRAY<T>(l) {}
00280 };
00281 
00282 
00283 
00284 //----------------------------------------------
00285 //
00286 //  OBSlist<OBS>:
00287 //
00288 //      Templated list of observers.  This makes it
00289 //      easy to create a class for a list of a specific
00290 //      type of observer.   Given that list class, 
00291 //      typically, you will create a single global
00292 //      instance that registers all observers and
00293 //      dispatches events to the observers.
00294 //
00295 //----------------------------------------------
00296 template <class OBS>
00297 class OBSlist 
00298 {
00299    protected:
00300       ARRAY<OBS *> _list;
00301    public:
00302       virtual ~OBSlist() {}
00303                OBSlist() : _list(0) {} // Start out with empty list
00304       int  num()             const { return _list.num(); }
00305       void obs(OBS *o)             { _list.add_uniquely(o); }
00306       void obs_first(OBS *o)       { if (_list.empty()) _list.add(o);
00307                                      else {
00308                                        _list.insert(0, 1);
00309                                        _list[0] = o;
00310                                     } }
00311       void unobs(OBS *o)           { _list.rem(o); }
00312 
00313       void notify(const GLUE_TYPENAME OBS::data &d) {
00314                                      for (int i=0; i < _list.num(); i++)
00315                                         _list[i]->notify(d); }
00316      
00317 };
00318 
00319 
00320 template<class T>
00321 ostream &
00322 operator<< (ostream &os, const ARRAY<T> &array)
00323 {
00324    for (int i = 0; i < array.num(); i++)  {
00325        os << array[i];
00326        if (array.num() > 1) os << endl;
00327    }
00328    return os;
00329 }
00330 
00331 template<class T>
00332 istream &
00333 operator>> (istream &is, ARRAY<T> &array)
00334 {
00335    array.clear();
00336    WHITESPACE(is); // skip over extra whitespace
00337    while (!is.eof() && is.peek() != '\0' && is.peek() != '}') {
00338       T x; is >> x; array += x;
00339       WHITESPACE(is); // skip over extra whitespace
00340    }
00341    return is;
00342 }
00343 
00344 #endif  // list.H
00345 
00346 /* end of file list.H.H */

Generated on Mon Sep 15 16:25:56 2003 for gluebase by doxygen1.2.18