STK++ 1.0
STK_IArray2DBase.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 Interface for the Array classes.
00028  * Author:   Serge Iovleff, serge.iovleff@stkpp.org
00029  *
00030  **/
00031 
00041 #ifndef STK_IARRAY2DBASE_H
00042 #define STK_IARRAY2DBASE_H
00043 
00044 #include "../../Sdk/include/STK_ITContainer2D.h"
00045 
00046 #include "STK_AllocatorBase.h"
00047 #include "STK_Array1D.h"
00048 
00049 namespace STK
00050 {
00074 template < class TYPE
00075          , class PTRCOL
00076          , class TArray2D
00077          >
00078 class IArray2DBase : public ITContainer2D< TYPE, TArray2D>
00079                    , public AllocatorBase<PTRCOL>
00080 {
00081   protected:
00085   Array1D<Integer> capacityCols_;
00086 
00089   Array1D<Range> rangeCols_;
00090 
00091   public:
00093     typedef AllocatorBase<PTRCOL> _AllocatorBaseType_;
00094 
00096     typedef ITContainer2D<TYPE, TArray2D> _ITContainer2DType;
00097 
00098   protected:
00103     IArray2DBase( Range const& I = Range(), Range const& J = Range())
00104                 : _ITContainer2DType(I, J)
00105                 , _AllocatorBaseType_()
00106                 , capacityCols_()
00107                 , rangeCols_()
00108                 , capacityHo_(0)
00109     { mallocHo(J);}
00110 
00117     IArray2DBase( const IArray2DBase& T, bool ref =false)
00118                 : _ITContainer2DType(T)
00119                 , _AllocatorBaseType_(T, ref)
00120                 , capacityCols_(T.capacityCols_)
00121                 , rangeCols_(T.rangeCols_)
00122                 , capacityHo_(T.capacityHo_)
00123     {
00124       if (!ref)
00125         mallocHo(T.rangeHo());
00126     }
00127 
00133     IArray2DBase( const IArray2DBase& T, Range const& I, Range const& J)
00134                 : _ITContainer2DType(I, J)
00135                 , _AllocatorBaseType_(T, true)
00136                 , capacityCols_(J)
00137                 , rangeCols_(J)
00138                 , capacityHo_(T.capacityHo_)
00139     {
00140 #ifdef STK_BOUNDS_CHECK
00141       if (I.first() < T.firstRow())
00142       { throw out_of_range("IArray2DBase::IArray2DBase(T, I, J) "
00143                            "I.first() < T.firstRow()");
00144       }
00145       if (I.last() > T.lastRow())
00146       { throw out_of_range("IArray2DBase::IArray2DBase(T, I, J) "
00147                            "I.last() > T.lastRow()");
00148       }
00149       if (J.first() < T.firstCol())
00150       { throw out_of_range("IArray2DBase::IArray2DBase(T, I, J) "
00151                            "J.first() < T.firstCol()");
00152       }
00153       if (J.last() > T.lastCol())
00154       { throw out_of_range("IArray2DBase::IArray2DBase(T, I, J) "
00155                            "J.last() > T.lastCol()");
00156       }
00157 #endif
00158       // adjust capacity and range of each Cols
00159       for (Integer j=J.first(); j<=J.last(); j++)
00160       {
00161         // copy capacity of the column j (is it necessary ?)
00162         capacityCols_[j] = T.capacityCols_[j];
00163         // compute available range of the column j
00164         rangeCols_[j] = Range::inf(I, T.rangeCols_[j]);
00165       }
00166     }
00167 
00173     IArray2DBase( PTRCOL* q, Range const& I, Range const& J)
00174                 : _ITContainer2DType(I, J)
00175                 , _AllocatorBaseType_(q, J)
00176                 , capacityCols_(J, I.size())
00177                 , rangeCols_(J, I)
00178                 , capacityHo_(0)
00179     { ;}
00180 
00181   public:
00185     virtual ~IArray2DBase()
00186     { ;}
00187 
00191     inline Integer const& capacityHo() const
00192     { return capacityHo_;}
00193 
00197     inline const Array1D<Integer> & capacityCols() const
00198     { return capacityCols_;}
00199 
00203     inline Integer const& capacityCol(Integer const& col) const
00204     { return capacityCols_[col];}
00205 
00208     inline Array1D<Range> const& rangeCols() const
00209     { return rangeCols_;}
00210 
00214     inline Range const& rangeCol(Integer const& col) const
00215     { return rangeCols_[col];}
00216 
00220     void shiftHo(Integer const& cbeg =1)
00221     {
00222       // compute increment
00223       Integer cinc = cbeg - this->firstCol();
00224       // if there is something to do
00225       if (cinc != 0)
00226       {
00227         // is this structure just a pointer?
00228         if (this->isRef())
00229         { throw runtime_error("IArray2DBase::shiftHo(cbeg) "
00230                                    "can't operate on references.");
00231         }
00232         // translate rangeHo_
00233         this->incRangeHo(cinc);
00234         // translate data
00235         this->shiftPtrData(cbeg);
00236         // tranlate capacityCols_
00237         capacityCols_.shift(cbeg);
00238         // translate rangeCols_
00239         rangeCols_.shift(cbeg);
00240       }
00241     }
00242 
00247     void swapCols(Integer const& pos1, Integer const& pos2)
00248     {
00249 #ifdef STK_BOUNDS_CHECK
00250       if (this->firstCol() > pos1)
00251       { throw out_of_range("IArray2D::swapCols(pos1, pos2) "
00252                            "this->firstCol() >pos1");
00253       }
00254       if (this->lastCol() < pos1)
00255       { throw out_of_range("IArray2D::swapCols(pos1, pos2) "
00256                            "this->lastCol() <pos1");
00257       }
00258       if (this->firstCol() > pos2)
00259       { throw out_of_range("IArray2D::swapCols(pos1, pos2) "
00260                            "this->firstCol() >pos2");
00261       }
00262       if (this->lastCol() < pos2)
00263       { throw out_of_range("IArray2D::swapCols(pos1, pos2) "
00264                            "this->lastCol() <pos2");
00265       }
00266 #endif
00267       // swap
00268       PTRCOL qaux(this->data(pos1));
00269       this->setData(pos1, this->data(pos2));
00270       this->setData(pos2, qaux);
00271       // update capacityCols_
00272       STK::swap(capacityCols_[pos1],  capacityCols_[pos2]);
00273       // update rangeCols_
00274       STK::swap(rangeCols_[pos1],  rangeCols_[pos2]);
00275     }
00276 
00280     void swap(IArray2DBase &T)
00281     {
00282       // swap AllocatorBase part
00283       this->AllocatorBase<PTRCOL>::swap(T);
00284 
00285       // swap ITContainer2D part
00286       this->_ITContainer2DType::swap(T);
00287 
00288       // swap IArray2DBase part
00289       STK::swap(this->capacityHo_, T.capacityHo_);
00290       capacityCols_.swap(T.capacityCols_);
00291       rangeCols_.swap(T.rangeCols_);
00292     }
00293 
00302     void pushBackByTransfer(IArray2DBase const& T)
00303     {
00304       // is this structure just a pointer?
00305       if (this->isRef())
00306       { throw runtime_error("In IArray2DBase::pushBackByTransfer(T) "
00307                                  "(*this) is a reference.");
00308       }
00309       // is T just a pointer?
00310       if (T.isRef())
00311       { throw runtime_error("In IArray2DBase::pushBackByTransfer(T) "
00312                                  "T is a reference.");
00313       }
00314       // if there is no columns, we can safely modify the vertical range
00315       if (this->sizeHo() <= 0)
00316         this->setRangeVe(T.rangeVe());
00317       // Are ranges corrects ?
00318       if (this->rangeVe() != T.rangeVe())
00319       { throw runtime_error("In IArray2DBase::pushBackByTransfer(T) "
00320                                  "this->rangeVe() != T.rangeVe().");
00321       }
00322       // break const reference
00323       IArray2DBase& Tref = const_cast<IArray2DBase&>(T);
00324       // compute horizontal range of the container after insertion
00325       Range rangeHo(this->rangeHo());
00326       // compute first index of the first column added
00327       const Integer first = rangeHo.last() + 1;
00328       // reallocate memory
00329       rangeHo.incLast(Tref.sizeHo());
00330       reallocHo(rangeHo);
00331       this->setRangeHo(rangeHo);
00332       // align T range
00333       const Integer last = rangeHo.last();
00334       Tref.shiftHo(first);
00335       // copy data from T
00336       for (Integer j=first; j<= last; j++)
00337       {
00338         copyColumn(Tref, j, j);
00339       }
00340       // release memory allocated for the columns
00341       Tref.freePtrData();
00342       Tref.setPtrData(this->ptrData(), this->rangeData());
00343       Tref.setRef(true);
00344     }
00345 
00346   protected:
00351     inline void setCapacityHo(Integer const& capacity = 0)
00352     { capacityHo_ = capacity;}
00353 
00362     void copyColumn( IArray2DBase const& T, Integer const& pos1, Integer const& pos2)
00363     {
00364       // copy column pos2 of T in pos1 of this
00365       this->setData(pos1, T.data(pos2));
00366       // set capacityCols_
00367       capacityCols_[pos1] = T.capacityCols_[pos2];
00368       // set rangeCols_
00369       rangeCols_[pos1] = T.rangeCols_[pos2];
00370     }
00371 
00381     void transferColumn( IArray2DBase& T, Integer const& pos1, Integer const& pos2)
00382     {
00383       // copy column pos2 of T in pos1 of this
00384       this->setData(pos1, T.data(pos2));
00385       // set capacityCols_
00386       capacityCols_[pos1] = T.capacityCols_[pos2];
00387       // set rangeCols_
00388       rangeCols_[pos1] = T.rangeCols_[pos2];
00389       // set column of T to default
00390       T.setDefaultCol(pos2);
00391     }
00392 
00399     void mallocHo(Range const& J)
00400     {
00401       // compute the size necessary (can be 0)
00402       Integer size = this->evalCapacity(J.size());
00403       // try to allocate memory
00404       try
00405       {
00406         // initialize this->capacityCols_
00407         capacityCols_.resize(J);
00408         // initialize this->rangeCols_
00409         rangeCols_.resize(J);
00410         // allocate memory for the columns
00411         this->mallocPtrData(size, J.first());
00412       }
00413       catch (runtime_error & error)   // if an error occur
00414       {
00415         // set default capacity (0)
00416         setCapacityHo();
00417         // set default range
00418         this->setRangeHo();
00419         // clear this->capacityCols_
00420         capacityCols_.clear();
00421         // clear this->rangeCols_
00422         rangeCols_.clear();
00423         // throw the error
00424         throw error;
00425       }
00426       // set new capacity if no error occur
00427       this->setCapacityHo(size);
00428     }
00429 
00436     void reallocHo(Range const& J)
00437     {
00438       // compute the size necessary (can be 0)
00439       Integer size = this->evalCapacity(J.size());
00440       // try to allocate memory
00441       try
00442       {
00443         // allocate memory for the columns
00444         this->reallocPtrData(size, J.first());
00445         // initialize this->capacityCols_
00446         capacityCols_.resize(J);
00447         // initialize this->rangeCols_
00448         rangeCols_.resize(J);
00449       }
00450       catch (runtime_error & error)   // if an error occur
00451       {
00452         // set default capacity (0)
00453         this->setCapacityHo();
00454         // set default range
00455         this->setRangeHo();
00456         // clear this->capacityCols_
00457         this->capacityCols_.clear();
00458         // clear this->rangeCols_
00459         this->rangeCols_.clear();
00460         // throw the error
00461         throw error;
00462       }
00463       // set new capacity if no error occur
00464       this->setCapacityHo(size);
00465     }
00466 
00473     void freeHo()
00474     {
00475       // Nothing to do for reference
00476       if (this->isRef()) return;
00477       // free memory allocated in AllocatorBase
00478       this->freePtrData();
00479       // set capacity size to default
00480       this->setCapacityHo();
00481       // set range of the Cols to default
00482       this->setRangeHo(Range(this->firstCol(), this->firstCol()-1));
00483       // set capacityCols_ to default
00484       capacityCols_.clear();
00485       // set rangeCols_ to default
00486       rangeCols_.clear();
00487     }
00488 
00489   private:
00493     Integer capacityHo_;
00494 
00500     inline void setDefaultCol(Integer const& pos)
00501     {
00502       // set column of T to default
00503       this->setData(pos, (PTRCOL)NULL);
00504       // set capacityCols_
00505       this->capacityCols_[pos] = 0;
00506       // set rangeCols_
00507       this->rangeCols_[pos] = Range();
00508     }
00509 };
00510 
00511 } // namespace STK
00512 
00513 #endif
00514 // STK_IARRAY2DBASE_H