Lunchbox  1.8.0
lfVector.ipp
1 
2 /* Copyright (c) 2011-2013, EPFL/Blue Brain Project
3  * Daniel Nachbaur <daniel.nachbaur@epfl.ch>
4  * Stefan.Eilemann@epfl.ch
5  *
6  * This file is part of Lunchbox <https://github.com/Eyescale/Lunchbox>
7  *
8  * This library is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License version 3.0 as published
10  * by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include "lfVectorIterator.h"
23 
24 namespace lunchbox
25 {
26 
27 template< class T, int32_t nSlots >
29  : size_( 0 )
30 {
31  setZero( slots_, nSlots * sizeof( T* ));
32 }
33 
34 template< class T, int32_t nSlots >
36  : size_( n )
37 {
38  LBASSERT( n != 0 );
39  setZero( slots_, nSlots * sizeof( T* ));
40  const int32_t s = getIndexOfLastBit( uint64_t( n ));
41  for( int32_t i = 0; i <= s; ++i )
42  slots_[ i ] = new T[ 1<<i ];
43 }
44 
45 template< class T, int32_t nSlots >
46 LFVector< T, nSlots >::LFVector( const size_t n, const T& t )
47  : size_( 0 )
48 {
49  LBASSERT( n != 0 );
50  setZero( slots_, nSlots * sizeof( T* ));
51  const int32_t s = getIndexOfLastBit( uint64_t( n ));
52  for( int32_t i = 0; i <= s; ++i )
53  {
54  const size_t sz = 1<<i;
55  slots_[ i ] = new T[ sz ];
56  for( size_t j = 0; size_ < n && j < sz ; ++j )
57  {
58  slots_[ i ][ j ] = t;
59  ++size_;
60  }
61  }
62  LBASSERTINFO( size_ == n, size_ << " != " << n );
63 }
64 
65 template< class T, int32_t nSlots >
67  : size_( 0 )
68  , lock_()
69 {
70  assign_( from );
71 }
72 
73 template< class T, int32_t nSlots >
74 template< int32_t fromSlots >
76  : size_( 0 )
77  , lock_()
78 {
79  assign_( from );
80 }
81 
82 template< class T, int32_t nSlots >
84 {
85  for( size_t i=0; i < nSlots; ++i )
86  delete [] slots_[i];
87 }
88 
89 template< class T, int32_t nSlots > LFVector< T, nSlots >&
91 {
92  if( &from == this )
93  return *this;
94 
95  ScopedWrite mutex1( lock_ ); // DEADLOCK when doing a=b and b=a
96  ScopedWrite mutex2( from.lock_ ); // consider trySet/yield approach
97  size_ = 0;
98  for( int32_t i = 0; i < nSlots; ++i )
99  {
100  if( from.slots_[i] )
101  {
102  const size_t sz = 1<<i;
103  if( !slots_[ i ] )
104  slots_[ i ] = new T[ sz ];
105 
106  for( size_t j = 0; size_ < from.size_ && j < sz ; ++j )
107  {
108  slots_[ i ][ j ] = from.slots_[ i ][ j ];
109  ++size_;
110  }
111  }
112  else if( slots_[ i ] ) // done copying, free unneeded slots
113  {
114  delete [] slots_[ i ];
115  slots_[ i ] = 0;
116  }
117  }
118 
119  LBASSERTINFO( size_ == from.size_, size_ << " != " << from.size_ );
120  return *this;
121 }
122 
123 template< class T, int32_t nSlots >
125 {
126  if( &rhs == this )
127  return true;
128 
129  if( size() != rhs.size() )
130  return false;
131 
132  const_iterator it = begin();
133  const_iterator rhsIt = rhs.begin();
134  for( ; it != end() && rhsIt != end(); ++it, ++rhsIt )
135  {
136  if( *it != *rhsIt )
137  return false;
138  }
139 
140  return true;
141 }
142 
143 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51721
144 #ifdef LB_GCC_4_6_OR_LATER
145 # pragma GCC diagnostic push
146 # pragma GCC diagnostic ignored "-Warray-bounds"
147 #endif
148 
149 template< class T, int32_t nSlots >
151 {
152  // one beyond end is possible when called by erase
153  LBASSERTINFO( size_ >= i, size_ << " < " << i );
154  ++i;
155  const int32_t slot = getIndexOfLastBit( i );
156  const size_t index = i ^ ( size_t( 1 )<<slot );
157 
158  LBASSERTINFO( slot >=0 && slot < nSlots, slot );
159  LBASSERT( slots_[ slot ] );
160  LBASSERT( index < (1ull<<slot) );
161  return slots_[ slot ][ index ];
162 }
163 
164 template< class T, int32_t nSlots >
165 const T& LFVector< T, nSlots >::operator[]( size_t i ) const
166 {
167  LBASSERTINFO( size_ > i, size_ << " <= " << i );
168  ++i;
169  const int32_t slot = getIndexOfLastBit( i );
170  const size_t index = i ^ ( size_t( 1 )<<slot );
171 
172  LBASSERTINFO( slot >=0 && slot < nSlots, slot );
173  LBASSERT( slots_[ slot ] );
174  LBASSERT( index < (1ull<<slot) );
175  return slots_[ slot ][ index ];
176 }
177 
178 #ifdef LB_GCC_4_6_OR_LATER
179 # pragma GCC diagnostic pop
180 #endif
181 
182 template< class T, int32_t nSlots >
184 {
185  LBASSERT( !empty( ));
186  return slots_[ 0 ][ 0 ];
187 }
188 
189 template< class T, int32_t nSlots >
191 {
192  LBASSERT( !empty( ));
193  return (*this)[ size_ - 1 ];
194 }
195 
196 template< class T, int32_t nSlots >
197 void LFVector< T, nSlots >::expand( const size_t newSize, const T& item )
198 {
199  ScopedWrite mutex( lock_ );
200  while( newSize > size( ))
201  push_back_unlocked_( item );
202 }
203 
204 template< class T, int32_t nSlots >
205 void LFVector< T, nSlots >::push_back( const T& item, bool lock )
206 {
207  ScopedWrite mutex( lock ? &lock_ : 0 );
208  push_back_unlocked_( item );
209 }
210 
211 template< class T, int32_t nSlots >
213 {
214  ScopedWrite mutex( lock_ );
215  if( size_ == 0 )
216  return;
217  --size_;
218  (*this)[size_] = T(); // not correct for all T? Needed to reset RefPtr
219  trim_();
220 }
221 
222 template< class T, int32_t nSlots >
224 {
225  ScopedWrite mutex( lock_ );
226  if( size_ == 0 )
227  return false;
228 
229  element = back();
230  --size_;
231  (*this)[size_] = T(); // not correct for all T? Needed to reset RefPtr
232  trim_();
233  return true;
234 }
235 
236 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::iterator
238 {
239  LBASSERT( pos.container_ == this );
240  if( pos.container_ != this || pos.i_ >= size_ )
241  return end();
242 
243  ScopedWrite mutex( lock_ );
244  --size_;
245 #pragma warning (push)
246 #pragma warning (disable: 4996) // unchecked iterators
247  std::copy( pos+1, end()+1, pos );
248 #pragma warning (pop)
249  (*this)[size_] = T(); // correct for all T? Needed to reset RefPtr
250  trim_();
251  return pos;
252 }
253 
254 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::iterator
255 LFVector< T, nSlots >::erase( const T& element )
256 {
257  ScopedWrite mutex( lock_ );
258  for( size_t i = size_; i != 0 ; --i )
259  {
260  if( (*this)[i-1] == element )
261  {
262  --size_;
263  iterator pos( this, i-1 );
264 #pragma warning (push)
265 #pragma warning (disable: 4996) // unchecked iterators
266  std::copy( pos+1, end()+1, pos );
267 #pragma warning (pop)
268  (*this)[size_] = 0; // see comment in other erase
269  trim_();
270  return pos;
271  }
272  }
273  return end();
274 }
275 
276 template< class T, int32_t nSlots >
277 void LFVector< T, nSlots >::resize( const size_t newSize, const T& value )
278 {
279  ScopedWrite mutex( lock_ );
280  while( size_ > newSize )
281  {
282  --size_;
283  (*this)[size_] = T(); // not correct for all T? Needed to reset RefPtr
284  }
285  trim_();
286 
287  while( size_ < newSize )
288  push_back_unlocked_( value );
289 }
290 
291 template< class T, int32_t nSlots >
293 {
294  ScopedWrite mutex( lock_ );
295  while( size_ > 0 )
296  {
297  --size_;
298  (*this)[size_] = T(); // Needed to reset RefPtr
299  }
300  for( int32_t i = 0; i < nSlots; ++i )
301  {
302  delete [] slots_[ i ];
303  slots_[ i ] = 0;
304  }
305 }
306 
307 template< class T, int32_t nSlots > typename LFVector< T, nSlots >::ScopedWrite
309 {
310  return ScopedWrite( lock_ );
311 }
312 
313 template< class T, int32_t nSlots >
314 template< int32_t fromSlots >
316 {
317  setZero( slots_, nSlots * sizeof( T* ));
318 
319  ScopedWrite mutex( from.lock_ );
320  for( int32_t i = 0; i < nSlots; ++i )
321  {
322  if( i >= fromSlots || !from.slots_[i] ) // done copying
323  {
324  LBASSERTINFO( size_ == from.size_,
325  size_ << " != " << from.size_ );
326  return;
327  }
328 
329  const size_t sz = 1<<i;
330  slots_[ i ] = new T[ sz ];
331  for( size_t j = 0; size_ < from.size_ && j < sz ; ++j )
332  {
333  slots_[ i ][ j ] = from.slots_[ i ][ j ];
334  ++size_;
335  }
336  }
337 }
338 
339 template< class T, int32_t nSlots >
340 void LFVector< T, nSlots >::push_back_unlocked_( const T& item )
341 {
342  const size_t i = size_ + 1;
343  const int32_t slot = getIndexOfLastBit( i );
344  const size_t sz = ( size_t( 1 )<<slot );
345  if( !slots_[ slot ] )
346  slots_[ slot ] = new T[ sz ];
347 
348  const ssize_t index = i ^ sz;
349  slots_[ slot ][ index ] = item;
350  ++size_;
351 }
352 
353 template< class T, int32_t nSlots >
354 void LFVector< T, nSlots >::trim_()
355 {
356  const int32_t nextSlot = getIndexOfLastBit( size_+1 ) + 1;
357  if( nextSlot < nSlots && slots_[ nextSlot ] )
358  {
359  delete [] slots_[ nextSlot ]; // delete next slot (keep a spare)
360  slots_[ nextSlot ] = 0;
361  }
362 }
363 
364 template< class T, int32_t nSlots > inline typename
366 {
367  return const_iterator( this, 0 );
368 }
369 
370 template< class T, int32_t nSlots > inline typename
372 {
373  return const_iterator( this, size_ );
374 }
375 
376 template< class T, int32_t nSlots > inline typename
378 {
379  return iterator( this, 0 );
380 }
381 
382 template< class T, int32_t nSlots > inline typename
384 {
385  return iterator( this, size_ );
386 }
387 
389 template< class T, int32_t nSlots > template< class Archive >
390 inline void LFVector< T, nSlots >::save( Archive& ar,
391  const unsigned int version ) const
392 {
393  ar << size_;
394  for( size_t i = 0; i < size_; ++i )
395  ar << operator[](i);
396 }
397 
398 template< class T, int32_t nSlots > template< class Archive >
399 inline void LFVector< T, nSlots >::load( Archive& ar,
400  const unsigned int version )
401 {
402  size_t newSize;
403  ar >> newSize;
404  expand( newSize );
405  LBASSERT( size_ == newSize );
406 
407  for( size_t i = 0; i < size_; ++i )
408  ar >> operator[](i);
409 }
412 template< class T >
413 std::ostream& operator << ( std::ostream& os, const LFVector< T >& v )
414 {
415  os << className( &v ) << " size " << v.size() << " [ ";
416  for(typename LFVector< T >::const_iterator i = v.begin(); i != v.end(); ++i)
417  {
418  if( i.getPosition() > 255 )
419  {
420  os << "... ";
421  break;
422  }
423  os << (*i) << ' ';
424  }
425  return os << ']' << std::endl;
426 }
427 
428 }