annotate DEPENDENCIES/generic/include/boost/signals2/detail/auto_buffer.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
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