Lunchbox  1.6.0
lfVector.ipp
00001 
00002 /* Copyright (c) 2011-2012, EPFL/Blue Brain Project
00003  *                          Daniel Nachbaur <daniel.nachbaur@epfl.ch>
00004  *                          Stefan.Eilemann@epfl.ch
00005  *
00006  * This file is part of Lunchbox <https://github.com/Eyescale/Lunchbox>
00007  *
00008  * This library is free software; you can redistribute it and/or modify it under
00009  * the terms of the GNU Lesser General Public License version 3.0 as published
00010  * by the Free Software Foundation.
00011  *
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00015  * details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  */
00021 
00022 #include "lfVectorIterator.h"
00023 
00024 namespace lunchbox
00025 {
00026 
00027 template< class T, int32_t nSlots >
00028 LFVector<T, nSlots >::LFVector()
00029     : size_( 0 )
00030 {
00031     lb_bzero( slots_, nSlots * sizeof( T* ));
00032 }
00033 
00034 template< class T, int32_t nSlots >
00035 LFVector<T, nSlots >::LFVector( const size_t n )
00036     : size_( n )
00037 {
00038     LBASSERT( n != 0 );
00039     lb_bzero( slots_, nSlots * sizeof( T* ));
00040     const int32_t s = getIndexOfLastBit( uint64_t( n ));
00041     for( int32_t i = 0; i <= s; ++i )
00042         slots_[ i ] = new T[ 1<<i ];
00043 }
00044 
00045 template< class T, int32_t nSlots >
00046 LFVector<T, nSlots >::LFVector( const size_t n, const T& t )
00047     : size_( 0 )
00048 {
00049     LBASSERT( n != 0 );
00050     lb_bzero( slots_, nSlots * sizeof( T* ));
00051     const int32_t s = getIndexOfLastBit( uint64_t( n ));
00052     for( int32_t i = 0; i <= s; ++i )
00053     {
00054         const size_t sz = 1<<i;
00055         slots_[ i ] = new T[ sz ];
00056         for( size_t j = 0; size_ < n && j < sz ; ++j )
00057         {
00058             slots_[ i ][ j ] = t;
00059             ++size_;
00060         }
00061     }
00062     LBASSERTINFO( size_ == n, size_ << " != " << n );
00063 }
00064 
00065 template< class T, int32_t nSlots >
00066 LFVector<T, nSlots >::LFVector( const LFVector& from )
00067     : size_( 0 )
00068     , lock_()
00069 {
00070     assign_( from );
00071 }
00072 
00073 template< class T, int32_t nSlots >
00074 template< int32_t fromSlots >
00075 LFVector<T, nSlots >::LFVector( const LFVector< T, fromSlots >& from )
00076     : size_( 0 )
00077     , lock_()
00078 {
00079     assign_( from );
00080 }
00081 
00082 template< class T, int32_t nSlots >
00083 LFVector<T, nSlots >::~LFVector()
00084 {
00085     for( size_t i=0; i < nSlots; ++i )
00086         delete [] slots_[i];
00087 }
00088 
00089 template< class T, int32_t nSlots > LFVector< T, nSlots >&
00090 LFVector< T, nSlots >::operator = ( const LFVector< T, nSlots >& from )
00091 {
00092     if( &from == this )
00093         return *this;
00094 
00095     ScopedWrite mutex1( lock_ ); // DEADLOCK when doing a=b and b=a
00096     ScopedWrite mutex2( from.lock_ ); // consider trySet/yield approach
00097     size_ = 0;
00098     for( int32_t i = 0; i < nSlots; ++i )
00099     {
00100         if( from.slots_[i] )
00101         {
00102             const size_t sz = 1<<i;
00103             if( !slots_[ i ] )
00104                 slots_[ i ] = new T[ sz ];
00105 
00106             for( size_t j = 0; size_ < from.size_ && j < sz ; ++j )
00107             {
00108                 slots_[ i ][ j ] = from.slots_[ i ][ j ];
00109                 ++size_;
00110             }
00111         }
00112         else if( slots_[ i ] ) // done copying, free unneeded slots
00113         {
00114             delete [] slots_[ i ];
00115             slots_[ i ] = 0;
00116         }
00117     }
00118 
00119     LBASSERTINFO( size_ == from.size_, size_ << " != " << from.size_ );
00120     return *this;
00121 }
00122 
00123 template< class T, int32_t nSlots >
00124 bool LFVector< T, nSlots >::operator == ( const LFVector& rhs ) const
00125 {
00126     if( &rhs == this )
00127         return true;
00128 
00129     if( size() != rhs.size() )
00130         return false;
00131 
00132     const_iterator it = begin();
00133     const_iterator rhsIt = rhs.begin();
00134     for( ; it != end() && rhsIt != end(); ++it, ++rhsIt )
00135     {
00136         if( *it != *rhsIt )
00137             return false;
00138     }
00139 
00140     return true;
00141 }
00142 
00143 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51721
00144 #ifdef LB_GCC_4_6_OR_LATER
00145 #  pragma GCC diagnostic push
00146 #  pragma GCC diagnostic ignored "-Warray-bounds"
00147 #endif
00148 
00149 template< class T, int32_t nSlots >
00150 T& LFVector< T, nSlots >::operator[]( size_t i )
00151 {
00152     // one beyond end is possible when called by erase
00153     LBASSERTINFO( size_ >= i, size_ << " < " << i );
00154     ++i;
00155     const int32_t slot = getIndexOfLastBit( i );
00156     const size_t index = i ^ ( size_t( 1 )<<slot );
00157 
00158     LBASSERTINFO( slot >=0 && slot < nSlots, slot );
00159     LBASSERT( slots_[ slot ] );
00160     LBASSERT( index < (1u<<slot) );
00161     return slots_[ slot ][ index ];
00162 }
00163 
00164 template< class T, int32_t nSlots >
00165 const T& LFVector< T, nSlots >::operator[]( size_t i ) const
00166 {
00167     LBASSERTINFO( size_ > i, size_ << " <= " << i );
00168     ++i;
00169     const int32_t slot = getIndexOfLastBit( i );
00170     const size_t index = i ^ ( size_t( 1 )<<slot );
00171 
00172     LBASSERTINFO( slot >=0 && slot < nSlots, slot );
00173     LBASSERT( slots_[ slot ] );
00174     LBASSERT( index < (1u<<slot) );
00175     return slots_[ slot ][ index ];
00176 }
00177 
00178 #ifdef LB_GCC_4_6_OR_LATER
00179 #  pragma GCC diagnostic pop
00180 #endif
00181 
00182 template< class T, int32_t nSlots >
00183 T& LFVector< T, nSlots >::front()
00184 {
00185     LBASSERT( !empty( ));
00186     return slots_[ 0 ][ 0 ];
00187 }
00188 
00189 template< class T, int32_t nSlots >
00190 T& LFVector< T, nSlots >::back()
00191 {
00192     LBASSERT( !empty( ));
00193     return (*this)[ size_ - 1 ];
00194 }
00195 
00196 template< class T, int32_t nSlots >
00197 void LFVector< T, nSlots >::expand( const size_t newSize, const T& item )
00198 {
00199     ScopedWrite mutex( lock_ );
00200     while( newSize > size( ))
00201         push_back_unlocked_( item );
00202 }
00203 
00204 template< class T, int32_t nSlots >
00205 void LFVector< T, nSlots >::push_back( const T& item, bool lock )
00206 {
00207     ScopedWrite mutex( lock ? &lock_ : 0 );
00208     push_back_unlocked_( item );
00209 }
00210 
00211 template< class T, int32_t nSlots >
00212 void LFVector< T, nSlots >::pop_back()
00213 {
00214     ScopedWrite mutex( lock_ );
00215     if( size_ == 0 )
00216         return;
00217     --size_;
00218     (*this)[size_] = 0; // not correct for all T? Needed to reset RefPtr
00219     trim_();
00220 }
00221 
00222 template< class T, int32_t nSlots >
00223 bool LFVector< T, nSlots >::pop_back( T& element )
00224 {
00225     ScopedWrite mutex( lock_ );
00226     if( size_ == 0 )
00227         return false;
00228 
00229     element = back();
00230     --size_;
00231     (*this)[size_] = 0; // not correct for all T? Needed to reset RefPtr
00232     trim_();
00233     return true;
00234 }
00235 
00236 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::iterator
00237 LFVector< T, nSlots >::erase( typename LFVector< T, nSlots >::iterator pos )
00238 {
00239     LBASSERT( pos.container_ == this );
00240     if( pos.container_ != this || pos.i_ >= size_ )
00241         return end();
00242 
00243     ScopedWrite mutex( lock_ );
00244     --size_;
00245 #pragma warning (push)
00246 #pragma warning (disable: 4996) // unchecked iterators
00247     std::copy( pos+1, end()+1, pos );
00248 #pragma warning (pop)
00249     (*this)[size_] = T(); // correct for all T? Needed to reset RefPtr
00250     trim_();
00251     return pos;
00252 }
00253 
00254 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::iterator
00255 LFVector< T, nSlots >::erase( const T& element )
00256 {
00257     ScopedWrite mutex( lock_ );
00258     for( size_t i = size_; i != 0 ; --i )
00259     {
00260         if( (*this)[i-1] == element )
00261         {
00262             --size_;
00263             iterator pos( this, i-1 );
00264 #pragma warning (push)
00265 #pragma warning (disable: 4996) // unchecked iterators
00266             std::copy( pos+1, end()+1, pos );
00267 #pragma warning (pop)
00268             (*this)[size_] = 0; // see comment in other erase
00269             trim_();
00270             return pos;
00271         }
00272     }
00273     return end();
00274 }
00275 
00276 template< class T, int32_t nSlots >
00277 void LFVector< T, nSlots >::clear()
00278 {
00279     ScopedWrite mutex( lock_ );
00280     while( size_ > 0 )
00281     {
00282         --size_;
00283         (*this)[size_] = 0; // Needed to reset RefPtr
00284     }
00285     for( int32_t i = 0; i < nSlots; ++i )
00286     {
00287         delete [] slots_[ i ];
00288         slots_[ i ] = 0;
00289     }
00290 }
00291 
00292 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::ScopedWrite
00293 LFVector< T, nSlots >::getWriteLock()
00294 {
00295     return ScopedWrite( lock_ );
00296 }
00297 
00298 template< class T, int32_t nSlots >
00299 template< int32_t fromSlots >
00300 void LFVector< T, nSlots >::assign_( const LFVector< T, fromSlots >& from )
00301 {
00302     lb_bzero( slots_, nSlots * sizeof( T* ));
00303 
00304     ScopedWrite mutex( from.lock_ );
00305     for( int32_t i = 0; i < nSlots; ++i )
00306     {
00307         if( i >= fromSlots || !from.slots_[i] ) // done copying
00308         {
00309             LBASSERTINFO( size_ == from.size_,
00310                           size_ << " != " << from.size_ );
00311             return;
00312         }
00313 
00314         const size_t sz = 1<<i;
00315         slots_[ i ] = new T[ sz ];
00316         for( size_t j = 0; size_ < from.size_ && j < sz ; ++j )
00317         {
00318             slots_[ i ][ j ] = from.slots_[ i ][ j ];
00319             ++size_;
00320         }
00321     }
00322 }
00323 
00324 template< class T, int32_t nSlots >
00325 void LFVector< T, nSlots >::push_back_unlocked_( const T& item )
00326 {
00327     const size_t i = size_ + 1;
00328     const int32_t slot = getIndexOfLastBit( i );
00329     const size_t sz = ( size_t( 1 )<<slot );
00330     if( !slots_[ slot ] )
00331         slots_[ slot ] = new T[ sz ];
00332 
00333     const ssize_t index = i ^ sz;
00334     slots_[ slot ][ index ] = item;
00335     ++size_;
00336 }
00337 
00338 template< class T, int32_t nSlots >
00339 void LFVector< T, nSlots >::trim_()
00340 {
00341     const int32_t nextSlot = getIndexOfLastBit( size_+1 ) + 1;
00342     if( nextSlot < nSlots && slots_[ nextSlot ] )
00343     {
00344         delete [] slots_[ nextSlot ]; // delete next slot (keep a spare)
00345         slots_[ nextSlot ] = 0;
00346     }
00347 }
00348 
00349 template< class T, int32_t nSlots > inline typename
00350 LFVector< T, nSlots >::const_iterator LFVector< T, nSlots >::begin() const
00351 {
00352     return const_iterator( this, 0 );
00353 }
00354 
00355 template< class T, int32_t nSlots > inline typename
00356 LFVector< T, nSlots >::const_iterator LFVector< T, nSlots >::end() const
00357 {
00358     return const_iterator( this, size_ );
00359 }
00360 
00361 template< class T, int32_t nSlots > inline typename
00362 LFVector< T, nSlots >::iterator LFVector< T, nSlots >::begin()
00363 {
00364     return iterator( this, 0 );
00365 }
00366 
00367 template< class T, int32_t nSlots > inline typename
00368 LFVector< T, nSlots >::iterator LFVector< T, nSlots >::end()
00369 {
00370     return iterator( this, size_ );
00371 }
00372 
00373 #ifdef LUNCHBOX_USE_BOOST
00374 template< class T, int32_t nSlots > template< class Archive >
00375 inline void LFVector< T, nSlots >::save( Archive& ar,
00376                                          const unsigned int version ) const
00377 {
00378     ar << size_;
00379     for( size_t i = 0; i < size_; ++i )
00380         ar << operator[](i);
00381 }
00382 
00383 template< class T, int32_t nSlots > template< class Archive >
00384 inline void LFVector< T, nSlots >::load( Archive& ar,
00385                                          const unsigned int version )
00386 {
00387     size_t newSize;
00388     ar >> newSize;
00389     expand( newSize );
00390     LBASSERT( size_ == newSize );
00391 
00392     for( size_t i = 0; i < size_; ++i )
00393         ar >> operator[](i);
00394 }
00395 #endif
00396 
00397 template< class T >
00398 std::ostream& operator << ( std::ostream& os, const LFVector< T >& v )
00399 {
00400     os << className( &v ) << " size " << v.size() << " [ ";
00401     for(typename LFVector< T >::const_iterator i = v.begin(); i != v.end(); ++i)
00402     {
00403         if( i.getPosition() > 255 )
00404         {
00405             os << "... ";
00406             break;
00407         }
00408         os << (*i) << ' ';
00409     }
00410     return os << ']' << std::endl;
00411 }
00412 
00413 }