STK++ 1.0
STK_List1D.h
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------*/
00002 /*     Copyright (C) 2004-2007  Serge Iovleff
00003 
00004     This program is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU Lesser General Public License as
00006     published by the Free Software Foundation; either version 2 of the
00007     License, or (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU Lesser General Public License for more details.
00013 
00014     You should have received a copy of the GNU Lesser General Public
00015     License along with this program; if not, write to the
00016     Free Software Foundation, Inc.,
00017     59 Temple Place,
00018     Suite 330,
00019     Boston, MA 02111-1307
00020     USA
00021 
00022     Contact : Serge.Iovleff@stkpp.org
00023 */
00024 
00025 /*
00026  * Project: stkpp::Arrays
00027  * Purpose:  Define the List1D class.
00028  * Author:   Serge Iovleff, serge.iovleff@stkpp.org
00029  *
00030  **/
00031 
00036 #ifndef STK_LIST_H
00037 #define STK_LIST_H
00038 
00039 #include "../../Sdk/include/STK_ITContainer1D.h"
00040 #include "../../Sdk/include/STK_IContainerRef.h"
00041 #include "../../Arrays/include/STK_Display1D.h"
00042 #include "STK_Cell.h"
00043 
00044 namespace STK
00045 {
00046 
00052 template<class TYPE>
00053 class List1D : public ITContainer1D<TYPE, List1D<TYPE> >
00054              , public IContainerRef
00055 {
00056   protected:
00057     CellHo<TYPE> *p_first_;       
00058     CellHo<TYPE> *p_last_;        
00059 
00060   public:
00064     List1D( Range const& I = Range())
00065           : ITContainer1D<TYPE, List1D>(I)
00066           , IContainerRef(false)
00067     { initialize(I); }
00068 
00073     List1D( Range const& I, TYPE const& v)
00074           : ITContainer1D<TYPE, List1D >(I)
00075           , IContainerRef(false)
00076     { initialize(I);
00077 
00078       CellHo<TYPE>* p1  = p_first_;
00079       for ( Integer j=this->first(); j<=this->last(); j++)
00080       { (*p1) = v;             // overwrite the value of the current cell
00081         p1    = p1->getRight();   // Goto Right place
00082       }
00083     }
00084 
00088     List1D( const List1D<TYPE> &T)
00089           : ITContainer1D<TYPE, List1D>(T)
00090           , IContainerRef(false)
00091     {
00092       // initialize container
00093       initialize(T.range());
00094       // copy the container
00095       CellHo<TYPE>* p1  = p_first_;
00096       CellHo<TYPE>* pt1 = T.p_first_;
00097 
00098       for (Integer j=T.first(); j<=T.last(); j++)
00099       { (*p1) = pt1->data();   // write the value of the current cell
00100         p1    = p1->getRight();   // Goto Right
00101         pt1   = pt1->getRight();  // Goto Right
00102       }
00103     }
00104 
00105   protected:
00115     List1D( CellHo<TYPE>* const & p_first
00116           , CellHo<TYPE>* const & p_last
00117           , Range const& J
00118           )
00119           : ITContainer1D<TYPE, List1D>(J)
00120           , IContainerRef(true)
00121           , p_first_(p_first)
00122           , p_last_(p_last)
00123     {
00124       // Current position
00125       currentPosition_  = this->first();
00126       p_current_ = p_first;
00127     }
00128 
00129   public:
00131     virtual ~List1D() { if (!this->isRef()) freeMem();}
00132 
00137      inline TYPE& elt(Integer const& pos)
00138     {
00139       moveCurr(pos);
00140       return (p_current_->data());
00141     }
00142 
00147     inline TYPE const& elt(Integer const& pos) const
00148     {
00149       moveCurr(pos);
00150       return (p_current_->data());
00151     }
00152 
00157     inline List1D<TYPE> elt(Range const& J) const
00158     {
00159 #ifdef STK_BOUNDS_CHECK
00160       if ((J.first()<this->first()))
00161       { throw out_of_range("List1D::elt(J) "
00162                            "J.first()<this->first()");
00163       }
00164       if ((J.last()>this->last()))
00165       { throw out_of_range("List1D::elt(J) "
00166                            "J.last()>this->last()");
00167       }
00168 #endif
00169       // get J.first() cell adress
00170       moveCurr(J.first());
00171       CellHo<TYPE>* p_first = p_current_;
00172       // get J.last() cell adress
00173       moveCurr(J.last());
00174       CellHo<TYPE>* p_last = p_current_;
00175       // return the reference
00176       return List1D<TYPE>(p_first, p_last, J);
00177     }
00178 
00182     void clear()
00183     {
00184       if (this->isRef()) return;   // Nothing to do for ref
00185       freeMem();        // Free mem
00186       this->setRange(); // Set to default the dimension
00187     }
00188 
00192     void shift(Integer const& beg =1)
00193     {
00194       if (this->first() == beg) return;
00195 #ifdef STK_DEBUG
00196       // is this structure just a pointer?
00197       if (this->isRef())
00198       { throw runtime_error("List1D::shift(pos, n) "
00199                             "can't operate on references.");
00200       }
00201 #endif
00202       //compute increment
00203       Integer inc = beg - this->first();
00204       this->incRange(inc);  // update this->range_()
00205       currentPosition_ += inc;         // update current position
00206     }
00207 
00211     void pushBack(Integer const& n=1)
00212     {
00213       // if n==0 nothing to do
00214       if (n <= 0) return;
00215 #ifdef STK_DEBUG
00216       // is this structure just a pointer?
00217       if (this->isRef())
00218       { throw runtime_error("List1D::pushBack(pos, n) "
00219                             "can't operate on references.");
00220       }
00221 #endif
00222       // If the container is empty : create it
00223       if (this->empty())
00224       {
00225         initialize(Range(this->first(), this->first()+ n -1));
00226       }
00227       else  // else adjust the beginning and the sizes
00228       {
00229         CellHo<TYPE> *p1, *p2;            // Auxiliary cells;
00230         try
00231         { p1 = new CellHo<TYPE>(p_last_);} // Create the end+1 cell
00232         catch (std::bad_alloc & error)   // if an alloc error is catched
00233         { // throw the Exception
00234           throw runtime_error("List1D::pushBack(n) "
00235                               "memory allocation failed.");
00236         }
00237         // if no error is intercepted
00238         p_last_->setRight(p1);             // Set the right ending cell
00239         for (Integer j=2; j<=n; j++)    // main loop for the other cells
00240         { try
00241           { p2 = new CellHo<TYPE>(p1);}  // try to allocate memory
00242           catch (std::bad_alloc & error) // if an alloc error occur
00243           {
00244             while ( p1 != p_last_)         // for all cells allocated
00245             { p2 = p1->getLeft();        // get the cell left
00246               delete p1;                 // delete the curent cell
00247               p1 = p2;                   // iterate
00248             }
00249             // set the original right side of cend
00250             p_last_->setRight(p_first_);
00251             // and throw an Exception
00252             throw runtime_error("List1D::pushBack(n) "
00253                                 "memory allocation failed.");
00254           } // end catch
00255           // if no error is intercepted
00256           p1->setRight(p2);  // Set the right cell of the current cell
00257           p1 = p2;           // Set the current cell to the the next cell
00258         }
00259         p1->setRight(p_first_);    // the last cell point on the first cell
00260         p_first_->setLeft(p1);     // the first cell point on the last cell
00261         p_last_ = p1;             // the last cell adress
00262         this->incLast(n); // Update size of the container
00263       }
00264     }
00265 
00270     void insert( Range const& I, TYPE const& v)
00271     {
00272       insertElt(I.first(), I.size());
00273       for (Integer i=I.first(); i<=I.last(); i++)
00274         elt(i) = v;
00275     }
00276 
00281     void insertElt( Integer const& pos, Integer const& n =1)
00282     {
00283       // if n<=0 nothing to do
00284       if (n <= 0) return;
00285       // is this structure just a pointer?
00286       if (this->isRef())
00287       { throw runtime_error("List1D::insertElt(pos, n) "
00288                                  "can't operate on references.");
00289       }
00290 #ifdef STK_BOUNDS_CHECK
00291       // check indices
00292       if (this->first() > pos)
00293       { throw out_of_range("List1D::insertElt(pos, n) "
00294                                 "this->first() > pos");
00295       }
00296       if (this->last()+1 < pos)
00297       { throw out_of_range("List1D::insertElt(pos, n) "
00298                                 "this->last()+1 < pos");
00299       }
00300 #endif
00301       // Move the current position to j
00302       moveCurr(pos);
00303       CellHo<TYPE> *p0 = p_current_->getLeft(); // Get the j-1 cell
00304       CellHo<TYPE> *p1 = p0;                    // Auxiliary cell;
00305       // main loop for the other cells
00306       for (Integer j1=1; j1<=n; j1++)
00307       {
00308         CellHo<TYPE> *p2;        // Auxiliary cell;
00309         try
00310         { p2 = new CellHo<TYPE>(p1);}  // try to allocate memory
00311         catch (std::bad_alloc & error) // if an alloc error occur
00312         { while ( p1 != p0)            // for all cells allocated
00313           { p2 = p1;                   // get the cell left
00314             delete p1;                 // delete the curent cell
00315             p1 = p2->getLeft();        // iterate
00316           }
00317           p0->setRight(p_current_);
00318           // and throw an Exception
00319           throw runtime_error("List1D::insert(j, n) "
00320                               "memory allocation failed.");
00321         } // catch block
00322         // if no error is intercepted
00323         p1->setRight(p2);  // Set the right cell of the current cell
00324         p1 = p2;           // iterate
00325       }
00326       p1->setRight(p_current_);     // the last cell point on the first cell
00327       p_current_->setLeft(p1);      // the first cell point on the last cell
00328       if ( pos==this->first() )     // if the beginning was modified
00329       { p_first_ = p0->getRight();} // set new beginning
00330       this->incLast(n);             // Update the size of the container
00331       currentPosition_ +=n;         // Update the current position
00332     }
00333 
00337     void popBack(Integer const& n=1)
00338     {
00339       // if n<=0 nothing to do
00340       if (n <= 0) return;
00341       // is this structure just a pointer?
00342       if (this->isRef())
00343       { throw runtime_error("List1D::popBack() "
00344                                  "can't operate on references.");
00345       }
00346 #ifdef STK_BOUNDS_CHECK
00347       // if there is elts to erase
00348       if (this->size()<n)
00349       { throw out_of_range("List1D::popBack(n) "
00350                                 "this->size() < n");
00351       }
00352 #endif
00353       // erase elts with pos = end -n +1
00354       erase(this->last() - n +1, n);
00355     }
00356 
00361     void erase(Integer const& pos, Integer const& n=1)
00362     {
00363       // if n==0 nothing to do
00364       if (n<=0) return;
00365       // is this structure just a pointer?
00366       if (this->isRef())
00367       { throw runtime_error("List1D::erase(pos, n) "
00368                                  "can't operate on references.");
00369       }
00370 #ifdef STK_BOUNDS_CHECK
00371       // check bounds
00372       if (this->first() > pos)
00373       { throw out_of_range("List1D::erase(pos, n) "
00374                            "this->first() > pos");
00375       }
00376       if (this->last() < pos)
00377       { throw out_of_range("List1D::erase(pos, n) "
00378                            "this->last() < pos");
00379       }
00380       if (this->last() < pos+n-1)
00381       { throw out_of_range("List1D::erase(pos, n) "
00382                            "this->last() < pos+n-1");
00383       }
00384 #endif
00385       // Move the current position to pos
00386       moveCurr(pos);
00387       CellHo<TYPE>* p2 = p_current_;  // get pos-th cell
00388       moveCurrLeft();                // set current to (pos-1)th position
00389       // delete n cells
00390       for (Integer l=1; l<=n; l++)
00391       { CellHo<TYPE>* p3 = p2->getRight();  // get right cell in p3
00392         delete p2;                          // delete current cell
00393         p2 = p3;                            // next
00394       }
00395       // If the last column have been erased update p_last_
00396       if (pos+n-1 == this->last()) { p_last_ = p_current_;}
00397       // Update the dimension of the container
00398       this->decLast(n);
00399       // If we have erased all cols
00400       if (this->size() == 0)
00401       { setDefault();}
00402       else
00403       { p2->setLeft(p_current_);        // p2 is the j+n cell
00404         p_current_->setRight(p2);       // p_current_ is on j-1 cell
00405         // If the first column has been erased
00406         if (pos == this->first())
00407         { p_first_  = p2;   // Set the new beg cell
00408           p_current_ = p2;   // p_current_
00409           currentPosition_++;       // and current position
00410         }
00411       }
00412     }
00413 
00418     void swap(Integer const& j1, Integer const& j2)
00419     {
00420 #ifdef STK_BOUNDS_CHECK
00421       if (j1<this->first())
00422       { throw out_of_range("List1D::swap(j1, j2) "
00423                            "j1<this->first()");
00424       }
00425       if (j1>this->last())
00426       { throw out_of_range("List1D::swap(j1, j2) "
00427                            "j1>this->last()");
00428       }
00429       if (j2<this->first())
00430       { throw out_of_range("List1D::swap(j1, j2) "
00431                            "j2<this->first()");
00432       }
00433       if (j2>this->last())
00434       { throw out_of_range("List1D::swap(j1, j2) "
00435                            "j2>this->last()");
00436       }
00437 #endif
00438       // get j1th value in aux
00439       moveCurr(j1);
00440       CellHo<TYPE> *p1 = p_current_;
00441       TYPE aux = p1->data();
00442       // set j2th value in j1th position
00443       moveCurr(j2);
00444       (*p1) = p_current_->data();
00445       // set j2th value to aux
00446       (*p_current_) = aux;
00447     }
00448 
00455      List1D<TYPE>& operator=(const List1D<TYPE> &T)
00456     {
00457       // We have to resize if this and T have not the same size
00458       // but if they have the same size, we don't scale the index
00459       if (this->size()!=T.size()) { this->resize(T.range());}
00460 
00461       /* copy without ovelapping.                                     */
00462       if (this->first() < T.first())
00463       { CellHo<TYPE> *p1 = p_first_, *pt1 = T.p_first_;
00464         for (Integer j=1; j<=this->size(); j++)
00465         { (*p1) = pt1->data();   // overwrite the value
00466           p1    = p1->getRight();   // Goto Right for this
00467           pt1   = pt1->getRight();  // Goto Right for T
00468         }
00469       }
00470       else
00471       { CellHo<TYPE> *p1 = p_last_, *pt1 = T.p_last_;
00472         for (Integer j=this->size(); j>=1; j--)
00473         { (*p1) = pt1->data();   // overwrite the value
00474           p1    = p1->getLeft();    // Goto Left for this
00475           pt1   = pt1->getLeft();   // Goto Left for T
00476         }
00477       }
00478       return *this;
00479     }
00480 
00484     List1D<TYPE>& operator=(TYPE const& v)
00485     {
00486       CellHo<TYPE>* p1 = p_first_;
00487       for (Integer j=1; j<=this->size(); j++)
00488       { p1->setData(v);      // overwrite the value of the current cell
00489         p1    = p1->getRight(); // Goto Right
00490       }
00491       return *this;
00492     }
00493 
00494   protected:
00496     void initialize(Range const& I)
00497     {
00498        // set new dimensions
00499       this->setRange(I);
00500       if (this->empty())
00501       {
00502         setDefault(); return;
00503       }
00504       // Allocate memory for the cells
00505       CellHo<TYPE> *p1, *p2;        // Auxiliary pointer for cells
00506 
00507       p1 = new CellHo<TYPE>();        // pointer on the first cell
00508       p_first_ = p1;                     // set the first cell
00509       // main loop for the other cells
00510       for (Integer j=this->first()+1; j<=this->last(); j++)
00511       { try
00512         { p2 = new CellHo<TYPE>(p1);}        // try to allocate memory
00513         catch (std::bad_alloc & error)       // if an alloc error occur
00514         { while (p1 != (CellHo<TYPE>*)NULL)  // for all cells allocated
00515           { p2 = p1->getLeft();              // get the cell left
00516             delete p1;                       // delete the cell
00517             p1 = p2;                         // and iterate
00518           }
00519           // set default
00520           setDefault();
00521           this->setRange();
00522           // and throw the Exception
00523           throw runtime_error("List1D::initialize(beg, end) "
00524                               "memory allocation failed.");
00525         }
00526         // if no error is catched
00527         p1->setRight(p2);      // Set the right cell
00528         p1 = p2;               // and iterate
00529       }
00530       p_last_ = p1;              // Set the last cell
00531       p_last_->setRight(p_first_);  // the last cell point on the first cell
00532       p_first_->setLeft(p_last_);   // the first cell point on the last cell
00533 
00534       currentPosition_  = this->first();    // current position is first position
00535       p_current_ = p_first_;            // Current cell is first cell
00536     }
00537 
00539     void freeMem()
00540     {
00541       if (this->isRef()) return;   // Nothing to do for ref
00542       CellHo<TYPE> *p2, *p1 =p_first_;   // Auxiliary pointers for cells
00543       // for all cells
00544       for (Integer j=this->first(); j<=this->last(); j++)
00545       { p2 = p1->getRight();               // get the right cell
00546         delete p1;                         // delete the curent cell
00547         p1 = p2;                           // and iterate
00548       }
00549       setDefault();
00550     }
00551 
00554     void setDefault()
00555     { p_first_  = (CellHo<TYPE>*)NULL;
00556       p_last_  = (CellHo<TYPE>*)NULL;
00557       p_current_ = (CellHo<TYPE>*)NULL;
00558       currentPosition_  = this->first();
00559     }
00560 
00561   private:
00565     mutable Integer currentPosition_;
00566 
00570     mutable CellHo<TYPE> *p_current_;
00571 
00581     void moveCurrLeft()  const
00582     {
00583       p_current_ = p_current_->getLeft();
00584       currentPosition_--;
00585     }
00588     void moveCurrRight() const
00589     {
00590       p_current_ = p_current_->getRight();
00591       currentPosition_++;
00592     }
00596     void moveCurr(Integer const& pos) const
00597     {
00598       // if j is greater than the current
00599       if (pos>currentPosition_)
00600       {
00601         if ((pos-currentPosition_) <= (this->last()-pos))    // if j is near the current
00602           for( ;currentPosition_!=pos; ) moveCurrRight(); // move to right
00603         else                                 // else we are near the end
00604           for( currentPosition_ = this->last(), p_current_ = p_last_
00605              ; currentPosition_!=pos
00606              ; )
00607              moveCurrLeft();
00608       }
00609       else  // else j is less than the current
00610       {
00611         if ((currentPosition_-pos) <= (pos-this->first()))  // if j is near the current
00612           for( ;currentPosition_!=pos; ) moveCurrLeft();  // move to left
00613         else                                 // else we are near the beg
00614           for( currentPosition_ = this->first(), p_current_ = p_first_
00615              ; currentPosition_!=pos
00616              ; )
00617              moveCurrRight();
00618       }
00619     }
00620  };
00621 
00626 template<class TYPE>
00627 ostream& operator<<(ostream& s, const List1D<TYPE>& V)
00628 { return out1D(s,V);}
00629 
00630 } // namespace STK
00631 
00632 #endif
00633 // STK_LIST_H