Implement the initial machinery to support "stored_size" option.

This commit is contained in:
Ion Gaztañaga
2025-09-22 00:35:20 +02:00
parent 679ace9b81
commit df4af0989c
4 changed files with 273 additions and 155 deletions

View File

@@ -71,20 +71,27 @@ struct deque_value_traits
BOOST_STATIC_CONSTEXPR bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move<value_type>::value; BOOST_STATIC_CONSTEXPR bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move<value_type>::value;
}; };
template<class T, std::size_t BlockBytes, std::size_t BlockSize> template<class T, std::size_t BlockBytes, std::size_t BlockSize, class StoredSizeType>
struct deque_block_traits struct deque_block_traits
{ {
BOOST_CONTAINER_STATIC_ASSERT_MSG(!(BlockBytes && BlockSize), "BlockBytes and BlockSize can't be specified at the same time"); BOOST_CONTAINER_STATIC_ASSERT_MSG(!(BlockBytes && BlockSize), "BlockBytes and BlockSize can't be specified at the same time");
BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = sizeof(void*)*128u; BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = sizeof(void*)*128u;
BOOST_STATIC_CONSTEXPR std::size_t default_block_start = default_block_bytes/sizeof(T); BOOST_STATIC_CONSTEXPR std::size_t default_block_start = default_block_bytes/sizeof(T);
BOOST_STATIC_CONSTEXPR std::size_t default_min_block_size = 16u; BOOST_STATIC_CONSTEXPR std::size_t default_min_block_size = 16u;
BOOST_STATIC_CONSTEXPR std::size_t default_block_size = default_block_start < default_min_block_size BOOST_STATIC_CONSTEXPR std::size_t default_block_size_initial = default_block_start < default_min_block_size
? default_min_block_size ? default_min_block_size
: dtl::upper_power_of_2_ct<std::size_t, default_block_start>::value; : dtl::upper_power_of_2_ct<std::size_t, default_block_start>::value;
BOOST_STATIC_CONSTEXPR std::size_t max_stored_size_block_size = std::size_t(1u) << (sizeof(StoredSizeType)*CHAR_BIT - 4u);
BOOST_STATIC_CONSTEXPR std::size_t default_block_size = default_block_size_initial > max_stored_size_block_size
? max_stored_size_block_size
: default_block_size_initial;
BOOST_STATIC_CONSTEXPR std::size_t value = BlockSize ? BlockSize BOOST_STATIC_CONSTEXPR std::size_t value = BlockSize ? BlockSize
: BlockBytes ? (BlockBytes-1u)/sizeof(T) + 1u : BlockBytes ? (BlockBytes-1u)/sizeof(T) + 1u
: default_block_size : default_block_size
; ;
BOOST_CONTAINER_STATIC_ASSERT_MSG(value <= max_stored_size_block_size, "BlockSize or BlockBytes is too big for the stored_size_type");
}; };
// Class invariants: // Class invariants:
@@ -106,7 +113,7 @@ struct deque_block_traits
// [map, map + map_size). // [map, map + map_size).
// A pointer in the range [map, map + map_size) points to an allocated node // A pointer in the range [map, map + map_size) points to an allocated node
// if and only if the pointer is in the range [start.node, finish.node]. // if and only if the pointer is in the range [start.node, finish.node].
template<class Pointer, bool IsConst, unsigned BlockBytes, unsigned BlockSize> template<class Pointer, bool IsConst, unsigned BlockBytes, unsigned BlockSize, class StoredSizeType>
class deque_iterator class deque_iterator
{ {
public: public:
@@ -128,8 +135,7 @@ class deque_iterator
BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW
{ {
BOOST_CONTAINER_STATIC_ASSERT((deque_block_traits<value_type, BlockBytes, BlockSize>::value)); return deque_block_traits<value_type, BlockBytes, BlockSize, StoredSizeType>::value;
return deque_block_traits<value_type, BlockBytes, BlockSize>::value;
} }
BOOST_CONSTEXPR inline static difference_type get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONSTEXPR inline static difference_type get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW
@@ -147,9 +153,10 @@ class deque_iterator
}; };
typedef typename dtl::if_c< IsConst typedef typename dtl::if_c< IsConst
, deque_iterator<Pointer, false, BlockBytes, BlockSize> , deque_iterator<Pointer, false, BlockBytes, BlockSize, StoredSizeType>
, nat>::type nonconst_iterator_arg; , nat>::type nonconst_iterator_arg;
typedef deque_iterator<Pointer, false, BlockBytes, BlockSize, StoredSizeType> nonconst_iterator;
Pointer m_cur; Pointer m_cur;
index_pointer m_node; index_pointer m_node;
@@ -183,9 +190,9 @@ class deque_iterator
inline deque_iterator& operator=(const nonconst_iterator_arg& x) BOOST_NOEXCEPT_OR_NOTHROW inline deque_iterator& operator=(const nonconst_iterator_arg& x) BOOST_NOEXCEPT_OR_NOTHROW
{ m_cur = x.get_cur(); m_node = x.get_node(); return *this; } { m_cur = x.get_cur(); m_node = x.get_node(); return *this; }
inline deque_iterator<Pointer, false, BlockBytes, BlockSize> unconst() const BOOST_NOEXCEPT_OR_NOTHROW inline nonconst_iterator unconst() const BOOST_NOEXCEPT_OR_NOTHROW
{ {
return deque_iterator<Pointer, false, BlockBytes, BlockSize>(this->get_cur(), this->get_node()); return nonconst_iterator(this->get_cur(), this->get_node());
} }
inline reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW inline reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW
@@ -338,18 +345,21 @@ class deque_iterator
}; };
template<class Options> template<class Options, class AllocatorSizeType>
struct get_deque_opt struct get_deque_opt
{ {
typedef Options type; typedef deque_opt< Options::block_bytes, Options::block_size
, typename default_if_void<typename Options::stored_size_type, AllocatorSizeType>::type
> type;
}; };
template<> template<class AllocatorSizeType>
struct get_deque_opt<void> struct get_deque_opt<void, AllocatorSizeType>
{ {
typedef deque_null_opt type; typedef deque_opt<0, 0, AllocatorSizeType> 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.
@@ -378,20 +388,26 @@ 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;
typedef val_alloc_diff difference_type; typedef val_alloc_diff difference_type;
typedef val_alloc_size stored_size_type;
private: private:
typedef typename get_deque_opt<Options>::type options_type; typedef typename get_deque_opt<Options, val_alloc_size>::type options_type;
protected: protected:
typedef deque_iterator<val_alloc_ptr, false, options_type::block_bytes, options_type::block_size> iterator; typedef typename options_type::stored_size_type stored_size_type;
typedef deque_iterator<val_alloc_ptr, true, options_type::block_bytes, options_type::block_size> const_iterator; typedef deque_iterator< val_alloc_ptr, false
, options_type::block_bytes
, options_type::block_size
, stored_size_type> iterator;
typedef deque_iterator< val_alloc_ptr, true
, options_type::block_bytes
, options_type::block_size
, stored_size_type> const_iterator;
BOOST_CONSTEXPR inline static val_alloc_diff get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONSTEXPR inline static val_alloc_diff get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW
{ return val_alloc_diff((get_block_size())); } { return val_alloc_diff((get_block_size())); }
BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW
{ return deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; } { return deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size, stored_size_type>::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;
@@ -443,16 +459,36 @@ class deque_base
this->members_.swap(x.members_); this->members_.swap(x.members_);
} }
void test_size_against_max(size_type n)
{
const size_type max_alloc = val_alloc_traits_type::max_size(this->alloc());
const size_type max = max_alloc <= stored_size_type(-1) ? max_alloc : stored_size_type(-1);
if (BOOST_UNLIKELY(max < n) )
boost::container::throw_length_error("get_next_capacity, allocator's max size reached");
}
void test_size_against_n_nodes(size_type n_nodes)
{
test_size_against_max(size_type(size_type(n_nodes * get_block_size()) - 1u));
}
void prot_initialize_map_and_nodes(size_type num_elements) void prot_initialize_map_and_nodes(size_type num_elements)
{ {
BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size();
//Even a zero element initialized map+nodes needs at least 1 node (for sentinel finish position) //Even a zero element initialized map+nodes needs at least 1 node (for sentinel finish position)
size_type num_nodes = num_elements / get_block_size() + 1u; size_type num_nodes = size_type(num_elements / block_size + 1u);
//Allocate at least one extra slot on each end to avoid inmediate map reallocation on push/front insertions //Allocate at least one extra slot on each end to avoid inmediate map reallocation on push/front insertions
this->members_.m_map_size = dtl::max_value((size_type) InitialMapSize, num_nodes + 2); const size_type map_size = dtl::max_value(size_type(InitialMapSize), size_type(num_nodes + 2u));
this->members_.m_map = this->prot_allocate_map(this->members_.m_map_size); const size_type start_map_pos = size_type(map_size - num_nodes)/2u;
ptr_alloc_ptr nstart = this->members_.m_map + difference_type(this->members_.m_map_size - num_nodes) / 2; //The end position must be representable in stored_size_type
this->test_size_against_n_nodes(map_size);
this->members_.m_map = this->prot_allocate_map(map_size);
this->members_.m_map_size = static_cast<stored_size_type>(map_size);
ptr_alloc_ptr nstart = this->members_.m_map + difference_type(start_map_pos);
ptr_alloc_ptr nfinish = nstart + difference_type(num_nodes); ptr_alloc_ptr nfinish = nstart + difference_type(num_nodes);
BOOST_CONTAINER_TRY { BOOST_CONTAINER_TRY {
@@ -466,8 +502,7 @@ class deque_base
} }
BOOST_CONTAINER_CATCH_END BOOST_CONTAINER_CATCH_END
this->members_.m_start_off = this->prot_non_null_node_to_off(nstart); this->prot_set_start_finish_from_node(start_map_pos, num_elements);
this->members_.m_finish_off = this->members_.m_start_off + num_elements;
} }
void prot_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) void prot_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish)
@@ -559,21 +594,21 @@ class deque_base
static BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_node_last(ptr_alloc_ptr idx) static BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_node_last(ptr_alloc_ptr idx)
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return *idx + (block_size - 1u); return *idx + (block_size - 1u);
} }
BOOST_CONTAINER_FORCEINLINE std::size_t prot_front_capacity() const BOOST_CONTAINER_FORCEINLINE size_type prot_front_capacity() const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return this->members_.m_start_off % block_size; return static_cast<size_type>(this->members_.m_start_off % block_size);
} }
BOOST_CONTAINER_FORCEINLINE std::size_t prot_back_capacity() const BOOST_CONTAINER_FORCEINLINE size_type prot_back_capacity() const
{ {
//m_finish_off points to positions [0....block_size-1], and one position is always needed as the sentinel node resulting [block_size-1....0] capacity //m_finish_off points to positions [0....block_size-1], and one position is always needed as the sentinel node resulting [block_size-1....0] capacity
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return this->members_.m_map ? (block_size - 1u) - (this->members_.m_finish_off % block_size) : 0u; return static_cast<size_type>(this->members_.m_map ? (block_size - 1u) - (this->members_.m_finish_off % block_size) : 0u);
} }
////////////////////////// //////////////////////////
@@ -585,7 +620,7 @@ class deque_base
const ptr_alloc_ptr n = it.get_node(); const ptr_alloc_ptr n = it.get_node();
BOOST_ASSERT(!this->members_.m_map == !n); //Both should be null or both non-null BOOST_ASSERT(!this->members_.m_map == !n); //Both should be null or both non-null
if (n) { if (n) {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return static_cast<stored_size_type>(std::size_t(n - this->members_.m_map)*block_size + std::size_t(it.get_cur() - *n)); return static_cast<stored_size_type>(std::size_t(n - this->members_.m_map)*block_size + std::size_t(it.get_cur() - *n));
} }
else{ else{
@@ -595,7 +630,7 @@ class deque_base
BOOST_CONTAINER_FORCEINLINE iterator prot_off_to_it(std::size_t off) const BOOST_CONTAINER_FORCEINLINE iterator prot_off_to_it(std::size_t off) const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
const ptr_alloc_ptr node = this->members_.m_map + off/block_size; const ptr_alloc_ptr node = this->members_.m_map + off/block_size;
return iterator(node ? *node + (off%block_size) : val_alloc_ptr(), node); return iterator(node ? *node + (off%block_size) : val_alloc_ptr(), node);
} }
@@ -604,7 +639,7 @@ class deque_base
{ {
const size_type off = this->prot_it_to_off(it); const size_type off = this->prot_it_to_off(it);
BOOST_ASSERT(off >= this->members_.m_start_off); BOOST_ASSERT(off >= this->members_.m_start_off);
return off - this->members_.m_start_off; return static_cast<stored_size_type>(off - this->members_.m_start_off);
} }
///////////// /////////////
@@ -613,7 +648,7 @@ class deque_base
BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_off_to_node(std::size_t off) const BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_off_to_node(std::size_t off) const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return this->members_.m_map + off/block_size; return this->members_.m_map + off/block_size;
} }
@@ -633,7 +668,7 @@ class deque_base
BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_off_to_cur_unchecked(std::size_t off) const BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_off_to_cur_unchecked(std::size_t off) const
{ {
BOOST_ASSERT(!!this->members_.m_map); BOOST_ASSERT(!!this->members_.m_map);
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
const ptr_alloc_ptr node = this->members_.m_map + off/block_size; const ptr_alloc_ptr node = this->members_.m_map + off/block_size;
return *node + off%block_size; return *node + off%block_size;
} }
@@ -670,21 +705,21 @@ class deque_base
{ return this->prot_off_to_it(members_.m_finish_off); } { return this->prot_off_to_it(members_.m_finish_off); }
BOOST_CONTAINER_FORCEINLINE const_iterator prot_nth(size_type n) const BOOST_CONTAINER_FORCEINLINE const_iterator prot_nth(size_type n) const
{ return this->prot_off_to_it(members_.m_start_off+n); } { return this->prot_off_to_it(size_type(members_.m_start_off + n)); }
BOOST_CONTAINER_FORCEINLINE iterator prot_nth(size_type n) BOOST_CONTAINER_FORCEINLINE iterator prot_nth(size_type n)
{ return this->prot_off_to_it(members_.m_start_off+n); } { return this->prot_off_to_it(size_type(members_.m_start_off + n)); }
BOOST_CONTAINER_FORCEINLINE iterator prot_back_it() BOOST_CONTAINER_FORCEINLINE iterator prot_back_it()
{ {
BOOST_ASSERT(members_.m_start_off != members_.m_finish_off); BOOST_ASSERT(members_.m_start_off != members_.m_finish_off);
return this->prot_off_to_it(members_.m_finish_off-1u); return this->prot_off_to_it(size_type(members_.m_finish_off - 1u));
} }
// //
// size/empty // size/empty
// //
BOOST_CONTAINER_FORCEINLINE std::size_t prot_size() const BOOST_CONTAINER_FORCEINLINE size_type prot_size() const
{ return size_type(this->members_.m_finish_off - this->members_.m_start_off); } { return size_type(this->members_.m_finish_off - this->members_.m_start_off); }
BOOST_CONTAINER_FORCEINLINE bool prot_empty() const BOOST_CONTAINER_FORCEINLINE bool prot_empty() const
@@ -722,18 +757,25 @@ class deque_base
// //
BOOST_CONTAINER_FORCEINLINE stored_size_type prot_non_null_node_to_off(ptr_alloc_ptr n) const BOOST_CONTAINER_FORCEINLINE stored_size_type prot_non_null_node_to_off(ptr_alloc_ptr n) const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
return static_cast<stored_size_type>(std::size_t(n - this->members_.m_map)*block_size); return static_cast<stored_size_type>(std::size_t(n - this->members_.m_map)*block_size);
} }
inline void prot_start_set_node(ptr_alloc_ptr new_start) void prot_set_start_finish_from_node(size_type node_idx, size_type n_elements)
{
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
this->members_.m_start_off = static_cast<stored_size_type>(node_idx*block_size);
this->members_.m_finish_off = static_cast<stored_size_type>(this->members_.m_start_off + n_elements);
}
inline void prot_start_update_node(ptr_alloc_ptr new_start)
{ {
//iG: to-do: optimizable avoiding some division/remainder //iG: to-do: optimizable avoiding some division/remainder
std::size_t new_block_off = prot_non_null_node_to_off(new_start); std::size_t new_block_off = prot_non_null_node_to_off(new_start);
this->members_.m_start_off = static_cast<stored_size_type>(new_block_off + (this->members_.m_start_off % get_block_size())); this->members_.m_start_off = static_cast<stored_size_type>(new_block_off + (this->members_.m_start_off % get_block_size()));
} }
inline void prot_finish_set_node(ptr_alloc_ptr new_finish) inline void prot_finish_update_node(ptr_alloc_ptr new_finish)
{ {
//iG: to-do: optimizable avoiding some division/remainder //iG: to-do: optimizable avoiding some division/remainder
std::size_t new_block_off = prot_non_null_node_to_off(new_finish); std::size_t new_block_off = prot_non_null_node_to_off(new_finish);
@@ -748,20 +790,22 @@ class deque_base
inline val_alloc_val *prot_push_back_simple_pos() const inline val_alloc_val *prot_push_back_simple_pos() const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
const std::size_t last_in_block = block_size - 1u; const std::size_t last_in_block = block_size - 1u;
const ptr_alloc_val *const node = boost::movelib::to_raw_pointer(this->members_.m_map); const ptr_alloc_val *const map = boost::movelib::to_raw_pointer(this->members_.m_map);
const std::size_t off = node ? this->members_.m_finish_off : last_in_block; if(BOOST_LIKELY(map != 0)) {
const std::size_t rem = off % block_size; const std::size_t off = this->members_.m_finish_off;
if(BOOST_LIKELY(rem != last_in_block)){ const std::size_t rem = off % block_size;
return boost::movelib::to_raw_pointer(node[off/block_size]) + rem; if(BOOST_LIKELY(rem != last_in_block)){
return boost::movelib::to_raw_pointer(map[off/block_size]) + rem;
}
} }
return 0; return 0;
} }
inline val_alloc_val *prot_push_front_simple_pos() const inline val_alloc_val *prot_push_front_simple_pos() const
{ {
BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits<val_alloc_val, options_type::block_bytes, options_type::block_size>::value; BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_base::get_block_size();
//No need to check !m_map, as m_start_off is zero in that case //No need to check !m_map, as m_start_off is zero in that case
const std::size_t off = this->members_.m_start_off; const std::size_t off = this->members_.m_start_off;
const std::size_t rem = off % block_size; const std::size_t rem = off % block_size;
@@ -778,7 +822,7 @@ class deque_base
BOOST_CONTAINER_FORCEINLINE bool prot_pop_front_simple_available() const BOOST_CONTAINER_FORCEINLINE bool prot_pop_front_simple_available() const
{ {
return (this->members_.m_start_off % get_block_size()) != (get_block_size() - 1u); return size_type(this->members_.m_start_off % get_block_size()) != size_type(get_block_size() - 1u);
} }
}; };
@@ -836,8 +880,9 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_STATIC_ASSERT((dtl::is_same<value_type, typename allocator_traits<ValAllocator>::value_type>::value)); BOOST_CONTAINER_STATIC_ASSERT((dtl::is_same<value_type, typename allocator_traits<ValAllocator>::value_type>::value));
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;
typedef allocator_traits<ValAllocator> allocator_traits_type; typedef allocator_traits<ValAllocator> allocator_traits_type;
typedef typename Base::stored_size_type stored_size_type;
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
@@ -1200,7 +1245,12 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
>::type * = 0 >::type * = 0
) )
{ {
const size_type n = boost::container::iterator_udistance(first, last); typedef typename iter_size<FwdIt>::type it_size_type;
const it_size_type sz = boost::container::iterator_udistance(first, last);
if (BOOST_UNLIKELY(sz > size_type(-1))){
boost::container::throw_length_error("vector::insert, FwdIt's max length reached");
}
const size_type n = static_cast<size_type>(sz);
dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first); dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first);
this->priv_assign(n, proxy); this->priv_assign(n, proxy);
} }
@@ -1411,9 +1461,9 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
{ {
const size_type len = this->size(); const size_type len = this->size();
if (new_size < len) if (new_size < len)
this->priv_erase_last_n(len - new_size); this->priv_erase_last_n(size_type(len - new_size));
else{ else{
const size_type n = new_size - this->size(); const size_type n = size_type(new_size - this->size());
dtl::insert_value_initialized_n_proxy<ValAllocator> proxy; dtl::insert_value_initialized_n_proxy<ValAllocator> proxy;
this->priv_insert_back_aux_impl(n, proxy); this->priv_insert_back_aux_impl(n, proxy);
} }
@@ -1431,9 +1481,9 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
{ {
const size_type len = size(); const size_type len = size();
if (new_size < len) if (new_size < len)
this->priv_erase_last_n(len - new_size); this->priv_erase_last_n(size_type(len - new_size));
else{ else{
const size_type n = new_size - this->size(); const size_type n = size_type(new_size - this->size());
dtl::insert_default_initialized_n_proxy<ValAllocator> proxy; dtl::insert_default_initialized_n_proxy<ValAllocator> proxy;
this->priv_insert_back_aux_impl(n, proxy); this->priv_insert_back_aux_impl(n, proxy);
} }
@@ -1449,9 +1499,9 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
{ {
const size_type sz = this->size(); const size_type sz = this->size();
if (new_size < sz) if (new_size < sz)
this->priv_erase_last_n(sz - new_size); this->priv_erase_last_n(size_type(sz - new_size));
else { else {
const size_type n = new_size - sz; const size_type n = size_type(new_size - sz);
dtl::insert_n_copies_proxy<ValAllocator> proxy(x); dtl::insert_n_copies_proxy<ValAllocator> proxy(x);
this->priv_insert_back_aux_impl(n, proxy); this->priv_insert_back_aux_impl(n, proxy);
} }
@@ -1968,8 +2018,16 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
) )
{ {
BOOST_ASSERT(this->priv_in_range_or_end(p)); BOOST_ASSERT(this->priv_in_range_or_end(p));
typedef typename iter_size<FwdIt>::type it_size_type;
const it_size_type sz = boost::container::iterator_udistance(first, last);
if (BOOST_UNLIKELY(sz > size_type(-1))){
boost::container::throw_length_error("vector::insert, FwdIt's max length reached");
}
const size_type n = static_cast<size_type>(sz);
dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first); dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first);
return this->priv_insert_aux_impl(p, boost::container::iterator_udistance(first, last), proxy); return this->priv_insert_aux_impl( p, n, proxy);
} }
#endif #endif
@@ -2025,14 +2083,14 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
iterator next = pos.unconst(); iterator next = pos.unconst();
++next; ++next;
const size_type index = this->prot_it_to_start_off(pos); const size_type index = this->prot_it_to_start_off(pos);
const size_type sz = this->prot_size();
if (index < (this->size()/2)) { if (index < sz/2u) {
this->priv_segmented_move_backward_n(pos.unconst(), index, next); this->priv_segmented_move_backward_n(pos.unconst(), index, next);
pop_front(); pop_front();
return next; return next;
} }
else { else {
this->priv_segmented_move_n(next, this->size() - index - 1u, pos.unconst()); this->priv_segmented_move_n(next, size_type(sz - size_type(index + 1u)), pos.unconst());
pop_back(); pop_back();
return pos.unconst(); return pos.unconst();
} }
@@ -2057,7 +2115,8 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
} }
else { else {
const size_type elems_before = this->prot_it_to_start_off(first); const size_type elems_before = this->prot_it_to_start_off(first);
if (elems_before < (this->size() - n) - elems_before) { const size_type elems_after = size_type(this->prot_size() - n - elems_before);
if (elems_before < elems_after) {
const iterator old_start = this->begin(); const iterator old_start = this->begin();
iterator new_start = this->priv_segmented_move_backward_n(first.unconst(), elems_before, last.unconst()); iterator new_start = this->priv_segmented_move_backward_n(first.unconst(), elems_before, last.unconst());
this->prot_destroy_range(old_start, new_start); this->prot_destroy_range(old_start, new_start);
@@ -2066,7 +2125,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
} }
else { else {
const iterator old_finish = this->end(); const iterator old_finish = this->end();
iterator new_finish = this->priv_segmented_move_n(last.unconst(), this->prot_size() - n - elems_before, first.unconst()); iterator new_finish = this->priv_segmented_move_n(last.unconst(), elems_after, first.unconst());
this->prot_destroy_range(new_finish, old_finish); this->prot_destroy_range(new_finish, old_finish);
this->prot_destroy_nodes(new_finish.m_node + 1, old_finish.get_node() + 1); this->prot_destroy_nodes(new_finish.m_node + 1, old_finish.get_node() + 1);
this->prot_dec_finish(n); this->prot_dec_finish(n);
@@ -2177,10 +2236,10 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
const size_type sz = this->prot_size(); const size_type sz = this->prot_size();
this->priv_segmented_proxy_copy_n_and_update(this->begin(), sz < n ? sz : n, proxy); this->priv_segmented_proxy_copy_n_and_update(this->begin(), sz < n ? sz : n, proxy);
if (n > sz) { if (n > sz) {
this->priv_insert_back_aux_impl(n - sz, proxy); this->priv_insert_back_aux_impl(size_type(n - sz), proxy);
} }
else{ else{
this->priv_erase_last_n(sz - n); this->priv_erase_last_n(size_type(sz - n));
} }
} }
@@ -2248,35 +2307,19 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
template <class U> template <class U>
BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x) BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x)
{ {
return this->priv_insert_aux_impl(p, 1, dtl::get_insert_value_proxy<iterator, ValAllocator>(::boost::forward<U>(x))); return this->emplace(p, ::boost::forward<U>(x));
} }
template <class U> template <class U>
void priv_push_back(BOOST_FWD_REF(U) u) BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u)
{ {
value_type *pr = this->prot_push_back_simple_pos(); this->emplace_back(::boost::forward<U>(u));
if(BOOST_LIKELY(pr != 0)){
allocator_traits_type::construct
(this->alloc(), pr, boost::forward<U>(u));
this->prot_inc_finish();
}
else{
this->priv_insert_back_aux_impl(1, dtl::get_insert_value_proxy<iterator, ValAllocator>(::boost::forward<U>(u)));
}
} }
template <class U> template <class U>
BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u) BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u)
{ {
value_type *pr = this->prot_push_front_simple_pos(); this->emplace_front(::boost::forward<U>(u));
if(BOOST_LIKELY(pr != 0)){
allocator_traits_type::construct
(this->alloc(), pr, boost::forward<U>(u));
this->prot_dec_start();
}
else{
this->priv_insert_front_aux_impl(1, dtl::get_insert_value_proxy<iterator, ValAllocator>(::boost::forward<U>(u)));
}
} }
void prot_destroy_range(iterator start, iterator finish) void prot_destroy_range(iterator start, iterator finish)
@@ -2341,12 +2384,12 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_CATCH_END BOOST_CONTAINER_CATCH_END
this->prot_dec_start(n); this->prot_dec_start(n);
iterator p = this->priv_segmented_move_n(start_n, elemsbefore-n, old_start); iterator p = this->priv_segmented_move_n(start_n, size_type(elemsbefore - n), old_start);
this->priv_segmented_proxy_copy_n_and_update(p, n, proxy); this->priv_segmented_proxy_copy_n_and_update(p, n, proxy);
return p; return p;
} }
else { else {
const size_type mid_count = n - elemsbefore; const size_type mid_count = size_type(n - elemsbefore);
iterator mid_start = old_start - difference_type(mid_count); iterator mid_start = old_start - difference_type(mid_count);
BOOST_CONTAINER_TRY { BOOST_CONTAINER_TRY {
@@ -2359,7 +2402,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_RETHROW BOOST_CONTAINER_RETHROW
} }
BOOST_CONTAINER_CATCH_END BOOST_CONTAINER_CATCH_END
this->prot_dec_start(n - mid_count); this->prot_dec_start(size_type(n - mid_count));
this->priv_segmented_proxy_copy_n_and_update(old_start, elemsbefore, proxy); this->priv_segmented_proxy_copy_n_and_update(old_start, elemsbefore, proxy);
return mid_start; return mid_start;
} }
@@ -2367,7 +2410,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
else { else {
this->priv_reserve_elements_at_back(n); this->priv_reserve_elements_at_back(n);
const iterator old_finish = this->prot_finish(); const iterator old_finish = this->prot_finish();
const size_type elemsafter = length - elemsbefore; const size_type elemsafter = size_type(length - elemsbefore);
BOOST_ASSERT(!single_t::value || elemsafter >= 1); BOOST_ASSERT(!single_t::value || elemsafter >= 1);
@@ -2384,14 +2427,14 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_CATCH_END BOOST_CONTAINER_CATCH_END
this->prot_inc_finish(n); this->prot_inc_finish(n);
const size_type move_n = elemsafter - n; const size_type move_n = size_type(elemsafter - n);
this->priv_segmented_move_backward_n(finish_n, move_n, old_finish); this->priv_segmented_move_backward_n(finish_n, move_n, old_finish);
finish_n -= difference_type(move_n); finish_n -= difference_type(move_n);
this->priv_segmented_proxy_copy_n_and_update(finish_n, n, proxy); this->priv_segmented_proxy_copy_n_and_update(finish_n, n, proxy);
return finish_n; return finish_n;
} }
else { else {
const size_type raw_gap = n - elemsafter; const size_type raw_gap = size_type(n - elemsafter);
iterator pos = old_finish - difference_type(elemsafter); iterator pos = old_finish - difference_type(elemsafter);
BOOST_CONTAINER_TRY{ BOOST_CONTAINER_TRY{
@@ -2447,16 +2490,16 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_TRY{ BOOST_CONTAINER_TRY{
const pointer cur = first.get_cur(); const pointer cur = first.get_cur();
const size_type block = block_size - size_type(cur - *current_node); const size_type block = size_type(block_size - size_type(cur - *current_node));
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt);
n -= cnt; n = size_type(n - cnt);
while (n) { while (n) {
++current_node; ++current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt);
n -= cnt; n = size_type(n - cnt);
} }
} }
BOOST_CONTAINER_CATCH(...) { BOOST_CONTAINER_CATCH(...) {
@@ -2481,16 +2524,16 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
index_pointer current_node = first.get_node(); index_pointer current_node = first.get_node();
const pointer cur = first.get_cur(); const pointer cur = first.get_cur();
const size_type block = block_size - size_type(cur - *current_node); const size_type block = size_type(block_size - size_type(cur - *current_node));
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt);
n -= cnt; n = size_type(n - cnt);
while (n) { while (n) {
++current_node; ++current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt);
n -= cnt; n = size_type(n - cnt);
} }
} }
} }
@@ -2524,7 +2567,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type n, dtl::bool_<false> /*!single element*/) static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type n, dtl::bool_<false> /*!single element*/)
{ it -= difference_type(n); } { it -= difference_type(n); }
void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_<true> /*single element*/) void priv_segmented_uninitialized_move_alloc_n(iterator first, size_type n, iterator dest, dtl::bool_<true> /*single element*/)
{ {
BOOST_ASSERT(n == 1); (void)n; BOOST_ASSERT(n == 1); (void)n;
allocator_traits_type::construct allocator_traits_type::construct
@@ -2533,7 +2576,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
, boost::move(*first)); , boost::move(*first));
} }
void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_<false> /*!single element*/) void priv_segmented_uninitialized_move_alloc_n(iterator first, size_type n, iterator dest, dtl::bool_<false> /*!single element*/)
{ {
if (BOOST_LIKELY(n != 0)) { //Check for empty range, current_node might be null if (BOOST_LIKELY(n != 0)) { //Check for empty range, current_node might be null
BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size();
@@ -2542,16 +2585,16 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_TRY{ BOOST_CONTAINER_TRY{
const pointer cur = first.get_cur(); const pointer cur = first.get_cur();
const size_type block = block_size - size_type(cur - *current_node); const size_type block = size_type(block_size - size_type(cur - *current_node));
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest);
n -= cnt; n = size_type(n - cnt);
while (n) { while (n) {
++current_node; ++current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt, dest); dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt, dest);
n -= cnt; n = size_type(n - cnt);
} }
} }
BOOST_CONTAINER_CATCH(...) { BOOST_CONTAINER_CATCH(...) {
@@ -2562,12 +2605,12 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
} }
} }
BOOST_CONTAINER_FORCEINLINE void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest) BOOST_CONTAINER_FORCEINLINE void priv_segmented_uninitialized_move_alloc_n(iterator first, size_type n, iterator dest)
{ {
this->priv_segmented_uninitialized_move_alloc_n(first, n, dest, dtl::bool_<false>()); this->priv_segmented_uninitialized_move_alloc_n(first, n, dest, dtl::bool_<false>());
} }
void priv_segmented_uninitialized_copy_alloc_n(const_iterator first, std::size_t n, iterator dest) void priv_segmented_uninitialized_copy_alloc_n(const_iterator first, size_type n, iterator dest)
{ {
if (BOOST_LIKELY(n != 0)) { //We might initialize an empty range and current_node might be null if (BOOST_LIKELY(n != 0)) { //We might initialize an empty range and current_node might be null
BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size();
@@ -2576,16 +2619,16 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
BOOST_CONTAINER_TRY{ BOOST_CONTAINER_TRY{
const pointer cur = first.get_cur(); const pointer cur = first.get_cur();
const size_type block = block_size - size_type(cur - *current_node); const size_type block = size_type(block_size - size_type(cur - *current_node));
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest);
n -= cnt; n = size_type(n - cnt);
while (n) { while (n) {
++current_node; ++current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt, dest); dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt, dest);
n -= cnt; n = size_type(n - cnt);
} }
} }
BOOST_CONTAINER_CATCH(...) { BOOST_CONTAINER_CATCH(...) {
@@ -2596,7 +2639,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
} }
} }
static iterator priv_segmented_move_n(const_iterator first, std::size_t n, iterator dest) static iterator priv_segmented_move_n(const_iterator first, size_type n, iterator dest)
{ {
index_pointer current_node = first.get_node(); index_pointer current_node = first.get_node();
BOOST_ASSERT(current_node != index_pointer()); BOOST_ASSERT(current_node != index_pointer());
@@ -2604,21 +2647,21 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
const pointer cur = first.get_cur(); const pointer cur = first.get_cur();
BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size();
const size_type block = block_size - size_type(cur - *current_node); const size_type block = size_type(block_size - size_type(cur - *current_node));
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(cur), cnt, dest); dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(cur), cnt, dest);
n -= cnt; n = size_type(n - cnt);
while (n) { while (n) {
++current_node; ++current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(*current_node), cnt, dest); dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(*current_node), cnt, dest);
n -= cnt; n = size_type(n - cnt);
} }
return dest; return dest;
} }
static iterator priv_segmented_move_backward_n(iterator last, std::size_t n, iterator dest_last) static iterator priv_segmented_move_backward_n(iterator last, size_type n, iterator dest_last)
{ {
index_pointer current_node = last.get_node(); index_pointer current_node = last.get_node();
BOOST_ASSERT(current_node != index_pointer()); BOOST_ASSERT(current_node != index_pointer());
@@ -2627,7 +2670,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
const size_type block = size_type(cur - *current_node); const size_type block = size_type(cur - *current_node);
size_type cnt = n < block ? n: block; size_type cnt = n < block ? n: block;
dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(cur), cnt, dest_last); dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(cur), cnt, dest_last);
n -= cnt; n = size_type(n - cnt);
BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size();
@@ -2635,7 +2678,7 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
--current_node; --current_node;
cnt = n < block_size ? n: block_size; cnt = n < block_size ? n: block_size;
dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(*current_node + block_size), cnt, dest_last); dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(*current_node + block_size), cnt, dest_last);
n -= cnt; n = size_type(n - cnt);
} }
return dest_last; return dest_last;
} }
@@ -2672,7 +2715,6 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
template <class InIt> template <class InIt>
void priv_range_initialize(InIt first, InIt last, typename iterator_enable_if_tag<InIt, std::input_iterator_tag>::type* =0) void priv_range_initialize(InIt first, InIt last, typename iterator_enable_if_tag<InIt, std::input_iterator_tag>::type* =0)
{ {
this->prot_initialize_map_and_nodes(0);
BOOST_CONTAINER_TRY { BOOST_CONTAINER_TRY {
for ( ; first != last; ++first) for ( ; first != last; ++first)
this->emplace_back(*first); this->emplace_back(*first);
@@ -2687,7 +2729,12 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
template <class FwdIt> template <class FwdIt>
void priv_range_initialize(FwdIt first, FwdIt last, typename iterator_disable_if_tag<FwdIt, std::input_iterator_tag>::type* =0) void priv_range_initialize(FwdIt first, FwdIt last, typename iterator_disable_if_tag<FwdIt, std::input_iterator_tag>::type* =0)
{ {
const size_type n = boost::container::iterator_udistance(first, last); typedef typename iter_size<FwdIt>::type it_size_type;
const it_size_type sz = boost::container::iterator_udistance(first, last);
if (BOOST_UNLIKELY(sz > size_type(-1))){
boost::container::throw_length_error("vector::insert, FwdIt's max length reached");
}
const size_type n = static_cast<size_type>(sz);
this->prot_initialize_map_and_nodes(n); this->prot_initialize_map_and_nodes(n);
dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first); dtl::insert_range_proxy<ValAllocator, FwdIt> proxy(first);
@@ -2743,17 +2790,17 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
if (n > vacancies){ //n == 0 handled in the else part if (n > vacancies){ //n == 0 handled in the else part
if(this->members_.m_map){ if(this->members_.m_map){
size_type new_elems = size_type(n - vacancies); const size_type new_elems = size_type(n - vacancies);
size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); const size_type additional_nodes = size_type((new_elems - 1u)/get_block_size() + 1u);
index_pointer start_node = this->prot_start_node(); index_pointer start_node = this->prot_start_node();
size_type s = (size_type)(start_node - this->members_.m_map); size_type front_unused_slots = size_type(start_node - this->members_.m_map);
if (new_nodes > s){ if (additional_nodes > front_unused_slots){
//Start node might have changed when reallocating the map //Start node might have changed when reallocating the map
index_pointer finish_node; index_pointer finish_node;
this->priv_reallocate_map(new_nodes, true, start_node, finish_node); this->priv_reallocate_map(additional_nodes, true, start_node, finish_node);
(void) finish_node; (void) finish_node;
} }
this->priv_allocate_nodes(start_node - difference_type(new_nodes), new_nodes); this->priv_allocate_nodes(start_node - difference_type(additional_nodes), additional_nodes);
} }
else { else {
this->prot_initialize_map_and_nodes(n); this->prot_initialize_map_and_nodes(n);
@@ -2768,17 +2815,18 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
if (n > vacancies){ //n == 0 handled in the else part if (n > vacancies){ //n == 0 handled in the else part
if(this->members_.m_map){ if(this->members_.m_map){
size_type new_elems = size_type(n - vacancies); const size_type new_elems = size_type(n - vacancies);
size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); const size_type additional_nodes = size_type((new_elems - 1u)/get_block_size() + 1u);
index_pointer finish_node = this->prot_finish_node(); index_pointer finish_node = this->prot_finish_node();
size_type s = (size_type)(this->members_.m_map_size - size_type(finish_node - this->members_.m_map)); //Finish node is already allocated so the unused slots are [finish_node + 1, m_map + map_size)
if (new_nodes + 1 > s){ const size_type back_unused_slots = size_type(this->members_.m_map_size - 1u - size_type(finish_node - this->members_.m_map));
if (additional_nodes > back_unused_slots){
index_pointer start_node; index_pointer start_node;
//Finish node might have changed when reallocating the map //Finish node might have changed when reallocating the map
this->priv_reallocate_map(new_nodes, false, start_node, finish_node); this->priv_reallocate_map(additional_nodes, false, start_node, finish_node);
(void) start_node; (void) start_node;
} }
this->priv_allocate_nodes(finish_node + 1, new_nodes); this->priv_allocate_nodes(finish_node + 1, additional_nodes);
} }
else{ else{
this->prot_initialize_map_and_nodes(n); this->prot_initialize_map_and_nodes(n);
@@ -2791,39 +2839,43 @@ class deque : protected deque_base<typename real_allocator<T, Allocator>::type,
{ {
const index_pointer start_node = this->prot_start_node(); const index_pointer start_node = this->prot_start_node();
const index_pointer finish_node = this->prot_finish_node(); const index_pointer finish_node = this->prot_finish_node();
size_type old_num_nodes = size_type(finish_node - start_node + 1); const index_pointer next_finish_node = finish_node + 1u;
size_type new_num_nodes = old_num_nodes + nodes_to_add; size_type old_num_nodes = size_type(next_finish_node - start_node);
size_type new_num_nodes = size_type(old_num_nodes + nodes_to_add);
index_pointer new_nstart; index_pointer new_nstart;
if (this->members_.m_map_size > 2 * new_num_nodes) { const size_type map_size = this->members_.m_map_size;
new_nstart = this->members_.m_map + difference_type(this->members_.m_map_size - new_num_nodes) / 2 if (map_size/2u >= new_num_nodes) {
+ difference_type(add_at_front ? nodes_to_add : 0u); new_nstart = this->members_.m_map + difference_type((map_size - new_num_nodes) / 2)
+ difference_type(add_at_front ? nodes_to_add : 0u);
if (new_nstart < start_node) if (new_nstart < start_node)
boost::container::move(start_node, finish_node + 1, new_nstart); boost::container::move_n(start_node, old_num_nodes, new_nstart);
else else
boost::container::move_backward boost::container::move_backward_n(next_finish_node, old_num_nodes, new_nstart + difference_type(old_num_nodes));
(start_node, finish_node + 1, new_nstart + difference_type(old_num_nodes));
} }
else { else {
//Doubling size, but at least one spare slot on each end //Doubling size, but at least one spare slot on each end
size_type new_map_size = const size_type new_map_size = dtl::max_value(size_type(map_size*2), size_type(nodes_to_add + 2u));
this->members_.m_map_size + dtl::max_value(this->members_.m_map_size, nodes_to_add + 2u);
index_pointer new_map = this->prot_allocate_map(new_map_size); //The end position must be representable in stored_size_type
new_nstart = new_map + difference_type(new_map_size - new_num_nodes) / 2 this->test_size_against_n_nodes(new_map_size);
+ difference_type(add_at_front ? nodes_to_add : 0u);
boost::container::move(start_node, finish_node + 1, new_nstart); const index_pointer new_map = this->prot_allocate_map(new_map_size);
new_nstart = new_map + difference_type((new_map_size - new_num_nodes) / 2)
+ difference_type(add_at_front ? nodes_to_add : 0u);;
boost::container::move_n(start_node, old_num_nodes, new_nstart);
this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size);
this->members_.m_map = new_map; this->members_.m_map = new_map;
this->members_.m_map_size = new_map_size; this->members_.m_map_size = static_cast<stored_size_type>(new_map_size);
} }
new_start_segment = new_nstart; new_start_segment = new_nstart;
new_finish_segment = new_nstart + difference_type(old_num_nodes - 1u); new_finish_segment = new_nstart + difference_type(old_num_nodes - 1u);
this->prot_start_set_node(new_start_segment); this->prot_start_update_node(new_start_segment);
this->prot_finish_set_node(new_finish_segment); this->prot_finish_update_node(new_finish_segment);
} }
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
}; };

View File

@@ -608,15 +608,22 @@ using devector_options_t = typename boost::container::devector_options<Options..
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<std::size_t BlockBytes, std::size_t BlockSize> template<std::size_t BlockBytes, std::size_t BlockSize, class StoredSizeType>
struct deque_opt struct deque_opt
{ {
BOOST_STATIC_CONSTEXPR std::size_t block_bytes = BlockBytes; BOOST_STATIC_CONSTEXPR std::size_t block_bytes = BlockBytes;
BOOST_STATIC_CONSTEXPR std::size_t block_size = BlockSize; BOOST_STATIC_CONSTEXPR std::size_t block_size = BlockSize;
BOOST_CONTAINER_STATIC_ASSERT_MSG(!(block_bytes && block_size), "block_bytes and block_size can't be specified at the same time"); BOOST_CONTAINER_STATIC_ASSERT_MSG(!(block_bytes && block_size), "block_bytes and block_size can't be specified at the same time");
typedef StoredSizeType stored_size_type;
template<class AllocTraits>
struct get_stored_size_type
: get_stored_size_type_with_alloctraits<AllocTraits, StoredSizeType>
{};
}; };
typedef deque_opt<0u, 0u> deque_null_opt; typedef deque_opt<0u, 0u, void> deque_null_opt;
#endif #endif
@@ -639,7 +646,10 @@ struct deque_options
Options... Options...
#endif #endif
>::type packed_options; >::type packed_options;
typedef deque_opt< packed_options::block_bytes, packed_options::block_size > implementation_defined; typedef deque_opt< packed_options::block_bytes
, packed_options::block_size
, typename packed_options::stored_size_type
> implementation_defined;
/// @endcond /// @endcond
typedef implementation_defined type; typedef implementation_defined type;
}; };

View File

@@ -8,10 +8,52 @@
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#include <boost/container/deque.hpp> #include <boost/container/deque.hpp>
#include <boost/container/new_allocator.hpp>
#include <boost/container/allocator.hpp>
#include <boost/core/lightweight_test.hpp> #include <boost/core/lightweight_test.hpp>
using namespace boost::container; using namespace boost::container;
using namespace boost::container;
template<class Unsigned, class VectorType>
void test_stored_size_type_impl()
{
#ifndef BOOST_NO_EXCEPTIONS
VectorType v;
typedef typename VectorType::size_type size_type;
size_type const max = Unsigned(-1);
v.resize(5);
BOOST_TEST_THROWS(v.resize(max+1), std::exception);
BOOST_TEST_THROWS(VectorType v2(max+1), std::exception);
#endif
}
template<class Unsigned>
void test_stored_size_type()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = deque_options_t< stored_size<Unsigned> >;
#else
typedef typename deque_options
< stored_size<Unsigned> >::type options_t;
#endif
typedef deque<unsigned char, new_allocator<unsigned char> > default_deque_t;
//Test first with a typical allocator
{
typedef deque<unsigned char, new_allocator<unsigned char>, options_t> deque_t;
BOOST_CONTAINER_STATIC_ASSERT(sizeof(deque_t) < sizeof(default_deque_t));
test_stored_size_type_impl<Unsigned, deque_t>();
}
//Test with a V2 allocator
{
typedef deque<unsigned char, allocator<unsigned char>, options_t> deque_t;
BOOST_CONTAINER_STATIC_ASSERT(sizeof(deque_t) < sizeof(default_deque_t));
test_stored_size_type_impl<Unsigned, deque_t>();
}
}
void test_block_bytes() void test_block_bytes()
{ {
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
@@ -38,5 +80,7 @@ int main()
{ {
test_block_bytes(); test_block_bytes();
test_block_elements(); test_block_elements();
test_stored_size_type<unsigned char>();
test_stored_size_type<unsigned short>();
return ::boost::report_errors(); return ::boost::report_errors();
} }

View File

@@ -36,8 +36,20 @@ template class boost::container::deque
< test::movable_and_copyable_int < test::movable_and_copyable_int
, allocator<test::movable_and_copyable_int> >; , allocator<test::movable_and_copyable_int> >;
template class deque_iterator<int*, true, 0, 0>; template class deque_iterator<int*, true, 0, 0, std::size_t>;
template class deque_iterator<int*, false, 0, 0>; template class deque_iterator<int*, false, 0, 0, std::size_t>;
//Test stored_size option
template class boost::container::deque < test::movable_and_copyable_int
, new_allocator<test::movable_and_copyable_int>
, deque_options< stored_size<unsigned short> >::type
>;
//test custom allocator with small size_type
template class boost::container::deque< test::movable_and_copyable_int
, test::small_size_type_allocator<test::movable_and_copyable_int>
>;
} //namespace boost { } //namespace boost {
} //namespace container { } //namespace container {