File indexing completed on 2025-01-18 09:51:40
0001
0002
0003
0004
0005
0006 #ifndef BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
0007 #define BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
0008
0009 #include <boost/detail/workaround.hpp>
0010
0011 #if defined(_MSC_VER)
0012 # pragma once
0013 #endif
0014
0015 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0016 #pragma warning(push)
0017 #pragma warning(disable:4996)
0018 #endif
0019
0020 #include <boost/assert.hpp>
0021 #include <boost/config.hpp>
0022 #include <boost/core/allocator_access.hpp>
0023 #include <boost/core/invoke_swap.hpp>
0024 #include <boost/iterator/reverse_iterator.hpp>
0025 #include <boost/iterator/iterator_traits.hpp>
0026 #include <boost/mpl/if.hpp>
0027 #include <boost/signals2/detail/scope_guard.hpp>
0028 #include <boost/type_traits/aligned_storage.hpp>
0029 #include <boost/type_traits/alignment_of.hpp>
0030 #include <boost/type_traits/has_nothrow_copy.hpp>
0031 #include <boost/type_traits/has_nothrow_assign.hpp>
0032 #include <boost/type_traits/has_trivial_assign.hpp>
0033 #include <boost/type_traits/has_trivial_constructor.hpp>
0034 #include <boost/type_traits/has_trivial_destructor.hpp>
0035 #include <algorithm>
0036 #include <cstring>
0037 #include <iterator>
0038 #include <memory>
0039 #include <stdexcept>
0040
0041 namespace boost
0042 {
0043 namespace signals2
0044 {
0045 namespace detail
0046 {
0047
0048
0049
0050 template< unsigned N >
0051 struct store_n_objects
0052 {
0053 BOOST_STATIC_CONSTANT( unsigned, value = N );
0054 };
0055
0056 template< unsigned N >
0057 struct store_n_bytes
0058 {
0059 BOOST_STATIC_CONSTANT( unsigned, value = N );
0060 };
0061
0062 namespace auto_buffer_detail
0063 {
0064 template< class Policy, class T >
0065 struct compute_buffer_size
0066 {
0067 BOOST_STATIC_CONSTANT( unsigned, value = Policy::value * sizeof(T) );
0068 };
0069
0070 template< unsigned N, class T >
0071 struct compute_buffer_size< store_n_bytes<N>, T >
0072 {
0073 BOOST_STATIC_CONSTANT( unsigned, value = N );
0074 };
0075
0076 template< class Policy, class T >
0077 struct compute_buffer_objects
0078 {
0079 BOOST_STATIC_CONSTANT( unsigned, value = Policy::value );
0080 };
0081
0082 template< unsigned N, class T >
0083 struct compute_buffer_objects< store_n_bytes<N>, T >
0084 {
0085 BOOST_STATIC_CONSTANT( unsigned, value = N / sizeof(T) );
0086 };
0087 }
0088
0089 struct default_grow_policy
0090 {
0091 template< class SizeType >
0092 static SizeType new_capacity( SizeType capacity )
0093 {
0094
0095
0096
0097
0098
0099 return capacity * 4u;
0100 }
0101
0102 template< class SizeType >
0103 static bool should_shrink( SizeType, SizeType )
0104 {
0105
0106
0107
0108
0109
0110
0111 return true;
0112 }
0113 };
0114
0115 template< class T,
0116 class StackBufferPolicy = store_n_objects<256>,
0117 class GrowPolicy = default_grow_policy,
0118 class Allocator = std::allocator<T> >
0119 class auto_buffer;
0120
0121
0122
0123 template
0124 <
0125 class T,
0126 class StackBufferPolicy,
0127 class GrowPolicy,
0128 class Allocator
0129 >
0130 class auto_buffer : Allocator
0131 {
0132 private:
0133 enum { N = auto_buffer_detail::
0134 compute_buffer_objects<StackBufferPolicy,T>::value };
0135
0136 BOOST_STATIC_CONSTANT( bool, is_stack_buffer_empty = N == 0u );
0137
0138 typedef auto_buffer<T, store_n_objects<0>, GrowPolicy, Allocator>
0139 local_buffer;
0140
0141 public:
0142 typedef Allocator allocator_type;
0143 typedef T value_type;
0144 typedef typename boost::allocator_size_type<Allocator>::type size_type;
0145 typedef typename boost::allocator_difference_type<Allocator>::type difference_type;
0146 typedef T* pointer;
0147 typedef typename boost::allocator_pointer<Allocator>::type allocator_pointer;
0148 typedef const T* const_pointer;
0149 typedef T& reference;
0150 typedef const T& const_reference;
0151 typedef pointer iterator;
0152 typedef const_pointer const_iterator;
0153 typedef boost::reverse_iterator<iterator> reverse_iterator;
0154 typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
0155 typedef typename boost::mpl::if_c< boost::has_trivial_assign<T>::value
0156 && sizeof(T) <= sizeof(long double),
0157 const value_type,
0158 const_reference >::type
0159 optimized_const_reference;
0160 private:
0161
0162 pointer allocate( size_type capacity_arg )
0163 {
0164 if( capacity_arg > N )
0165 return &*get_allocator().allocate( capacity_arg );
0166 else
0167 return static_cast<T*>( members_.address() );
0168 }
0169
0170 void deallocate( pointer where, size_type capacity_arg )
0171 {
0172 if( capacity_arg <= N )
0173 return;
0174 get_allocator().deallocate( allocator_pointer(where), capacity_arg );
0175 }
0176
0177 template< class I >
0178 static void copy_impl( I begin, I end, pointer where, std::random_access_iterator_tag )
0179 {
0180 copy_rai( begin, end, where, boost::has_trivial_assign<T>() );
0181 }
0182
0183 static void copy_rai( const T* begin, const T* end,
0184 pointer where, const boost::true_type& )
0185 {
0186 std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
0187 }
0188
0189 template< class I, bool b >
0190 static void copy_rai( I begin, I end,
0191 pointer where, const boost::integral_constant<bool, b>& )
0192 {
0193 std::uninitialized_copy( begin, end, where );
0194 }
0195
0196 template< class I >
0197 static void copy_impl( I begin, I end, pointer where, std::bidirectional_iterator_tag )
0198 {
0199 std::uninitialized_copy( begin, end, where );
0200 }
0201
0202 template< class I >
0203 static void copy_impl( I begin, I end, pointer where )
0204 {
0205 copy_impl( begin, end, where,
0206 typename std::iterator_traits<I>::iterator_category() );
0207 }
0208
0209 template< class I, class I2 >
0210 static void assign_impl( I begin, I end, I2 where )
0211 {
0212 assign_impl( begin, end, where, boost::has_trivial_assign<T>() );
0213 }
0214
0215 template< class I, class I2 >
0216 static void assign_impl( I begin, I end, I2 where, const boost::true_type& )
0217 {
0218 std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
0219 }
0220
0221 template< class I, class I2 >
0222 static void assign_impl( I begin, I end, I2 where, const boost::false_type& )
0223 {
0224 for( ; begin != end; ++begin, ++where )
0225 *where = *begin;
0226 }
0227
0228 void unchecked_push_back_n( size_type n, const boost::true_type& )
0229 {
0230 std::uninitialized_fill( end(), end() + n, T() );
0231 size_ += n;
0232 }
0233
0234 void unchecked_push_back_n( size_type n, const boost::false_type& )
0235 {
0236 for( size_type i = 0u; i < n; ++i )
0237 unchecked_push_back();
0238 }
0239
0240 void auto_buffer_destroy( pointer where, const boost::false_type& )
0241 {
0242 (*where).~T();
0243 }
0244
0245 void auto_buffer_destroy( pointer, const boost::true_type& )
0246 { }
0247
0248 void auto_buffer_destroy( pointer where )
0249 {
0250 auto_buffer_destroy( where, boost::has_trivial_destructor<T>() );
0251 }
0252
0253 void auto_buffer_destroy()
0254 {
0255 BOOST_ASSERT( is_valid() );
0256 if( buffer_ )
0257
0258 auto_buffer_destroy( boost::has_trivial_destructor<T>() );
0259 }
0260
0261 void destroy_back_n( size_type n, const boost::false_type& )
0262 {
0263 BOOST_ASSERT( n > 0 );
0264 pointer buffer = buffer_ + size_ - 1u;
0265 pointer new_end = buffer - n;
0266 for( ; buffer > new_end; --buffer )
0267 auto_buffer_destroy( buffer );
0268 }
0269
0270 void destroy_back_n( size_type, const boost::true_type& )
0271 { }
0272
0273 void destroy_back_n( size_type n )
0274 {
0275 destroy_back_n( n, boost::has_trivial_destructor<T>() );
0276 }
0277
0278 void auto_buffer_destroy( const boost::false_type& x )
0279 {
0280 if( size_ )
0281 destroy_back_n( size_, x );
0282 deallocate( buffer_, members_.capacity_ );
0283 }
0284
0285 void auto_buffer_destroy( const boost::true_type& )
0286 {
0287 deallocate( buffer_, members_.capacity_ );
0288 }
0289
0290 pointer move_to_new_buffer( size_type new_capacity, const boost::false_type& )
0291 {
0292 pointer new_buffer = allocate( new_capacity );
0293 scope_guard guard = make_obj_guard( *this,
0294 &auto_buffer::deallocate,
0295 new_buffer,
0296 new_capacity );
0297 copy_impl( begin(), end(), new_buffer );
0298 guard.dismiss();
0299 return new_buffer;
0300 }
0301
0302 pointer move_to_new_buffer( size_type new_capacity, const boost::true_type& )
0303 {
0304 pointer new_buffer = allocate( new_capacity );
0305 copy_impl( begin(), end(), new_buffer );
0306 return new_buffer;
0307 }
0308
0309 void reserve_impl( size_type new_capacity )
0310 {
0311 pointer new_buffer = move_to_new_buffer( new_capacity,
0312 boost::has_nothrow_copy<T>() );
0313 auto_buffer_destroy();
0314 buffer_ = new_buffer;
0315 members_.capacity_ = new_capacity;
0316 BOOST_ASSERT( size_ <= members_.capacity_ );
0317 }
0318
0319 size_type new_capacity_impl( size_type n )
0320 {
0321 BOOST_ASSERT( n > members_.capacity_ );
0322 size_type new_capacity = GrowPolicy::new_capacity( members_.capacity_ );
0323
0324 return (std::max)(new_capacity,n);
0325 }
0326
0327 static void swap_helper( auto_buffer& l, auto_buffer& r,
0328 const boost::true_type& )
0329 {
0330 BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
0331
0332 auto_buffer temp( l.begin(), l.end() );
0333 assign_impl( r.begin(), r.end(), l.begin() );
0334 assign_impl( temp.begin(), temp.end(), r.begin() );
0335 boost::core::invoke_swap( l.size_, r.size_ );
0336 boost::core::invoke_swap( l.members_.capacity_, r.members_.capacity_ );
0337 }
0338
0339 static void swap_helper( auto_buffer& l, auto_buffer& r,
0340 const boost::false_type& )
0341 {
0342 BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
0343 size_type min_size = (std::min)(l.size_,r.size_);
0344 size_type max_size = (std::max)(l.size_,r.size_);
0345 size_type diff = max_size - min_size;
0346 auto_buffer* smallest = l.size_ == min_size ? &l : &r;
0347 auto_buffer* largest = smallest == &l ? &r : &l;
0348
0349
0350
0351
0352
0353 size_type i = 0u;
0354 for( ; i < min_size; ++i )
0355 boost::core::invoke_swap( (*smallest)[i], (*largest)[i] );
0356
0357 for( ; i < max_size; ++i )
0358 smallest->unchecked_push_back( (*largest)[i] );
0359
0360 largest->pop_back_n( diff );
0361 boost::core::invoke_swap( l.members_.capacity_, r.members_.capacity_ );
0362 }
0363
0364 void one_sided_swap( auto_buffer& temp )
0365 {
0366 BOOST_ASSERT( !temp.is_on_stack() );
0367 auto_buffer_destroy();
0368
0369 get_allocator() = temp.get_allocator();
0370 members_.capacity_ = temp.members_.capacity_;
0371 buffer_ = temp.buffer_;
0372 BOOST_ASSERT( temp.size_ >= size_ + 1u );
0373 size_ = temp.size_;
0374 temp.buffer_ = 0;
0375 BOOST_ASSERT( temp.is_valid() );
0376 }
0377
0378 template< class I >
0379 void insert_impl( const_iterator before, I begin_arg, I end_arg,
0380 std::input_iterator_tag )
0381 {
0382 for( ; begin_arg != end_arg; ++begin_arg )
0383 {
0384 before = insert( before, *begin_arg );
0385 ++before;
0386 }
0387 }
0388
0389 void grow_back( size_type n, const boost::true_type& )
0390 {
0391 BOOST_ASSERT( size_ + n <= members_.capacity_ );
0392 size_ += n;
0393 }
0394
0395 void grow_back( size_type n, const boost::false_type& )
0396 {
0397 unchecked_push_back_n(n);
0398 }
0399
0400 void grow_back( size_type n )
0401 {
0402 grow_back( n, boost::has_trivial_constructor<T>() );
0403 }
0404
0405 void grow_back_one( const boost::true_type& )
0406 {
0407 BOOST_ASSERT( size_ + 1 <= members_.capacity_ );
0408 size_ += 1;
0409 }
0410
0411 void grow_back_one( const boost::false_type& )
0412 {
0413 unchecked_push_back();
0414 }
0415
0416 void grow_back_one()
0417 {
0418 grow_back_one( boost::has_trivial_constructor<T>() );
0419 }
0420
0421 template< class I >
0422 void insert_impl( const_iterator before, I begin_arg, I end_arg,
0423 std::forward_iterator_tag )
0424 {
0425 difference_type n = std::distance(begin_arg, end_arg);
0426
0427 if( size_ + n <= members_.capacity_ )
0428 {
0429 bool is_back_insertion = before == cend();
0430 if( !is_back_insertion )
0431 {
0432 grow_back( n );
0433 iterator where = const_cast<T*>(before);
0434 std::copy( before, cend() - n, where + n );
0435 assign_impl( begin_arg, end_arg, where );
0436 }
0437 else
0438 {
0439 unchecked_push_back( begin_arg, end_arg );
0440 }
0441 BOOST_ASSERT( is_valid() );
0442 return;
0443 }
0444
0445 auto_buffer temp( new_capacity_impl( size_ + n ) );
0446 temp.unchecked_push_back( cbegin(), before );
0447 temp.unchecked_push_back( begin_arg, end_arg );
0448 temp.unchecked_push_back( before, cend() );
0449 one_sided_swap( temp );
0450 BOOST_ASSERT( is_valid() );
0451 }
0452
0453 public:
0454 bool is_valid() const
0455 {
0456
0457
0458
0459 if( buffer_ == 0 )
0460 return true;
0461
0462 if( members_.capacity_ < N )
0463 return false;
0464
0465 if( !is_on_stack() && members_.capacity_ <= N )
0466 return false;
0467
0468 if( buffer_ == members_.address() )
0469 if( members_.capacity_ > N )
0470 return false;
0471
0472 if( size_ > members_.capacity_ )
0473 return false;
0474
0475 return true;
0476 }
0477
0478 auto_buffer()
0479 : members_( N ),
0480 buffer_( static_cast<T*>(members_.address()) ),
0481 size_( 0u )
0482 {
0483 BOOST_ASSERT( is_valid() );
0484 }
0485
0486 auto_buffer( const auto_buffer& r )
0487 : members_( (std::max)(r.size_,size_type(N)) ),
0488 buffer_( allocate( members_.capacity_ ) ),
0489 size_( 0 )
0490 {
0491 copy_impl( r.begin(), r.end(), buffer_ );
0492 size_ = r.size_;
0493 BOOST_ASSERT( is_valid() );
0494 }
0495
0496 auto_buffer& operator=( const auto_buffer& r )
0497 {
0498 if( this == &r )
0499 return *this;
0500
0501 difference_type diff = size_ - r.size_;
0502 if( diff >= 0 )
0503 {
0504 pop_back_n( static_cast<size_type>(diff) );
0505 assign_impl( r.begin(), r.end(), begin() );
0506 }
0507 else
0508 {
0509 if( members_.capacity_ >= r.size() )
0510 {
0511 unchecked_push_back_n( static_cast<size_type>(-diff) );
0512 assign_impl( r.begin(), r.end(), begin() );
0513 }
0514 else
0515 {
0516
0517
0518 auto_buffer_destroy();
0519 buffer_ = 0;
0520 pointer new_buffer = allocate( r.size() );
0521 scope_guard guard = make_obj_guard( *this,
0522 &auto_buffer::deallocate,
0523 new_buffer,
0524 r.size() );
0525 copy_impl( r.begin(), r.end(), new_buffer );
0526 guard.dismiss();
0527 buffer_ = new_buffer;
0528 members_.capacity_ = r.size();
0529 size_ = members_.capacity_;
0530 }
0531 }
0532
0533 BOOST_ASSERT( size() == r.size() );
0534 BOOST_ASSERT( is_valid() );
0535 return *this;
0536 }
0537
0538 explicit auto_buffer( size_type capacity_arg )
0539 : members_( (std::max)(capacity_arg, size_type(N)) ),
0540 buffer_( allocate(members_.capacity_) ),
0541 size_( 0 )
0542 {
0543 BOOST_ASSERT( is_valid() );
0544 }
0545
0546 auto_buffer( size_type size_arg, optimized_const_reference init_value )
0547 : members_( (std::max)(size_arg, size_type(N)) ),
0548 buffer_( allocate(members_.capacity_) ),
0549 size_( 0 )
0550 {
0551 std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
0552 size_ = size_arg;
0553 BOOST_ASSERT( is_valid() );
0554 }
0555
0556 auto_buffer( size_type capacity_arg, const allocator_type& a )
0557 : allocator_type( a ),
0558 members_( (std::max)(capacity_arg, size_type(N)) ),
0559 buffer_( allocate(members_.capacity_) ),
0560 size_( 0 )
0561 {
0562 BOOST_ASSERT( is_valid() );
0563 }
0564
0565 auto_buffer( size_type size_arg, optimized_const_reference init_value,
0566 const allocator_type& a )
0567 : allocator_type( a ),
0568 members_( (std::max)(size_arg, size_type(N)) ),
0569 buffer_( allocate(members_.capacity_) ),
0570 size_( 0 )
0571 {
0572 std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
0573 size_ = size_arg;
0574 BOOST_ASSERT( is_valid() );
0575 }
0576
0577 template< class ForwardIterator >
0578 auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg )
0579 :
0580 members_( std::distance(begin_arg, end_arg) ),
0581 buffer_( allocate(members_.capacity_) ),
0582 size_( 0 )
0583 {
0584 copy_impl( begin_arg, end_arg, buffer_ );
0585 size_ = members_.capacity_;
0586 if( members_.capacity_ < N )
0587 members_.capacity_ = N;
0588 BOOST_ASSERT( is_valid() );
0589 }
0590
0591 template< class ForwardIterator >
0592 auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg,
0593 const allocator_type& a )
0594 : allocator_type( a ),
0595 members_( std::distance(begin_arg, end_arg) ),
0596 buffer_( allocate(members_.capacity_) ),
0597 size_( 0 )
0598 {
0599 copy_impl( begin_arg, end_arg, buffer_ );
0600 size_ = members_.capacity_;
0601 if( members_.capacity_ < N )
0602 members_.capacity_ = N;
0603 BOOST_ASSERT( is_valid() );
0604 }
0605
0606 ~auto_buffer()
0607 {
0608 auto_buffer_destroy();
0609 }
0610
0611 public:
0612 bool empty() const
0613 {
0614 return size_ == 0;
0615 }
0616
0617 bool full() const
0618 {
0619 return size_ == members_.capacity_;
0620 }
0621
0622 bool is_on_stack() const
0623 {
0624 return members_.capacity_ <= N;
0625 }
0626
0627 size_type size() const
0628 {
0629 return size_;
0630 }
0631
0632 size_type capacity() const
0633 {
0634 return members_.capacity_;
0635 }
0636
0637 public:
0638 pointer data()
0639 {
0640 return buffer_;
0641 }
0642
0643 const_pointer data() const
0644 {
0645 return buffer_;
0646 }
0647
0648 allocator_type& get_allocator()
0649 {
0650 return static_cast<allocator_type&>(*this);
0651 }
0652
0653 const allocator_type& get_allocator() const
0654 {
0655 return static_cast<const allocator_type&>(*this);
0656 }
0657
0658 public:
0659 iterator begin()
0660 {
0661 return buffer_;
0662 }
0663
0664 const_iterator begin() const
0665 {
0666 return buffer_;
0667 }
0668
0669 iterator end()
0670 {
0671 return buffer_ + size_;
0672 }
0673
0674 const_iterator end() const
0675 {
0676 return buffer_ + size_;
0677 }
0678
0679 reverse_iterator rbegin()
0680 {
0681 return reverse_iterator(end());
0682 }
0683
0684 const_reverse_iterator rbegin() const
0685 {
0686 return const_reverse_iterator(end());
0687 }
0688
0689 reverse_iterator rend()
0690 {
0691 return reverse_iterator(begin());
0692 }
0693
0694 const_reverse_iterator rend() const
0695 {
0696 return const_reverse_iterator(begin());
0697 }
0698
0699 const_iterator cbegin() const
0700 {
0701 return const_cast<const auto_buffer*>(this)->begin();
0702 }
0703
0704 const_iterator cend() const
0705 {
0706 return const_cast<const auto_buffer*>(this)->end();
0707 }
0708
0709 const_reverse_iterator crbegin() const
0710 {
0711 return const_cast<const auto_buffer*>(this)->rbegin();
0712 }
0713
0714 const_reverse_iterator crend() const
0715 {
0716 return const_cast<const auto_buffer*>(this)->rend();
0717 }
0718
0719 public:
0720 reference front()
0721 {
0722 return buffer_[0];
0723 }
0724
0725 optimized_const_reference front() const
0726 {
0727 return buffer_[0];
0728 }
0729
0730 reference back()
0731 {
0732 return buffer_[size_-1];
0733 }
0734
0735 optimized_const_reference back() const
0736 {
0737 return buffer_[size_-1];
0738 }
0739
0740 reference operator[]( size_type n )
0741 {
0742 BOOST_ASSERT( n < size_ );
0743 return buffer_[n];
0744 }
0745
0746 optimized_const_reference operator[]( size_type n ) const
0747 {
0748 BOOST_ASSERT( n < size_ );
0749 return buffer_[n];
0750 }
0751
0752 void unchecked_push_back()
0753 {
0754 BOOST_ASSERT( !full() );
0755 new (buffer_ + size_) T;
0756 ++size_;
0757 }
0758
0759 void unchecked_push_back_n( size_type n )
0760 {
0761 BOOST_ASSERT( size_ + n <= members_.capacity_ );
0762 unchecked_push_back_n( n, boost::has_trivial_assign<T>() );
0763 }
0764
0765 void unchecked_push_back( optimized_const_reference x )
0766 {
0767 BOOST_ASSERT( !full() );
0768 new (buffer_ + size_) T( x );
0769 ++size_;
0770 }
0771
0772 template< class ForwardIterator >
0773 void unchecked_push_back( ForwardIterator begin_arg,
0774 ForwardIterator end_arg )
0775 {
0776 BOOST_ASSERT( size_ + std::distance(begin_arg, end_arg) <= members_.capacity_ );
0777 copy_impl( begin_arg, end_arg, buffer_ + size_ );
0778 size_ += std::distance(begin_arg, end_arg);
0779 }
0780
0781 void reserve_precisely( size_type n )
0782 {
0783 BOOST_ASSERT( members_.capacity_ >= N );
0784
0785 if( n <= members_.capacity_ )
0786 return;
0787 reserve_impl( n );
0788 BOOST_ASSERT( members_.capacity_ == n );
0789 }
0790
0791 void reserve( size_type n )
0792 {
0793 BOOST_ASSERT( members_.capacity_ >= N );
0794
0795 if( n <= members_.capacity_ )
0796 return;
0797
0798 reserve_impl( new_capacity_impl( n ) );
0799 BOOST_ASSERT( members_.capacity_ >= n );
0800 }
0801
0802 void push_back()
0803 {
0804 if( size_ != members_.capacity_ )
0805 {
0806 unchecked_push_back();
0807 }
0808 else
0809 {
0810 reserve( size_ + 1u );
0811 unchecked_push_back();
0812 }
0813 }
0814
0815 void push_back( optimized_const_reference x )
0816 {
0817 if( size_ != members_.capacity_ )
0818 {
0819 unchecked_push_back( x );
0820 }
0821 else
0822 {
0823 reserve( size_ + 1u );
0824 unchecked_push_back( x );
0825 }
0826 }
0827
0828 template< class ForwardIterator >
0829 void push_back( ForwardIterator begin_arg, ForwardIterator end_arg )
0830 {
0831 difference_type diff = std::distance(begin_arg, end_arg);
0832 if( size_ + diff > members_.capacity_ )
0833 reserve( size_ + diff );
0834 unchecked_push_back( begin_arg, end_arg );
0835 }
0836
0837 iterator insert( const_iterator before, optimized_const_reference x )
0838 {
0839
0840 if( size_ < members_.capacity_ )
0841 {
0842 bool is_back_insertion = before == cend();
0843 iterator where = const_cast<T*>(before);
0844
0845 if( !is_back_insertion )
0846 {
0847 grow_back_one();
0848 std::copy( before, cend() - 1u, where + 1u );
0849 *where = x;
0850 BOOST_ASSERT( is_valid() );
0851 }
0852 else
0853 {
0854 unchecked_push_back( x );
0855 }
0856 return where;
0857 }
0858
0859 auto_buffer temp( new_capacity_impl( size_ + 1u ) );
0860 temp.unchecked_push_back( cbegin(), before );
0861 iterator result = temp.end();
0862 temp.unchecked_push_back( x );
0863 temp.unchecked_push_back( before, cend() );
0864 one_sided_swap( temp );
0865 BOOST_ASSERT( is_valid() );
0866 return result;
0867 }
0868
0869 void insert( const_iterator before, size_type n,
0870 optimized_const_reference x )
0871 {
0872
0873 if( size_ + n <= members_.capacity_ )
0874 {
0875 grow_back( n );
0876 iterator where = const_cast<T*>(before);
0877 std::copy( before, cend() - n, where + n );
0878 std::fill( where, where + n, x );
0879 BOOST_ASSERT( is_valid() );
0880 return;
0881 }
0882
0883 auto_buffer temp( new_capacity_impl( size_ + n ) );
0884 temp.unchecked_push_back( cbegin(), before );
0885 std::uninitialized_fill_n( temp.end(), n, x );
0886 temp.size_ += n;
0887 temp.unchecked_push_back( before, cend() );
0888 one_sided_swap( temp );
0889 BOOST_ASSERT( is_valid() );
0890 }
0891
0892 template< class ForwardIterator >
0893 void insert( const_iterator before,
0894 ForwardIterator begin_arg, ForwardIterator end_arg )
0895 {
0896 typedef typename std::iterator_traits<ForwardIterator>
0897 ::iterator_category category;
0898 insert_impl( before, begin_arg, end_arg, category() );
0899 }
0900
0901 void pop_back()
0902 {
0903 BOOST_ASSERT( !empty() );
0904 auto_buffer_destroy( buffer_ + size_ - 1, boost::has_trivial_destructor<T>() );
0905 --size_;
0906 }
0907
0908 void pop_back_n( size_type n )
0909 {
0910 BOOST_ASSERT( n <= size_ );
0911 if( n )
0912 {
0913 destroy_back_n( n );
0914 size_ -= n;
0915 }
0916 }
0917
0918 void clear()
0919 {
0920 pop_back_n( size_ );
0921 }
0922
0923 iterator erase( const_iterator where )
0924 {
0925 BOOST_ASSERT( !empty() );
0926 BOOST_ASSERT( cbegin() <= where );
0927 BOOST_ASSERT( cend() > where );
0928
0929 unsigned elements = cend() - where - 1u;
0930
0931 if( elements > 0u )
0932 {
0933 const_iterator start = where + 1u;
0934 std::copy( start, start + elements,
0935 const_cast<T*>(where) );
0936 }
0937 pop_back();
0938 BOOST_ASSERT( !full() );
0939 iterator result = const_cast<T*>( where );
0940 BOOST_ASSERT( result <= end() );
0941 return result;
0942 }
0943
0944 iterator erase( const_iterator from, const_iterator to )
0945 {
0946 BOOST_ASSERT( !(std::distance(from,to)>0) ||
0947 !empty() );
0948 BOOST_ASSERT( cbegin() <= from );
0949 BOOST_ASSERT( cend() >= to );
0950
0951 unsigned elements = std::distance(to,cend());
0952
0953 if( elements > 0u )
0954 {
0955 BOOST_ASSERT( elements > 0u );
0956 std::copy( to, to + elements,
0957 const_cast<T*>(from) );
0958 }
0959 pop_back_n( std::distance(from,to) );
0960 BOOST_ASSERT( !full() );
0961 iterator result = const_cast<T*>( from );
0962 BOOST_ASSERT( result <= end() );
0963 return result;
0964 }
0965
0966 void shrink_to_fit()
0967 {
0968 if( is_on_stack() || !GrowPolicy::should_shrink(size_,members_.capacity_) )
0969 return;
0970
0971 reserve_impl( size_ );
0972 members_.capacity_ = (std::max)(size_type(N),members_.capacity_);
0973 BOOST_ASSERT( is_on_stack() || size_ == members_.capacity_ );
0974 BOOST_ASSERT( !is_on_stack() || size_ <= members_.capacity_ );
0975 }
0976
0977 pointer uninitialized_grow( size_type n )
0978 {
0979 if( size_ + n > members_.capacity_ )
0980 reserve( size_ + n );
0981
0982 pointer res = end();
0983 size_ += n;
0984 return res;
0985 }
0986
0987 void uninitialized_shrink( size_type n )
0988 {
0989
0990 BOOST_ASSERT( size_ - n <= members_.capacity_ );
0991 size_ -= n;
0992 }
0993
0994 void uninitialized_resize( size_type n )
0995 {
0996 if( n > size() )
0997 uninitialized_grow( n - size() );
0998 else if( n < size() )
0999 uninitialized_shrink( size() - n );
1000
1001 BOOST_ASSERT( size() == n );
1002 }
1003
1004
1005
1006
1007
1008
1009
1010 void swap( auto_buffer& r )
1011 {
1012 bool on_stack = is_on_stack();
1013 bool r_on_stack = r.is_on_stack();
1014 bool both_on_heap = !on_stack && !r_on_stack;
1015 if( both_on_heap )
1016 {
1017 boost::core::invoke_swap( get_allocator(), r.get_allocator() );
1018 boost::core::invoke_swap( members_.capacity_, r.members_.capacity_ );
1019 boost::core::invoke_swap( buffer_, r.buffer_ );
1020 boost::core::invoke_swap( size_, r.size_ );
1021 BOOST_ASSERT( is_valid() );
1022 BOOST_ASSERT( r.is_valid() );
1023 return;
1024 }
1025
1026 BOOST_ASSERT( on_stack || r_on_stack );
1027 bool exactly_one_on_stack = (on_stack && !r_on_stack) ||
1028 (!on_stack && r_on_stack);
1029
1030
1031
1032
1033
1034 if( exactly_one_on_stack )
1035 {
1036 auto_buffer* one_on_stack = on_stack ? this : &r;
1037 auto_buffer* other = on_stack ? &r : this;
1038 pointer new_buffer = static_cast<T*>(other->members_.address());
1039 copy_impl( one_on_stack->begin(), one_on_stack->end(),
1040 new_buffer );
1041 one_on_stack->auto_buffer_destroy();
1042 boost::core::invoke_swap( get_allocator(), r.get_allocator() );
1043 boost::core::invoke_swap( members_.capacity_, r.members_.capacity_ );
1044 boost::core::invoke_swap( size_, r.size_ );
1045 one_on_stack->buffer_ = other->buffer_;
1046 other->buffer_ = new_buffer;
1047 BOOST_ASSERT( other->is_on_stack() );
1048 BOOST_ASSERT( !one_on_stack->is_on_stack() );
1049 BOOST_ASSERT( is_valid() );
1050 BOOST_ASSERT( r.is_valid() );
1051 return;
1052 }
1053
1054 BOOST_ASSERT( on_stack && r_on_stack );
1055 swap_helper( *this, r, boost::has_trivial_assign<T>() );
1056 BOOST_ASSERT( is_valid() );
1057 BOOST_ASSERT( r.is_valid() );
1058 }
1059
1060 private:
1061 typedef boost::aligned_storage< N * sizeof(T),
1062 boost::alignment_of<T>::value >
1063 storage;
1064
1065 struct members_type : storage
1066 {
1067 size_type capacity_;
1068
1069 members_type( size_type capacity )
1070 : capacity_(capacity)
1071 { }
1072
1073 void* address() const
1074 { return const_cast<storage&>(static_cast<const storage&>(*this)).address(); }
1075 };
1076
1077 members_type members_;
1078 pointer buffer_;
1079 size_type size_;
1080
1081 };
1082
1083 template< class T, class SBP, class GP, class A >
1084 inline void swap( auto_buffer<T,SBP,GP,A>& l, auto_buffer<T,SBP,GP,A>& r )
1085 {
1086 l.swap( r );
1087 }
1088
1089 template< class T, class SBP, class GP, class A >
1090 inline bool operator==( const auto_buffer<T,SBP,GP,A>& l,
1091 const auto_buffer<T,SBP,GP,A>& r )
1092 {
1093 if( l.size() != r.size() )
1094 return false;
1095 return std::equal( l.begin(), l.end(), r.begin() );
1096 }
1097
1098 template< class T, class SBP, class GP, class A >
1099 inline bool operator!=( const auto_buffer<T,SBP,GP,A>& l,
1100 const auto_buffer<T,SBP,GP,A>& r )
1101 {
1102 return !(l == r);
1103 }
1104
1105 template< class T, class SBP, class GP, class A >
1106 inline bool operator<( const auto_buffer<T,SBP,GP,A>& l,
1107 const auto_buffer<T,SBP,GP,A>& r )
1108 {
1109 return std::lexicographical_compare( l.begin(), l.end(),
1110 r.begin(), r.end() );
1111 }
1112
1113 template< class T, class SBP, class GP, class A >
1114 inline bool operator>( const auto_buffer<T,SBP,GP,A>& l,
1115 const auto_buffer<T,SBP,GP,A>& r )
1116 {
1117 return (r < l);
1118 }
1119
1120 template< class T, class SBP, class GP, class A >
1121 inline bool operator<=( const auto_buffer<T,SBP,GP,A>& l,
1122 const auto_buffer<T,SBP,GP,A>& r )
1123 {
1124 return !(l > r);
1125 }
1126
1127 template< class T, class SBP, class GP, class A >
1128 inline bool operator>=( const auto_buffer<T,SBP,GP,A>& l,
1129 const auto_buffer<T,SBP,GP,A>& r )
1130 {
1131 return !(l < r);
1132 }
1133
1134 }
1135 }
1136 }
1137
1138 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
1139 #pragma warning(pop)
1140 #endif
1141
1142 #endif