|
STK++ 1.0
|
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