00001 #ifndef CPPTL_DEQUE_H_INCLUDED
00002 # define CPPTL_DEQUE_H_INCLUDED
00003
00004 # include "_stlimpl.h"
00005
00006 namespace CppTL {
00007
00008 struct YesType
00009 {
00010 char dummy[256];
00011 };
00012
00013 struct NoType
00014 {
00015 };
00016
00017 template<class T>
00018 struct IsInteger
00019 {
00020 typedef NoType value_type;
00021 };
00022
00023 #define CPPTL_DECLARE_INTEGER_TYPE( type ) \
00024 template<> struct IsInteger<type> { \
00025 typedef YesType value_type; \
00026 }
00027
00028 CPPTL_DECLARE_INTEGER_TYPE( bool );
00029 CPPTL_DECLARE_INTEGER_TYPE( char );
00030 CPPTL_DECLARE_INTEGER_TYPE( signed char );
00031 CPPTL_DECLARE_INTEGER_TYPE( unsigned char );
00032 CPPTL_DECLARE_INTEGER_TYPE( signed int );
00033 CPPTL_DECLARE_INTEGER_TYPE( unsigned int );
00034 CPPTL_DECLARE_INTEGER_TYPE( signed short);
00035 CPPTL_DECLARE_INTEGER_TYPE( unsigned short );
00036 CPPTL_DECLARE_INTEGER_TYPE( signed long );
00037 CPPTL_DECLARE_INTEGER_TYPE( unsigned long );
00038
00039
00040 class DequeBase
00041 {
00042 public:
00043 typedef unsigned int size_t;
00044 enum { elementPerPage = 32 };
00045
00046 protected:
00047 DequeBase();
00048 ~DequeBase();
00049
00050 void swap( DequeBase &other );
00051 void prependPage( void *newPage );
00052 void appendPage( void *newPage );
00053
00054 void growPageMap( size_t pagesToPrepend, size_t pagesToAppend );
00055
00056 protected:
00057
00058
00059
00060 void **pageMapBuffer_;
00061 void **pageMap_;
00062 size_t pageMapBufferSize_;
00063 size_t usedPages_;
00064
00065
00066
00067 size_t firstPageStartIndex_;
00068 size_t lastPageEndIndex_;
00069
00070 private:
00071 void initialize();
00072 };
00073
00074
00075 class DequeIteratorCommonBase
00076 {
00077 public:
00078 typedef DequeBase::size_t size_t;
00079 typedef int difference_type;
00080 enum { elementPerPage = DequeBase::elementPerPage };
00081
00082 size_t index() const;
00083
00084 protected:
00085 DequeIteratorCommonBase();
00086
00087 DequeIteratorCommonBase( void **pageMapBegin,
00088 void **pageMapEnd,
00089 void **pageMapCurrent,
00090 size_t indexInCurrentPage,
00091 size_t firstPageStartIndex,
00092 size_t lastPageStartIndex );
00093
00094 void increment();
00095
00096 void decrement();
00097
00098 void advance( difference_type n );
00099
00100 difference_type computeDistance( const DequeIteratorCommonBase &other ) const;
00101
00102 inline bool isEqual( const DequeIteratorCommonBase &other ) const
00103 {
00104 return indexInCurrentPage_ == other.indexInCurrentPage_ &&
00105 pageMapCurrent_ == other.pageMapCurrent_;
00106 }
00107
00108 inline bool isLess( const DequeIteratorCommonBase &other ) const
00109 {
00110 return pageMapCurrent_ < other.pageMapCurrent_
00111 || (pageMapCurrent_ == other.pageMapCurrent_ &&
00112 indexInCurrentPage_ < other.indexInCurrentPage_ );
00113 }
00114
00115 protected:
00116 void **pageMapBegin_;
00117 void **pageMapEnd_;
00118 void **pageMapCurrent_;
00119 size_t indexInCurrentPage_;
00120 size_t firstPageStartIndex_;
00121 size_t lastPageStartIndex_;
00122 };
00123
00124
00125 template<class T>
00126 class DequeIteratorBase : public DequeIteratorCommonBase
00127 {
00128 public:
00129 typedef DequeBase::size_t size_t;
00130 typedef int difference_type;
00131 enum { elementPerPage = DequeBase::elementPerPage };
00132
00133 inline T **currentPage() const
00134 {
00135 return pageMapCurrent_;
00136 }
00137
00138 inline size_t indexInCurrentPage() const
00139 {
00140 return indexInCurrentPage_;
00141 }
00142
00143 bool operator ==( const DequeIteratorBase &other ) const
00144 {
00145 return isEqual( other );
00146 }
00147
00148 bool operator !=( const DequeIteratorBase &other ) const
00149 {
00150 return !isEqual( other );
00151 }
00152
00153 bool operator <( const DequeIteratorBase &other ) const
00154 {
00155 return isLess( other );
00156 }
00157
00158 bool operator <=( const DequeIteratorBase &other ) const
00159 {
00160 return !other.isLess( *this );
00161 }
00162
00163 bool operator >=( const DequeIteratorBase &other ) const
00164 {
00165 return !isLess( other );
00166 }
00167
00168 bool operator >( const DequeIteratorBase &other ) const
00169 {
00170 return other.isLess( *this );
00171 }
00172
00173 protected:
00174 DequeIteratorBase()
00175 {
00176 }
00177
00178 DequeIteratorBase( void **pageMapBegin,
00179 void **pageMapEnd,
00180 void **pageMapCurrent,
00181 size_t indexInCurrentPage,
00182 size_t firstPageStartIndex,
00183 size_t lastPageStartIndex )
00184 : DequeIteratorCommonBase( pageMapBegin, pageMapEnd,
00185 pageMapCurrent, indexInCurrentPage,
00186 firstPageStartIndex, lastPageStartIndex )
00187 {
00188 }
00189
00190
00191 T &deref() const
00192 {
00193 CPPTL_ASSERT_MESSAGE( pageMapCurrent_ != pageMapEnd_
00194 || indexInCurrentPage_ != lastPageStartIndex_,
00195 "DequeIterator: dereferencing invalid iterator" );
00196 return (*pageMapCurrent_)[indexInCurrentPage];
00197 }
00198 };
00199
00200
00201 template<class T, class Traits>
00202 class DequeIterator : public DequeIteratorBase<T>
00203 {
00204 public:
00205 typedef DequeBase::size_t size_t;
00206 typedef int difference_type;
00207 typedef T value_type;
00208 typedef CPPTL_TYPENAME Traits::reference reference;
00209 typedef CPPTL_TYPENAME Traits::pointer pointer;
00210
00211 typedef DequeIterator<T,Traits> SelfType;
00212 typedef DequeIteratorBase<T> SuperClass;
00213 typedef DequeIterator< T, ::CppTL::Impl::ConstIteratorTraits<T> > ConstDequeIterator;
00214 typedef DequeIterator< T, ::CppTL::Impl::NonConstIteratorTraits<T> > NonConstDequeIterator;
00215
00216 DequeIterator()
00217 {
00218 }
00219
00220
00221
00222 DequeIterator( const NonConstDequeIterator &other )
00223 : DequeIteratorBase<T>( other )
00224 {
00225 }
00226
00227 DequeIterator( void **pageMapBegin,
00228 void **pageMapEnd,
00229 void **pageMapCurrent,
00230 size_t indexInCurrentPage,
00231 size_t firstPageStartIndex,
00232 size_t lastPageStartIndex )
00233 : SuperClass( pageMapBegin, pageMapEnd,
00234 pageMapCurrent, indexInCurrentPage,
00235 firstPageStartIndex, lastPageStartIndex )
00236 {
00237 }
00238
00239 SelfType &operator++()
00240 {
00241 increment();
00242 return *this;
00243 }
00244
00245 SelfType &operator++( int )
00246 {
00247 SelfType temp( *this );
00248 ++*this;
00249 return temp;
00250 }
00251
00252 SelfType &operator--()
00253 {
00254 decrement();
00255 return *this;
00256 }
00257
00258 SelfType &operator--( int )
00259 {
00260 SelfType temp( *this );
00261 --*this;
00262 return temp;
00263 }
00264
00265 SelfType &operator +=( difference_type n )
00266 {
00267 advance( n );
00268 return *this;
00269 }
00270
00271 SelfType operator +( difference_type n ) const
00272 {
00273 SelfType temp( *this );
00274 return temp += n;
00275 }
00276
00277 SelfType &operator -=( difference_type n )
00278 {
00279 advance( -n );
00280 return *this;
00281 }
00282
00283 SelfType operator -( difference_type n ) const
00284 {
00285 SelfType temp( *this );
00286 return temp -= n;
00287 }
00288
00289 reference operator[]( difference_type n ) const
00290 {
00291 return *( *this + n );
00292 }
00293
00294 reference operator *() const
00295 {
00296 return deref();
00297 }
00298
00299 reference operator->() const
00300 {
00301 return deref();
00302 }
00303
00304 difference_type operator -( const SelfType &other ) const
00305 {
00306 return computeDistance( other );
00307 }
00308 };
00309
00310
00311 template<class T>
00312 class Deque : public DequeBase
00313 {
00314 public:
00315 typedef T value_type;
00316 typedef T *pointer;
00317 typedef const T *const_pointer;
00318 typedef T &reference;
00319 typedef const T &const_reference;
00320 typedef unsigned int size_t;
00321 typedef DequeIterator< T, ::CppTL::Impl::NonConstIteratorTraits<T> > iterator;
00322 typedef DequeIterator< T, ::CppTL::Impl::ConstIteratorTraits<T> > const_iterator;
00323 typedef Deque<T> SelfType;
00324
00325 Deque()
00326 {
00327 }
00328
00329 Deque( size_t count )
00330 {
00331 insert( begin(), count, T() );
00332 }
00333
00334 Deque( size_t count, const T &value )
00335 {
00336 insert( begin(), count, value );
00337 }
00338
00339 Deque( const_iterator first, const_iterator last )
00340 {
00341 insert( begin(), first, last );
00342 }
00343
00344 ~Deque()
00345 {
00346 if ( pageMap_ && usedPages_ > 0 )
00347 {
00348 ::CppTL::Impl::destruct_range( begin(), end() );
00349 void **pageMapEnd = pageMap_ + usedPages_;
00350 for ( void **pageMap = pageMap_; pageMap != pageMapEnd; ++pageMap )
00351 freePage( *pageMap );
00352 }
00353 }
00354
00355 size_t size() const
00356 {
00357 return (usedPages_+1) * elementPerPage - firstPageStartIndex_ - lastPageEndIndex_;
00358 }
00359
00360 bool empty() const
00361 {
00362 return usedPages_ == 0
00363 || ( usedPages_ == 1 && firstPageStartIndex_ == lastPageEndIndex_ );
00364 }
00365
00366 void push_front( const T &element )
00367 {
00368
00369 if ( usedPages_ == 0 || firstPageStartIndex_ == 0 )
00370 {
00371 T *newPage = allocatePage()
00372 CPPTL_TRY_BEGIN
00373 {
00374 prependPage( newPage );
00375 }
00376 CPPTL_TRY_END_CLEANUP( releasePage( newPage ) )
00377 firstPageStartIndex_ = elementPerPage;
00378 if ( usedPages_ == 1 )
00379 lastPageEndIndex_ = elementPerPage;
00380 }
00381 T *newElement = page(0) + firstPageStartIndex_ - 1;
00382
00383
00384 new (newElement)( element );
00385 --firstPageStartIndex_;
00386 }
00387
00388 void push_back( const T &element )
00389 {
00390
00391 if ( usedPages_ == 0 || lastPageEndIndex_ == elementPerPage )
00392 {
00393 T *newPage = allocatePage()
00394 CPPTL_TRY_BEGIN
00395 {
00396 appendPage( newPage );
00397 }
00398 CPPTL_TRY_END_CLEANUP( releasePage( newPage ) )
00399 lastPageEndIndex_ = 0;
00400 }
00401 T *newElement = page(usedPages_-1) + lastPageEndIndex_;
00402
00403
00404 new (newElement)( element );
00405 ++lastPageEndIndex_;
00406 }
00407
00408 void swap( SelfType &other )
00409 {
00410 DequeBase::swap( other );
00411 }
00412
00413 void pop_front()
00414 {
00415 CPPTL_ASSERT_MESSAGE( !empty(), "Deque<T>::pop_front(): logic error, deque is empty" );
00416 normalizeFirstPageStartIndex();
00417 T *newElement = page(0) + firstPageStartIndex_;
00418 newElement->~T();
00419 ++firstPageStartIndex_;
00420 }
00421
00422 void pop_back()
00423 {
00424 CPPTL_ASSERT_MESSAGE( !empty(), "Deque<T>::pop_back(): logic error, deque is empty" );
00425 normalizeLastPageEndIndex();
00426 T *newElement = page(usedPages_ - 1) + lastPageEndIndex_ - 1;
00427 newElement->~T();
00428 --lastPageEndIndex_;
00429 }
00430
00431 void resize( size_t newSize )
00432 {
00433 size_t oldSize = size();
00434 if ( newSize < oldSize )
00435 {
00436 usedPages_ = 0;
00437 lastPageEndIndex_ = firstPageStartIndex_;
00438 }
00439 else if ( newSize > oldSize )
00440 {
00441 insert( end(), newSize-oldSize, T() );
00442 }
00443 }
00444
00445 T &back()
00446 {
00447 CPPTL_ASSERT_MESSAGE( !empty(), "Deque<T>::back(): logic error, deque is empty" );
00448 normalizeLastPageEndIndex();
00449 return page(usedPages_)[lastPageEndIndex_];
00450 }
00451
00452 T &front()
00453 {
00454 CPPTL_ASSERT_MESSAGE( !empty(), "Deque<T>::front(): logic error, deque is empty" );
00455 normalizeFirstPageStartIndex();
00456 return page(0)[firstPageStartIndex_];
00457 }
00458
00459 T &at( size_t index )
00460 {
00461 CPPTL_ASSERT_MESSAGE( index < size(), "Deque<T>::at(): logic error, bad index" );
00462 index += firstPageStartIndex_;
00463 indexInPage = index % elementPerPage;
00464 return pageMap_[index/elementPerPage][indexInPage];
00465 }
00466
00467 T &operator[]( size_t index )
00468 {
00469 return at( index );
00470 }
00471
00472 const T &back() const
00473 {
00474 return const_cast<SelfType *>(this)->back();
00475 }
00476
00477 const T &front() const
00478 {
00479 return const_cast<SelfType *>(this)->front();
00480 }
00481
00482 const T &at( size_t index ) const
00483 {
00484 return const_cast<SelfType *>(this)->at(index);
00485 }
00486
00487 const T &operator[]( size_t index ) const
00488 {
00489 return const_cast<SelfType *>(this)->at(index);
00490 }
00491
00492 void clear()
00493 {
00494 Deque empty;
00495 swap( empty );
00496 }
00497
00498 iterator begin()
00499 {
00500 return iterator( pageMap_, pageMap_ + usedPages_,
00501 pageMap_, firstPageStartIndex_,
00502 firstPageStartIndex_, lastPageEndIndex_ );
00503 }
00504
00505 iterator end()
00506 {
00507 T **lastPage = usedPages_ ? pageMap_ + usedPages_ - 1 : pageMap_;
00508 return iterator( pageMap_, pageMap_ + usedPages_,
00509 lastPage, lastPageEndIndex_,
00510 firstPageStartIndex_, lastPageEndIndex_ );
00511 }
00512
00513 const_iterator begin() const
00514 {
00515 return const_iterator( pageMap_, pageMap_ + usedPages_,
00516 pageMap_, firstPageStartIndex_,
00517 firstPageStartIndex_, lastPageEndIndex_ );
00518 }
00519
00520 const_iterator end() const
00521 {
00522 T **lastPage = usedPages_ ? pageMap_ + usedPages_ - 1 : pageMap_;
00523 return const_iterator( pageMap_, pageMap_ + usedPages_,
00524 lastPage, lastPageEndIndex_,
00525 firstPageStartIndex_, lastPageEndIndex_ );
00526 }
00527
00528 iterator erase( iterator where )
00529 {
00530 size_t index = where.index();
00531 size_t currentSize = size();
00532 CPPTL_ASSERT_MESSAGE( index < currentSize, "Deque<T>::erase(): invalid iterator" );
00533 if ( index < currentSize / 2 )
00534 {
00535 ::CppTL::Impl::copy_backwards( begin(), where-1, where );
00536 pop_front();
00537 }
00538 else
00539 {
00540 ::CppTL::Impl::cpptl_copy( where+1, end(), where );
00541 pop_back();
00542 }
00543 }
00544
00545 iterator erase( iterator first, iterator last )
00546 {
00547 size_t indexFirst = first.index();
00548 size_t indexLast = last.index();
00549 size_t currentSize = size();
00550 size_t afterErasedRange = size - indexLast;
00551 CPPTL_ASSERT_MESSAGE( index < currentSize, "Deque<T>::erase(): invalid iterator" );
00552 if ( indexFirst < afterErasedRange )
00553 {
00554 iterator beginIt = begin();
00555 ::CppTL::Impl::copy_backwards( beginIt, first, last );
00556 ::CppTL::Impl::destruct_range( beginIt, last - indexFirst );
00557 usedPages_ -= lastErasedIt.currentPage() - beginIt.currentPage();
00558 lastPageEndIndex_ = lastErasedIt.indexInCurrentPage();
00559 }
00560 else
00561 {
00562 iterator endIt = end();
00563 ::CppTL::Impl::cpptl_copy( last, endIt, first );
00564 ::CppTL::Impl::destruct_range( first + afterErasedRange, endIt );
00565 usedPages_ -= endIt.currentPage() - beginErasedRange.currentPage();
00566 lastPageEndIndex_ = beginErasedRange.indexInCurrentPage();
00567 }
00568 }
00569
00570 iterator insert( iterator where, const value_type &value )
00571 {
00572 size_t index = where.index();
00573 size_t currentSize = size();
00574 CPPTL_ASSERT_MESSAGE( index < currentSize, "Deque<T>::erase(): invalid iterator" );
00575 if ( index < currentSize / 2 )
00576 {
00577 reserveAtFront( 1 );
00578 iterator itBegin = begin();
00579 iterator itWhere = itBegin + index;
00580 ::CppTL::Impl::copy_and_destroy( itWhere, itWhere+1, itBegin );
00581 new (&*itWhere)( value );
00582 }
00583 else
00584 {
00585 reserveAtEnd( 1 );
00586 iterator itWhere = begin() + index;
00587 iterator itEnd = end();
00588 ::CppTL::Impl::copy_backwards_and_destroy( itWhere+1, itEnd-1, itEnd );
00589 new (&*itWhere)( value );
00590 }
00591 }
00592
00593 iterator insert( iterator where, size_t count, const value_type &value )
00594 {
00595 size_t count = last - first;
00596 size_t currentSize = size();
00597 size_t whereIndex = where.index();
00598 size_t elementAfter = currentSize - whereIndex;
00599 if ( whereIndex < elementAfter )
00600 {
00601 reserveAtFront( count );
00602 iterator itBegin = begin();
00603 ::CppTL::Impl::copy_and_destroy( itBegin + count, itBegin + (count+whereIndex),
00604 itBegin );
00605 ::CppTL::Impl::copy_with_construct_value( itBegin + index, count, value );
00606 }
00607 else
00608 {
00609 reserveAtEnd( count );
00610 iterator itNewWhere = begin() + whereIndex;
00611 iterator itOldEnd = itNewWhere + ( currentSize - whereIndex );
00612 ::CppTL::Impl::copy_backwards_and_destroy( itNewWhere, itOldEnd, itEnd );
00613 ::CppTL::Impl::copy_with_construct_value( itNewWhere , count, value );
00614 }
00615 CPPTL_ASSERT_MESSAGE( size() == currentSize + count, "Deque<T>::insert: internal logic error." );
00616 }
00617
00618 iterator insert( iterator where, const_iterator first, const_iterator last )
00619 {
00620 size_t count = last - first;
00621 size_t currentSize = size();
00622 size_t whereIndex = where.index();
00623 size_t elementAfter = currentSize - whereIndex;
00624 if ( whereIndex < elementAfter )
00625 {
00626 reserveAtFront( count );
00627 iterator itBegin = begin();
00628 ::CppTL::Impl::copy_and_destroy( itBegin + count, itBegin + (count+whereIndex),
00629 itBegin );
00630 ::CppTL::Impl::copy_with_construct( first, last, itBegin + index );
00631 }
00632 else
00633 {
00634 reserveAtEnd( count );
00635 iterator itNewWhere = begin() + whereIndex;
00636 iterator itOldEnd = itNewWhere + ( currentSize - whereIndex );
00637 ::CppTL::Impl::copy_backwards_and_destroy( itNewWhere, itOldEnd, itEnd );
00638 ::CppTL::Impl::copy_with_construct( first, last, itNewWhere );
00639 }
00640 CPPTL_ASSERT_MESSAGE( size() == currentSize + count, "Deque<T>::insert: internal logic error." );
00641 }
00642
00643 private:
00644 T **page( size_t index )
00645 {
00646 CPPTL_ASSERT_MESSAGE( index <= usedPages_, "Deque<T>::page(): invalid parameter" );
00647 return static_cast<T **>( pageMap_ + index );
00648 }
00649
00652 void reserveAtFront( size_t count )
00653 {
00654 if ( count <= firstPageStartIndex_ )
00655 {
00656 firstPageStartIndex_ -= count;
00657 }
00658 else
00659 {
00660 size_t newPageCount = (count - firstPageStartIndex_ + elementPerPage - 1) / elementPerPage;
00661 firstPageStartIndex_ = (firstPageStartIndex_ - count) % elementPerPage + elementPerPage;
00662 while ( --newPageCount >= 0 )
00663 {
00664 T *newPage = allocatePage()
00665 CPPTL_TRY_BEGIN
00666 {
00667 prependPage( newPage );
00668 }
00669 CPPTL_TRY_END_CLEANUP( releasePage( newPage ) )
00670 }
00671 }
00672 }
00673
00674 void reserverAtEnd( size_t count )
00675 {
00676 size_t remainingInLastPage = elementPerPage - lastPageEndIndex_;
00677 if ( count <= remainingInLastPage )
00678 {
00679 lastPageEndIndex_ += count;
00680 }
00681 else
00682 {
00683 size_t newPageCount = (count - remainingInLastPage + elementPerPage - 1) / elementPerPage;
00684 lastPageEndIndex_ = (lastPageEndIndex_ - count ) % elementPerPage + elementPerPage;
00685 while ( --newPageCount >= 0 )
00686 {
00687 T *newPage = allocatePage()
00688 CPPTL_TRY_BEGIN
00689 {
00690 appendPage( newPage );
00691 }
00692 CPPTL_TRY_END_CLEANUP( releasePage( newPage ) )
00693 }
00694 }
00695 }
00696
00697 inline void normalizeFirstPageStartIndex()
00698 {
00699 if ( firstPageStartIndex_ == elementPerPage )
00700 {
00701 CPPTL_ASSERT_MESSAGE( usedPages_ > 0, "Deque<T>::normalizeFirstPageStartIndex(): internal logic error." );
00702 ++pageMap_;
00703 --usedPages_;
00704 firstPageStartIndex_ = 0;
00705 }
00706 }
00707
00708 inline void normalizeLastPageEndIndex()
00709 {
00710 if ( lastPageEndIndex_ == 0 )
00711 {
00712 CPPTL_ASSERT_MESSAGE( usedPages_ > 0, "Deque<T>::normalizeLastPageEndIndex(): internal logic error." );
00713 --usedPages_;
00714 lastPageEndIndex_ = elementPerPage;
00715 }
00716 }
00717
00718 T *allocatePage()
00719 {
00720 return static_cast<T *>( malloc( sizeof(T) * elementPerPage ) );
00721 }
00722
00723 void freePage( T *page )
00724 {
00725 free( page );
00726 }
00727 };
00728
00729
00730
00731 }
00732
00733 #endif // CPPTL_DEQUE_H_INCLUDED