mirror of
https://github.com/boostorg/container.git
synced 2025-07-29 12:07:19 +02:00
Add block size customization options to deque.
This commit is contained in:
@ -33,7 +33,7 @@ In short, what does [*Boost.Container] offer?
|
||||
|
||||
* 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
|
||||
* 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]
|
||||
(they can be safely placed in shared memory).
|
||||
* 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
|
||||
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
|
||||
impact (on average, more memory will be unused). A user can provide it's own implementation and some predefined
|
||||
policies are available: [classref boost::container::growth_factor_50 growth_factor_50],
|
||||
impact (on average, more memory will be unused). A user can provide a custom implementation of the growth factor and some
|
||||
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_50 growth_factor_100].
|
||||
|
||||
@ -695,6 +695,31 @@ used to customize `vector` container:
|
||||
|
||||
[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]
|
||||
|
||||
[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/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]
|
||||
|
||||
[section:release_notes_boost_1_70_00 Boost 1.70 Release]
|
||||
|
41
example/doc_custom_deque.cpp
Normal file
41
example/doc_custom_deque.cpp
Normal 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;
|
||||
}
|
||||
//]
|
@ -117,7 +117,8 @@ template < class T, std::size_t N
|
||||
class small_vector;
|
||||
|
||||
template <class T
|
||||
,class Allocator = void >
|
||||
,class Allocator = void
|
||||
,class Options = void>
|
||||
class deque;
|
||||
|
||||
template <class T
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <boost/container/container_fwd.hpp>
|
||||
#include <boost/container/new_allocator.hpp> //new_allocator
|
||||
#include <boost/container/throw_exception.hpp>
|
||||
#include <boost/container/options.hpp>
|
||||
// container/detail
|
||||
#include <boost/container/detail/advanced_insert_int.hpp>
|
||||
#include <boost/container/detail/algorithm.hpp> //algo_equal(), algo_lexicographical_compare
|
||||
@ -61,7 +62,7 @@ namespace boost {
|
||||
namespace container {
|
||||
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
template <class T, class Allocator>
|
||||
template <class T, class Allocator, class Options>
|
||||
class deque;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// Note: this function is simply a kludge to work around several compilers'
|
||||
// bugs in handling constant expressions.
|
||||
template<class T>
|
||||
struct deque_buf_size
|
||||
template<class T, std::size_t BlockBytes, std::size_t BlockSize>
|
||||
struct deque_block_size
|
||||
{
|
||||
static const std::size_t min_size = 512u;
|
||||
static const std::size_t sizeof_t = sizeof(T);
|
||||
static const std::size_t value = sizeof_t < min_size ? (min_size/sizeof_t) : std::size_t(1);
|
||||
BOOST_STATIC_ASSERT_MSG(!(BlockBytes && BlockSize), "BlockBytes and BlockSize can't be specified at the same time");
|
||||
static const std::size_t block_bytes = BlockBytes ? BlockBytes : 512u;
|
||||
static const std::size_t value = BlockSize ? BlockSize : (sizeof(T) < block_bytes ? (block_bytes/sizeof(T)) : std::size_t(1));
|
||||
};
|
||||
|
||||
namespace dtl {
|
||||
@ -132,9 +131,6 @@ class deque_iterator
|
||||
, deque_iterator<Pointer, false>
|
||||
, 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 typename boost::intrusive::pointer_traits<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 index_pointer get_node() const { return m_node; }
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE deque_iterator(val_alloc_ptr x, index_pointer y) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
: m_cur(x), m_first(*y), m_last(*y + s_buffer_size()), m_node(y)
|
||||
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 + block_size), m_node(y)
|
||||
{}
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
@ -190,15 +186,20 @@ class deque_iterator
|
||||
if(!this->m_cur && !x.m_cur){
|
||||
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);
|
||||
}
|
||||
|
||||
deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(!!m_cur);
|
||||
++this->m_cur;
|
||||
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;
|
||||
}
|
||||
return *this;
|
||||
@ -213,8 +214,11 @@ class deque_iterator
|
||||
|
||||
deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(!!m_cur);
|
||||
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;
|
||||
@ -230,16 +234,19 @@ class deque_iterator
|
||||
|
||||
deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
BOOST_ASSERT(!!m_cur);
|
||||
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;
|
||||
else {
|
||||
difference_type node_offset =
|
||||
offset > 0 ? offset / difference_type(this->s_buffer_size())
|
||||
: -difference_type((-offset - 1) / this->s_buffer_size()) - 1;
|
||||
this->priv_set_node(this->m_node + node_offset);
|
||||
offset > 0 ? (offset / block_size)
|
||||
: (-difference_type((-offset - 1) / block_size) - 1);
|
||||
this->priv_set_node(this->m_node + node_offset, block_size);
|
||||
this->m_cur = this->m_first +
|
||||
(offset - node_offset * difference_type(this->s_buffer_size()));
|
||||
(offset - node_offset * block_size);
|
||||
}
|
||||
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
|
||||
{ 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_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
|
||||
@ -287,10 +294,22 @@ class deque_iterator
|
||||
|
||||
} //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
|
||||
// and destructor allocate (but don't initialize) storage. This makes
|
||||
// exception safety easier.
|
||||
template <class Allocator>
|
||||
template <class Allocator, class Options>
|
||||
class deque_base
|
||||
{
|
||||
BOOST_COPYABLE_AND_MOVABLE(deque_base)
|
||||
@ -315,19 +334,24 @@ class deque_base
|
||||
typedef allocator_type stored_allocator_type;
|
||||
typedef val_alloc_size size_type;
|
||||
|
||||
private:
|
||||
typedef typename get_deque_opt<Options>::type options_type;
|
||||
|
||||
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 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()
|
||||
{ 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
|
||||
{ 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)
|
||||
{ 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
|
||||
{ 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)
|
||||
: members_(a)
|
||||
{ this->priv_initialize_map(num_elements); }
|
||||
@ -379,7 +400,7 @@ class deque_base
|
||||
void priv_initialize_map(size_type 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 = this->priv_allocate_map(this->members_.m_map_size);
|
||||
@ -398,11 +419,11 @@ class deque_base
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
this->members_.m_start.priv_set_node(nstart);
|
||||
this->members_.m_finish.priv_set_node(nfinish - 1);
|
||||
this->members_.m_start.priv_set_node(nstart, get_block_size());
|
||||
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_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.
|
||||
//!
|
||||
//! \tparam T The type of object that is stored in the deque
|
||||
//! \tparam Allocator The allocator used for all internal memory management
|
||||
template <class T, class Allocator = new_allocator<T> >
|
||||
//! \tparam A The allocator used for all internal memory management, use void
|
||||
//! 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
|
||||
template <class T, class Allocator>
|
||||
template <class T, class Allocator, class Options>
|
||||
#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
|
||||
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
|
||||
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
|
||||
BOOST_COPYABLE_AND_MOVABLE(deque)
|
||||
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;
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
public:
|
||||
|
||||
BOOST_CONSTEXPR BOOST_CONTAINER_FORCEINLINE static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return Base::get_block_size(); }
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//
|
||||
// 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;
|
||||
node < this->members_.m_finish.m_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);
|
||||
}
|
||||
|
||||
@ -2087,13 +2112,13 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
|
||||
BOOST_TRY {
|
||||
for ( ; cur < this->members_.m_finish.m_node; ++cur){
|
||||
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
|
||||
(this->alloc(), this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value);
|
||||
}
|
||||
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_CATCH_END
|
||||
@ -2125,14 +2150,14 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type>
|
||||
BOOST_TRY {
|
||||
for (; cur_node < this->members_.m_finish.m_node; ++cur_node) {
|
||||
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);
|
||||
first = mid;
|
||||
}
|
||||
::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first);
|
||||
}
|
||||
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_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
|
||||
{
|
||||
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;
|
||||
allocator_traits_type::destroy
|
||||
( 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)
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
if (n > vacancies){
|
||||
size_type new_elems = n-vacancies;
|
||||
size_type new_nodes = (new_elems + this->s_buffer_size() - 1) /
|
||||
this->s_buffer_size();
|
||||
size_type new_nodes = (new_elems + get_block_size() - 1) /
|
||||
get_block_size();
|
||||
size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map);
|
||||
if (new_nodes > s){
|
||||
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;
|
||||
if (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));
|
||||
if (new_nodes + 1 > s){
|
||||
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_start.priv_set_node(new_nstart);
|
||||
this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1);
|
||||
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, get_block_size());
|
||||
}
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
};
|
||||
@ -2266,8 +2291,8 @@ namespace boost {
|
||||
|
||||
//!has_trivial_destructor_after_move<> == true_type
|
||||
//!specialization for optimizations
|
||||
template <class T, class Allocator>
|
||||
struct has_trivial_destructor_after_move<boost::container::deque<T, Allocator> >
|
||||
template <class T, class Allocator, class Options>
|
||||
struct has_trivial_destructor_after_move<boost::container::deque<T, Allocator, Options> >
|
||||
{
|
||||
typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
|
||||
static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <boost/container/detail/config_begin.hpp>
|
||||
#include <boost/container/container_fwd.hpp>
|
||||
#include <boost/intrusive/pack_options.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
@ -111,6 +112,22 @@ using tree_assoc_options_t = typename boost::container::tree_assoc_options<Optio
|
||||
|
||||
#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>
|
||||
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
|
||||
//!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.
|
||||
//!
|
||||
//!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
|
||||
//!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
|
||||
//!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
|
||||
@ -236,6 +253,75 @@ using vector_options_t = typename boost::container::vector_options<Options...>::
|
||||
|
||||
#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 boost {
|
||||
|
@ -702,18 +702,6 @@ struct vector_alloc_holder<Allocator, StoredSizeType, version_0>
|
||||
|
||||
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>
|
||||
struct get_vector_opt
|
||||
{
|
||||
@ -728,7 +716,6 @@ struct get_vector_opt<void, AllocatorSizeType>
|
||||
typedef vector_opt<growth_factor_60, AllocatorSizeType> type;
|
||||
};
|
||||
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
//! A vector is a sequence that supports random access to elements, constant
|
||||
|
43
test/deque_options_test.cpp
Normal file
43
test/deque_options_test.cpp
Normal 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();
|
||||
}
|
Reference in New Issue
Block a user