Add block size customization options to deque.

This commit is contained in:
Ion Gaztañaga
2019-04-28 19:18:22 +02:00
parent 47226ff16f
commit 24e420abe9
7 changed files with 287 additions and 76 deletions

View File

@ -33,7 +33,7 @@ In short, what does [*Boost.Container] offer?
* Emplacement and move semantics are implemented, including emulation for pre-C++11 compilers. * Emplacement and move semantics are implemented, including emulation for pre-C++11 compilers.
* Polymorphic allocators and memory resources, including implementation and emulation for pre-C++17 compilers * Polymorphic allocators and memory resources, including implementation and emulation for pre-C++17 compilers
* New advanced features (e.g. recursive containers, configuration options for containers) are present. * New advanced features (e.g. recursive containers) and configurability options [link container.configurable_containers] for containers.
* Containers support stateful allocators and are compatible with [*Boost.Interprocess] * Containers support stateful allocators and are compatible with [*Boost.Interprocess]
(they can be safely placed in shared memory). (they can be safely placed in shared memory).
* Users obtain a more uniform performance across all plataforms, * Users obtain a more uniform performance across all plataforms,
@ -676,8 +676,8 @@ the last template parameter and defined using the utility class
The rate at which the capacity of a vector grows is implementation dependent and The rate at which the capacity of a vector grows is implementation dependent and
implementations choose exponential growth in order to meet the amortized constant time requirement for push_back. implementations choose exponential growth in order to meet the amortized constant time requirement for push_back.
A higher growth factor will make it faster as it will require less data movement, but it will have a greater memory A higher growth factor will make it faster as it will require less data movement, but it will have a greater memory
impact (on average, more memory will be unused). A user can provide it's own implementation and some predefined impact (on average, more memory will be unused). A user can provide a custom implementation of the growth factor and some
policies are available: [classref boost::container::growth_factor_50 growth_factor_50], predefined policies are available: [classref boost::container::growth_factor_50 growth_factor_50],
[classref boost::container::growth_factor_60 growth_factor_60] and [classref boost::container::growth_factor_60 growth_factor_60] and
[classref boost::container::growth_factor_50 growth_factor_100]. [classref boost::container::growth_factor_50 growth_factor_100].
@ -695,6 +695,31 @@ used to customize `vector` container:
[endsect] [endsect]
[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 last template parameter and defined using the utility class
[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:
* [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.
See the following example to see how [classref boost::container::deque_options deque_options] can be
used to customize `deque` container:
[import ../example/doc_custom_deque.cpp]
[doc_custom_deque]
[endsect]
[endsect] [endsect]
[section:extended_allocators Extended functionality: Extended allocators] [section:extended_allocators Extended functionality: Extended allocators]
@ -1251,6 +1276,9 @@ use [*Boost.Container]? There are several reasons for that:
* [@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/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"]]. * [@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].
The block size/bytes can be be specified.
[endsect] [endsect]
[section:release_notes_boost_1_70_00 Boost 1.70 Release] [section:release_notes_boost_1_70_00 Boost 1.70 Release]

View File

@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2013-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//[doc_custom_deque
#include <boost/container/deque.hpp>
#include <boost/static_assert.hpp>
//Make sure assertions are active
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <cassert>
int main ()
{
using namespace boost::container;
//This option specifies the desired block size for deque
typedef deque_options< block_size<128u> >::type block_128_option_t;
//This deque will allocate blocks of 128 elements
typedef deque<int, void, block_128_option_t > block_128_deque_t;
assert(block_128_deque_t::get_block_size() == 128u);
//This option specifies the maximum block size for deque
//in bytes
typedef deque_options< block_bytes<1024u> >::type block_1024_bytes_option_t;
//This deque will allocate blocks of 1024 bytes
typedef deque<int, void, block_1024_bytes_option_t > block_1024_bytes_deque_t;
assert(block_1024_bytes_deque_t::get_block_size() == 1024u/sizeof(int));
return 0;
}
//]

View File

@ -117,7 +117,8 @@ template < class T, std::size_t N
class small_vector; class small_vector;
template <class T template <class T
,class Allocator = void > ,class Allocator = void
,class Options = void>
class deque; class deque;
template <class T template <class T

View File

@ -25,6 +25,7 @@
#include <boost/container/container_fwd.hpp> #include <boost/container/container_fwd.hpp>
#include <boost/container/new_allocator.hpp> //new_allocator #include <boost/container/new_allocator.hpp> //new_allocator
#include <boost/container/throw_exception.hpp> #include <boost/container/throw_exception.hpp>
#include <boost/container/options.hpp>
// container/detail // container/detail
#include <boost/container/detail/advanced_insert_int.hpp> #include <boost/container/detail/advanced_insert_int.hpp>
#include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare #include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare
@ -61,7 +62,7 @@ namespace boost {
namespace container { namespace container {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
template <class T, class Allocator> template <class T, class Allocator, class Options>
class deque; class deque;
template <class T> template <class T>
@ -72,14 +73,12 @@ struct deque_value_traits
static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move<value_type>::value; static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move<value_type>::value;
}; };
// Note: this function is simply a kludge to work around several compilers' template<class T, std::size_t BlockBytes, std::size_t BlockSize>
// bugs in handling constant expressions. struct deque_block_size
template<class T>
struct deque_buf_size
{ {
static const std::size_t min_size = 512u; BOOST_STATIC_ASSERT_MSG(!(BlockBytes && BlockSize), "BlockBytes and BlockSize can't be specified at the same time");
static const std::size_t sizeof_t = sizeof(T); static const std::size_t block_bytes = BlockBytes ? BlockBytes : 512u;
static const std::size_t value = sizeof_t < min_size ? (min_size/sizeof_t) : std::size_t(1); static const std::size_t value = BlockSize ? BlockSize : (sizeof(T) < block_bytes ? (block_bytes/sizeof(T)) : std::size_t(1));
}; };
namespace dtl { namespace dtl {
@ -132,9 +131,6 @@ class deque_iterator
, deque_iterator<Pointer, false> , deque_iterator<Pointer, false>
, nat>::type nonconst_iterator; , nat>::type nonconst_iterator;
BOOST_CONTAINER_FORCEINLINE static std::size_t s_buffer_size()
{ return deque_buf_size<value_type>::value; }
typedef Pointer val_alloc_ptr; typedef Pointer val_alloc_ptr;
typedef typename boost::intrusive::pointer_traits<Pointer>:: typedef typename boost::intrusive::pointer_traits<Pointer>::
template rebind_pointer<Pointer>::type index_pointer; template rebind_pointer<Pointer>::type index_pointer;
@ -151,8 +147,8 @@ class deque_iterator
BOOST_CONTAINER_FORCEINLINE Pointer get_last() const { return m_last; } BOOST_CONTAINER_FORCEINLINE Pointer get_last() const { return m_last; }
BOOST_CONTAINER_FORCEINLINE index_pointer get_node() const { return m_node; } BOOST_CONTAINER_FORCEINLINE index_pointer get_node() const { return m_node; }
BOOST_CONTAINER_FORCEINLINE deque_iterator(val_alloc_ptr x, index_pointer y) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE deque_iterator(val_alloc_ptr x, index_pointer y, difference_type block_size) BOOST_NOEXCEPT_OR_NOTHROW
: m_cur(x), m_first(*y), m_last(*y + s_buffer_size()), m_node(y) : m_cur(x), m_first(*y), m_last(*y + block_size), m_node(y)
{} {}
BOOST_CONTAINER_FORCEINLINE deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW
@ -190,15 +186,20 @@ class deque_iterator
if(!this->m_cur && !x.m_cur){ if(!this->m_cur && !x.m_cur){
return 0; return 0;
} }
return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + const difference_type block_size = this->m_last - this->m_first;
BOOST_ASSERT(block_size);
return block_size * (this->m_node - x.m_node - 1) +
(this->m_cur - this->m_first) + (x.m_last - x.m_cur); (this->m_cur - this->m_first) + (x.m_last - x.m_cur);
} }
deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW
{ {
BOOST_ASSERT(!!m_cur);
++this->m_cur; ++this->m_cur;
if (this->m_cur == this->m_last) { if (this->m_cur == this->m_last) {
this->priv_set_node(this->m_node + 1); const difference_type block_size = m_last - m_first;
BOOST_ASSERT(block_size);
this->priv_set_node(this->m_node + 1, block_size);
this->m_cur = this->m_first; this->m_cur = this->m_first;
} }
return *this; return *this;
@ -213,8 +214,11 @@ class deque_iterator
deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW
{ {
BOOST_ASSERT(!!m_cur);
if (this->m_cur == this->m_first) { if (this->m_cur == this->m_first) {
this->priv_set_node(this->m_node - 1); const difference_type block_size = m_last - m_first;
BOOST_ASSERT(block_size);
this->priv_set_node(this->m_node - 1, block_size);
this->m_cur = this->m_last; this->m_cur = this->m_last;
} }
--this->m_cur; --this->m_cur;
@ -230,16 +234,19 @@ class deque_iterator
deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW
{ {
BOOST_ASSERT(!!m_cur);
difference_type offset = n + (this->m_cur - this->m_first); difference_type offset = n + (this->m_cur - this->m_first);
if (offset >= 0 && offset < difference_type(this->s_buffer_size())) const difference_type block_size = this->m_last - this->m_first;
BOOST_ASSERT(block_size);
if (offset >= 0 && offset < block_size)
this->m_cur += n; this->m_cur += n;
else { else {
difference_type node_offset = difference_type node_offset =
offset > 0 ? offset / difference_type(this->s_buffer_size()) offset > 0 ? (offset / block_size)
: -difference_type((-offset - 1) / this->s_buffer_size()) - 1; : (-difference_type((-offset - 1) / block_size) - 1);
this->priv_set_node(this->m_node + node_offset); this->priv_set_node(this->m_node + node_offset, block_size);
this->m_cur = this->m_first + this->m_cur = this->m_first +
(offset - node_offset * difference_type(this->s_buffer_size())); (offset - node_offset * block_size);
} }
return *this; return *this;
} }
@ -274,11 +281,11 @@ class deque_iterator
BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW
{ return !(l < r); } { return !(l < r); }
BOOST_CONTAINER_FORCEINLINE void priv_set_node(index_pointer new_node) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE void priv_set_node(index_pointer new_node, difference_type block_size) BOOST_NOEXCEPT_OR_NOTHROW
{ {
this->m_node = new_node; this->m_node = new_node;
this->m_first = *new_node; this->m_first = *new_node;
this->m_last = this->m_first + this->s_buffer_size(); this->m_last = this->m_first + block_size;
} }
BOOST_CONTAINER_FORCEINLINE friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW
@ -287,10 +294,22 @@ class deque_iterator
} //namespace dtl { } //namespace dtl {
template<class Options>
struct get_deque_opt
{
typedef Options type;
};
template<>
struct get_deque_opt<void>
{
typedef deque_null_opt type;
};
// Deque base class. It has two purposes. First, its constructor // Deque base class. It has two purposes. First, its constructor
// and destructor allocate (but don't initialize) storage. This makes // and destructor allocate (but don't initialize) storage. This makes
// exception safety easier. // exception safety easier.
template <class Allocator> template <class Allocator, class Options>
class deque_base class deque_base
{ {
BOOST_COPYABLE_AND_MOVABLE(deque_base) BOOST_COPYABLE_AND_MOVABLE(deque_base)
@ -315,19 +334,24 @@ class deque_base
typedef allocator_type stored_allocator_type; typedef allocator_type stored_allocator_type;
typedef val_alloc_size size_type; typedef val_alloc_size size_type;
private:
typedef typename get_deque_opt<Options>::type options_type;
protected: protected:
typedef dtl::deque_iterator<val_alloc_ptr, false> iterator;
typedef dtl::deque_iterator<val_alloc_ptr, true > const_iterator;
BOOST_CONSTEXPR BOOST_CONTAINER_FORCEINLINE static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW
{ return deque_block_size<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; }
typedef deque_value_traits<val_alloc_val> traits_t; typedef deque_value_traits<val_alloc_val> traits_t;
typedef ptr_alloc_t map_allocator_type; typedef ptr_alloc_t map_allocator_type;
BOOST_CONTAINER_FORCEINLINE static size_type s_buffer_size() BOOST_NOEXCEPT_OR_NOTHROW
{ return deque_buf_size<val_alloc_val>::value; }
BOOST_CONTAINER_FORCEINLINE val_alloc_ptr priv_allocate_node() BOOST_CONTAINER_FORCEINLINE val_alloc_ptr priv_allocate_node()
{ return this->alloc().allocate(s_buffer_size()); } { return this->alloc().allocate(get_block_size()); }
BOOST_CONTAINER_FORCEINLINE void priv_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE void priv_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW
{ this->alloc().deallocate(p, s_buffer_size()); } { this->alloc().deallocate(p, get_block_size()); }
BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr priv_allocate_map(size_type n) BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr priv_allocate_map(size_type n)
{ return this->ptr_alloc().allocate(n); } { return this->ptr_alloc().allocate(n); }
@ -335,9 +359,6 @@ class deque_base
BOOST_CONTAINER_FORCEINLINE void priv_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONTAINER_FORCEINLINE void priv_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW
{ this->ptr_alloc().deallocate(p, n); } { this->ptr_alloc().deallocate(p, n); }
typedef dtl::deque_iterator<val_alloc_ptr, false> iterator;
typedef dtl::deque_iterator<val_alloc_ptr, true > const_iterator;
BOOST_CONTAINER_FORCEINLINE deque_base(size_type num_elements, const allocator_type& a) BOOST_CONTAINER_FORCEINLINE deque_base(size_type num_elements, const allocator_type& a)
: members_(a) : members_(a)
{ this->priv_initialize_map(num_elements); } { this->priv_initialize_map(num_elements); }
@ -379,7 +400,7 @@ class deque_base
void priv_initialize_map(size_type num_elements) void priv_initialize_map(size_type num_elements)
{ {
// if(num_elements){ // if(num_elements){
size_type num_nodes = num_elements / s_buffer_size() + 1; size_type num_nodes = num_elements / get_block_size() + 1;
this->members_.m_map_size = dtl::max_value((size_type) InitialMapSize, num_nodes + 2); this->members_.m_map_size = dtl::max_value((size_type) InitialMapSize, num_nodes + 2);
this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size);
@ -398,11 +419,11 @@ class deque_base
} }
BOOST_CATCH_END BOOST_CATCH_END
this->members_.m_start.priv_set_node(nstart); this->members_.m_start.priv_set_node(nstart, get_block_size());
this->members_.m_finish.priv_set_node(nfinish - 1); this->members_.m_finish.priv_set_node(nfinish - 1, get_block_size());
this->members_.m_start.m_cur = this->members_.m_start.m_first; this->members_.m_start.m_cur = this->members_.m_start.m_first;
this->members_.m_finish.m_cur = this->members_.m_finish.m_first + this->members_.m_finish.m_cur = this->members_.m_finish.m_first +
num_elements % s_buffer_size(); num_elements % get_block_size();
// } // }
} }
@ -490,16 +511,18 @@ class deque_base
//! and removal of elements at the end of the sequence, and linear time insertion and removal of elements in the middle. //! and removal of elements at the end of the sequence, and linear time insertion and removal of elements in the middle.
//! //!
//! \tparam T The type of object that is stored in the deque //! \tparam T The type of object that is stored in the deque
//! \tparam Allocator The allocator used for all internal memory management //! \tparam A The allocator used for all internal memory management, use void
template <class T, class Allocator = new_allocator<T> > //! for the default allocator
//! \tparam Options A type produced from \c boost::container::vector_options.
template <class T, class Allocator = void, class Options = void>
#else #else
template <class T, class Allocator> template <class T, class Allocator, class Options>
#endif #endif
class deque : protected deque_base<typename real_allocator<T, Allocator>::type> class deque : protected deque_base<typename real_allocator<T, Allocator>::type, Options>
{ {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private: private:
typedef deque_base<typename real_allocator<T, Allocator>::type> Base; typedef deque_base<typename real_allocator<T, Allocator>::type, Options> Base;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
typedef typename real_allocator<T, Allocator>::type ValAllocator; typedef typename real_allocator<T, Allocator>::type ValAllocator;
@ -530,13 +553,15 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
private: // Internal typedefs private: // Internal typedefs
BOOST_COPYABLE_AND_MOVABLE(deque) BOOST_COPYABLE_AND_MOVABLE(deque)
typedef typename Base::ptr_alloc_ptr index_pointer; typedef typename Base::ptr_alloc_ptr index_pointer;
BOOST_CONTAINER_FORCEINLINE static size_type s_buffer_size()
{ return Base::s_buffer_size(); }
typedef allocator_traits<ValAllocator> allocator_traits_type; typedef allocator_traits<ValAllocator> allocator_traits_type;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public: public:
BOOST_CONSTEXPR BOOST_CONTAINER_FORCEINLINE static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW
{ return Base::get_block_size(); }
////////////////////////////////////////////// //////////////////////////////////////////////
// //
// construct/copy/destroy // construct/copy/destroy
@ -1776,7 +1801,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
for (index_pointer node = this->members_.m_start.m_node + 1; for (index_pointer node = this->members_.m_start.m_node + 1;
node < this->members_.m_finish.m_node; node < this->members_.m_finish.m_node;
++node) { ++node) {
this->priv_destroy_range(*node, *node + this->s_buffer_size()); this->priv_destroy_range(*node, *node + get_block_size());
this->priv_deallocate_node(*node); this->priv_deallocate_node(*node);
} }
@ -2087,13 +2112,13 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
BOOST_TRY { BOOST_TRY {
for ( ; cur < this->members_.m_finish.m_node; ++cur){ for ( ; cur < this->members_.m_finish.m_node; ++cur){
boost::container::uninitialized_fill_alloc boost::container::uninitialized_fill_alloc
(this->alloc(), *cur, *cur + this->s_buffer_size(), value); (this->alloc(), *cur, *cur + get_block_size(), value);
} }
boost::container::uninitialized_fill_alloc boost::container::uninitialized_fill_alloc
(this->alloc(), this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); (this->alloc(), this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value);
} }
BOOST_CATCH(...){ BOOST_CATCH(...){
this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur, get_block_size()));
BOOST_RETHROW BOOST_RETHROW
} }
BOOST_CATCH_END BOOST_CATCH_END
@ -2125,14 +2150,14 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
BOOST_TRY { BOOST_TRY {
for (; cur_node < this->members_.m_finish.m_node; ++cur_node) { for (; cur_node < this->members_.m_finish.m_node; ++cur_node) {
FwdIt mid = first; FwdIt mid = first;
boost::container::iterator_advance(mid, this->s_buffer_size()); boost::container::iterator_advance(mid, get_block_size());
::boost::container::uninitialized_copy_alloc(this->alloc(), first, mid, *cur_node); ::boost::container::uninitialized_copy_alloc(this->alloc(), first, mid, *cur_node);
first = mid; first = mid;
} }
::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first); ::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first);
} }
BOOST_CATCH(...){ BOOST_CATCH(...){
this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node, get_block_size()));
BOOST_RETHROW BOOST_RETHROW
} }
BOOST_CATCH_END BOOST_CATCH_END
@ -2142,7 +2167,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW
{ {
this->priv_deallocate_node(this->members_.m_finish.m_first); this->priv_deallocate_node(this->members_.m_finish.m_first);
this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1); this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1, get_block_size());
this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1; this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1;
allocator_traits_type::destroy allocator_traits_type::destroy
( this->alloc() ( this->alloc()
@ -2161,7 +2186,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
, boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur)
); );
this->priv_deallocate_node(this->members_.m_start.m_first); this->priv_deallocate_node(this->members_.m_start.m_first);
this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1); this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1, get_block_size());
this->members_.m_start.m_cur = this->members_.m_start.m_first; this->members_.m_start.m_cur = this->members_.m_start.m_first;
} }
@ -2170,8 +2195,8 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first;
if (n > vacancies){ if (n > vacancies){
size_type new_elems = n-vacancies; size_type new_elems = n-vacancies;
size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / size_type new_nodes = (new_elems + get_block_size() - 1) /
this->s_buffer_size(); get_block_size();
size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map);
if (new_nodes > s){ if (new_nodes > s){
this->priv_reallocate_map(new_nodes, true); this->priv_reallocate_map(new_nodes, true);
@ -2196,7 +2221,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1;
if (n > vacancies){ if (n > vacancies){
size_type new_elems = n - vacancies; size_type new_elems = n - vacancies;
size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); size_type new_nodes = (new_elems + get_block_size() - 1)/get_block_size();
size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map));
if (new_nodes + 1 > s){ if (new_nodes + 1 > s){
this->priv_reallocate_map(new_nodes, false); this->priv_reallocate_map(new_nodes, false);
@ -2245,8 +2270,8 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
this->members_.m_map_size = new_map_size; this->members_.m_map_size = new_map_size;
} }
this->members_.m_start.priv_set_node(new_nstart); this->members_.m_start.priv_set_node(new_nstart, get_block_size());
this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1, get_block_size());
} }
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
}; };
@ -2266,8 +2291,8 @@ namespace boost {
//!has_trivial_destructor_after_move<> == true_type //!has_trivial_destructor_after_move<> == true_type
//!specialization for optimizations //!specialization for optimizations
template <class T, class Allocator> template <class T, class Allocator, class Options>
struct has_trivial_destructor_after_move<boost::container::deque<T, Allocator> > struct has_trivial_destructor_after_move<boost::container::deque<T, Allocator, Options> >
{ {
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer; typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value && static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&

View File

@ -24,6 +24,7 @@
#include <boost/container/detail/config_begin.hpp> #include <boost/container/detail/config_begin.hpp>
#include <boost/container/container_fwd.hpp> #include <boost/container/container_fwd.hpp>
#include <boost/intrusive/pack_options.hpp> #include <boost/intrusive/pack_options.hpp>
#include <boost/static_assert.hpp>
namespace boost { namespace boost {
namespace container { namespace container {
@ -111,6 +112,22 @@ using tree_assoc_options_t = typename boost::container::tree_assoc_options<Optio
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<class T, class Default>
struct default_if_void
{
typedef T type;
};
template<class Default>
struct default_if_void<void, Default>
{
typedef Default type;
};
#endif
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<class AllocTraits, class StoredSizeType> template<class AllocTraits, class StoredSizeType>
struct get_stored_size_type_with_alloctraits struct get_stored_size_type_with_alloctraits
{ {
@ -177,7 +194,7 @@ BOOST_INTRUSIVE_OPTION_TYPE(growth_factor, GrowthFactor, GrowthFactor, growth_fa
//!This option specifies the unsigned integer type that a user wants the container //!This option specifies the unsigned integer type that a user wants the container
//!to use to hold size-related information inside a container (e.g. current size, current capacity). //!to use to hold size-related information inside a container (e.g. current size, current capacity).
//! //!
//!\tparam StoredSizeType A unsigned integer type. It shall be smaller than than the size //!\tparam StoredSizeType An unsigned integer type. It shall be smaller than than the size
//! of the size_type deduced from `allocator_traits<A>::size_type` or the same type. //! of the size_type deduced from `allocator_traits<A>::size_type` or the same type.
//! //!
//!If the maximum capacity() to be used is limited, a user can try to use 8-bit, 16-bit //!If the maximum capacity() to be used is limited, a user can try to use 8-bit, 16-bit
@ -185,7 +202,7 @@ BOOST_INTRUSIVE_OPTION_TYPE(growth_factor, GrowthFactor, GrowthFactor, growth_fa
//!memory can be saved for empty vectors. This could potentially performance benefits due to better //!memory can be saved for empty vectors. This could potentially performance benefits due to better
//!cache usage. //!cache usage.
//! //!
//!Note that alignment requirements can disallow theoritical space savings. Example: //!Note that alignment requirements can disallow theoretical space savings. Example:
//!\c vector holds a pointer and two size types (for size and capacity), in a 32 bit machine //!\c vector holds a pointer and two size types (for size and capacity), in a 32 bit machine
//!a 8 bit size type (total size: 4 byte pointer + 2 x 1 byte sizes = 6 bytes) //!a 8 bit size type (total size: 4 byte pointer + 2 x 1 byte sizes = 6 bytes)
//!will not save space when comparing two 16-bit size types because usually //!will not save space when comparing two 16-bit size types because usually
@ -236,6 +253,75 @@ using vector_options_t = typename boost::container::vector_options<Options...>::
#endif #endif
////////////////////////////////////////////////////////////////
//
//
// OPTIONS FOR DEQUE-BASED CONTAINERS
//
//
////////////////////////////////////////////////////////////////
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<std::size_t BlockBytes, std::size_t BlockSize>
struct deque_opt
{
static const std::size_t block_bytes = BlockBytes;
static const std::size_t block_size = BlockSize;
BOOST_STATIC_ASSERT_MSG(!(block_bytes && block_size), "block_bytes and block_size can't be specified at the same time");
};
typedef deque_opt<0u, 0u> deque_null_opt;
#endif
//! Helper metafunction to combine options into a single type to be used
//! by \c boost::container::deque.
//! Supported options are: \c boost::container::block_bytes
#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 deque_options
{
/// @cond
typedef typename ::boost::intrusive::pack_options
< deque_null_opt,
#if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef deque_opt< packed_options::block_bytes, packed_options::block_size > 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::deque.
//! Supported options are: \c boost::container::block_bytes
template<class ...Options>
using deque_options_t = typename boost::container::deque_options<Options...>::type;
#endif
//!This option specifies the maximum size of a block in bytes: this delimites the number of contiguous elements
//!that will be allocated by deque as min(1u, BlockBytes/sizeof(value_type))
//!A value zero represents the default value.
//!
//!\tparam BlockBytes An unsigned integer value.
BOOST_INTRUSIVE_OPTION_CONSTANT(block_bytes, std::size_t, BlockBytes, block_bytes)
//!This option specifies the size of a block, delimites the number of contiguous elements
//!that will be allocated by deque as BlockSize.
//!A value zero represents the default value.
//!
//!\tparam BlockBytes An unsigned integer value.
BOOST_INTRUSIVE_OPTION_CONSTANT(block_size, std::size_t, BlockSize, block_size)
} //namespace container { } //namespace container {
} //namespace boost { } //namespace boost {

View File

@ -702,18 +702,6 @@ struct vector_alloc_holder<Allocator, StoredSizeType, version_0>
struct growth_factor_60; struct growth_factor_60;
template<class T, class Default>
struct default_if_void
{
typedef T type;
};
template<class Default>
struct default_if_void<void, Default>
{
typedef Default type;
};
template<class Options, class AllocatorSizeType> template<class Options, class AllocatorSizeType>
struct get_vector_opt struct get_vector_opt
{ {
@ -728,7 +716,6 @@ struct get_vector_opt<void, AllocatorSizeType>
typedef vector_opt<growth_factor_60, AllocatorSizeType> type; typedef vector_opt<growth_factor_60, AllocatorSizeType> type;
}; };
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
//! A vector is a sequence that supports random access to elements, constant //! A vector is a sequence that supports random access to elements, constant

View File

@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/deque.hpp>
#include <boost/container/allocator.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::container;
void test_block_bytes()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = deque_options_t< block_bytes<128u> >;
#else
typedef deque_options< block_bytes<128u> >::type options_t;
#endif
typedef deque<unsigned short, void, options_t> deque_t;
BOOST_TEST(deque_t::get_block_size() == 128u/sizeof(unsigned short));
}
void test_block_elements()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = deque_options_t< block_size<64> >;
#else
typedef deque_options< block_size<64 > >::type options_t;
#endif
typedef deque<unsigned char, void, options_t> deque_t;
BOOST_TEST(deque_t::get_block_size() == 64U);
}
int main()
{
test_block_bytes();
test_block_elements();
return ::boost::report_errors();
}