Chris@16
|
1 // Copyright Thorsten Ottosen, 2009.
|
Chris@16
|
2 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
3 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
4 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
|
Chris@16
|
7 #define BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/detail/workaround.hpp>
|
Chris@16
|
10
|
Chris@101
|
11 #if defined(_MSC_VER)
|
Chris@16
|
12 # pragma once
|
Chris@16
|
13 #endif
|
Chris@16
|
14
|
Chris@16
|
15 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
Chris@16
|
16 #pragma warning(push)
|
Chris@16
|
17 #pragma warning(disable:4996)
|
Chris@16
|
18 #endif
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/assert.hpp>
|
Chris@16
|
21 #include <boost/iterator/reverse_iterator.hpp>
|
Chris@16
|
22 #include <boost/iterator/iterator_traits.hpp>
|
Chris@16
|
23 #include <boost/mpl/if.hpp>
|
Chris@16
|
24 #include <boost/multi_index/detail/scope_guard.hpp>
|
Chris@16
|
25 #include <boost/swap.hpp>
|
Chris@16
|
26 #include <boost/throw_exception.hpp>
|
Chris@16
|
27 #include <boost/type_traits/aligned_storage.hpp>
|
Chris@16
|
28 #include <boost/type_traits/alignment_of.hpp>
|
Chris@16
|
29 #include <boost/type_traits/has_nothrow_copy.hpp>
|
Chris@16
|
30 #include <boost/type_traits/has_nothrow_assign.hpp>
|
Chris@16
|
31 #include <boost/type_traits/has_trivial_assign.hpp>
|
Chris@16
|
32 #include <boost/type_traits/has_trivial_constructor.hpp>
|
Chris@16
|
33 #include <boost/type_traits/has_trivial_destructor.hpp>
|
Chris@16
|
34 #include <algorithm>
|
Chris@16
|
35 #include <cstring>
|
Chris@16
|
36 #include <iterator>
|
Chris@16
|
37 #include <memory>
|
Chris@16
|
38 #include <stdexcept>
|
Chris@16
|
39
|
Chris@16
|
40 namespace boost
|
Chris@16
|
41 {
|
Chris@16
|
42 namespace signals2
|
Chris@16
|
43 {
|
Chris@16
|
44 namespace detail
|
Chris@16
|
45 {
|
Chris@16
|
46 //
|
Chris@16
|
47 // Policies for creating the stack buffer.
|
Chris@16
|
48 //
|
Chris@16
|
49 template< unsigned N >
|
Chris@16
|
50 struct store_n_objects
|
Chris@16
|
51 {
|
Chris@16
|
52 BOOST_STATIC_CONSTANT( unsigned, value = N );
|
Chris@16
|
53 };
|
Chris@16
|
54
|
Chris@16
|
55 template< unsigned N >
|
Chris@16
|
56 struct store_n_bytes
|
Chris@16
|
57 {
|
Chris@16
|
58 BOOST_STATIC_CONSTANT( unsigned, value = N );
|
Chris@16
|
59 };
|
Chris@16
|
60
|
Chris@16
|
61 namespace auto_buffer_detail
|
Chris@16
|
62 {
|
Chris@16
|
63 template< class Policy, class T >
|
Chris@16
|
64 struct compute_buffer_size
|
Chris@16
|
65 {
|
Chris@16
|
66 BOOST_STATIC_CONSTANT( unsigned, value = Policy::value * sizeof(T) );
|
Chris@16
|
67 };
|
Chris@16
|
68
|
Chris@16
|
69 template< unsigned N, class T >
|
Chris@16
|
70 struct compute_buffer_size< store_n_bytes<N>, T >
|
Chris@16
|
71 {
|
Chris@16
|
72 BOOST_STATIC_CONSTANT( unsigned, value = N );
|
Chris@16
|
73 };
|
Chris@16
|
74
|
Chris@16
|
75 template< class Policy, class T >
|
Chris@16
|
76 struct compute_buffer_objects
|
Chris@16
|
77 {
|
Chris@16
|
78 BOOST_STATIC_CONSTANT( unsigned, value = Policy::value );
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81 template< unsigned N, class T >
|
Chris@16
|
82 struct compute_buffer_objects< store_n_bytes<N>, T >
|
Chris@16
|
83 {
|
Chris@16
|
84 BOOST_STATIC_CONSTANT( unsigned, value = N / sizeof(T) );
|
Chris@16
|
85 };
|
Chris@16
|
86 }
|
Chris@16
|
87
|
Chris@16
|
88 struct default_grow_policy
|
Chris@16
|
89 {
|
Chris@16
|
90 template< class SizeType >
|
Chris@16
|
91 static SizeType new_capacity( SizeType capacity )
|
Chris@16
|
92 {
|
Chris@16
|
93 //
|
Chris@16
|
94 // @remark: we grow the capacity quite agressively.
|
Chris@16
|
95 // this is justified since we aim to minimize
|
Chris@16
|
96 // heap-allocations, and because we mostly use
|
Chris@16
|
97 // the buffer locally.
|
Chris@16
|
98 return capacity * 4u;
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 template< class SizeType >
|
Chris@16
|
102 static bool should_shrink( SizeType size, SizeType capacity )
|
Chris@16
|
103 {
|
Chris@16
|
104 //
|
Chris@16
|
105 // @remark: when defining a new grow policy, one might
|
Chris@16
|
106 // choose that if the waated space is less
|
Chris@16
|
107 // than a certain percentage, then it is of
|
Chris@16
|
108 // little use to shrink.
|
Chris@16
|
109 //
|
Chris@16
|
110 return true;
|
Chris@16
|
111 }
|
Chris@16
|
112 };
|
Chris@16
|
113
|
Chris@16
|
114 template< class T,
|
Chris@16
|
115 class StackBufferPolicy = store_n_objects<256>,
|
Chris@16
|
116 class GrowPolicy = default_grow_policy,
|
Chris@16
|
117 class Allocator = std::allocator<T> >
|
Chris@16
|
118 class auto_buffer;
|
Chris@16
|
119
|
Chris@16
|
120
|
Chris@16
|
121
|
Chris@16
|
122 template
|
Chris@16
|
123 <
|
Chris@16
|
124 class T,
|
Chris@16
|
125 class StackBufferPolicy,
|
Chris@16
|
126 class GrowPolicy,
|
Chris@16
|
127 class Allocator
|
Chris@16
|
128 >
|
Chris@16
|
129 class auto_buffer : Allocator
|
Chris@16
|
130 {
|
Chris@16
|
131 private:
|
Chris@16
|
132 enum { N = auto_buffer_detail::
|
Chris@16
|
133 compute_buffer_objects<StackBufferPolicy,T>::value };
|
Chris@16
|
134
|
Chris@16
|
135 BOOST_STATIC_CONSTANT( bool, is_stack_buffer_empty = N == 0u );
|
Chris@16
|
136
|
Chris@16
|
137 typedef auto_buffer<T, store_n_objects<0>, GrowPolicy, Allocator>
|
Chris@16
|
138 local_buffer;
|
Chris@16
|
139
|
Chris@16
|
140 public:
|
Chris@16
|
141 typedef Allocator allocator_type;
|
Chris@16
|
142 typedef T value_type;
|
Chris@16
|
143 typedef typename Allocator::size_type size_type;
|
Chris@16
|
144 typedef typename Allocator::difference_type difference_type;
|
Chris@16
|
145 typedef T* pointer;
|
Chris@16
|
146 typedef typename Allocator::pointer allocator_pointer;
|
Chris@16
|
147 typedef const T* const_pointer;
|
Chris@16
|
148 typedef T& reference;
|
Chris@16
|
149 typedef const T& const_reference;
|
Chris@16
|
150 typedef pointer iterator;
|
Chris@16
|
151 typedef const_pointer const_iterator;
|
Chris@16
|
152 typedef boost::reverse_iterator<iterator> reverse_iterator;
|
Chris@16
|
153 typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
|
Chris@16
|
154 typedef typename boost::mpl::if_c< boost::has_trivial_assign<T>::value
|
Chris@16
|
155 && sizeof(T) <= sizeof(long double),
|
Chris@16
|
156 const value_type,
|
Chris@16
|
157 const_reference >::type
|
Chris@16
|
158 optimized_const_reference;
|
Chris@16
|
159 private:
|
Chris@16
|
160
|
Chris@16
|
161 pointer allocate( size_type capacity_arg )
|
Chris@16
|
162 {
|
Chris@16
|
163 if( capacity_arg > N )
|
Chris@16
|
164 return &*get_allocator().allocate( capacity_arg );
|
Chris@16
|
165 else
|
Chris@16
|
166 return static_cast<T*>( members_.address() );
|
Chris@16
|
167 }
|
Chris@16
|
168
|
Chris@16
|
169 void deallocate( pointer where, size_type capacity_arg )
|
Chris@16
|
170 {
|
Chris@16
|
171 if( capacity_arg <= N )
|
Chris@16
|
172 return;
|
Chris@16
|
173 get_allocator().deallocate( allocator_pointer(where), capacity_arg );
|
Chris@16
|
174 }
|
Chris@16
|
175
|
Chris@16
|
176 template< class I >
|
Chris@16
|
177 static void copy_impl( I begin, I end, pointer where, std::random_access_iterator_tag )
|
Chris@16
|
178 {
|
Chris@16
|
179 copy_rai( begin, end, where, boost::has_trivial_assign<T>() );
|
Chris@16
|
180 }
|
Chris@16
|
181
|
Chris@16
|
182 static void copy_rai( const T* begin, const T* end,
|
Chris@16
|
183 pointer where, const boost::true_type& )
|
Chris@16
|
184 {
|
Chris@16
|
185 std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
|
Chris@16
|
186 }
|
Chris@16
|
187
|
Chris@16
|
188 template< class I, bool b >
|
Chris@16
|
189 static void copy_rai( I begin, I end,
|
Chris@16
|
190 pointer where, const boost::integral_constant<bool, b>& )
|
Chris@16
|
191 {
|
Chris@16
|
192 std::uninitialized_copy( begin, end, where );
|
Chris@16
|
193 }
|
Chris@16
|
194
|
Chris@16
|
195 template< class I >
|
Chris@16
|
196 static void copy_impl( I begin, I end, pointer where, std::bidirectional_iterator_tag )
|
Chris@16
|
197 {
|
Chris@16
|
198 std::uninitialized_copy( begin, end, where );
|
Chris@16
|
199 }
|
Chris@16
|
200
|
Chris@16
|
201 template< class I >
|
Chris@16
|
202 static void copy_impl( I begin, I end, pointer where )
|
Chris@16
|
203 {
|
Chris@16
|
204 copy_impl( begin, end, where,
|
Chris@16
|
205 typename std::iterator_traits<I>::iterator_category() );
|
Chris@16
|
206 }
|
Chris@16
|
207
|
Chris@16
|
208 template< class I, class I2 >
|
Chris@16
|
209 static void assign_impl( I begin, I end, I2 where )
|
Chris@16
|
210 {
|
Chris@16
|
211 assign_impl( begin, end, where, boost::has_trivial_assign<T>() );
|
Chris@16
|
212 }
|
Chris@16
|
213
|
Chris@16
|
214 template< class I, class I2 >
|
Chris@16
|
215 static void assign_impl( I begin, I end, I2 where, const boost::true_type& )
|
Chris@16
|
216 {
|
Chris@16
|
217 std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
|
Chris@16
|
218 }
|
Chris@16
|
219
|
Chris@16
|
220 template< class I, class I2 >
|
Chris@16
|
221 static void assign_impl( I begin, I end, I2 where, const boost::false_type& )
|
Chris@16
|
222 {
|
Chris@16
|
223 for( ; begin != end; ++begin, ++where )
|
Chris@16
|
224 *where = *begin;
|
Chris@16
|
225 }
|
Chris@16
|
226
|
Chris@16
|
227 void unchecked_push_back_n( size_type n, const boost::true_type& )
|
Chris@16
|
228 {
|
Chris@16
|
229 std::uninitialized_fill( end(), end() + n, T() );
|
Chris@16
|
230 size_ += n;
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 void unchecked_push_back_n( size_type n, const boost::false_type& )
|
Chris@16
|
234 {
|
Chris@16
|
235 for( size_type i = 0u; i < n; ++i )
|
Chris@16
|
236 unchecked_push_back();
|
Chris@16
|
237 }
|
Chris@16
|
238
|
Chris@16
|
239 void auto_buffer_destroy( pointer where, const boost::false_type& )
|
Chris@16
|
240 {
|
Chris@16
|
241 (*where).~T();
|
Chris@16
|
242 }
|
Chris@16
|
243
|
Chris@16
|
244 void auto_buffer_destroy( pointer, const boost::true_type& )
|
Chris@16
|
245 { }
|
Chris@16
|
246
|
Chris@16
|
247 void auto_buffer_destroy( pointer where )
|
Chris@16
|
248 {
|
Chris@16
|
249 auto_buffer_destroy( where, boost::has_trivial_destructor<T>() );
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 void destroy_back_n( size_type n, const boost::false_type& )
|
Chris@16
|
253 {
|
Chris@16
|
254 BOOST_ASSERT( n > 0 );
|
Chris@16
|
255 pointer buffer = buffer_ + size_ - 1u;
|
Chris@16
|
256 pointer new_end = buffer - n;
|
Chris@16
|
257 for( ; buffer > new_end; --buffer )
|
Chris@16
|
258 auto_buffer_destroy( buffer );
|
Chris@16
|
259 }
|
Chris@16
|
260
|
Chris@16
|
261 void destroy_back_n( size_type n, const boost::true_type& )
|
Chris@16
|
262 { }
|
Chris@16
|
263
|
Chris@16
|
264 void destroy_back_n( size_type n )
|
Chris@16
|
265 {
|
Chris@16
|
266 destroy_back_n( n, boost::has_trivial_destructor<T>() );
|
Chris@16
|
267 }
|
Chris@16
|
268
|
Chris@16
|
269 void auto_buffer_destroy( const boost::false_type& x )
|
Chris@16
|
270 {
|
Chris@16
|
271 if( size_ )
|
Chris@16
|
272 destroy_back_n( size_, x );
|
Chris@16
|
273 deallocate( buffer_, members_.capacity_ );
|
Chris@16
|
274 }
|
Chris@16
|
275
|
Chris@16
|
276 void auto_buffer_destroy( const boost::true_type& )
|
Chris@16
|
277 {
|
Chris@16
|
278 deallocate( buffer_, members_.capacity_ );
|
Chris@16
|
279 }
|
Chris@16
|
280
|
Chris@16
|
281 pointer move_to_new_buffer( size_type new_capacity, const boost::false_type& )
|
Chris@16
|
282 {
|
Chris@16
|
283 pointer new_buffer = allocate( new_capacity ); // strong
|
Chris@16
|
284 boost::multi_index::detail::scope_guard guard =
|
Chris@16
|
285 boost::multi_index::detail::make_obj_guard( *this,
|
Chris@16
|
286 &auto_buffer::deallocate,
|
Chris@16
|
287 new_buffer,
|
Chris@16
|
288 new_capacity );
|
Chris@16
|
289 copy_impl( begin(), end(), new_buffer ); // strong
|
Chris@16
|
290 guard.dismiss(); // nothrow
|
Chris@16
|
291 return new_buffer;
|
Chris@16
|
292 }
|
Chris@16
|
293
|
Chris@16
|
294 pointer move_to_new_buffer( size_type new_capacity, const boost::true_type& )
|
Chris@16
|
295 {
|
Chris@16
|
296 pointer new_buffer = allocate( new_capacity ); // strong
|
Chris@16
|
297 copy_impl( begin(), end(), new_buffer ); // nothrow
|
Chris@16
|
298 return new_buffer;
|
Chris@16
|
299 }
|
Chris@16
|
300
|
Chris@16
|
301 void reserve_impl( size_type new_capacity )
|
Chris@16
|
302 {
|
Chris@16
|
303 pointer new_buffer = move_to_new_buffer( new_capacity,
|
Chris@16
|
304 boost::has_nothrow_copy<T>() );
|
Chris@16
|
305 (*this).~auto_buffer();
|
Chris@16
|
306 buffer_ = new_buffer;
|
Chris@16
|
307 members_.capacity_ = new_capacity;
|
Chris@16
|
308 BOOST_ASSERT( size_ <= members_.capacity_ );
|
Chris@16
|
309 }
|
Chris@16
|
310
|
Chris@16
|
311 size_type new_capacity_impl( size_type n )
|
Chris@16
|
312 {
|
Chris@16
|
313 BOOST_ASSERT( n > members_.capacity_ );
|
Chris@16
|
314 size_type new_capacity = GrowPolicy::new_capacity( members_.capacity_ );
|
Chris@16
|
315 // @todo: consider to check for allocator.max_size()
|
Chris@16
|
316 return (std::max)(new_capacity,n);
|
Chris@16
|
317 }
|
Chris@16
|
318
|
Chris@16
|
319 static void swap_helper( auto_buffer& l, auto_buffer& r,
|
Chris@16
|
320 const boost::true_type& )
|
Chris@16
|
321 {
|
Chris@16
|
322 BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
|
Chris@16
|
323
|
Chris@16
|
324 auto_buffer temp( l.begin(), l.end() );
|
Chris@16
|
325 assign_impl( r.begin(), r.end(), l.begin() );
|
Chris@16
|
326 assign_impl( temp.begin(), temp.end(), r.begin() );
|
Chris@16
|
327 boost::swap( l.size_, r.size_ );
|
Chris@16
|
328 boost::swap( l.members_.capacity_, r.members_.capacity_ );
|
Chris@16
|
329 }
|
Chris@16
|
330
|
Chris@16
|
331 static void swap_helper( auto_buffer& l, auto_buffer& r,
|
Chris@16
|
332 const boost::false_type& )
|
Chris@16
|
333 {
|
Chris@16
|
334 BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
|
Chris@16
|
335 size_type min_size = (std::min)(l.size_,r.size_);
|
Chris@16
|
336 size_type max_size = (std::max)(l.size_,r.size_);
|
Chris@16
|
337 size_type diff = max_size - min_size;
|
Chris@16
|
338 auto_buffer* smallest = l.size_ == min_size ? &l : &r;
|
Chris@16
|
339 auto_buffer* largest = smallest == &l ? &r : &l;
|
Chris@16
|
340
|
Chris@16
|
341 // @remark: the implementation below is not as fast
|
Chris@16
|
342 // as it could be if we assumed T had a default
|
Chris@16
|
343 // constructor.
|
Chris@16
|
344
|
Chris@16
|
345 size_type i = 0u;
|
Chris@16
|
346 for( ; i < min_size; ++i )
|
Chris@16
|
347 boost::swap( (*smallest)[i], (*largest)[i] );
|
Chris@16
|
348
|
Chris@16
|
349 for( ; i < max_size; ++i )
|
Chris@16
|
350 smallest->unchecked_push_back( (*largest)[i] );
|
Chris@16
|
351
|
Chris@16
|
352 largest->pop_back_n( diff );
|
Chris@16
|
353 boost::swap( l.members_.capacity_, r.members_.capacity_ );
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 void one_sided_swap( auto_buffer& temp ) // nothrow
|
Chris@16
|
357 {
|
Chris@16
|
358 BOOST_ASSERT( !temp.is_on_stack() );
|
Chris@16
|
359 this->~auto_buffer();
|
Chris@16
|
360 // @remark: must be nothrow
|
Chris@16
|
361 get_allocator() = temp.get_allocator();
|
Chris@16
|
362 members_.capacity_ = temp.members_.capacity_;
|
Chris@16
|
363 buffer_ = temp.buffer_;
|
Chris@16
|
364 BOOST_ASSERT( temp.size_ >= size_ + 1u );
|
Chris@16
|
365 size_ = temp.size_;
|
Chris@16
|
366 temp.buffer_ = 0;
|
Chris@16
|
367 BOOST_ASSERT( temp.is_valid() );
|
Chris@16
|
368 }
|
Chris@16
|
369
|
Chris@16
|
370 template< class I >
|
Chris@16
|
371 void insert_impl( const_iterator before, I begin_arg, I end_arg,
|
Chris@16
|
372 std::input_iterator_tag )
|
Chris@16
|
373 {
|
Chris@16
|
374 for( ; begin_arg != end_arg; ++begin_arg )
|
Chris@16
|
375 {
|
Chris@16
|
376 before = insert( before, *begin_arg );
|
Chris@16
|
377 ++before;
|
Chris@16
|
378 }
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 void grow_back( size_type n, const boost::true_type& )
|
Chris@16
|
382 {
|
Chris@16
|
383 BOOST_ASSERT( size_ + n <= members_.capacity_ );
|
Chris@16
|
384 size_ += n;
|
Chris@16
|
385 }
|
Chris@16
|
386
|
Chris@16
|
387 void grow_back( size_type n, const boost::false_type& )
|
Chris@16
|
388 {
|
Chris@16
|
389 unchecked_push_back_n(n);
|
Chris@16
|
390 }
|
Chris@16
|
391
|
Chris@16
|
392 void grow_back( size_type n )
|
Chris@16
|
393 {
|
Chris@16
|
394 grow_back( n, boost::has_trivial_constructor<T>() );
|
Chris@16
|
395 }
|
Chris@16
|
396
|
Chris@16
|
397 void grow_back_one( const boost::true_type& )
|
Chris@16
|
398 {
|
Chris@16
|
399 BOOST_ASSERT( size_ + 1 <= members_.capacity_ );
|
Chris@16
|
400 size_ += 1;
|
Chris@16
|
401 }
|
Chris@16
|
402
|
Chris@16
|
403 void grow_back_one( const boost::false_type& )
|
Chris@16
|
404 {
|
Chris@16
|
405 unchecked_push_back();
|
Chris@16
|
406 }
|
Chris@16
|
407
|
Chris@16
|
408 void grow_back_one()
|
Chris@16
|
409 {
|
Chris@16
|
410 grow_back_one( boost::has_trivial_constructor<T>() );
|
Chris@16
|
411 }
|
Chris@16
|
412
|
Chris@16
|
413 template< class I >
|
Chris@16
|
414 void insert_impl( const_iterator before, I begin_arg, I end_arg,
|
Chris@16
|
415 std::forward_iterator_tag )
|
Chris@16
|
416 {
|
Chris@16
|
417 difference_type n = std::distance(begin_arg, end_arg);
|
Chris@16
|
418
|
Chris@16
|
419 if( size_ + n <= members_.capacity_ )
|
Chris@16
|
420 {
|
Chris@16
|
421 bool is_back_insertion = before == cend();
|
Chris@16
|
422 if( !is_back_insertion )
|
Chris@16
|
423 {
|
Chris@16
|
424 grow_back( n );
|
Chris@16
|
425 iterator where = const_cast<T*>(before);
|
Chris@16
|
426 std::copy( before, cend() - n, where + n );
|
Chris@16
|
427 assign_impl( begin_arg, end_arg, where );
|
Chris@16
|
428 }
|
Chris@16
|
429 else
|
Chris@16
|
430 {
|
Chris@16
|
431 unchecked_push_back( begin_arg, end_arg );
|
Chris@16
|
432 }
|
Chris@16
|
433 BOOST_ASSERT( is_valid() );
|
Chris@16
|
434 return;
|
Chris@16
|
435 }
|
Chris@16
|
436
|
Chris@16
|
437 auto_buffer temp( new_capacity_impl( size_ + n ) );
|
Chris@16
|
438 temp.unchecked_push_back( cbegin(), before );
|
Chris@16
|
439 temp.unchecked_push_back( begin_arg, end_arg );
|
Chris@16
|
440 temp.unchecked_push_back( before, cend() );
|
Chris@16
|
441 one_sided_swap( temp );
|
Chris@16
|
442 BOOST_ASSERT( is_valid() );
|
Chris@16
|
443 }
|
Chris@16
|
444
|
Chris@16
|
445 public:
|
Chris@16
|
446 bool is_valid() const // invariant
|
Chris@16
|
447 {
|
Chris@16
|
448 // @remark: allowed for N==0 and when
|
Chris@16
|
449 // using a locally instance
|
Chris@16
|
450 // in insert()/one_sided_swap()
|
Chris@16
|
451 if( buffer_ == 0 )
|
Chris@16
|
452 return true;
|
Chris@16
|
453
|
Chris@16
|
454 if( members_.capacity_ < N )
|
Chris@16
|
455 return false;
|
Chris@16
|
456
|
Chris@16
|
457 if( !is_on_stack() && members_.capacity_ <= N )
|
Chris@16
|
458 return false;
|
Chris@16
|
459
|
Chris@16
|
460 if( buffer_ == members_.address() )
|
Chris@16
|
461 if( members_.capacity_ > N )
|
Chris@16
|
462 return false;
|
Chris@16
|
463
|
Chris@16
|
464 if( size_ > members_.capacity_ )
|
Chris@16
|
465 return false;
|
Chris@16
|
466
|
Chris@16
|
467 return true;
|
Chris@16
|
468 }
|
Chris@16
|
469
|
Chris@16
|
470 auto_buffer()
|
Chris@16
|
471 : members_( N ),
|
Chris@16
|
472 buffer_( static_cast<T*>(members_.address()) ),
|
Chris@16
|
473 size_( 0u )
|
Chris@16
|
474 {
|
Chris@16
|
475 BOOST_ASSERT( is_valid() );
|
Chris@16
|
476 }
|
Chris@16
|
477
|
Chris@16
|
478 auto_buffer( const auto_buffer& r )
|
Chris@16
|
479 : members_( (std::max)(r.size_,size_type(N)) ),
|
Chris@16
|
480 buffer_( allocate( members_.capacity_ ) ),
|
Chris@16
|
481 size_( 0 )
|
Chris@16
|
482 {
|
Chris@16
|
483 copy_impl( r.begin(), r.end(), buffer_ );
|
Chris@16
|
484 size_ = r.size_;
|
Chris@16
|
485 BOOST_ASSERT( is_valid() );
|
Chris@16
|
486 }
|
Chris@16
|
487
|
Chris@16
|
488 auto_buffer& operator=( const auto_buffer& r ) // basic
|
Chris@16
|
489 {
|
Chris@16
|
490 if( this == &r )
|
Chris@16
|
491 return *this;
|
Chris@16
|
492
|
Chris@16
|
493 difference_type diff = size_ - r.size_;
|
Chris@16
|
494 if( diff >= 0 )
|
Chris@16
|
495 {
|
Chris@16
|
496 pop_back_n( static_cast<size_type>(diff) );
|
Chris@16
|
497 assign_impl( r.begin(), r.end(), begin() );
|
Chris@16
|
498 }
|
Chris@16
|
499 else
|
Chris@16
|
500 {
|
Chris@16
|
501 if( members_.capacity_ >= r.size() )
|
Chris@16
|
502 {
|
Chris@16
|
503 unchecked_push_back_n( static_cast<size_type>(-diff) );
|
Chris@16
|
504 assign_impl( r.begin(), r.end(), begin() );
|
Chris@16
|
505 }
|
Chris@16
|
506 else
|
Chris@16
|
507 {
|
Chris@16
|
508 // @remark: we release memory as early as possible
|
Chris@16
|
509 // since we only give the basic guarantee
|
Chris@16
|
510 (*this).~auto_buffer();
|
Chris@16
|
511 buffer_ = 0;
|
Chris@16
|
512 pointer new_buffer = allocate( r.size() );
|
Chris@16
|
513 boost::multi_index::detail::scope_guard guard =
|
Chris@16
|
514 boost::multi_index::detail::make_obj_guard( *this,
|
Chris@16
|
515 &auto_buffer::deallocate,
|
Chris@16
|
516 new_buffer,
|
Chris@16
|
517 r.size() );
|
Chris@16
|
518 copy_impl( r.begin(), r.end(), new_buffer );
|
Chris@16
|
519 guard.dismiss();
|
Chris@16
|
520 buffer_ = new_buffer;
|
Chris@16
|
521 members_.capacity_ = r.size();
|
Chris@16
|
522 size_ = members_.capacity_;
|
Chris@16
|
523 }
|
Chris@16
|
524 }
|
Chris@16
|
525
|
Chris@16
|
526 BOOST_ASSERT( size() == r.size() );
|
Chris@16
|
527 BOOST_ASSERT( is_valid() );
|
Chris@16
|
528 return *this;
|
Chris@16
|
529 }
|
Chris@16
|
530
|
Chris@16
|
531 explicit auto_buffer( size_type capacity_arg )
|
Chris@16
|
532 : members_( (std::max)(capacity_arg, size_type(N)) ),
|
Chris@16
|
533 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
534 size_( 0 )
|
Chris@16
|
535 {
|
Chris@16
|
536 BOOST_ASSERT( is_valid() );
|
Chris@16
|
537 }
|
Chris@16
|
538
|
Chris@16
|
539 auto_buffer( size_type size_arg, optimized_const_reference init_value )
|
Chris@16
|
540 : members_( (std::max)(size_arg, size_type(N)) ),
|
Chris@16
|
541 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
542 size_( 0 )
|
Chris@16
|
543 {
|
Chris@16
|
544 std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
|
Chris@16
|
545 size_ = size_arg;
|
Chris@16
|
546 BOOST_ASSERT( is_valid() );
|
Chris@16
|
547 }
|
Chris@16
|
548
|
Chris@16
|
549 auto_buffer( size_type capacity_arg, const allocator_type& a )
|
Chris@16
|
550 : allocator_type( a ),
|
Chris@16
|
551 members_( (std::max)(capacity_arg, size_type(N)) ),
|
Chris@16
|
552 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
553 size_( 0 )
|
Chris@16
|
554 {
|
Chris@16
|
555 BOOST_ASSERT( is_valid() );
|
Chris@16
|
556 }
|
Chris@16
|
557
|
Chris@16
|
558 auto_buffer( size_type size_arg, optimized_const_reference init_value,
|
Chris@16
|
559 const allocator_type& a )
|
Chris@16
|
560 : allocator_type( a ),
|
Chris@16
|
561 members_( (std::max)(size_arg, size_type(N)) ),
|
Chris@16
|
562 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
563 size_( 0 )
|
Chris@16
|
564 {
|
Chris@16
|
565 std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
|
Chris@16
|
566 size_ = size_arg;
|
Chris@16
|
567 BOOST_ASSERT( is_valid() );
|
Chris@16
|
568 }
|
Chris@16
|
569
|
Chris@16
|
570 template< class ForwardIterator >
|
Chris@16
|
571 auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg )
|
Chris@16
|
572 :
|
Chris@16
|
573 members_( std::distance(begin_arg, end_arg) ),
|
Chris@16
|
574 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
575 size_( 0 )
|
Chris@16
|
576 {
|
Chris@16
|
577 copy_impl( begin_arg, end_arg, buffer_ );
|
Chris@16
|
578 size_ = members_.capacity_;
|
Chris@16
|
579 if( members_.capacity_ < N )
|
Chris@16
|
580 members_.capacity_ = N;
|
Chris@16
|
581 BOOST_ASSERT( is_valid() );
|
Chris@16
|
582 }
|
Chris@16
|
583
|
Chris@16
|
584 template< class ForwardIterator >
|
Chris@16
|
585 auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg,
|
Chris@16
|
586 const allocator_type& a )
|
Chris@16
|
587 : allocator_type( a ),
|
Chris@16
|
588 members_( std::distance(begin_arg, end_arg) ),
|
Chris@16
|
589 buffer_( allocate(members_.capacity_) ),
|
Chris@16
|
590 size_( 0 )
|
Chris@16
|
591 {
|
Chris@16
|
592 copy_impl( begin_arg, end_arg, buffer_ );
|
Chris@16
|
593 size_ = members_.capacity_;
|
Chris@16
|
594 if( members_.capacity_ < N )
|
Chris@16
|
595 members_.capacity_ = N;
|
Chris@16
|
596 BOOST_ASSERT( is_valid() );
|
Chris@16
|
597 }
|
Chris@16
|
598
|
Chris@16
|
599 ~auto_buffer()
|
Chris@16
|
600 {
|
Chris@16
|
601 BOOST_ASSERT( is_valid() );
|
Chris@16
|
602 if( buffer_ ) // do we need this check? Yes, but only
|
Chris@16
|
603 // for N = 0u + local instances in one_sided_swap()
|
Chris@16
|
604 auto_buffer_destroy( boost::has_trivial_destructor<T>() );
|
Chris@16
|
605 }
|
Chris@16
|
606
|
Chris@16
|
607 public:
|
Chris@16
|
608 bool empty() const
|
Chris@16
|
609 {
|
Chris@16
|
610 return size_ == 0;
|
Chris@16
|
611 }
|
Chris@16
|
612
|
Chris@16
|
613 bool full() const
|
Chris@16
|
614 {
|
Chris@16
|
615 return size_ == members_.capacity_;
|
Chris@16
|
616 }
|
Chris@16
|
617
|
Chris@16
|
618 bool is_on_stack() const
|
Chris@16
|
619 {
|
Chris@16
|
620 return members_.capacity_ <= N;
|
Chris@16
|
621 }
|
Chris@16
|
622
|
Chris@16
|
623 size_type size() const
|
Chris@16
|
624 {
|
Chris@16
|
625 return size_;
|
Chris@16
|
626 }
|
Chris@16
|
627
|
Chris@16
|
628 size_type capacity() const
|
Chris@16
|
629 {
|
Chris@16
|
630 return members_.capacity_;
|
Chris@16
|
631 }
|
Chris@16
|
632
|
Chris@16
|
633 public:
|
Chris@16
|
634 pointer data()
|
Chris@16
|
635 {
|
Chris@16
|
636 return buffer_;
|
Chris@16
|
637 }
|
Chris@16
|
638
|
Chris@16
|
639 const_pointer data() const
|
Chris@16
|
640 {
|
Chris@16
|
641 return buffer_;
|
Chris@16
|
642 }
|
Chris@16
|
643
|
Chris@16
|
644 allocator_type& get_allocator()
|
Chris@16
|
645 {
|
Chris@16
|
646 return static_cast<allocator_type&>(*this);
|
Chris@16
|
647 }
|
Chris@16
|
648
|
Chris@16
|
649 const allocator_type& get_allocator() const
|
Chris@16
|
650 {
|
Chris@16
|
651 return static_cast<const allocator_type&>(*this);
|
Chris@16
|
652 }
|
Chris@16
|
653
|
Chris@16
|
654 public:
|
Chris@16
|
655 iterator begin()
|
Chris@16
|
656 {
|
Chris@16
|
657 return buffer_;
|
Chris@16
|
658 }
|
Chris@16
|
659
|
Chris@16
|
660 const_iterator begin() const
|
Chris@16
|
661 {
|
Chris@16
|
662 return buffer_;
|
Chris@16
|
663 }
|
Chris@16
|
664
|
Chris@16
|
665 iterator end()
|
Chris@16
|
666 {
|
Chris@16
|
667 return buffer_ + size_;
|
Chris@16
|
668 }
|
Chris@16
|
669
|
Chris@16
|
670 const_iterator end() const
|
Chris@16
|
671 {
|
Chris@16
|
672 return buffer_ + size_;
|
Chris@16
|
673 }
|
Chris@16
|
674
|
Chris@16
|
675 reverse_iterator rbegin()
|
Chris@16
|
676 {
|
Chris@16
|
677 return reverse_iterator(end());
|
Chris@16
|
678 }
|
Chris@16
|
679
|
Chris@16
|
680 const_reverse_iterator rbegin() const
|
Chris@16
|
681 {
|
Chris@16
|
682 return const_reverse_iterator(end());
|
Chris@16
|
683 }
|
Chris@16
|
684
|
Chris@16
|
685 reverse_iterator rend()
|
Chris@16
|
686 {
|
Chris@16
|
687 return reverse_iterator(begin());
|
Chris@16
|
688 }
|
Chris@16
|
689
|
Chris@16
|
690 const_reverse_iterator rend() const
|
Chris@16
|
691 {
|
Chris@16
|
692 return const_reverse_iterator(begin());
|
Chris@16
|
693 }
|
Chris@16
|
694
|
Chris@16
|
695 const_iterator cbegin() const
|
Chris@16
|
696 {
|
Chris@16
|
697 return const_cast<const auto_buffer*>(this)->begin();
|
Chris@16
|
698 }
|
Chris@16
|
699
|
Chris@16
|
700 const_iterator cend() const
|
Chris@16
|
701 {
|
Chris@16
|
702 return const_cast<const auto_buffer*>(this)->end();
|
Chris@16
|
703 }
|
Chris@16
|
704
|
Chris@16
|
705 const_reverse_iterator crbegin() const
|
Chris@16
|
706 {
|
Chris@16
|
707 return const_cast<const auto_buffer*>(this)->rbegin();
|
Chris@16
|
708 }
|
Chris@16
|
709
|
Chris@16
|
710 const_reverse_iterator crend() const
|
Chris@16
|
711 {
|
Chris@16
|
712 return const_cast<const auto_buffer*>(this)->rend();
|
Chris@16
|
713 }
|
Chris@16
|
714
|
Chris@16
|
715 public:
|
Chris@16
|
716 reference front()
|
Chris@16
|
717 {
|
Chris@16
|
718 return buffer_[0];
|
Chris@16
|
719 }
|
Chris@16
|
720
|
Chris@16
|
721 optimized_const_reference front() const
|
Chris@16
|
722 {
|
Chris@16
|
723 return buffer_[0];
|
Chris@16
|
724 }
|
Chris@16
|
725
|
Chris@16
|
726 reference back()
|
Chris@16
|
727 {
|
Chris@16
|
728 return buffer_[size_-1];
|
Chris@16
|
729 }
|
Chris@16
|
730
|
Chris@16
|
731 optimized_const_reference back() const
|
Chris@16
|
732 {
|
Chris@16
|
733 return buffer_[size_-1];
|
Chris@16
|
734 }
|
Chris@16
|
735
|
Chris@16
|
736 reference operator[]( size_type n )
|
Chris@16
|
737 {
|
Chris@16
|
738 BOOST_ASSERT( n < size_ );
|
Chris@16
|
739 return buffer_[n];
|
Chris@16
|
740 }
|
Chris@16
|
741
|
Chris@16
|
742 optimized_const_reference operator[]( size_type n ) const
|
Chris@16
|
743 {
|
Chris@16
|
744 BOOST_ASSERT( n < size_ );
|
Chris@16
|
745 return buffer_[n];
|
Chris@16
|
746 }
|
Chris@16
|
747
|
Chris@16
|
748 void unchecked_push_back()
|
Chris@16
|
749 {
|
Chris@16
|
750 BOOST_ASSERT( !full() );
|
Chris@16
|
751 new (buffer_ + size_) T;
|
Chris@16
|
752 ++size_;
|
Chris@16
|
753 }
|
Chris@16
|
754
|
Chris@16
|
755 void unchecked_push_back_n( size_type n )
|
Chris@16
|
756 {
|
Chris@16
|
757 BOOST_ASSERT( size_ + n <= members_.capacity_ );
|
Chris@16
|
758 unchecked_push_back_n( n, boost::has_trivial_assign<T>() );
|
Chris@16
|
759 }
|
Chris@16
|
760
|
Chris@16
|
761 void unchecked_push_back( optimized_const_reference x ) // non-growing
|
Chris@16
|
762 {
|
Chris@16
|
763 BOOST_ASSERT( !full() );
|
Chris@16
|
764 new (buffer_ + size_) T( x );
|
Chris@16
|
765 ++size_;
|
Chris@16
|
766 }
|
Chris@16
|
767
|
Chris@16
|
768 template< class ForwardIterator >
|
Chris@16
|
769 void unchecked_push_back( ForwardIterator begin_arg,
|
Chris@16
|
770 ForwardIterator end_arg ) // non-growing
|
Chris@16
|
771 {
|
Chris@16
|
772 BOOST_ASSERT( size_ + std::distance(begin_arg, end_arg) <= members_.capacity_ );
|
Chris@16
|
773 copy_impl( begin_arg, end_arg, buffer_ + size_ );
|
Chris@16
|
774 size_ += std::distance(begin_arg, end_arg);
|
Chris@16
|
775 }
|
Chris@16
|
776
|
Chris@16
|
777 void reserve_precisely( size_type n )
|
Chris@16
|
778 {
|
Chris@16
|
779 BOOST_ASSERT( members_.capacity_ >= N );
|
Chris@16
|
780
|
Chris@16
|
781 if( n <= members_.capacity_ )
|
Chris@16
|
782 return;
|
Chris@16
|
783 reserve_impl( n );
|
Chris@16
|
784 BOOST_ASSERT( members_.capacity_ == n );
|
Chris@16
|
785 }
|
Chris@16
|
786
|
Chris@16
|
787 void reserve( size_type n ) // strong
|
Chris@16
|
788 {
|
Chris@16
|
789 BOOST_ASSERT( members_.capacity_ >= N );
|
Chris@16
|
790
|
Chris@16
|
791 if( n <= members_.capacity_ )
|
Chris@16
|
792 return;
|
Chris@16
|
793
|
Chris@16
|
794 reserve_impl( new_capacity_impl( n ) );
|
Chris@16
|
795 BOOST_ASSERT( members_.capacity_ >= n );
|
Chris@16
|
796 }
|
Chris@16
|
797
|
Chris@16
|
798 void push_back()
|
Chris@16
|
799 {
|
Chris@16
|
800 if( size_ != members_.capacity_ )
|
Chris@16
|
801 {
|
Chris@16
|
802 unchecked_push_back();
|
Chris@16
|
803 }
|
Chris@16
|
804 else
|
Chris@16
|
805 {
|
Chris@16
|
806 reserve( size_ + 1u );
|
Chris@16
|
807 unchecked_push_back();
|
Chris@16
|
808 }
|
Chris@16
|
809 }
|
Chris@16
|
810
|
Chris@16
|
811 void push_back( optimized_const_reference x )
|
Chris@16
|
812 {
|
Chris@16
|
813 if( size_ != members_.capacity_ )
|
Chris@16
|
814 {
|
Chris@16
|
815 unchecked_push_back( x );
|
Chris@16
|
816 }
|
Chris@16
|
817 else
|
Chris@16
|
818 {
|
Chris@16
|
819 reserve( size_ + 1u );
|
Chris@16
|
820 unchecked_push_back( x );
|
Chris@16
|
821 }
|
Chris@16
|
822 }
|
Chris@16
|
823
|
Chris@16
|
824 template< class ForwardIterator >
|
Chris@16
|
825 void push_back( ForwardIterator begin_arg, ForwardIterator end_arg )
|
Chris@16
|
826 {
|
Chris@16
|
827 difference_type diff = std::distance(begin_arg, end_arg);
|
Chris@16
|
828 if( size_ + diff > members_.capacity_ )
|
Chris@16
|
829 reserve( size_ + diff );
|
Chris@16
|
830 unchecked_push_back( begin_arg, end_arg );
|
Chris@16
|
831 }
|
Chris@16
|
832
|
Chris@16
|
833 iterator insert( const_iterator before, optimized_const_reference x ) // basic
|
Chris@16
|
834 {
|
Chris@16
|
835 // @todo: consider if we want to support x in 'this'
|
Chris@16
|
836 if( size_ < members_.capacity_ )
|
Chris@16
|
837 {
|
Chris@16
|
838 bool is_back_insertion = before == cend();
|
Chris@16
|
839 iterator where = const_cast<T*>(before);
|
Chris@16
|
840
|
Chris@16
|
841 if( !is_back_insertion )
|
Chris@16
|
842 {
|
Chris@16
|
843 grow_back_one();
|
Chris@16
|
844 std::copy( before, cend() - 1u, where + 1u );
|
Chris@16
|
845 *where = x;
|
Chris@16
|
846 BOOST_ASSERT( is_valid() );
|
Chris@16
|
847 }
|
Chris@16
|
848 else
|
Chris@16
|
849 {
|
Chris@16
|
850 unchecked_push_back( x );
|
Chris@16
|
851 }
|
Chris@16
|
852 return where;
|
Chris@16
|
853 }
|
Chris@16
|
854
|
Chris@16
|
855 auto_buffer temp( new_capacity_impl( size_ + 1u ) );
|
Chris@16
|
856 temp.unchecked_push_back( cbegin(), before );
|
Chris@16
|
857 iterator result = temp.end();
|
Chris@16
|
858 temp.unchecked_push_back( x );
|
Chris@16
|
859 temp.unchecked_push_back( before, cend() );
|
Chris@16
|
860 one_sided_swap( temp );
|
Chris@16
|
861 BOOST_ASSERT( is_valid() );
|
Chris@16
|
862 return result;
|
Chris@16
|
863 }
|
Chris@16
|
864
|
Chris@16
|
865 void insert( const_iterator before, size_type n,
|
Chris@16
|
866 optimized_const_reference x )
|
Chris@16
|
867 {
|
Chris@16
|
868 // @todo: see problems above
|
Chris@16
|
869 if( size_ + n <= members_.capacity_ )
|
Chris@16
|
870 {
|
Chris@16
|
871 grow_back( n );
|
Chris@16
|
872 iterator where = const_cast<T*>(before);
|
Chris@16
|
873 std::copy( before, cend() - n, where + n );
|
Chris@16
|
874 std::fill( where, where + n, x );
|
Chris@16
|
875 BOOST_ASSERT( is_valid() );
|
Chris@16
|
876 return;
|
Chris@16
|
877 }
|
Chris@16
|
878
|
Chris@16
|
879 auto_buffer temp( new_capacity_impl( size_ + n ) );
|
Chris@16
|
880 temp.unchecked_push_back( cbegin(), before );
|
Chris@16
|
881 std::uninitialized_fill_n( temp.end(), n, x );
|
Chris@16
|
882 temp.size_ += n;
|
Chris@16
|
883 temp.unchecked_push_back( before, cend() );
|
Chris@16
|
884 one_sided_swap( temp );
|
Chris@16
|
885 BOOST_ASSERT( is_valid() );
|
Chris@16
|
886 }
|
Chris@16
|
887
|
Chris@16
|
888 template< class ForwardIterator >
|
Chris@16
|
889 void insert( const_iterator before,
|
Chris@16
|
890 ForwardIterator begin_arg, ForwardIterator end_arg ) // basic
|
Chris@16
|
891 {
|
Chris@16
|
892 typedef typename std::iterator_traits<ForwardIterator>
|
Chris@16
|
893 ::iterator_category category;
|
Chris@16
|
894 insert_impl( before, begin_arg, end_arg, category() );
|
Chris@16
|
895 }
|
Chris@16
|
896
|
Chris@16
|
897 void pop_back()
|
Chris@16
|
898 {
|
Chris@16
|
899 BOOST_ASSERT( !empty() );
|
Chris@16
|
900 auto_buffer_destroy( buffer_ + size_ - 1, boost::has_trivial_destructor<T>() );
|
Chris@16
|
901 --size_;
|
Chris@16
|
902 }
|
Chris@16
|
903
|
Chris@16
|
904 void pop_back_n( size_type n )
|
Chris@16
|
905 {
|
Chris@16
|
906 BOOST_ASSERT( n <= size_ );
|
Chris@16
|
907 if( n )
|
Chris@16
|
908 {
|
Chris@16
|
909 destroy_back_n( n );
|
Chris@16
|
910 size_ -= n;
|
Chris@16
|
911 }
|
Chris@16
|
912 }
|
Chris@16
|
913
|
Chris@16
|
914 void clear()
|
Chris@16
|
915 {
|
Chris@16
|
916 pop_back_n( size_ );
|
Chris@16
|
917 }
|
Chris@16
|
918
|
Chris@16
|
919 iterator erase( const_iterator where )
|
Chris@16
|
920 {
|
Chris@16
|
921 BOOST_ASSERT( !empty() );
|
Chris@16
|
922 BOOST_ASSERT( cbegin() <= where );
|
Chris@16
|
923 BOOST_ASSERT( cend() > where );
|
Chris@16
|
924
|
Chris@16
|
925 unsigned elements = cend() - where - 1u;
|
Chris@16
|
926
|
Chris@16
|
927 if( elements > 0u )
|
Chris@16
|
928 {
|
Chris@16
|
929 const_iterator start = where + 1u;
|
Chris@16
|
930 std::copy( start, start + elements,
|
Chris@16
|
931 const_cast<T*>(where) );
|
Chris@16
|
932 }
|
Chris@16
|
933 pop_back();
|
Chris@16
|
934 BOOST_ASSERT( !full() );
|
Chris@16
|
935 iterator result = const_cast<T*>( where );
|
Chris@16
|
936 BOOST_ASSERT( result <= end() );
|
Chris@16
|
937 return result;
|
Chris@16
|
938 }
|
Chris@16
|
939
|
Chris@16
|
940 iterator erase( const_iterator from, const_iterator to )
|
Chris@16
|
941 {
|
Chris@16
|
942 BOOST_ASSERT( !(std::distance(from,to)>0) ||
|
Chris@16
|
943 !empty() );
|
Chris@16
|
944 BOOST_ASSERT( cbegin() <= from );
|
Chris@16
|
945 BOOST_ASSERT( cend() >= to );
|
Chris@16
|
946
|
Chris@16
|
947 unsigned elements = std::distance(to,cend());
|
Chris@16
|
948
|
Chris@16
|
949 if( elements > 0u )
|
Chris@16
|
950 {
|
Chris@16
|
951 BOOST_ASSERT( elements > 0u );
|
Chris@16
|
952 std::copy( to, to + elements,
|
Chris@16
|
953 const_cast<T*>(from) );
|
Chris@16
|
954 }
|
Chris@16
|
955 pop_back_n( std::distance(from,to) );
|
Chris@16
|
956 BOOST_ASSERT( !full() );
|
Chris@16
|
957 iterator result = const_cast<T*>( from );
|
Chris@16
|
958 BOOST_ASSERT( result <= end() );
|
Chris@16
|
959 return result;
|
Chris@16
|
960 }
|
Chris@16
|
961
|
Chris@16
|
962 void shrink_to_fit()
|
Chris@16
|
963 {
|
Chris@16
|
964 if( is_on_stack() || !GrowPolicy::should_shrink(size_,members_.capacity_) )
|
Chris@16
|
965 return;
|
Chris@16
|
966
|
Chris@16
|
967 reserve_impl( size_ );
|
Chris@16
|
968 members_.capacity_ = (std::max)(size_type(N),members_.capacity_);
|
Chris@16
|
969 BOOST_ASSERT( is_on_stack() || size_ == members_.capacity_ );
|
Chris@16
|
970 BOOST_ASSERT( !is_on_stack() || size_ <= members_.capacity_ );
|
Chris@16
|
971 }
|
Chris@16
|
972
|
Chris@16
|
973 pointer uninitialized_grow( size_type n ) // strong
|
Chris@16
|
974 {
|
Chris@16
|
975 if( size_ + n <= members_.capacity_ )
|
Chris@16
|
976 reserve( size_ + n );
|
Chris@16
|
977
|
Chris@16
|
978 pointer res = end();
|
Chris@16
|
979 size_ += n;
|
Chris@16
|
980 return res;
|
Chris@16
|
981 }
|
Chris@16
|
982
|
Chris@16
|
983 void uninitialized_shrink( size_type n ) // nothrow
|
Chris@16
|
984 {
|
Chris@16
|
985 // @remark: test for wrap-around
|
Chris@16
|
986 BOOST_ASSERT( size_ - n <= members_.capacity_ );
|
Chris@16
|
987 size_ -= n;
|
Chris@16
|
988 }
|
Chris@16
|
989
|
Chris@16
|
990 void uninitialized_resize( size_type n )
|
Chris@16
|
991 {
|
Chris@16
|
992 if( n > size() )
|
Chris@16
|
993 uninitialized_grow( n - size() );
|
Chris@16
|
994 else if( n < size() )
|
Chris@16
|
995 uninitialized_shrink( size() - n );
|
Chris@16
|
996
|
Chris@16
|
997 BOOST_ASSERT( size() == n );
|
Chris@16
|
998 }
|
Chris@16
|
999
|
Chris@16
|
1000 // nothrow - if both buffer are on the heap, or
|
Chris@16
|
1001 // - if one buffer is on the heap and one has
|
Chris@16
|
1002 // 'has_allocated_buffer() == false', or
|
Chris@16
|
1003 // - if copy-construction cannot throw
|
Chris@16
|
1004 // basic - otherwise (better guarantee impossible)
|
Chris@16
|
1005 // requirement: the allocator must be no-throw-swappable
|
Chris@16
|
1006 void swap( auto_buffer& r )
|
Chris@16
|
1007 {
|
Chris@16
|
1008 bool on_stack = is_on_stack();
|
Chris@16
|
1009 bool r_on_stack = r.is_on_stack();
|
Chris@16
|
1010 bool both_on_heap = !on_stack && !r_on_stack;
|
Chris@16
|
1011 if( both_on_heap )
|
Chris@16
|
1012 {
|
Chris@16
|
1013 boost::swap( get_allocator(), r.get_allocator() );
|
Chris@16
|
1014 boost::swap( members_.capacity_, r.members_.capacity_ );
|
Chris@16
|
1015 boost::swap( buffer_, r.buffer_ );
|
Chris@16
|
1016 boost::swap( size_, r.size_ );
|
Chris@16
|
1017 BOOST_ASSERT( is_valid() );
|
Chris@16
|
1018 BOOST_ASSERT( r.is_valid() );
|
Chris@16
|
1019 return;
|
Chris@16
|
1020 }
|
Chris@16
|
1021
|
Chris@16
|
1022 BOOST_ASSERT( on_stack || r_on_stack );
|
Chris@16
|
1023 bool exactly_one_on_stack = (on_stack && !r_on_stack) ||
|
Chris@16
|
1024 (!on_stack && r_on_stack);
|
Chris@16
|
1025
|
Chris@16
|
1026 //
|
Chris@16
|
1027 // Remark: we now know that we can copy into
|
Chris@16
|
1028 // the unused stack buffer.
|
Chris@16
|
1029 //
|
Chris@16
|
1030 if( exactly_one_on_stack )
|
Chris@16
|
1031 {
|
Chris@16
|
1032 auto_buffer* one_on_stack = on_stack ? this : &r;
|
Chris@16
|
1033 auto_buffer* other = on_stack ? &r : this;
|
Chris@16
|
1034 pointer new_buffer = static_cast<T*>(other->members_.address());
|
Chris@16
|
1035 copy_impl( one_on_stack->begin(), one_on_stack->end(),
|
Chris@16
|
1036 new_buffer ); // strong
|
Chris@16
|
1037 one_on_stack->~auto_buffer(); // nothrow
|
Chris@16
|
1038 boost::swap( get_allocator(), r.get_allocator() ); // assume nothrow
|
Chris@16
|
1039 boost::swap( members_.capacity_, r.members_.capacity_ );
|
Chris@16
|
1040 boost::swap( size_, r.size_ );
|
Chris@16
|
1041 one_on_stack->buffer_ = other->buffer_;
|
Chris@16
|
1042 other->buffer_ = new_buffer;
|
Chris@16
|
1043 BOOST_ASSERT( other->is_on_stack() );
|
Chris@16
|
1044 BOOST_ASSERT( !one_on_stack->is_on_stack() );
|
Chris@16
|
1045 BOOST_ASSERT( is_valid() );
|
Chris@16
|
1046 BOOST_ASSERT( r.is_valid() );
|
Chris@16
|
1047 return;
|
Chris@16
|
1048 }
|
Chris@16
|
1049
|
Chris@16
|
1050 BOOST_ASSERT( on_stack && r_on_stack );
|
Chris@16
|
1051 swap_helper( *this, r, boost::has_trivial_assign<T>() );
|
Chris@16
|
1052 BOOST_ASSERT( is_valid() );
|
Chris@16
|
1053 BOOST_ASSERT( r.is_valid() );
|
Chris@16
|
1054 }
|
Chris@16
|
1055
|
Chris@16
|
1056 private:
|
Chris@16
|
1057 typedef boost::aligned_storage< N * sizeof(T),
|
Chris@16
|
1058 boost::alignment_of<T>::value >
|
Chris@16
|
1059 storage;
|
Chris@16
|
1060
|
Chris@16
|
1061 struct members_type : storage /* to enable EBO */
|
Chris@16
|
1062 {
|
Chris@16
|
1063 size_type capacity_;
|
Chris@16
|
1064
|
Chris@16
|
1065 members_type( size_type capacity )
|
Chris@16
|
1066 : capacity_(capacity)
|
Chris@16
|
1067 { }
|
Chris@16
|
1068
|
Chris@16
|
1069 void* address() const
|
Chris@16
|
1070 { return const_cast<storage&>(static_cast<const storage&>(*this)).address(); }
|
Chris@16
|
1071 };
|
Chris@16
|
1072
|
Chris@16
|
1073 members_type members_;
|
Chris@16
|
1074 pointer buffer_;
|
Chris@16
|
1075 size_type size_;
|
Chris@16
|
1076
|
Chris@16
|
1077 };
|
Chris@16
|
1078
|
Chris@16
|
1079 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1080 inline void swap( auto_buffer<T,SBP,GP,A>& l, auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1081 {
|
Chris@16
|
1082 l.swap( r );
|
Chris@16
|
1083 }
|
Chris@16
|
1084
|
Chris@16
|
1085 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1086 inline bool operator==( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1087 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1088 {
|
Chris@16
|
1089 if( l.size() != r.size() )
|
Chris@16
|
1090 return false;
|
Chris@16
|
1091 return std::equal( l.begin(), l.end(), r.begin() );
|
Chris@16
|
1092 }
|
Chris@16
|
1093
|
Chris@16
|
1094 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1095 inline bool operator!=( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1096 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1097 {
|
Chris@16
|
1098 return !(l == r);
|
Chris@16
|
1099 }
|
Chris@16
|
1100
|
Chris@16
|
1101 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1102 inline bool operator<( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1103 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1104 {
|
Chris@16
|
1105 return std::lexicographical_compare( l.begin(), l.end(),
|
Chris@16
|
1106 r.begin(), r.end() );
|
Chris@16
|
1107 }
|
Chris@16
|
1108
|
Chris@16
|
1109 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1110 inline bool operator>( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1111 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1112 {
|
Chris@16
|
1113 return (r < l);
|
Chris@16
|
1114 }
|
Chris@16
|
1115
|
Chris@16
|
1116 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1117 inline bool operator<=( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1118 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1119 {
|
Chris@16
|
1120 return !(r > l);
|
Chris@16
|
1121 }
|
Chris@16
|
1122
|
Chris@16
|
1123 template< class T, class SBP, class GP, class A >
|
Chris@16
|
1124 inline bool operator>=( const auto_buffer<T,SBP,GP,A>& l,
|
Chris@16
|
1125 const auto_buffer<T,SBP,GP,A>& r )
|
Chris@16
|
1126 {
|
Chris@16
|
1127 return !(l < r);
|
Chris@16
|
1128 }
|
Chris@16
|
1129
|
Chris@16
|
1130 } // namespace detail
|
Chris@16
|
1131 } // namespace signals2
|
Chris@16
|
1132 }
|
Chris@16
|
1133
|
Chris@16
|
1134 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
|
Chris@16
|
1135 #pragma warning(pop)
|
Chris@16
|
1136 #endif
|
Chris@16
|
1137
|
Chris@16
|
1138 #endif
|