Lunchbox
1.6.0
|
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 }