CppUnit project page CppUnit home page

smallmap.h

Go to the documentation of this file.
00001 #ifndef CPPTL_VECTOR_H_INCLUDED
00002 # define CPPTL_VECTOR_H_INCLUDED
00003 
00004 # include "_stlimpl.h"
00005 
00006 // Notes: exception handling is bugged:
00007 // In case where an exception is thrown by a copy constructor while copying a range,
00008 // All destructors are not called correctly.
00009 
00010 
00011 namespace CppTL {
00012 
00013 template<class Item>
00014 class SmallMapBase
00015 {
00016 public:
00017    typedef unsigned int size_t;
00018 
00019    SmallMapBase()
00020       : data_( 0 )
00021       , size_( 0 )
00022       , capacity_( 0 )
00023    {
00024    }
00025 
00026    SmallMapBase( Item *data, size_t size, size_t capacity )
00027       : data_( data )
00028       , size_( size )
00029       , capacity_( capacity )
00030    {
00031    }
00032 
00033    Item *data_;
00034    size_t size_;
00035    size_t capacity_;
00036 };
00037 
00038 
00039 template<class T>
00040 class SmallMapIteratorBase
00041 {
00042 public:
00043    typedef unsigned int size_t;
00044    typedef int difference_type;
00045    typedef SmallMapIteratorBase<T> SelfType;
00046    typedef T Item;
00047 
00048    size_t index() const
00049    {
00050       CPPTL_ASSERT_MESSAGE( map_ != 0, "SmallMapIterator::index(): invalid iterator" );
00051       return current_ - map_->data_;
00052    }
00053 
00054    bool operator ==( const SelfType &other ) const
00055    {
00056       return isEqual( other );
00057    }
00058 
00059    bool operator !=( const SelfType &other ) const
00060    {
00061       return !isEqual( other );
00062    }
00063 
00064    bool operator <( const SelfType &other ) const
00065    {
00066       return isLess( other );
00067    }
00068 
00069    bool operator <=( const SelfType &other ) const
00070    {
00071       return !other.isLess( *this );
00072    }
00073 
00074    bool operator >=( const SelfType &other ) const
00075    {
00076       return !isLess( other );
00077    }
00078 
00079    bool operator >( const SelfType &other ) const
00080    {
00081       return other.isLess( *this );
00082    }
00083 
00084 protected:
00085    SmallMapIteratorBase()
00086       : map_( 0 )
00087       , current_( 0 )
00088    {
00089    }
00090 
00091    SmallMapIteratorBase( const SmallMapBase<Item> &map,
00092                          Item *current )
00093       : map_( &map )
00094       , current_( current )
00095    {
00096    }
00097 
00098 
00099    T &deref() const
00100    {
00101       CPPTL_ASSERT_MESSAGE( current_ != 0,
00102                             "SmallMapIterator: dereferencing invalid iterator" );
00103       return *current_;
00104    }
00105 
00106    void increment()
00107    {
00108       CPPTL_ASSERT_MESSAGE( map_  &&  ( current_ < map_->data_ + map_->size_ ), 
00109                            "SmallMapIterator::increment: incrementing beyond end" );
00110       ++current_;
00111    }
00112 
00113    void decrement()
00114    {
00115       CPPTL_ASSERT_MESSAGE( map_  &&  ( current_ > map_->data_ ), 
00116                            "SmallMapIterator::decrement: decrementing beyond beginning" );
00117       --current_;
00118    }
00119 
00120    void advance( difference_type n )
00121    {
00122       if ( n != 0 )
00123       {
00124          CPPTL_ASSERT_MESSAGE( map_  &&  map_->size_  &&
00125                               ( current_+n <= map_->data_ + map_->size_  &&  current_+n >= map_->data_), 
00126                               "SmallMapIterator::advance: advancing beyond end or beginning" );
00127          current_ += n;
00128       }
00129    }
00130 
00131    difference_type computeDistance( const SelfType &other ) const
00132    {
00133       CPPTL_ASSERT_MESSAGE( map_->data_ == other.map_->data_, "Comparing iterator on different container." );
00134       return current_ - other.current_;
00135    }
00136 
00137    bool isEqual( const SmallMapIteratorBase &other ) const
00138    {
00139       return current_ == other.current_;
00140    }
00141 
00142    bool isLess( const SmallMapIteratorBase &other ) const
00143    {
00144       return current_ < other.current_;
00145    }
00146 
00147 protected:
00148    const SmallMapBase<Item> *map_;
00149    Item *current_;
00150 };
00151 
00152 
00153 
00154 
00155 template<class T, class Traits>
00156 class SmallMapIterator : public SmallMapIteratorBase<T>
00157 {
00158 public:
00159    typedef unsigned int size_t;
00160    typedef int difference_type;
00161    typedef T value_type;
00162    typedef CPPTL_TYPENAME Traits::reference reference;
00163    typedef CPPTL_TYPENAME Traits::pointer pointer;
00164 
00165    typedef SmallMapIterator<T,Traits> SelfType;
00166    typedef SmallMapIteratorBase<T> SuperClass;
00167    typedef SmallMapIterator< T, ::CppTL::Impl::NonConstIteratorTraits<T> > NonConstSmallMapIterator;
00168 
00169    SmallMapIterator()
00170    {
00171    }
00172 
00173    // This constructor ensure that it is possible to construct a
00174    // const iterator from a non const iterator.
00175    SmallMapIterator( const NonConstSmallMapIterator &other )
00176       : SuperClass( other )
00177    {
00178    }
00179 
00180    SmallMapIterator( const SmallMapBase<T> &map, T *current )
00181       : SuperClass( map, current )
00182    {
00183    }
00184 
00185    SmallMapIterator( const SmallMapBase<T> &map, size_t currentIndex )
00186       : SuperClass( map, map.data_ + currentIndex )
00187    {
00188    }
00189 
00190    SelfType &operator++()
00191    {
00192       this->increment();
00193       return *this;
00194    }
00195 
00196    SelfType operator++( int )
00197    {
00198       SelfType temp( *this );
00199       ++*this;
00200       return temp;
00201    }
00202 
00203    SelfType &operator--()
00204    {
00205       this->decrement();
00206       return *this;
00207    }
00208 
00209    SelfType operator--( int )
00210    {
00211       SelfType temp( *this );
00212       --*this;
00213       return temp;
00214    }
00215 
00216    SelfType &operator +=( difference_type n )
00217    {
00218       this->advance( n );
00219       return *this;
00220    }
00221 
00222    SelfType operator +( difference_type n ) const
00223    {
00224       SelfType temp( *this );
00225       return temp += n;
00226    }
00227 
00228    SelfType &operator -=( difference_type n )
00229    {
00230       this->advance( -n );
00231       return *this;
00232    }
00233 
00234    SelfType operator -( difference_type n ) const
00235    {
00236       SelfType temp( *this );
00237       return temp -= n;
00238    }
00239 
00240    reference operator[]( difference_type n ) const
00241    {
00242       return *( *this + n );
00243    }
00244 
00245    reference operator *() const
00246    {
00247       return this->deref();
00248    }
00249 
00250    pointer operator->() const
00251    {
00252       return &(this->deref());
00253    }
00254 
00255    difference_type operator -( const SelfType &other ) const
00256    {
00257       return computeDistance( other );
00258    }
00259 };
00260 
00261 
00262 
00264 template< class Key
00265         , class Value
00266         , class PredLess = CppTL::LessPred<Key>
00267         , class Allocator = CppTL::MallocAllocator< Pair<Key,Value> > >
00268 class SmallMap : private SmallMapBase< Pair<Key,Value> >
00269 {
00270 public:
00271    typedef Pair<Key,Value> Item;
00272 
00273    typedef Item value_type;
00274    typedef Key key_type;
00275    typedef Value mapped_type;
00276    typedef SmallMapIterator<Item, ::CppTL::Impl::NonConstIteratorTraits<Item> > iterator;
00277    typedef SmallMapIterator<Item, ::CppTL::Impl::ConstIteratorTraits<Item> > const_iterator;
00278    typedef SmallMap<Key, Value, PredLess, Allocator> SelfType;
00279    typedef SmallMapBase< Pair<Key,Value> > SuperClass;
00280 
00281    SmallMap()
00282    {
00283    }
00284 
00285    SmallMap( const SmallMap &other )
00286       : SuperClass( 0, other.size_, other.size_ )
00287       , allocator_( other.allocator_ )
00288    {
00289       this->data_ = allocator_.allocateArray( this->size_ );
00290       CPPTL_TRY_BEGIN
00291       {
00292          ::CppTL::Impl::copy_with_construct( other.begin(), other.end(), this->data_ );
00293       }
00294       CPPTL_TRY_END_CLEANUP( allocator.releaseArray( this->data_, this->size_ ) )
00295    }
00296 
00297    ~SmallMap()
00298    {
00299    }
00300 
00301    SelfType &operator =( const SmallMap &other )
00302    {
00303       SelfType temp( other );
00304       swap( temp );
00305       return *this;
00306    }
00307 
00308    size_t size() const
00309    {
00310       return this->size_;
00311    }
00312 
00313    const_iterator find( const Key &key ) const
00314    {
00315       Item *found = lookUp( key );
00316       if ( found )
00317          return const_iterator( *this, found );
00318       return end();
00319    }
00320 
00321    iterator find( const Key &key )
00322    {
00323       Item *found = lookUp( key );
00324       if ( found )
00325          return iterator( *this, found );
00326       return end();
00327    }
00328 
00329    iterator lower_bound( const Key &key )
00330    {
00331       size_t index = insertionIndex( key, 0 );
00332       return iterator( *this, index );
00333    }
00334 
00335    iterator upper_bound( const Key &key )
00336    {
00337       size_t index = insertionIndex( key, 0 );
00338       return iterator( *this, index );
00339    }
00340 
00341    Pair<iterator,iterator> equal_range( const Key &key )
00342    {
00343       size_t index = insertionIndex( key, 0 );
00344       iterator it( *this, index );
00345       return Pair<iterator,iterator>( it, it );
00346    }
00347 
00348    const_iterator lower_bound( const Key &key ) const
00349    {
00350       size_t index = insertionIndex( key, 0 );
00351       return const_iterator( *this, index );
00352    }
00353 
00354    const_iterator upper_bound( const Key &key ) const
00355    {
00356       size_t index = insertionIndex( key, 0 );
00357       return const_iterator( *this, index );
00358    }
00359 
00360    Pair<const_iterator,const_iterator> equal_range( const Key &key ) const
00361    {
00362       size_t index = insertionIndex( key, 0 );
00363       const_iterator it( *this, index );
00364       return Pair<const_iterator,const_iterator>( it, it );
00365    }
00366 
00367    void clear()
00368    {
00369       SelfType temp;
00370       swap( temp );
00371    }
00372 
00373    iterator begin()
00374    {
00375       return iterator( *this, this->data_ );
00376    }
00377 
00378    iterator end()
00379    {
00380       return iterator( *this, this->size_ );
00381    }
00382 
00383    const_iterator begin() const
00384    {
00385       return const_iterator( *this, this->data_ );
00386    }
00387 
00388    const_iterator end() const
00389    {
00390       return const_iterator( *this, this->size_ );
00391    }
00392 
00393    size_t count( const Key &key ) const
00394    {
00395       return lookUp( key ) ? 1 : 0;
00396    }
00397 
00398    bool empty() const
00399    {
00400       return this->size_ == 0;
00401    }
00402 
00403    // equal_range
00404 
00405    iterator erase( iterator where )
00406    {
00407       CPPTL_ASSERT_MESSAGE( where >= begin()  &&  where < end(), "SmallMap<T>::erase(): invalid iterator" );
00408       ::CppTL::Impl::copy_and_destroy( where+1, end(), where );
00409       --(this->size_);
00410       return where;
00411    }
00412 
00413    iterator erase( iterator first, iterator last )
00414    {
00415       size_t whereIndex = first.index();
00416       size_t count = last - first;
00417       ::CppTL::Impl::copy_and_destroy( last, end(), first );
00418       this->size_ -= count;
00419       return iterator( *this, whereIndex );
00420    }
00421 
00422    iterator erase( const Key &key )
00423    {
00424       Item *found = lookUp( key );
00425       if ( found )
00426          return erase( iterator( *this, found ) );
00427       return end();
00428    }
00429 
00430    Value &operator[]( const Key &key )
00431    {
00432       typedef Pair<iterator,bool> ResultType;
00433       size_t whereIndex = insertionIndex( key, 0 );
00434       if ( whereIndex < this->size_
00435            &&  !less_( key, this->data_[whereIndex].first ) )
00436       {
00437          return this->data_[whereIndex].second;
00438       }
00439       return doInsert( whereIndex, Item( key, Value() ) )->second;
00440    }
00441 
00442    Pair<iterator,bool> insert( const Item &item )
00443    {
00444       typedef Pair<iterator,bool> ResultType;
00445       size_t whereIndex = insertionIndex( item.first, 0 );
00446       if ( whereIndex < this->size_
00447            &&  !less_( item.first, this->data_[whereIndex].first ) )
00448       {
00449          return ResultType( iterator( *this, whereIndex ), false );
00450       }
00451       return ResultType( doInsert( whereIndex, item ), true );
00452    }
00453 
00454    iterator insert( iterator where, const Item &item )
00455    {
00456       size_t whereIndex = insertionIndex( item.first, where.index() );
00457       if ( this->size_ == this->capacity_ )
00458       {
00459          if ( reserve( 1, whereIndex, &item ) )  // element was inserted when increasing capacity.
00460             return iterator( *this, whereIndex );
00461       }
00462       ++(this->size_);
00463       iterator itWhere( *this, whereIndex );
00464       ::CppTL::Impl::copy_backwards_and_destroy( itWhere, end()-1, end() );
00465       ::CppTL::Impl::construct( *itWhere, item );
00466       return itWhere;
00467    }
00468 
00469    void insert( const_iterator first , const_iterator last )
00470    {
00471       reserve( last - first );
00472       iterator itHint = begin();
00473       for ( ; first != last; ++first )
00474          itHint = insert( itHint, *first ).first;
00475    }
00476 
00477    void swap( SelfType &other )
00478    {
00479       CppTL::swap( this->data_, other.data_ );
00480       CppTL::swap( this->size_, other.size_ );
00481       CppTL::swap( this->capacity_, other.capacity_ );
00482       allocator_.swap( other.allocator_ );
00483       CppTL::swap( less_, other.less_ );
00484    }
00485 
00486    bool operator <( const SelfType &other ) const
00487    {
00488       if ( this->size_ < other.size_ )
00489          return true;
00490       if ( this->size_ > other.size_  ||  this->size_ == 0 )
00491          return false;
00492       Item *i1 = this->data_, *i2 = other.data_;
00493       Item *i1end = this->data_ + this->size_;
00494       for ( ; i1 != i1end; ++i1, ++i2 )
00495       {
00496          if ( itemIsLess( *i1, *i2 ) )
00497             return true;
00498          if ( itemIsLess( *i2, *i1 ) )
00499             return false;
00500       }
00501       return false;
00502    }
00503 
00504    bool operator ==( const SelfType &other ) const
00505    {
00506       if ( this->size_ != other.size_ )
00507          return false;
00508       Item *i1 = this->data_, *i2 = other.data_;
00509       Item *i1end = this->data_ + this->size_;
00510       for ( ; i1 != i1end; ++i1, ++i2 )
00511       {
00512          if ( itemIsLess( *i1, *i2 )  ||  itemIsLess( *i2, *i1 ) )
00513             return false;
00514       }
00515       return true;
00516    }
00517 
00518 private:
00519    // Ensure capacity is large enough to add count elements.
00520    // Optionaly, insert a new item in the middle at position insertIndex.
00521    bool reserve( size_t count, size_t insertIndex = 0, const Item *item = 0)
00522    {
00523       if ( this->size_ + count <= this->capacity_ )
00524          return false;
00525       const size_t initialCapacity = 8;
00526       const size_t minCapacityIncrement = 8;
00527       size_t newCapacity = this->size_ + count;
00528       newCapacity += CPPTL_MAX( newCapacity / 4, minCapacityIncrement );
00529       newCapacity = CPPTL_MAX( initialCapacity, newCapacity );
00530       Item *newData = allocator_.allocateArray( newCapacity );
00531       CPPTL_TRY_BEGIN
00532       {
00533          if ( !item )
00534             insertIndex = this->size_;
00535          ::CppTL::Impl::copy_and_destroy( begin(), begin() + insertIndex, newData );
00536          if ( item )
00537          {
00538             new (newData+insertIndex) Item( *item );
00539             ::CppTL::Impl::copy_and_destroy( begin() + insertIndex, end(), 
00540                                              newData + (insertIndex+1) );
00541          }
00542       }
00543       CPPTL_TRY_END_CLEANUP( allocator_.release( newData, newCapacity ) );
00544       if ( this->data_ )
00545          allocator_.releaseArray( this->data_, this->capacity_ );
00546       this->data_ = newData;
00547       this->capacity_ = newCapacity;
00548       if ( item )
00549          ++(this->size_);
00550       return true;
00551    }
00552 
00553    size_t insertionIndex( const Key &key, size_t min = 0 ) const
00554    {
00555       size_t max = this->size_;
00556       while ( min != max )
00557       {
00558          size_t mid = (max+min) / 2;
00559          if ( less_( this->data_[mid].first, key ) )
00560             min = mid + 1;
00561          else
00562             max = mid;
00563       }
00564       return min;
00565    }
00566 
00567    Item *lookUp( const Key &key ) const
00568    {
00569       size_t pos = insertionIndex( key, 0 );
00570       if ( pos  < this->size_  &&  !less_( key, this->data_[pos].first ) )
00571          return this->data_ + pos;
00572       return 0;
00573    }
00574 
00575    iterator doInsert( size_t whereIndex, const Item &item )
00576    {
00577       if ( this->size_ == this->capacity_ )
00578       {
00579          if ( reserve( 1, whereIndex, &item ) )  // element was inserted when increasing capacity.
00580             return begin() + whereIndex;
00581       }
00582       ++(this->size_);
00583       iterator itWhere( *this, whereIndex );
00584       iterator itEnd = end();
00585       if ( whereIndex != this->size_ - 1 )
00586          ::CppTL::Impl::copy_backwards_and_destroy( itWhere, itEnd-1, itEnd );
00587       ::CppTL::Impl::construct( *itWhere, item);
00588       return itWhere;
00589    }
00590 
00591    bool itemIsLess( const Item &a, const Item &b ) const
00592    {
00593       return less_( a.first, b.first )  ||
00594              ( !less_(b.first, a.first) &&  a.second < b.second );
00595    }
00596 
00597 
00598 private:
00599    Allocator allocator_;
00600    PredLess less_;
00601 };
00602 
00603 
00604 
00605 } // namespace CppTL
00606 
00607 
00608 #endif // CPPTL_VECTOR_H_INCLUDED

SourceForge Logo hosts this site. Send comments to:
CppUnit Developers