12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142 |
- // Copyright Thorsten Ottosen, 2009.
- // Distributed under the Boost Software License, Version 1.0. (See
- // accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
- #define BOOST_SIGNALS2_DETAIL_AUTO_BUFFER_HPP_25_02_2009
- #include <boost/detail/workaround.hpp>
- #if defined(_MSC_VER)
- # pragma once
- #endif
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(push)
- #pragma warning(disable:4996)
- #endif
- #include <boost/assert.hpp>
- #include <boost/config.hpp>
- #include <boost/core/allocator_access.hpp>
- #include <boost/iterator/reverse_iterator.hpp>
- #include <boost/iterator/iterator_traits.hpp>
- #include <boost/mpl/if.hpp>
- #include <boost/signals2/detail/scope_guard.hpp>
- #include <boost/swap.hpp>
- #include <boost/type_traits/aligned_storage.hpp>
- #include <boost/type_traits/alignment_of.hpp>
- #include <boost/type_traits/has_nothrow_copy.hpp>
- #include <boost/type_traits/has_nothrow_assign.hpp>
- #include <boost/type_traits/has_trivial_assign.hpp>
- #include <boost/type_traits/has_trivial_constructor.hpp>
- #include <boost/type_traits/has_trivial_destructor.hpp>
- #include <algorithm>
- #include <cstring>
- #include <iterator>
- #include <memory>
- #include <stdexcept>
- namespace boost
- {
- namespace signals2
- {
- namespace detail
- {
- //
- // Policies for creating the stack buffer.
- //
- template< unsigned N >
- struct store_n_objects
- {
- BOOST_STATIC_CONSTANT( unsigned, value = N );
- };
- template< unsigned N >
- struct store_n_bytes
- {
- BOOST_STATIC_CONSTANT( unsigned, value = N );
- };
- namespace auto_buffer_detail
- {
- template< class Policy, class T >
- struct compute_buffer_size
- {
- BOOST_STATIC_CONSTANT( unsigned, value = Policy::value * sizeof(T) );
- };
- template< unsigned N, class T >
- struct compute_buffer_size< store_n_bytes<N>, T >
- {
- BOOST_STATIC_CONSTANT( unsigned, value = N );
- };
- template< class Policy, class T >
- struct compute_buffer_objects
- {
- BOOST_STATIC_CONSTANT( unsigned, value = Policy::value );
- };
- template< unsigned N, class T >
- struct compute_buffer_objects< store_n_bytes<N>, T >
- {
- BOOST_STATIC_CONSTANT( unsigned, value = N / sizeof(T) );
- };
- }
- struct default_grow_policy
- {
- template< class SizeType >
- static SizeType new_capacity( SizeType capacity )
- {
- //
- // @remark: we grow the capacity quite agressively.
- // this is justified since we aim to minimize
- // heap-allocations, and because we mostly use
- // the buffer locally.
- return capacity * 4u;
- }
- template< class SizeType >
- static bool should_shrink( SizeType, SizeType )
- {
- //
- // @remark: when defining a new grow policy, one might
- // choose that if the waated space is less
- // than a certain percentage, then it is of
- // little use to shrink.
- //
- return true;
- }
- };
- template< class T,
- class StackBufferPolicy = store_n_objects<256>,
- class GrowPolicy = default_grow_policy,
- class Allocator = std::allocator<T> >
- class auto_buffer;
- template
- <
- class T,
- class StackBufferPolicy,
- class GrowPolicy,
- class Allocator
- >
- class auto_buffer : Allocator
- {
- private:
- enum { N = auto_buffer_detail::
- compute_buffer_objects<StackBufferPolicy,T>::value };
- BOOST_STATIC_CONSTANT( bool, is_stack_buffer_empty = N == 0u );
- typedef auto_buffer<T, store_n_objects<0>, GrowPolicy, Allocator>
- local_buffer;
- public:
- typedef Allocator allocator_type;
- typedef T value_type;
- typedef typename boost::allocator_size_type<Allocator>::type size_type;
- typedef typename boost::allocator_difference_type<Allocator>::type difference_type;
- typedef T* pointer;
- typedef typename boost::allocator_pointer<Allocator>::type allocator_pointer;
- typedef const T* const_pointer;
- typedef T& reference;
- typedef const T& const_reference;
- typedef pointer iterator;
- typedef const_pointer const_iterator;
- typedef boost::reverse_iterator<iterator> reverse_iterator;
- typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
- typedef typename boost::mpl::if_c< boost::has_trivial_assign<T>::value
- && sizeof(T) <= sizeof(long double),
- const value_type,
- const_reference >::type
- optimized_const_reference;
- private:
- pointer allocate( size_type capacity_arg )
- {
- if( capacity_arg > N )
- return &*get_allocator().allocate( capacity_arg );
- else
- return static_cast<T*>( members_.address() );
- }
- void deallocate( pointer where, size_type capacity_arg )
- {
- if( capacity_arg <= N )
- return;
- get_allocator().deallocate( allocator_pointer(where), capacity_arg );
- }
- template< class I >
- static void copy_impl( I begin, I end, pointer where, std::random_access_iterator_tag )
- {
- copy_rai( begin, end, where, boost::has_trivial_assign<T>() );
- }
- static void copy_rai( const T* begin, const T* end,
- pointer where, const boost::true_type& )
- {
- std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
- }
- template< class I, bool b >
- static void copy_rai( I begin, I end,
- pointer where, const boost::integral_constant<bool, b>& )
- {
- std::uninitialized_copy( begin, end, where );
- }
- template< class I >
- static void copy_impl( I begin, I end, pointer where, std::bidirectional_iterator_tag )
- {
- std::uninitialized_copy( begin, end, where );
- }
- template< class I >
- static void copy_impl( I begin, I end, pointer where )
- {
- copy_impl( begin, end, where,
- typename std::iterator_traits<I>::iterator_category() );
- }
- template< class I, class I2 >
- static void assign_impl( I begin, I end, I2 where )
- {
- assign_impl( begin, end, where, boost::has_trivial_assign<T>() );
- }
- template< class I, class I2 >
- static void assign_impl( I begin, I end, I2 where, const boost::true_type& )
- {
- std::memcpy( where, begin, sizeof(T) * std::distance(begin,end) );
- }
- template< class I, class I2 >
- static void assign_impl( I begin, I end, I2 where, const boost::false_type& )
- {
- for( ; begin != end; ++begin, ++where )
- *where = *begin;
- }
- void unchecked_push_back_n( size_type n, const boost::true_type& )
- {
- std::uninitialized_fill( end(), end() + n, T() );
- size_ += n;
- }
- void unchecked_push_back_n( size_type n, const boost::false_type& )
- {
- for( size_type i = 0u; i < n; ++i )
- unchecked_push_back();
- }
- void auto_buffer_destroy( pointer where, const boost::false_type& )
- {
- (*where).~T();
- }
- void auto_buffer_destroy( pointer, const boost::true_type& )
- { }
- void auto_buffer_destroy( pointer where )
- {
- auto_buffer_destroy( where, boost::has_trivial_destructor<T>() );
- }
- void auto_buffer_destroy()
- {
- BOOST_ASSERT( is_valid() );
- if( buffer_ ) // do we need this check? Yes, but only
- // for N = 0u + local instances in one_sided_swap()
- auto_buffer_destroy( boost::has_trivial_destructor<T>() );
- }
- void destroy_back_n( size_type n, const boost::false_type& )
- {
- BOOST_ASSERT( n > 0 );
- pointer buffer = buffer_ + size_ - 1u;
- pointer new_end = buffer - n;
- for( ; buffer > new_end; --buffer )
- auto_buffer_destroy( buffer );
- }
- void destroy_back_n( size_type, const boost::true_type& )
- { }
- void destroy_back_n( size_type n )
- {
- destroy_back_n( n, boost::has_trivial_destructor<T>() );
- }
- void auto_buffer_destroy( const boost::false_type& x )
- {
- if( size_ )
- destroy_back_n( size_, x );
- deallocate( buffer_, members_.capacity_ );
- }
- void auto_buffer_destroy( const boost::true_type& )
- {
- deallocate( buffer_, members_.capacity_ );
- }
- pointer move_to_new_buffer( size_type new_capacity, const boost::false_type& )
- {
- pointer new_buffer = allocate( new_capacity ); // strong
- scope_guard guard = make_obj_guard( *this,
- &auto_buffer::deallocate,
- new_buffer,
- new_capacity );
- copy_impl( begin(), end(), new_buffer ); // strong
- guard.dismiss(); // nothrow
- return new_buffer;
- }
- pointer move_to_new_buffer( size_type new_capacity, const boost::true_type& )
- {
- pointer new_buffer = allocate( new_capacity ); // strong
- copy_impl( begin(), end(), new_buffer ); // nothrow
- return new_buffer;
- }
- void reserve_impl( size_type new_capacity )
- {
- pointer new_buffer = move_to_new_buffer( new_capacity,
- boost::has_nothrow_copy<T>() );
- auto_buffer_destroy();
- buffer_ = new_buffer;
- members_.capacity_ = new_capacity;
- BOOST_ASSERT( size_ <= members_.capacity_ );
- }
- size_type new_capacity_impl( size_type n )
- {
- BOOST_ASSERT( n > members_.capacity_ );
- size_type new_capacity = GrowPolicy::new_capacity( members_.capacity_ );
- // @todo: consider to check for allocator.max_size()
- return (std::max)(new_capacity,n);
- }
- static void swap_helper( auto_buffer& l, auto_buffer& r,
- const boost::true_type& )
- {
- BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
- auto_buffer temp( l.begin(), l.end() );
- assign_impl( r.begin(), r.end(), l.begin() );
- assign_impl( temp.begin(), temp.end(), r.begin() );
- boost::swap( l.size_, r.size_ );
- boost::swap( l.members_.capacity_, r.members_.capacity_ );
- }
- static void swap_helper( auto_buffer& l, auto_buffer& r,
- const boost::false_type& )
- {
- BOOST_ASSERT( l.is_on_stack() && r.is_on_stack() );
- size_type min_size = (std::min)(l.size_,r.size_);
- size_type max_size = (std::max)(l.size_,r.size_);
- size_type diff = max_size - min_size;
- auto_buffer* smallest = l.size_ == min_size ? &l : &r;
- auto_buffer* largest = smallest == &l ? &r : &l;
- // @remark: the implementation below is not as fast
- // as it could be if we assumed T had a default
- // constructor.
- size_type i = 0u;
- for( ; i < min_size; ++i )
- boost::swap( (*smallest)[i], (*largest)[i] );
- for( ; i < max_size; ++i )
- smallest->unchecked_push_back( (*largest)[i] );
- largest->pop_back_n( diff );
- boost::swap( l.members_.capacity_, r.members_.capacity_ );
- }
- void one_sided_swap( auto_buffer& temp ) // nothrow
- {
- BOOST_ASSERT( !temp.is_on_stack() );
- auto_buffer_destroy();
- // @remark: must be nothrow
- get_allocator() = temp.get_allocator();
- members_.capacity_ = temp.members_.capacity_;
- buffer_ = temp.buffer_;
- BOOST_ASSERT( temp.size_ >= size_ + 1u );
- size_ = temp.size_;
- temp.buffer_ = 0;
- BOOST_ASSERT( temp.is_valid() );
- }
- template< class I >
- void insert_impl( const_iterator before, I begin_arg, I end_arg,
- std::input_iterator_tag )
- {
- for( ; begin_arg != end_arg; ++begin_arg )
- {
- before = insert( before, *begin_arg );
- ++before;
- }
- }
- void grow_back( size_type n, const boost::true_type& )
- {
- BOOST_ASSERT( size_ + n <= members_.capacity_ );
- size_ += n;
- }
- void grow_back( size_type n, const boost::false_type& )
- {
- unchecked_push_back_n(n);
- }
- void grow_back( size_type n )
- {
- grow_back( n, boost::has_trivial_constructor<T>() );
- }
- void grow_back_one( const boost::true_type& )
- {
- BOOST_ASSERT( size_ + 1 <= members_.capacity_ );
- size_ += 1;
- }
- void grow_back_one( const boost::false_type& )
- {
- unchecked_push_back();
- }
- void grow_back_one()
- {
- grow_back_one( boost::has_trivial_constructor<T>() );
- }
- template< class I >
- void insert_impl( const_iterator before, I begin_arg, I end_arg,
- std::forward_iterator_tag )
- {
- difference_type n = std::distance(begin_arg, end_arg);
- if( size_ + n <= members_.capacity_ )
- {
- bool is_back_insertion = before == cend();
- if( !is_back_insertion )
- {
- grow_back( n );
- iterator where = const_cast<T*>(before);
- std::copy( before, cend() - n, where + n );
- assign_impl( begin_arg, end_arg, where );
- }
- else
- {
- unchecked_push_back( begin_arg, end_arg );
- }
- BOOST_ASSERT( is_valid() );
- return;
- }
- auto_buffer temp( new_capacity_impl( size_ + n ) );
- temp.unchecked_push_back( cbegin(), before );
- temp.unchecked_push_back( begin_arg, end_arg );
- temp.unchecked_push_back( before, cend() );
- one_sided_swap( temp );
- BOOST_ASSERT( is_valid() );
- }
- public:
- bool is_valid() const // invariant
- {
- // @remark: allowed for N==0 and when
- // using a locally instance
- // in insert()/one_sided_swap()
- if( buffer_ == 0 )
- return true;
- if( members_.capacity_ < N )
- return false;
- if( !is_on_stack() && members_.capacity_ <= N )
- return false;
- if( buffer_ == members_.address() )
- if( members_.capacity_ > N )
- return false;
- if( size_ > members_.capacity_ )
- return false;
- return true;
- }
- auto_buffer()
- : members_( N ),
- buffer_( static_cast<T*>(members_.address()) ),
- size_( 0u )
- {
- BOOST_ASSERT( is_valid() );
- }
- auto_buffer( const auto_buffer& r )
- : members_( (std::max)(r.size_,size_type(N)) ),
- buffer_( allocate( members_.capacity_ ) ),
- size_( 0 )
- {
- copy_impl( r.begin(), r.end(), buffer_ );
- size_ = r.size_;
- BOOST_ASSERT( is_valid() );
- }
- auto_buffer& operator=( const auto_buffer& r ) // basic
- {
- if( this == &r )
- return *this;
- difference_type diff = size_ - r.size_;
- if( diff >= 0 )
- {
- pop_back_n( static_cast<size_type>(diff) );
- assign_impl( r.begin(), r.end(), begin() );
- }
- else
- {
- if( members_.capacity_ >= r.size() )
- {
- unchecked_push_back_n( static_cast<size_type>(-diff) );
- assign_impl( r.begin(), r.end(), begin() );
- }
- else
- {
- // @remark: we release memory as early as possible
- // since we only give the basic guarantee
- auto_buffer_destroy();
- buffer_ = 0;
- pointer new_buffer = allocate( r.size() );
- scope_guard guard = make_obj_guard( *this,
- &auto_buffer::deallocate,
- new_buffer,
- r.size() );
- copy_impl( r.begin(), r.end(), new_buffer );
- guard.dismiss();
- buffer_ = new_buffer;
- members_.capacity_ = r.size();
- size_ = members_.capacity_;
- }
- }
- BOOST_ASSERT( size() == r.size() );
- BOOST_ASSERT( is_valid() );
- return *this;
- }
- explicit auto_buffer( size_type capacity_arg )
- : members_( (std::max)(capacity_arg, size_type(N)) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- BOOST_ASSERT( is_valid() );
- }
- auto_buffer( size_type size_arg, optimized_const_reference init_value )
- : members_( (std::max)(size_arg, size_type(N)) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
- size_ = size_arg;
- BOOST_ASSERT( is_valid() );
- }
- auto_buffer( size_type capacity_arg, const allocator_type& a )
- : allocator_type( a ),
- members_( (std::max)(capacity_arg, size_type(N)) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- BOOST_ASSERT( is_valid() );
- }
- auto_buffer( size_type size_arg, optimized_const_reference init_value,
- const allocator_type& a )
- : allocator_type( a ),
- members_( (std::max)(size_arg, size_type(N)) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- std::uninitialized_fill( buffer_, buffer_ + size_arg, init_value );
- size_ = size_arg;
- BOOST_ASSERT( is_valid() );
- }
- template< class ForwardIterator >
- auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg )
- :
- members_( std::distance(begin_arg, end_arg) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- copy_impl( begin_arg, end_arg, buffer_ );
- size_ = members_.capacity_;
- if( members_.capacity_ < N )
- members_.capacity_ = N;
- BOOST_ASSERT( is_valid() );
- }
- template< class ForwardIterator >
- auto_buffer( ForwardIterator begin_arg, ForwardIterator end_arg,
- const allocator_type& a )
- : allocator_type( a ),
- members_( std::distance(begin_arg, end_arg) ),
- buffer_( allocate(members_.capacity_) ),
- size_( 0 )
- {
- copy_impl( begin_arg, end_arg, buffer_ );
- size_ = members_.capacity_;
- if( members_.capacity_ < N )
- members_.capacity_ = N;
- BOOST_ASSERT( is_valid() );
- }
- ~auto_buffer()
- {
- auto_buffer_destroy();
- }
- public:
- bool empty() const
- {
- return size_ == 0;
- }
- bool full() const
- {
- return size_ == members_.capacity_;
- }
- bool is_on_stack() const
- {
- return members_.capacity_ <= N;
- }
- size_type size() const
- {
- return size_;
- }
- size_type capacity() const
- {
- return members_.capacity_;
- }
- public:
- pointer data()
- {
- return buffer_;
- }
- const_pointer data() const
- {
- return buffer_;
- }
- allocator_type& get_allocator()
- {
- return static_cast<allocator_type&>(*this);
- }
- const allocator_type& get_allocator() const
- {
- return static_cast<const allocator_type&>(*this);
- }
- public:
- iterator begin()
- {
- return buffer_;
- }
- const_iterator begin() const
- {
- return buffer_;
- }
- iterator end()
- {
- return buffer_ + size_;
- }
- const_iterator end() const
- {
- return buffer_ + size_;
- }
- reverse_iterator rbegin()
- {
- return reverse_iterator(end());
- }
- const_reverse_iterator rbegin() const
- {
- return const_reverse_iterator(end());
- }
- reverse_iterator rend()
- {
- return reverse_iterator(begin());
- }
- const_reverse_iterator rend() const
- {
- return const_reverse_iterator(begin());
- }
- const_iterator cbegin() const
- {
- return const_cast<const auto_buffer*>(this)->begin();
- }
- const_iterator cend() const
- {
- return const_cast<const auto_buffer*>(this)->end();
- }
- const_reverse_iterator crbegin() const
- {
- return const_cast<const auto_buffer*>(this)->rbegin();
- }
- const_reverse_iterator crend() const
- {
- return const_cast<const auto_buffer*>(this)->rend();
- }
- public:
- reference front()
- {
- return buffer_[0];
- }
- optimized_const_reference front() const
- {
- return buffer_[0];
- }
- reference back()
- {
- return buffer_[size_-1];
- }
- optimized_const_reference back() const
- {
- return buffer_[size_-1];
- }
- reference operator[]( size_type n )
- {
- BOOST_ASSERT( n < size_ );
- return buffer_[n];
- }
- optimized_const_reference operator[]( size_type n ) const
- {
- BOOST_ASSERT( n < size_ );
- return buffer_[n];
- }
- void unchecked_push_back()
- {
- BOOST_ASSERT( !full() );
- new (buffer_ + size_) T;
- ++size_;
- }
- void unchecked_push_back_n( size_type n )
- {
- BOOST_ASSERT( size_ + n <= members_.capacity_ );
- unchecked_push_back_n( n, boost::has_trivial_assign<T>() );
- }
- void unchecked_push_back( optimized_const_reference x ) // non-growing
- {
- BOOST_ASSERT( !full() );
- new (buffer_ + size_) T( x );
- ++size_;
- }
- template< class ForwardIterator >
- void unchecked_push_back( ForwardIterator begin_arg,
- ForwardIterator end_arg ) // non-growing
- {
- BOOST_ASSERT( size_ + std::distance(begin_arg, end_arg) <= members_.capacity_ );
- copy_impl( begin_arg, end_arg, buffer_ + size_ );
- size_ += std::distance(begin_arg, end_arg);
- }
- void reserve_precisely( size_type n )
- {
- BOOST_ASSERT( members_.capacity_ >= N );
- if( n <= members_.capacity_ )
- return;
- reserve_impl( n );
- BOOST_ASSERT( members_.capacity_ == n );
- }
- void reserve( size_type n ) // strong
- {
- BOOST_ASSERT( members_.capacity_ >= N );
- if( n <= members_.capacity_ )
- return;
- reserve_impl( new_capacity_impl( n ) );
- BOOST_ASSERT( members_.capacity_ >= n );
- }
- void push_back()
- {
- if( size_ != members_.capacity_ )
- {
- unchecked_push_back();
- }
- else
- {
- reserve( size_ + 1u );
- unchecked_push_back();
- }
- }
- void push_back( optimized_const_reference x )
- {
- if( size_ != members_.capacity_ )
- {
- unchecked_push_back( x );
- }
- else
- {
- reserve( size_ + 1u );
- unchecked_push_back( x );
- }
- }
- template< class ForwardIterator >
- void push_back( ForwardIterator begin_arg, ForwardIterator end_arg )
- {
- difference_type diff = std::distance(begin_arg, end_arg);
- if( size_ + diff > members_.capacity_ )
- reserve( size_ + diff );
- unchecked_push_back( begin_arg, end_arg );
- }
- iterator insert( const_iterator before, optimized_const_reference x ) // basic
- {
- // @todo: consider if we want to support x in 'this'
- if( size_ < members_.capacity_ )
- {
- bool is_back_insertion = before == cend();
- iterator where = const_cast<T*>(before);
- if( !is_back_insertion )
- {
- grow_back_one();
- std::copy( before, cend() - 1u, where + 1u );
- *where = x;
- BOOST_ASSERT( is_valid() );
- }
- else
- {
- unchecked_push_back( x );
- }
- return where;
- }
- auto_buffer temp( new_capacity_impl( size_ + 1u ) );
- temp.unchecked_push_back( cbegin(), before );
- iterator result = temp.end();
- temp.unchecked_push_back( x );
- temp.unchecked_push_back( before, cend() );
- one_sided_swap( temp );
- BOOST_ASSERT( is_valid() );
- return result;
- }
- void insert( const_iterator before, size_type n,
- optimized_const_reference x )
- {
- // @todo: see problems above
- if( size_ + n <= members_.capacity_ )
- {
- grow_back( n );
- iterator where = const_cast<T*>(before);
- std::copy( before, cend() - n, where + n );
- std::fill( where, where + n, x );
- BOOST_ASSERT( is_valid() );
- return;
- }
- auto_buffer temp( new_capacity_impl( size_ + n ) );
- temp.unchecked_push_back( cbegin(), before );
- std::uninitialized_fill_n( temp.end(), n, x );
- temp.size_ += n;
- temp.unchecked_push_back( before, cend() );
- one_sided_swap( temp );
- BOOST_ASSERT( is_valid() );
- }
- template< class ForwardIterator >
- void insert( const_iterator before,
- ForwardIterator begin_arg, ForwardIterator end_arg ) // basic
- {
- typedef typename std::iterator_traits<ForwardIterator>
- ::iterator_category category;
- insert_impl( before, begin_arg, end_arg, category() );
- }
- void pop_back()
- {
- BOOST_ASSERT( !empty() );
- auto_buffer_destroy( buffer_ + size_ - 1, boost::has_trivial_destructor<T>() );
- --size_;
- }
- void pop_back_n( size_type n )
- {
- BOOST_ASSERT( n <= size_ );
- if( n )
- {
- destroy_back_n( n );
- size_ -= n;
- }
- }
- void clear()
- {
- pop_back_n( size_ );
- }
- iterator erase( const_iterator where )
- {
- BOOST_ASSERT( !empty() );
- BOOST_ASSERT( cbegin() <= where );
- BOOST_ASSERT( cend() > where );
- unsigned elements = cend() - where - 1u;
- if( elements > 0u )
- {
- const_iterator start = where + 1u;
- std::copy( start, start + elements,
- const_cast<T*>(where) );
- }
- pop_back();
- BOOST_ASSERT( !full() );
- iterator result = const_cast<T*>( where );
- BOOST_ASSERT( result <= end() );
- return result;
- }
- iterator erase( const_iterator from, const_iterator to )
- {
- BOOST_ASSERT( !(std::distance(from,to)>0) ||
- !empty() );
- BOOST_ASSERT( cbegin() <= from );
- BOOST_ASSERT( cend() >= to );
- unsigned elements = std::distance(to,cend());
- if( elements > 0u )
- {
- BOOST_ASSERT( elements > 0u );
- std::copy( to, to + elements,
- const_cast<T*>(from) );
- }
- pop_back_n( std::distance(from,to) );
- BOOST_ASSERT( !full() );
- iterator result = const_cast<T*>( from );
- BOOST_ASSERT( result <= end() );
- return result;
- }
- void shrink_to_fit()
- {
- if( is_on_stack() || !GrowPolicy::should_shrink(size_,members_.capacity_) )
- return;
- reserve_impl( size_ );
- members_.capacity_ = (std::max)(size_type(N),members_.capacity_);
- BOOST_ASSERT( is_on_stack() || size_ == members_.capacity_ );
- BOOST_ASSERT( !is_on_stack() || size_ <= members_.capacity_ );
- }
- pointer uninitialized_grow( size_type n ) // strong
- {
- if( size_ + n > members_.capacity_ )
- reserve( size_ + n );
- pointer res = end();
- size_ += n;
- return res;
- }
- void uninitialized_shrink( size_type n ) // nothrow
- {
- // @remark: test for wrap-around
- BOOST_ASSERT( size_ - n <= members_.capacity_ );
- size_ -= n;
- }
- void uninitialized_resize( size_type n )
- {
- if( n > size() )
- uninitialized_grow( n - size() );
- else if( n < size() )
- uninitialized_shrink( size() - n );
- BOOST_ASSERT( size() == n );
- }
- // nothrow - if both buffer are on the heap, or
- // - if one buffer is on the heap and one has
- // 'has_allocated_buffer() == false', or
- // - if copy-construction cannot throw
- // basic - otherwise (better guarantee impossible)
- // requirement: the allocator must be no-throw-swappable
- void swap( auto_buffer& r )
- {
- bool on_stack = is_on_stack();
- bool r_on_stack = r.is_on_stack();
- bool both_on_heap = !on_stack && !r_on_stack;
- if( both_on_heap )
- {
- boost::swap( get_allocator(), r.get_allocator() );
- boost::swap( members_.capacity_, r.members_.capacity_ );
- boost::swap( buffer_, r.buffer_ );
- boost::swap( size_, r.size_ );
- BOOST_ASSERT( is_valid() );
- BOOST_ASSERT( r.is_valid() );
- return;
- }
- BOOST_ASSERT( on_stack || r_on_stack );
- bool exactly_one_on_stack = (on_stack && !r_on_stack) ||
- (!on_stack && r_on_stack);
- //
- // Remark: we now know that we can copy into
- // the unused stack buffer.
- //
- if( exactly_one_on_stack )
- {
- auto_buffer* one_on_stack = on_stack ? this : &r;
- auto_buffer* other = on_stack ? &r : this;
- pointer new_buffer = static_cast<T*>(other->members_.address());
- copy_impl( one_on_stack->begin(), one_on_stack->end(),
- new_buffer ); // strong
- one_on_stack->auto_buffer_destroy(); // nothrow
- boost::swap( get_allocator(), r.get_allocator() ); // assume nothrow
- boost::swap( members_.capacity_, r.members_.capacity_ );
- boost::swap( size_, r.size_ );
- one_on_stack->buffer_ = other->buffer_;
- other->buffer_ = new_buffer;
- BOOST_ASSERT( other->is_on_stack() );
- BOOST_ASSERT( !one_on_stack->is_on_stack() );
- BOOST_ASSERT( is_valid() );
- BOOST_ASSERT( r.is_valid() );
- return;
- }
- BOOST_ASSERT( on_stack && r_on_stack );
- swap_helper( *this, r, boost::has_trivial_assign<T>() );
- BOOST_ASSERT( is_valid() );
- BOOST_ASSERT( r.is_valid() );
- }
- private:
- typedef boost::aligned_storage< N * sizeof(T),
- boost::alignment_of<T>::value >
- storage;
- struct members_type : storage /* to enable EBO */
- {
- size_type capacity_;
- members_type( size_type capacity )
- : capacity_(capacity)
- { }
- void* address() const
- { return const_cast<storage&>(static_cast<const storage&>(*this)).address(); }
- };
- members_type members_;
- pointer buffer_;
- size_type size_;
- };
- template< class T, class SBP, class GP, class A >
- inline void swap( auto_buffer<T,SBP,GP,A>& l, auto_buffer<T,SBP,GP,A>& r )
- {
- l.swap( r );
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator==( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- if( l.size() != r.size() )
- return false;
- return std::equal( l.begin(), l.end(), r.begin() );
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator!=( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- return !(l == r);
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator<( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- return std::lexicographical_compare( l.begin(), l.end(),
- r.begin(), r.end() );
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator>( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- return (r < l);
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator<=( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- return !(l > r);
- }
- template< class T, class SBP, class GP, class A >
- inline bool operator>=( const auto_buffer<T,SBP,GP,A>& l,
- const auto_buffer<T,SBP,GP,A>& r )
- {
- return !(l < r);
- }
- } // namespace detail
- } // namespace signals2
- }
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(pop)
- #endif
- #endif
|