forked from boostorg/container
Add block size customization options to deque.
This commit is contained in:
1 parent
47226ff16f
commit
24e420abe9
7 files changed
+287
-76
No files matched your search
@@ -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 &&
|
||||
|
||||
Reference in new issue
Block a user