Added options to static_vector: throw_on_overflow/alignment

This commit is contained in:
Ion Gaztañaga
2019-05-09 13:25:50 +02:00
parent e23c57337f
commit 5d96b11fe0
7 changed files with 336 additions and 218 deletions

View File

@@ -627,6 +627,11 @@ then the operation is constant time, even with an O(1) size.
[section:configurable_containers Extended functionality: Configurable containers]
[*Boost.Container] offers the possibility to configure at compile time some parameters of
several containers, apart from the stored type and the allocator. This configuration is passed as
the last template parameter and defined using the utility classes. The following containers can receive
useful configuration options:
[section:configurable_tree_based_associative_containers Configurable tree-based associative ordered containers]
[classref boost::container::set set], [classref boost::container::multiset multiset],
@@ -667,8 +672,7 @@ used to customize these containers:
[section:configurable_vectors Configurable vectors]
[*Boost.Container] offers the possibility to configure at compile time some parameters of
[classref boost::container::vector vector] implementation. This configuration is passed as
The configuration for [classref boost::container::vector vector] is passed as
the last template parameter and defined using the utility class
[classref boost::container::vector_options vector_options]. The following parameters can be configured:
@@ -697,10 +701,9 @@ used to customize `vector` container:
[section:configurable_deques Configurable deques]
[*Boost.Container] offers the possibility to configure at compile time some parameters of
[classref boost::container::deque deque] implementation. This configuration is passed as
The configuration for [classref boost::container::deque deque] is passed as
the last template parameter and defined using the utility class
[classref boost::container::deque_options deque_options].The following parameters can be configured:
[classref boost::container::deque_options deque_options]. The following parameters can be configured:
Parameters that control the size of deque's 'block' (deque allocates contiguous chunks of elements, called 'blocks').
Only one of these paratemers can be specified:
@@ -708,6 +711,7 @@ Only one of these paratemers can be specified:
* [classref boost::container::block_bytes block_bytes]: the number of bytes deque will allocate for store
elements contiguously: `deque::get_block_size()` will return aproximately `block_bytes/sizeof(value_type)`.
A value of zero means the default value.
* [classref boost::container::block_size block_size]: the number of elements deque will allocate contiguously.
If this option is specified, `deque::get_block_size()` will return the specified `block_size`.
A value of zero means the default value.
@@ -720,6 +724,28 @@ used to customize `deque` container:
[endsect]
[section:configurable_static_vectors Configurable static vector]
The configuration for [classref boost::container::static_vector static_vector] is passed as
the last template parameter and defined using the utility class
[classref boost::container::static_vector_options static_vector_options]. The following parameters can be configured:
* [classref boost::container::alignment alignment]: the minimum alignment (in bytes) that the stored value type
needs. This option allows static vectors that need non-default alignments, e.g., to be used in SIMD operations.
* [classref boost::container::throw_on_overflow throw_on_overflow]: A boolean that specifies if the
container should throw an exception when the compile-time capacity is not enough to hold the requesteed number
of objects. When "false", if the capacit is overflowd, the implementation calls to BOOST_ASSERT and if that assertion
does not throw or abort, undefined behavior is triggered.
See the following example to see how [classref boost::container::static_vector_options static_vector_options] can be
used to customize `static_vector` container:
[import ../example/doc_custom_static_vector.cpp]
[doc_custom_static_vector]
[endsect]
[endsect]
[section:extended_allocators Extended functionality: Extended allocators]
@@ -1267,19 +1293,24 @@ use [*Boost.Container]? There are several reasons for that:
[section:release_notes Release Notes]
[section:release_notes_boost_1_71_00 Boost 1.71 Release]
* Fixed bugs:
* [@https://github.com/boostorg/container/issues/88 GitHub #88: ['"Implement C++17 MoveAssignable requirements for self-move assignments"]].
* [@https://github.com/boostorg/container/issues/107 GitHub #107: ['"Alignment ignored in resource_adaptor"]].
* [@https://github.com/boostorg/container/pull/109 GitHub #109: ['"Get rid of integer overflow in copy_move_algo.hpp (-fsanitize=integer)"]].
* [@https://github.com/boostorg/container/pull/110 GitHub #110: ['"Avoid gcc 9 deprecated copy warnings in new_allocator.hpp"]].
* [@https://github.com/boostorg/container/pull/109 GitHub #109: ['"Get rid of integer overflow in copy_move_algo.hpp (-fsanitize=integer)"]].
* [@https://github.com/boostorg/container/pull/110 GitHub #110: ['"Avoid gcc 9 deprecated copy warnings in new_allocator.hpp"]].
* [@https://github.com/boostorg/container/issues/112 GitHub #112: ['"vector::resize() compilation error with msvc-10..12: data is not a member of boost::detail::aligned_storage"]].
* [@https://github.com/boostorg/container/issues/114 GitHub #114: ['"Fix small_vector noexcept specification"]].
* [@https://github.com/boostorg/container/issues/116 GitHub #116: ['"MSVC + boost 1.70 compilation error when windows.h is already included (detail/thread_mutex.hpp)"]].
* [@https://github.com/boostorg/container/issues/117 GitHub #117: ['"flat_map/map::insert_or_assign with hint has wrong return types"]].
* [@https://github.com/boostorg/container/issues/118 GitHub #118: ['"Non-unique inplace_set_difference used in in flat_tree_merge_unique and iterator invalidation in insert_unique"]].
* ['deque] can now have options, using [classref boost::container::deque_options deque_options].
* [classref boost::container::deque deque] can now have options, using [classref boost::container::deque_options deque_options].
The block size/bytes can be be specified.
* [classref boost::container::static_vector static_vector] can now have options, using [classref boost::container::static_vector_options static_vector_options].
The alignment and throwing behaviour can be be specified.
[endsect]
[section:release_notes_boost_1_70_00 Boost 1.70 Release]

View File

@@ -106,7 +106,7 @@ template <class T
,class Allocator = void >
class stable_vector;
template <class T, std::size_t Capacity>
template <class T, std::size_t Capacity, class Options = void>
class static_vector;
template <class T, class Allocator = void >

View File

@@ -195,17 +195,17 @@ struct insert_move_proxy
typedef typename alloc_traits::size_type size_type;
typedef typename alloc_traits::value_type value_type;
explicit insert_move_proxy(value_type &v)
BOOST_CONTAINER_FORCEINLINE explicit insert_move_proxy(value_type &v)
: v_(v)
{}
void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const
BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const
{
BOOST_ASSERT(n == 1); (void)n;
alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) );
}
void copy_n_and_update(Allocator &, Iterator p, size_type n) const
BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) const
{
BOOST_ASSERT(n == 1); (void)n;
*p = ::boost::move(v_);

View File

@@ -19,6 +19,7 @@
#endif
#include <boost/container/allocator_traits.hpp>
#include <boost/container/container_fwd.hpp>
namespace boost {
@@ -49,27 +50,6 @@ namespace dtl {
typedef Cont<U> type;
};
//for small_vector,static_vector
template <template <class, std::size_t, class, class...> class Cont, typename V, std::size_t N, typename A, class... An, class U>
struct container_rebind<Cont<V, N, A, An...>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, An...> type;
};
//Needed for non-conforming compilers like GCC 4.3
template <template <class, std::size_t, class> class Cont, typename V, std::size_t N, typename A, class U>
struct container_rebind<Cont<V, N, A>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type> type;
};
template <template <class, std::size_t> class Cont, typename V, std::size_t N, class U>
struct container_rebind<Cont<V, N>, U>
{
typedef Cont<U, N> type;
};
#else //C++03 compilers
template <template <class> class Cont //0arg
@@ -160,97 +140,22 @@ namespace dtl {
typedef Cont<U, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6, P7, P8> type;
};
//For small_vector/static_vector
template <template <class, std::size_t> class Cont //0arg
, typename V, std::size_t N
, class U>
struct container_rebind<Cont<V, N>, U>
{
typedef Cont<U, N> type;
};
template <template <class, std::size_t, class> class Cont //0arg
, typename V, std::size_t N, typename A
, class U>
struct container_rebind<Cont<V, N, A>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type> type;
};
template <template <class, std::size_t, class, class> class Cont //1arg
, typename V, std::size_t N, typename A, class P0
, class U>
struct container_rebind<Cont<V, N, A, P0>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0> type;
};
template <template <class, std::size_t, class, class, class> class Cont //2arg
, typename V, std::size_t N, typename A, class P0, class P1
, class U>
struct container_rebind<Cont<V, N, A, P0, P1>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1> type;
};
template <template <class, std::size_t, class, class, class, class> class Cont //3arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2> type;
};
template <template <class, std::size_t, class, class, class, class, class> class Cont //4arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3> type;
};
template <template <class, std::size_t, class, class, class, class, class, class> class Cont //5arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3, class P4
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3, P4>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4> type;
};
template <template <class, std::size_t, class, class, class, class, class, class, class> class Cont //6arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3, class P4, class P5
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3, P4, P5>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5> type;
};
template <template <class, std::size_t, class, class, class, class, class, class, class, class> class Cont //7arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3, P4, P5, P6>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6> type;
};
template <template <class, std::size_t, class, class, class, class, class, class, class, class, class> class Cont //8arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6, class P7
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3, P4, P5, P6, P7>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6, P7> type;
};
template <template <class, std::size_t, class, class, class, class, class, class, class, class, class, class> class Cont //9arg
, typename V, std::size_t N, typename A, class P0, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8
, class U>
struct container_rebind<Cont<V, N, A, P0, P1, P2, P3, P4, P5, P6, P7, P8>, U>
{
typedef Cont<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type, P0, P1, P2, P3, P4, P5, P6, P7, P8> type;
};
#endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
//for small_vector,static_vector
template <typename V, std::size_t N, typename A, class U>
struct container_rebind<small_vector<V, N, A>, U>
{
typedef small_vector<U, N, typename allocator_traits<typename real_allocator<V, A>::type>::template portable_rebind_alloc<U>::type> type;
};
template <typename V, std::size_t N, typename O, class U>
struct container_rebind<static_vector<V, N, O>, U>
{
typedef static_vector<U, N, O> type;
};
} //namespace dtl {
} //namespace container {
} //namespace boost {

