mirror of
https://github.com/boostorg/container.git
synced 2025-08-02 14:04:26 +02:00
Update small_vector documentation + update links to Howard Hinnant's papers.
This commit is contained in:
@@ -514,6 +514,21 @@ are a particular case where `static_vector` can be beneficial.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:small_vector ['small_vector]]
|
||||
|
||||
`small_vector` is a vector-like container optimized for the case when it contains few elements.
|
||||
It contains some preallocated elements in-place, which allows it to avoid the use of dynamic storage allocation
|
||||
when the actual number of elements is below that preallocated threshold. `small_vector` is inspired by
|
||||
[@http://llvm.org/docs/ProgrammersManual.html#llvm-adt-smallvector-h LLVM's `SmallVector`] container.
|
||||
Unlike `static_vector`, `small_vector`'s capacity can grow beyond the initial preallocated capacity.
|
||||
|
||||
`small_vector<T, N, Allocator>` is convertible to `small_vector_base<T, Allocator>`, a type that is independent
|
||||
from the preallocated element count, allowing client code that does not need to be templated on that N argument.
|
||||
`small_vector` inherits all `vector`'s member functions so it supports all standard features like emplacement,
|
||||
stateful allocators, etc.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:extended_functionality Extended functionality]
|
||||
@@ -596,7 +611,7 @@ used to customize these containers:
|
||||
|
||||
In the first C++ standard `list::size()` was not required to be constant-time,
|
||||
and that caused some controversy in the C++ community. Quoting Howard Hinnant's
|
||||
[@http://home.roadrunner.com/~hinnant/On_list_size.html ['On List Size]] paper:
|
||||
[@http://howardhinnant.github.io/On_list_size.html ['On List Size]] paper:
|
||||
|
||||
[: ['There is a considerable debate on whether `std::list<T>::size()` should be O(1) or O(N).
|
||||
The usual argument notes that it is a tradeoff with:]
|
||||
@@ -899,7 +914,7 @@ unsuccessful tries to deprecate or remove it from the standard. [*Boost.Containe
|
||||
as there is a superior [@http://www.boost.org/libs/dynamic_bitset/ Boost.DynamicBitset]
|
||||
solution. For issues with `vector<bool>` see the following papers:
|
||||
|
||||
* [@http://home.roadrunner.com/~hinnant/onvectorbool.html On `vector<bool>`]
|
||||
* [@http://howardhinnant.github.io/onvectorbool.html On `vector<bool>`]
|
||||
* [@http://www.gotw.ca/publications/N1211.pdf vector<bool>: N1211: More Problems, Better Solutions],
|
||||
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2160.html N2160: Library Issue 96: Fixing vector<bool>],
|
||||
* [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2204.html N2204 A Specification to deprecate vector<bool>].
|
||||
@@ -1082,15 +1097,16 @@ use [*Boost.Container]? There are several reasons for that:
|
||||
[section:release_notes Release Notes]
|
||||
|
||||
[section:release_notes_boost_1_58_00 Boost 1.58 Release]
|
||||
* Massive dependency reorganization. Now [*Boost.Container depends on very basic utilities like Boost.Core
|
||||
* Experimental [classref boost::container::small_vector small_vector] container.
|
||||
* Massive dependency reorganization. Now [*Boost.Container] depends on very basic utilities like Boost.Core
|
||||
and [*Boost.Intrusive]. Preprocessed code size have decreased considerably and compilation times have improved.
|
||||
* Added `nth` and `index_of` functions to containers with random-access iterators (except `basic_string`).
|
||||
* Added C++17's `allocator_traits<Allocator>::is_always_equal`.
|
||||
* Experimental [classref boost::container::small_vector small_vector] container.
|
||||
* Updated containers to implement new constructors as specified in
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2210 2210. Missing allocator-extended constructor for allocator-aware containers].
|
||||
* Fixed bugs:
|
||||
* [@https://svn.boost.org/trac/boost/ticket/9931 #9931: ['"flat_map::insert(ordered_unique_range_t...) fails with move_iterators"]] (reopened).
|
||||
* [@https://svn.boost.org/trac/boost/ticket/11076 #11076: ['"Unqualified calls to memmove/memcpy in container/detail/copy_move_algo.hpp"]].
|
||||
* [@https://svn.boost.org/trac/boost/ticket/10790 Trac #10790 (['long long errors from container"])].
|
||||
* [@https://svn.boost.org/trac/boost/ticket/10808 Trac #10808 (['compare equal operator of vector is broken"])].
|
||||
* [*Source Breaking]: [classref boost::container::scoped_allocator_adaptor scoped_allocator_adaptor]'s
|
||||
|
@@ -161,11 +161,10 @@ struct allocator_traits
|
||||
//! Allocator::is_always_equal if such a type exists, otherwise a type
|
||||
//! with an internal constant static boolean member <code>value</code> == is_empty<Allocator>::value
|
||||
typedef see_documentation is_always_equal;
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //Still experimental
|
||||
//! Allocator::is_partially_propagable if such a type exists, otherwise a type
|
||||
//! with an internal constant static boolean member <code>value</code> == false
|
||||
//! <b>Note</b>: Non-standard extension used to implement `small_vector_allocator`.
|
||||
typedef see_documentation is_partially_propagable;
|
||||
#endif
|
||||
//! Defines an allocator: Allocator::rebind<T>::other if such a type exists; otherwise, Allocator<T, Args>
|
||||
//! if Allocator is a class template instantiation of the form Allocator<U, Args>, where Args is zero or
|
||||
//! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed.
|
||||
@@ -240,8 +239,6 @@ struct allocator_traits
|
||||
typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::container_detail::, Allocator,
|
||||
is_partially_propagable, container_detail::false_type)
|
||||
is_partially_propagable;
|
||||
//is_always_equal and is_partially_propagable are not compatible
|
||||
BOOST_STATIC_ASSERT((!is_always_equal::value || !is_partially_propagable::value));
|
||||
|
||||
//rebind_alloc & rebind_traits
|
||||
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
|
||||
@@ -348,7 +345,6 @@ struct allocator_traits
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||
//! <b>Returns</b>: <code>a.storage_is_unpropagable(p)</code> if is_partially_propagable::value is true; otherwise,
|
||||
//! <code>false</code>.
|
||||
static bool storage_is_unpropagable(const Allocator &a, pointer p) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
@@ -365,6 +361,7 @@ struct allocator_traits
|
||||
return allocator_traits::priv_equal(flag, a, b);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||
private:
|
||||
static pointer priv_allocate(container_detail::true_type, Allocator &a, size_type n, const_void_pointer p)
|
||||
{ return a.allocate(n, p); }
|
||||
|
@@ -53,11 +53,34 @@ namespace container {
|
||||
template <class T, class Allocator = new_allocator<T> >
|
||||
class small_vector_base;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// small_vector_allocator
|
||||
//
|
||||
/////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
//! A non-standard allocator used to implement `small_vector`.
|
||||
//! Users should never use it directly. It is described here
|
||||
//! for documentation purposes.
|
||||
//!
|
||||
//! This allocator inherits from a standard-conforming allocator
|
||||
//! and forwards member functiond to the standard allocator except
|
||||
//! when internal storage is being used as memory source.
|
||||
//!
|
||||
//! This allocator is a "partially_propagable" allocator and
|
||||
//! defines `is_partially_propagable` as true_type.
|
||||
//!
|
||||
//! A partially propagable allocator means that not all storage
|
||||
//! allocatod by an instance of `small_vector_allocator` can be
|
||||
//! deallocated by another instance of this type, even is both
|
||||
//! instances compare equal or an instance is propagated to another
|
||||
//! one using the copy/move constructor or assignment. The storage that
|
||||
//! can never be propagated is identified by `storage_is_unpropagable(p)`.
|
||||
//!
|
||||
//! `boost::container::vector` supports partially propagable allocators
|
||||
//! fallbacking to deep copy/swap/move operations when internal storage
|
||||
//! is being used to store vector elements.
|
||||
//!
|
||||
//! `small_vector_allocator` assumes that will be instantiated as
|
||||
//! `boost::container::vector< T, small_vector_allocator<Allocator> >`
|
||||
//! and internal storage can be obtained downcasting that vector
|
||||
//! to `small_vector_base<T>`.
|
||||
template<class Allocator>
|
||||
class small_vector_allocator
|
||||
: public Allocator
|
||||
@@ -65,24 +88,20 @@ class small_vector_allocator
|
||||
typedef unsigned int allocation_type;
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
private:
|
||||
//Self type
|
||||
typedef small_vector_allocator<Allocator> self_t;
|
||||
|
||||
BOOST_COPYABLE_AND_MOVABLE(small_vector_allocator)
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
const Allocator &as_base() const
|
||||
{ return static_cast<const Allocator&>(*this); }
|
||||
|
||||
Allocator &as_base()
|
||||
{ return static_cast<Allocator&>(*this); }
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
public:
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
typedef allocator_traits<Allocator> allocator_traits_type;
|
||||
typedef typename
|
||||
container_detail::version<Allocator>::type version;
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
typedef typename allocator_traits<Allocator>::value_type value_type;
|
||||
@@ -95,18 +114,22 @@ class small_vector_allocator
|
||||
typedef typename allocator_traits<Allocator>::void_pointer void_pointer;
|
||||
typedef typename allocator_traits<Allocator>::const_void_pointer const_void_pointer;
|
||||
|
||||
typedef typename allocator_traits_type::propagate_on_container_copy_assignment propagate_on_container_copy_assignment;
|
||||
typedef typename allocator_traits_type::propagate_on_container_move_assignment propagate_on_container_move_assignment;
|
||||
typedef typename allocator_traits_type::propagate_on_container_swap propagate_on_container_swap;
|
||||
typedef container_detail::bool_<false> is_always_equal;
|
||||
typedef container_detail::bool_<true> is_partially_propagable;
|
||||
typedef typename allocator_traits<Allocator>::propagate_on_container_copy_assignment propagate_on_container_copy_assignment;
|
||||
typedef typename allocator_traits<Allocator>::propagate_on_container_move_assignment propagate_on_container_move_assignment;
|
||||
typedef typename allocator_traits<Allocator>::propagate_on_container_swap propagate_on_container_swap;
|
||||
//! An integral constant with member `::value == false`
|
||||
typedef BOOST_CONTAINER_IMPDEF(container_detail::bool_<false>) is_always_equal;
|
||||
//! An integral constant with member `::value == true`
|
||||
typedef BOOST_CONTAINER_IMPDEF(container_detail::bool_<true>) is_partially_propagable;
|
||||
|
||||
BOOST_CONTAINER_DOCIGN(typedef container_detail::version_type<small_vector_allocator BOOST_CONTAINER_I 1> version;)
|
||||
|
||||
//!Obtains an small_vector_allocator that allocates
|
||||
//!objects of type T2
|
||||
template<class T2>
|
||||
struct rebind
|
||||
{
|
||||
typedef typename allocator_traits_type::template rebind_alloc<T2>::type other;
|
||||
typedef typename allocator_traits<Allocator>::template rebind_alloc<T2>::type other;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||
@@ -174,7 +197,8 @@ class small_vector_allocator
|
||||
small_vector_allocator & operator=(BOOST_RV_REF(small_vector_allocator<OtherAllocator>) other) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return static_cast<small_vector_allocator&>(this->Allocator::operator=(::boost::move(other.as_base()))); }
|
||||
|
||||
pointer allocate(size_type count, const_void_pointer hint)
|
||||
//!Allocates storage from the standard-conforming allocator
|
||||
pointer allocate(size_type count, const_void_pointer hint = const_void_pointer())
|
||||
{ return allocator_traits_type::allocate(this->as_base(), count, hint); }
|
||||
|
||||
//!Deallocates previously allocated memory.
|
||||
@@ -198,18 +222,20 @@ class small_vector_allocator
|
||||
|
||||
//!Swaps two allocators, does nothing
|
||||
//!because this small_vector_allocator is stateless
|
||||
friend void swap(self_t &l, self_t &r) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
friend void swap(small_vector_allocator &l, small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ boost::adl_move_swap(l.as_base(), r.as_base()); }
|
||||
|
||||
//!An small_vector_allocator always compares to true, as memory allocated with one
|
||||
//!instance can be deallocated by another instance
|
||||
friend bool operator==(const small_vector_allocator &, const small_vector_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return false; }
|
||||
//!instance can be deallocated by another instance (except for unpropagable storage)
|
||||
friend bool operator==(const small_vector_allocator &l, const small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return allocator_traits_type::equal(l.as_base(), r.as_base()); }
|
||||
|
||||
//!An small_vector_allocator always compares to false, as memory allocated with one
|
||||
//!instance can be deallocated by another instance
|
||||
friend bool operator!=(const small_vector_allocator &, const small_vector_allocator &) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return true; }
|
||||
friend bool operator!=(const small_vector_allocator &l, const small_vector_allocator &r) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return !(l == r); }
|
||||
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
/*
|
||||
//!An advanced function that offers in-place expansion shrink to fit and new allocation
|
||||
//!capabilities. Memory allocated with this function can only be deallocated with deallocate()
|
||||
@@ -230,11 +256,11 @@ class small_vector_allocator
|
||||
{ return allocator_traits_type::size(p); }
|
||||
*/
|
||||
private:
|
||||
/*
|
||||
//!Allocates just one object. Memory allocated with this function
|
||||
//!must be deallocated only with deallocate_one().
|
||||
//!Throws bad_alloc if there is no enough memory
|
||||
//!This function is available only with Version == 2
|
||||
/*
|
||||
using Allocator::allocate_one;
|
||||
using Allocator::allocate_individual;
|
||||
using Allocator::deallocate_one;
|
||||
@@ -242,8 +268,6 @@ class small_vector_allocator
|
||||
using Allocator::allocate_many;
|
||||
using Allocator::deallocate_many;*/
|
||||
|
||||
private:
|
||||
|
||||
bool is_internal_storage(pointer p) const
|
||||
{ return this->internal_storage() == p; }
|
||||
|
||||
@@ -259,20 +283,13 @@ class small_vector_allocator
|
||||
const derived_type &d_base = static_cast<const derived_type &>(v_base);
|
||||
return d_base.internal_storage();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// small_vector_base
|
||||
//
|
||||
/////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
//! This class consists of common code from all small_vector<T, N> types that don't depend on the
|
||||
//! "N" template parameter. This class is non-copyable and non-destructible, so this class tipically
|
||||
//! used as reference argument to functions that read or write small vectors. Since small_vector<T, N>
|
||||
//! derives from small_vector_base<T>, the conversion to small_vector_base is implicit:
|
||||
//! used as reference argument to functions that read or write small vectors. Since `small_vector<T, N>`
|
||||
//! derives from `small_vector_base<T>`, the conversion to `small_vector_base` is implicit:
|
||||
//! <code>
|
||||
//!
|
||||
//! //Clients can pass any small_vector<Foo, N>.
|
||||
@@ -298,19 +315,24 @@ class small_vector_base
|
||||
|
||||
BOOST_COPYABLE_AND_MOVABLE(small_vector_base)
|
||||
|
||||
public:
|
||||
friend class small_vector_allocator<SecondaryAllocator>;
|
||||
|
||||
pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
return boost::intrusive::pointer_traits<pointer>::pointer_to
|
||||
(*const_cast<T*>(static_cast<const T*>(static_cast<const void*>(&m_storage_start))));
|
||||
}
|
||||
|
||||
typedef vector<T, small_vector_allocator<SecondaryAllocator> > base_type;
|
||||
base_type &as_base() { return static_cast<base_type&>(*this); }
|
||||
const base_type &as_base() const { return static_cast<const base_type&>(*this); }
|
||||
|
||||
public:
|
||||
typedef typename container_detail::aligned_storage
|
||||
<sizeof(T), container_detail::alignment_of<T>::value>::type storage_type;
|
||||
typedef small_vector_allocator<SecondaryAllocator> allocator_type;
|
||||
|
||||
pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return boost::intrusive::pointer_traits<pointer>::pointer_to(*const_cast<T*>(static_cast<const T*>(static_cast<const void*>(&m_storage_start)))); }
|
||||
|
||||
protected:
|
||||
base_type &as_base() { return static_cast<base_type&>(*this); }
|
||||
const base_type &as_base() const { return static_cast<const base_type&>(*this); }
|
||||
|
||||
typedef typename base_type::initial_capacity_t initial_capacity_t;
|
||||
|
||||
explicit small_vector_base(initial_capacity_t, std::size_t initial_capacity)
|
||||
@@ -367,7 +389,7 @@ template<class Storage, class Allocator, class T, std::size_t N>
|
||||
struct small_vector_storage_calculator
|
||||
{
|
||||
typedef small_vector_base<T, Allocator> svh_type;
|
||||
typedef typename svh_type::base_type svhb_type;
|
||||
typedef vector<T, small_vector_allocator<Allocator> > svhb_type;
|
||||
static const std::size_t s_align = container_detail::alignment_of<Storage>::value;
|
||||
static const std::size_t s_size = sizeof(Storage);
|
||||
static const std::size_t svh_sizeof = sizeof(svh_type);
|
||||
@@ -407,20 +429,22 @@ struct small_vector_storage_definer
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
//! small_vector a vector-like container optimized for the case when it contains few elements.
|
||||
//! It contains some preallocated elements in-place, which allows it to avoid the use of the small_vector_allocator
|
||||
//! It contains some preallocated elements in-place, which allows it to avoid the use of dynamic storage allocation
|
||||
//! when the actual number of elements is below that preallocated threshold.
|
||||
//!
|
||||
//! small_vector<T, N, Allocator> is convertible to small_vector_unbounded<T, Allocator> that is independent
|
||||
//! `small_vector<T, N, Allocator>` is convertible to `small_vector_base<T, Allocator>` that is independent
|
||||
//! from the preallocated element capacity, so client code does not need to be templated on that N argument.
|
||||
//!
|
||||
//! All `boost::container:vector` member functions are inherited. See `vector` documentation for details.
|
||||
//! All `boost::container::vector` member functions are inherited. See `vector` documentation for details.
|
||||
//!
|
||||
//! \tparam T The type of object that is stored in the small_vector
|
||||
//! \tparam N The number of preallocated elements stored inside small_vector. It shall be less than Allocator::max_size();
|
||||
//! \tparam Allocator The small_vector_allocator used for memory management when the number of elements exceeds N.
|
||||
//! \tparam Allocator The allocator used for memory management when the number of elements exceeds N.
|
||||
template <class T, std::size_t N, class Allocator BOOST_CONTAINER_DOCONLY(= new_allocator<T>) >
|
||||
class small_vector : public small_vector_base<T, Allocator>
|
||||
BOOST_CONTAINER_DOCIGN(BOOST_CONTAINER_I private small_vector_storage_definer<Allocator BOOST_CONTAINER_I N>::type)
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
, private small_vector_storage_definer<Allocator, N>::type
|
||||
#endif
|
||||
{
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
typedef small_vector_base<T, Allocator> base_type;
|
||||
|
Reference in New Issue
Block a user