View File

@@ -253,6 +253,137 @@ using vector_options_t = typename boost::container::vector_options<Options...>::
#endif
////////////////////////////////////////////////////////////////
//
//
// OPTIONS FOR SMALL-VECTOR CONTAINER
//
//
////////////////////////////////////////////////////////////////
//! This option specifies the desired alignment for the value_type stored
//! in the container.
//! A value zero represents the natural alignment.
//!
//!\tparam Alignment An unsigned integer value. Must be power of two.
BOOST_INTRUSIVE_OPTION_CONSTANT(alignment, std::size_t, Alignment, alignment)
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<class GrowthType, std::size_t Alignment>
struct small_vector_opt
{
typedef GrowthType growth_factor_type;
static const std::size_t alignment = Alignment;
};
typedef small_vector_opt<void, 0u> small_vector_null_opt;
#endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! Helper metafunction to combine options into a single type to be used
//! by \c boost::container::small_vector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::alignment
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
#endif
struct small_vector_options
{
/// @cond
typedef typename ::boost::intrusive::pack_options
< small_vector_null_opt,
#if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef small_vector_opt< typename packed_options::growth_factor_type
, packed_options::alignment> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
//! Helper alias metafunction to combine options into a single type to be used
//! by \c boost::container::small_vector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size
template<class ...Options>
using small_vector_options_t = typename boost::container::small_vector_options<Options...>::type;
#endif
////////////////////////////////////////////////////////////////
//
//
// OPTIONS FOR STATIC-VECTOR CONTAINER
//
//
////////////////////////////////////////////////////////////////
//!This option specifies if the container will throw if in
//!the static capacity is not sufficient to hold the required
//!values. If false is specified, insufficient capacity will
//!lead to BOOST_ASSERT, and if this assertion returns, to undefined behaviour,
//!which potentially can lead to better static_vector performance.
//!The default value is true.
//!
//!\tparam ThrowOnExhaustion A boolean value. True if throw is required.
BOOST_INTRUSIVE_OPTION_CONSTANT(throw_on_overflow, bool, ThrowOnOverflow, throw_on_overflow)
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<bool ThrowOnOverflow, std::size_t Alignment>
struct static_vector_opt
{
static const bool throw_on_overflow = ThrowOnOverflow;
static const std::size_t alignment = Alignment;
};
typedef static_vector_opt<true, 0u> static_vector_null_opt;
#endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! Helper metafunction to combine options into a single type to be used
//! by \c boost::container::static_vector.
//! Supported options are: \c boost::container::throw_on_overflow and \c boost::container::alignment
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
#endif
struct static_vector_options
{
/// @cond
typedef typename ::boost::intrusive::pack_options
< static_vector_null_opt,
#if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef static_vector_opt< packed_options::throw_on_overflow
, packed_options::alignment> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
//! Helper alias metafunction to combine options into a single type to be used
//! by \c boost::container::static_vector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size
template<class ...Options>
using static_vector_options_t = typename boost::container::static_vector_options<Options...>::type;
#endif
////////////////////////////////////////////////////////////////
//
//

View File

@@ -35,9 +35,21 @@ namespace boost { namespace container {
namespace dtl {
template<class T, std::size_t N>
template<class T, std::size_t N, std::size_t Alignment, bool ThrowOnOverflow>
class static_storage_allocator
{
typedef bool_<ThrowOnOverflow> throw_on_overflow_t;
static BOOST_NORETURN BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow(true_type)
{
(throw_bad_alloc)();
}
static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow(false_type)
{
BOOST_ASSERT_MSG(false, "ERROR: static vector capacity overflow");
}
public:
typedef T value_type;
@@ -61,6 +73,11 @@ class static_storage_allocator
std::size_t max_size() const
{ return N; }
static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow()
{
(on_capacity_overflow)(throw_on_overflow_t());
}
typedef boost::container::dtl::version_type<static_storage_allocator, 0> version;
BOOST_CONTAINER_FORCEINLINE friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
@@ -70,9 +87,36 @@ class static_storage_allocator
{ return true; }
private:
typename dtl::aligned_storage<sizeof(T)*N, dtl::alignment_of<T>::value>::type storage;
BOOST_STATIC_ASSERT_MSG(!Alignment || (Alignment & (Alignment-1)) == 0, "Alignment option must be zero or power of two");
static const std::size_t final_alignment = Alignment ? Alignment : dtl::alignment_of<T>::value;
typename dtl::aligned_storage<sizeof(T)*N, final_alignment>::type storage;
};
template<class Options>
struct get_static_vector_opt
{
typedef Options type;
};
template<>
struct get_static_vector_opt<void>
{
typedef static_vector_null_opt type;
};
template <typename T, std::size_t Capacity, class Options>
struct get_static_vector_allocator
{
typedef typename get_static_vector_opt<Options>::type options_t;
typedef dtl::static_storage_allocator
< T
, Capacity
, options_t::alignment
, options_t::throw_on_overflow
> type;
};
} //namespace dtl {
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -99,22 +143,23 @@ class static_storage_allocator
//! std::out_of_range is thrown if out of bounds access is performed in <code>at()</code> if exceptions are
//! enabled, throw_out_of_range() if not enabled.
//!
//!@tparam Value The type of element that will be stored.
//!@tparam T The type of element that will be stored.
//!@tparam Capacity The maximum number of elements static_vector can store, fixed at compile time.
template <typename Value, std::size_t Capacity>
template <typename T, std::size_t Capacity, class Options BOOST_CONTAINER_DOCONLY(= void) >
class static_vector
: public vector<Value, dtl::static_storage_allocator<Value, Capacity> >
: public vector<T, typename dtl::get_static_vector_allocator< T, Capacity, Options>::type>
{
public:
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
typedef vector<Value, dtl::static_storage_allocator<Value, Capacity> > base_t;
typedef typename dtl::get_static_vector_allocator< T, Capacity, Options>::type allocator_type;
typedef vector<T, allocator_type > base_t;
BOOST_COPYABLE_AND_MOVABLE(static_vector)
template<class U, std::size_t OtherCapacity>
template<class U, std::size_t OtherCapacity, class OtherOptions>
friend class static_vector;
public:
typedef dtl::static_storage_allocator<Value, Capacity> allocator_type;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
@@ -162,7 +207,7 @@ public:
//! @param count The number of values which will be contained in the container.
//!
//! @par Throws
//! If Value's value initialization throws.
//! If T's value initialization throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -177,7 +222,7 @@ public:
//! @param count The number of values which will be contained in the container.
//!
//! @par Throws
//! If Value's default initialization throws.
//! If T's default initialization throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -196,7 +241,7 @@ public:
//! @param value The value which will be used to copy construct values.
//!
//! @par Throws
//! If Value's copy constructor throws.
//! If T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -214,7 +259,7 @@ public:
//! @param last The iterator to the one after the last element in range.
//!
//! @par Throws
//! If Value's constructor taking a dereferenced Iterator throws.
//! If T's constructor taking a dereferenced Iterator throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -232,7 +277,7 @@ public:
//! @param il std::initializer_list with values to initialize vector.
//!
//! @par Throws
//! If Value's constructor taking a dereferenced std::initializer_list throws.
//! If T's constructor taking a dereferenced std::initializer_list throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -246,7 +291,7 @@ public:
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor throws.
//! If T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -274,12 +319,12 @@ public:
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor throws.
//! If T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
BOOST_CONTAINER_FORCEINLINE static_vector(static_vector<value_type, C> const& other)
template <std::size_t C, class O>
BOOST_CONTAINER_FORCEINLINE static_vector(static_vector<T, C, O> const& other)
: base_t(other)
{}
@@ -288,8 +333,8 @@ public:
//! @param other The static_vector which content will be moved to this one.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor throws.
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor throws.
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor throws.
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -305,14 +350,14 @@ public:
//! @param other The static_vector which content will be moved to this one.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor throws.
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor throws.
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor throws.
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
BOOST_CONTAINER_FORCEINLINE static_vector(BOOST_RV_REF_BEG static_vector<value_type, C> BOOST_RV_REF_END other)
: base_t(BOOST_MOVE_BASE(typename static_vector<value_type BOOST_MOVE_I C>::base_t, other))
template <std::size_t C, class O>
BOOST_CONTAINER_FORCEINLINE static_vector(BOOST_RV_REF_BEG static_vector<T, C, O> BOOST_RV_REF_END other)
: base_t(BOOST_MOVE_BASE(typename static_vector<T BOOST_MOVE_I C>::base_t, other))
{}
//! @brief Copy assigns Values stored in the other static_vector to this one.
@@ -320,7 +365,7 @@ public:
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//! If T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -335,7 +380,7 @@ public:
//! @param il The std::initializer_list which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//! If T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -350,15 +395,15 @@ public:
//! @param other The static_vector which content will be copied to this one.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//! If T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
BOOST_CONTAINER_FORCEINLINE static_vector & operator=(static_vector<value_type, C> const& other)
template <std::size_t C, class O>
BOOST_CONTAINER_FORCEINLINE static_vector & operator=(static_vector<T, C, O> const& other)
{
return static_cast<static_vector&>(base_t::operator=
(static_cast<typename static_vector<value_type, C>::base_t const&>(other)));
(static_cast<typename static_vector<T, C, O>::base_t const&>(other)));
}
//! @brief Move assignment. Moves Values stored in the other static_vector to this one.
@@ -366,8 +411,8 @@ public:
//! @param other The static_vector which content will be moved to this one.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws.
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws.
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor or move assignment throws.
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -384,16 +429,16 @@ public:
//! @param other The static_vector which content will be moved to this one.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws.
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws.
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor or move assignment throws.
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
BOOST_CONTAINER_FORCEINLINE static_vector & operator=(BOOST_RV_REF_BEG static_vector<value_type, C> BOOST_RV_REF_END other)
template <std::size_t C, class O>
BOOST_CONTAINER_FORCEINLINE static_vector & operator=(BOOST_RV_REF_BEG static_vector<T, C, O> BOOST_RV_REF_END other)
{
return static_cast<static_vector&>(base_t::operator=
(BOOST_MOVE_BASE(typename static_vector<value_type BOOST_MOVE_I C>::base_t, other)));
(BOOST_MOVE_BASE(typename static_vector<T BOOST_MOVE_I C>::base_t, other)));
}
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -412,8 +457,8 @@ public:
//! @param other The static_vector which content will be swapped with this one's content.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws,
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor or move assignment throws,
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
@@ -426,13 +471,13 @@ public:
//! @param other The static_vector which content will be swapped with this one's content.
//!
//! @par Throws
//! @li If \c has_nothrow_move<Value>::value is \c true and Value's move constructor or move assignment throws,
//! @li If \c has_nothrow_move<Value>::value is \c false and Value's copy constructor or copy assignment throws,
//! @li If \c has_nothrow_move<T>::value is \c true and T's move constructor or move assignment throws,
//! @li If \c has_nothrow_move<T>::value is \c false and T's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
template <std::size_t C>
void swap(static_vector<value_type, C> & other);
template <std::size_t C, class O>
void swap(static_vector<T, C, O> & other);
//! @pre <tt>count <= capacity()</tt>
//!
@@ -442,7 +487,7 @@ public:
//! @param count The number of elements which will be stored in the container.
//!
//! @par Throws
//! If Value's value initialization throws.
//! If T's value initialization throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -456,7 +501,7 @@ public:
//! @param count The number of elements which will be stored in the container.
//!
//! @par Throws
//! If Value's default initialization throws.
//! If T's default initialization throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -474,7 +519,7 @@ public:
//! @param value The value used to copy construct the new element.
//!
//! @par Throws
//! If Value's copy constructor throws.
//! If T's copy constructor throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -500,7 +545,7 @@ public:
//! @param value The value used to copy construct the new element.
//!
//! @par Throws
//! If Value's copy constructor throws.
//! If T's copy constructor throws.
//!
//! @par Complexity
//! Constant O(1).
@@ -513,7 +558,7 @@ public:
//! @param value The value to move construct the new element.
//!
//! @par Throws
//! If Value's move constructor throws.
//! If T's move constructor throws.
//!
//! @par Complexity
//! Constant O(1).
@@ -540,8 +585,8 @@ public:
//! @param value The value used to copy construct the new element.
//!
//! @par Throws
//! @li If Value's copy constructor or copy assignment throws
//! @li If Value's move constructor or move assignment throws.
//! @li If T's copy constructor or copy assignment throws
//! @li If T's move constructor or move assignment throws.
//!
//! @par Complexity
//! Constant or linear.
@@ -557,7 +602,7 @@ public:
//! @param value The value used to move construct the new element.
//!
//! @par Throws
//! If Value's move constructor or move assignment throws.
//! If T's move constructor or move assignment throws.
//!
//! @par Complexity
//! Constant or linear.
@@ -574,8 +619,8 @@ public:
//! @param value The value used to copy construct new elements.
//!
//! @par Throws
//! @li If Value's copy constructor or copy assignment throws.
//! @li If Value's move constructor or move assignment throws.
//! @li If T's copy constructor or copy assignment throws.
//! @li If T's move constructor or move assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -593,8 +638,8 @@ public:
//! @param last The iterator to the one after the last element of a range used to construct new elements.
//!
//! @par Throws
//! @li If Value's constructor and assignment taking a dereferenced \c Iterator.
//! @li If Value's move constructor or move assignment throws.
//! @li If T's constructor and assignment taking a dereferenced \c Iterator.
//! @li If T's move constructor or move assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -611,7 +656,7 @@ public:
//! @param il The std::initializer_list which contains elements that will be inserted.
//!
//! @par Throws
//! @li If Value's constructor and assignment taking a dereferenced std::initializer_list iterator.
//! @li If T's constructor and assignment taking a dereferenced std::initializer_list iterator.
//!
//! @par Complexity
//! Linear O(N).
@@ -619,12 +664,12 @@ public:
//! @pre \c p must be a valid iterator of \c *this in range <tt>[begin(), end())</tt>
//!
//! @brief Erases Value from p.
//! @brief Erases T from p.
//!
//! @param p The position of the element which will be erased from the container.
//!
//! @par Throws
//! If Value's move assignment throws.
//! If T's move assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -640,7 +685,7 @@ public:
//! @param last The position of the one after the last element of a range which will be erased from the container.
//!
//! @par Throws
//! If Value's move assignment throws.
//! If T's move assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -654,7 +699,7 @@ public:
//! @param last The iterator to the one after the last element of a range used to construct new content of this container.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws,
//! If T's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
@@ -668,7 +713,7 @@ public:
//! @param il std::initializer_list with values used to construct new content of this container.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws,
//! If T's copy constructor or copy assignment throws,
//!
//! @par Complexity
//! Linear O(N).
@@ -682,7 +727,7 @@ public:
//! @param value The value which will be used to copy construct the new content.
//!
//! @par Throws
//! If Value's copy constructor or copy assignment throws.
//! If T's copy constructor or copy assignment throws.
//!
//! @par Complexity
//! Linear O(N).
@@ -690,7 +735,7 @@ public:
//! @pre <tt>size() < capacity()</tt>
//!
//! @brief Inserts a Value constructed with
//! @brief Inserts a T constructed with
//! \c std::forward<Args>(args)... in the end of the container.
//!
//! @return A reference to the created object.
@@ -698,7 +743,7 @@ public:
//! @param args The arguments of the constructor of the new element which will be created at the end of the container.
//!
//! @par Throws
//! If in-place constructor throws or Value's move constructor throws.
//! If in-place constructor throws or T's move constructor throws.
//!
//! @par Complexity
//! Constant O(1).
@@ -709,14 +754,14 @@ public:
//! @li \c p must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>
//! @li <tt>size() < capacity()</tt>
//!
//! @brief Inserts a Value constructed with
//! @brief Inserts a T constructed with
//! \c std::forward<Args>(args)... before p
//!
//! @param p The position at which new elements will be inserted.
//! @param args The arguments of the constructor of the new element.
//!
//! @par Throws
//! If in-place constructor throws or if Value's move constructor or move assignment throws.
//! If in-place constructor throws or if T's move constructor or move assignment throws.
//!
//! @par Complexity
//! Constant or linear.
@@ -920,7 +965,7 @@ public:
//!
//! @par Complexity
//! Constant O(1).
Value * data() BOOST_NOEXCEPT_OR_NOTHROW;
T * data() BOOST_NOEXCEPT_OR_NOTHROW;
//! @brief Const pointer such that <tt>[data(), data() + size())</tt> is a valid range.
//! For a non-empty vector <tt>data() == &front()</tt>.
@@ -930,7 +975,7 @@ public:
//!
//! @par Complexity
//! Constant O(1).
const Value * data() const BOOST_NOEXCEPT_OR_NOTHROW;
const T * data() const BOOST_NOEXCEPT_OR_NOTHROW;
//! @brief Returns iterator to the first element.
//!
@@ -1138,8 +1183,8 @@ public:
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator== (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator== (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Checks if contents of two static_vectors are not equal.
//!
@@ -1152,8 +1197,8 @@ bool operator== (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator!= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator!= (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Lexicographically compares static_vectors.
//!
@@ -1166,8 +1211,8 @@ bool operator!= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator< (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator< (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Lexicographically compares static_vectors.
//!
@@ -1180,8 +1225,8 @@ bool operator< (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator> (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator> (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Lexicographically compares static_vectors.
//!
@@ -1194,8 +1239,8 @@ bool operator> (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator<= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator<= (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Lexicographically compares static_vectors.
//!
@@ -1208,8 +1253,8 @@ bool operator<= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
bool operator>= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
bool operator>= (static_vector<V, C1, O1> const& x, static_vector<V, C2, O2> const& y);
//! @brief Swaps contents of two static_vectors.
//!
@@ -1222,13 +1267,13 @@ bool operator>= (static_vector<V, C1> const& x, static_vector<V, C2> const& y);
//!
//! @par Complexity
//! Linear O(N).
template<typename V, std::size_t C1, std::size_t C2>
inline void swap(static_vector<V, C1> & x, static_vector<V, C2> & y);
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
inline void swap(static_vector<V, C1, O1> & x, static_vector<V, C2, O2> & y);
#else
template<typename V, std::size_t C1, std::size_t C2>
inline void swap(static_vector<V, C1> & x, static_vector<V, C2> & y
template<typename V, std::size_t C1, std::size_t C2, class O1, class O2>
inline void swap(static_vector<V, C1, O1> & x, static_vector<V, C2, O2> & y
, typename dtl::enable_if_c< C1 != C2>::type * = 0)
{
x.swap(y);

View File

@@ -501,6 +501,9 @@ struct vector_alloc_holder
BOOST_CONTAINER_FORCEINLINE void capacity(const size_type &c) BOOST_NOEXCEPT_OR_NOTHROW
{ BOOST_ASSERT( c <= stored_size_type(-1)); m_capacity = c; }
static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow()
{ }
private:
void priv_first_allocation(size_type cap)
{
@@ -631,10 +634,13 @@ struct vector_alloc_holder<Allocator, StoredSizeType, version_0>
(this->alloc(), boost::movelib::to_raw_pointer(holder.start()), n, boost::movelib::to_raw_pointer(this->start()));
}
static BOOST_CONTAINER_FORCEINLINE void on_capacity_overflow()
{ allocator_type::on_capacity_overflow(); }
BOOST_CONTAINER_FORCEINLINE void priv_first_allocation(size_type cap)
{
if(cap > allocator_type::internal_capacity){
throw_bad_alloc();
on_capacity_overflow();
}
}
@@ -648,20 +654,20 @@ struct vector_alloc_holder<Allocator, StoredSizeType, version_0>
{
typedef typename real_allocator<value_type, OtherAllocator>::type other_allocator_type;
if(this->m_size > other_allocator_type::internal_capacity || x.m_size > allocator_type::internal_capacity){
throw_bad_alloc();
on_capacity_overflow();
}
this->priv_deep_swap(x);
}
BOOST_CONTAINER_FORCEINLINE void swap_resources(vector_alloc_holder &) BOOST_NOEXCEPT_OR_NOTHROW
{ //Containers with version 0 allocators can't be moved without moving elements one by one
throw_bad_alloc();
on_capacity_overflow();
}
BOOST_CONTAINER_FORCEINLINE void steal_resources(vector_alloc_holder &)
{ //Containers with version 0 allocators can't be moved without moving elements one by one
throw_bad_alloc();
on_capacity_overflow();
}
BOOST_CONTAINER_FORCEINLINE allocator_type &alloc() BOOST_NOEXCEPT_OR_NOTHROW
@@ -2327,7 +2333,7 @@ private:
template<class FwdIt, class Compare>
BOOST_CONTAINER_FORCEINLINE void priv_merge_in_new_buffer(FwdIt, size_type, Compare, version_0)
{
throw_bad_alloc();
alloc_holder_t::on_capacity_overflow();
}
template<class FwdIt, class Compare, class Version>
@@ -2407,7 +2413,7 @@ private:
{
if(!dtl::is_same<typename real_allocator<T, OtherA>::type, allocator_type>::value &&
this->capacity() < x.size()){
throw_bad_alloc();
alloc_holder_t::on_capacity_overflow();
}
T* const this_start = this->priv_raw_begin();
T* const other_start = x.priv_raw_begin();
@@ -2459,7 +2465,7 @@ private:
{
if(!dtl::is_same<typename real_allocator<T, OtherA>::type, allocator_type>::value &&
this->capacity() < x.size()){
throw_bad_alloc();
alloc_holder_t::on_capacity_overflow();
}
T* const this_start = this->priv_raw_begin();
T* const other_start = x.priv_raw_begin();
@@ -2528,7 +2534,7 @@ private:
}
void priv_reserve_no_capacity(size_type, version_0)
{ throw_bad_alloc(); }
{ alloc_holder_t::on_capacity_overflow(); }
dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy()
{
@@ -2627,10 +2633,10 @@ private:
( vector_iterator_get_ptr(p), 1, dtl::get_insert_value_proxy<T*, allocator_type>(::boost::forward<U>(x)));
}
dtl::insert_copy_proxy<allocator_type, T*> priv_single_insert_proxy(const T &x)
BOOST_CONTAINER_FORCEINLINE dtl::insert_copy_proxy<allocator_type, T*> priv_single_insert_proxy(const T &x)
{ return dtl::insert_copy_proxy<allocator_type, T*> (x); }
dtl::insert_move_proxy<allocator_type, T*> priv_single_insert_proxy(BOOST_RV_REF(T) x)
BOOST_CONTAINER_FORCEINLINE dtl::insert_move_proxy<allocator_type, T*> priv_single_insert_proxy(BOOST_RV_REF(T) x)
{ return dtl::insert_move_proxy<allocator_type, T*> (x); }
template <class U>
@@ -2731,7 +2737,7 @@ private:
iterator priv_forward_range_insert_no_capacity
(const pointer &pos, const size_type, const InsertionProxy , version_0)
{
throw_bad_alloc();
alloc_holder_t::on_capacity_overflow();
return iterator(pos);
}
@@ -2831,7 +2837,7 @@ private:
if (n > remaining){
//This will trigger an error
throw_bad_alloc();
alloc_holder_t::on_capacity_overflow();
}
this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy);
return this->end();