From 5be25a65dbd79492a0c1c014ab4e676d0a723818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 20 Sep 2025 10:48:50 +0200 Subject: [PATCH] Add new deque implementation. --- bench/bench_vectors.cpp | 109 +- bench/new_deque.hpp | 2886 --------------------------- doc/container.qbk | 7 + include/boost/container/deque.hpp | 1873 +++++++++-------- include/boost/container/options.hpp | 5 +- test/deque_test.cpp | 26 + test/new_deque_test.cpp | 475 ----- 7 files changed, 1040 insertions(+), 4341 deletions(-) delete mode 100644 bench/new_deque.hpp delete mode 100644 test/new_deque_test.cpp diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp index 6df433b..456222b 100644 --- a/bench/bench_vectors.cpp +++ b/bench/bench_vectors.cpp @@ -12,7 +12,6 @@ #include #include #include -#include "new_deque.hpp" #include #include #include @@ -73,6 +72,66 @@ class MyInt } }; +class MyFatInt +{ + int int0_; + int int1_; + int int2_; + int int3_; + int int4_; + int int5_; + int int6_; + int int7_; + + public: + inline explicit MyFatInt(int i = 0) + : int0_(i++) + , int1_(i++) + , int2_(i++) + , int3_(i++) + , int4_(i++) + , int5_(i++) + , int6_(i++) + , int7_(i++) + {} + + inline MyFatInt(const MyFatInt &other) + : int0_(other.int0_) + , int1_(other.int1_) + , int2_(other.int2_) + , int3_(other.int3_) + , int4_(other.int4_) + , int5_(other.int5_) + , int6_(other.int6_) + , int7_(other.int7_) + {} + + inline MyFatInt & operator=(const MyFatInt &other) + { + int0_ = other.int0_; + int1_ = other.int1_; + int2_ = other.int2_; + int3_ = other.int3_; + int4_ = other.int4_; + int5_ = other.int5_; + int6_ = other.int6_; + int7_ = other.int7_; + return *this; + } + + inline ~MyFatInt() + { + int0_ = 0u; + int1_ = 0u; + int2_ = 0u; + int3_ = 0u; + int4_ = 0u; + int5_ = 0u; + int6_ = 0u; + int7_ = 0u; + } +}; + template::value> struct capacity_wrapper @@ -99,7 +158,7 @@ const std::size_t RangeSize = 8; template struct insert_end_range { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return RangeSize; } template @@ -115,7 +174,7 @@ struct insert_end_range template struct insert_end_repeated { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return RangeSize; } template @@ -131,7 +190,7 @@ struct insert_end_repeated template struct push_back { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return 1; } template @@ -145,12 +204,12 @@ struct push_back template struct emplace_back { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return 1; } template inline void operator()(C &c, int i) - { c.emplace_back(i); } + { c.emplace_back(IntType(i)); } inline const char *name() const { return "emplace_back"; } @@ -159,7 +218,7 @@ struct emplace_back template struct insert_near_end_repeated { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return RangeSize; } template @@ -173,7 +232,7 @@ struct insert_near_end_repeated template struct insert_near_end_range { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return RangeSize; } template @@ -191,7 +250,7 @@ struct insert_near_end_range template struct insert_near_end { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return 1; } template @@ -210,7 +269,7 @@ struct insert_near_end template struct emplace_near_end { - inline std::size_t capacity_multiplier() const + static inline std::size_t capacity_multiplier() { return 1; } @@ -221,7 +280,7 @@ struct emplace_near_end typedef typename C::iterator it_t; it_t it(c.end()); it -= static_cast(c.size() >= 2) * 2; - c.emplace(it, i); + c.emplace(it, IntType(i)); } inline const char* name() const @@ -246,10 +305,9 @@ void vector_test_template(std::size_t num_iterations, std::size_t num_elements, const std::size_t max = num_elements/multiplier; for(std::size_t r = 0; r != num_iterations; ++r){ - //Unroll the loop to avoid noise from loop code int i = 0; - if (r > 0) //Exclude first iteration to avoid noise + if (r > num_iterations/10) //Exclude first iterations to avoid noise timer.resume(); for(std::size_t e = 0; e < max/16; ++e){ op(c, static_cast(i++)); @@ -270,7 +328,7 @@ void vector_test_template(std::size_t num_iterations, std::size_t num_elements, op(c, static_cast(i++)); } - if (r > 0) + if (r > num_iterations/10) timer.stop(); c.clear(); } @@ -303,11 +361,11 @@ void test_vectors_impl() std::size_t numele [] = { 100000 }; #elif defined SIMPLE_IT #ifdef NDEBUG - std::size_t numit [] = { 50 }; + std::size_t numit [] = { 150 }; #else std::size_t numit [] = { 10 }; #endif - std::size_t numele [] = { 100000 }; + std::size_t numele [] = { 500000 }; #else #ifdef NDEBUG unsigned int numit [] = { 1000, 10000, 100000, 1000000 }; @@ -335,8 +393,6 @@ void test_vectors_impl() #define P_END 1 #endif - typedef bc::vector_options< bc::growth_factor >::type growth_100_option_t; - for (unsigned p = P_INIT; p != P_END; ++p) { std::cout << "---------------------------------\n"; std::cout << "IntType:" << typeid(IntType).name() << " op:" << Operation().name() << ", prereserve: " << (p ? "1" : "0") << "\n"; @@ -345,14 +401,12 @@ void test_vectors_impl() const std::size_t it_count = sizeof(numele)/sizeof(numele[0]); for(unsigned int i = 0; i < it_count; ++i){ std::cout << "\n" << " ---- numit[i]: " << numit[i] << " numele[i] : " << numele[i] << " ---- \n"; - vector_test_template< std::vector >, Operation >(numit[i], numele[i], "std::vector ", bp); - vector_test_template< bc::vector >, Operation >(numit[i], numele[i] , "vector ", bp); - vector_test_template< bc::vector, growth_100_option_t >, Operation >(numit[i], numele[i], "vector(2x) ", bp); - vector_test_template< bc::small_vector >, Operation >(numit[i], numele[i], "small_vector ", bp); - vector_test_template< bc::devector >, Operation >(numit[i], numele[i], "devector ", bp); - vector_test_template< std::deque >, Operation >(numit[i], numele[i], "std::deque ", bp); - vector_test_template< bc::deque >, Operation >(numit[i], numele[i], "deque ", bp); - vector_test_template< bc::new_deque >, Operation >(numit[i], numele[i], "new_deque ", bp); + vector_test_template< std::vector >, Operation >(numit[i], numele[i], "std::vector ", bp); + vector_test_template< bc::vector >, Operation >(numit[i], numele[i] , "vector ", bp); + vector_test_template< bc::small_vector >, Operation >(numit[i], numele[i], "small_vector ", bp); + vector_test_template< bc::devector >, Operation >(numit[i], numele[i], "devector ", bp); + vector_test_template< std::deque >, Operation >(numit[i], numele[i], "std::deque ", bp); + vector_test_template< bc::deque >, Operation >(numit[i], numele[i], "deque ", bp); } std::cout << "---------------------------------\n---------------------------------\n"; } @@ -381,8 +435,9 @@ void test_vectors() int main() { - //test_vectors(); test_vectors(); + test_vectors(); + test_vectors(); return 0; } diff --git a/bench/new_deque.hpp b/bench/new_deque.hpp deleted file mode 100644 index bc1fc35..0000000 --- a/bench/new_deque.hpp +++ /dev/null @@ -1,2886 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2005-2025. 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. -// -////////////////////////////////////////////////////////////////////////////// -#ifndef BOOST_CONTAINER_NEW_DEQUE_HPP -#define BOOST_CONTAINER_NEW_DEQUE_HPP - -#ifndef BOOST_CONFIG_HPP -# include -#endif - -#if defined(BOOST_HAS_PRAGMA_ONCE) -# pragma once -#endif - -#include -#include -// container -#include -#include -#include //new_allocator -#include -#include -// container/detail -#include -#include //algo_equal(), algo_lexicographical_compare -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// move -#include -#include -#include -#include -// move/detail -#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -#include -#endif -#include -// other -#include -// std -#include - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) -#include -#endif - -namespace boost { -namespace container { - -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -template -class new_deque; - -template -struct new_deque_value_traits -{ - typedef T value_type; - BOOST_STATIC_CONSTEXPR bool trivial_dctr = dtl::is_trivially_destructible::value; - BOOST_STATIC_CONSTEXPR bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move::value; -}; - -template -struct new_deque_block_traits -{ - 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*)*64u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = sizeof(void*)*128u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = sizeof(void*)*512u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = sizeof(void*)*256u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 4*1024*256; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 4096u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 2048u; - //BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 1024u; - BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 512u; - BOOST_STATIC_CONSTEXPR std::size_t default_block_start = default_block_bytes/sizeof(T); - BOOST_STATIC_CONSTEXPR std::size_t default_block_size = default_block_start < 8u ? 8u : dtl::upper_power_of_2_ct::value; - BOOST_STATIC_CONSTEXPR std::size_t value = BlockSize ? BlockSize - : BlockBytes ? (BlockBytes-1u)/sizeof(T) + 1u - : default_block_size - ; -}; - -namespace dtl { - - -// Class invariants: -// For any nonsingular iterator i: -// i.node is the address of an element in the map array. The -// contents of i.node is a pointer to the beginning of a node. -// i.cur is a pointer in the range [i.first, i.last). NOTE: -// the implication of this is that i.cur is always a dereferenceable -// pointer, even if i is a past-the-end iterator. -// For every node other than start.node and finish.node, every element -// in the node is an initialized object. If start.node == finish.node, -// then [start.cur, finish.cur) are initialized objects, and -// the elements outside that range are uninitialized storage. Otherwise, -// [start.cur, start.last) and [finish.first, finish.cur) are initialized -// objects, and [start.first, start.cur) and [finish.cur, finish.last) -// are uninitialized storage. -// [map, map + map_size) is a valid range. -// [start.node, finish.node] is a valid range contained within -// [map, map + map_size). -// 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]. -template -class new_deque_iterator -{ - public: - typedef std::random_access_iterator_tag iterator_category; - typedef typename boost::intrusive::pointer_traits::element_type value_type; - typedef typename boost::intrusive::pointer_traits::difference_type difference_type; - typedef typename boost::intrusive::pointer_traits::size_type size_type; - typedef typename if_c - < IsConst - , typename boost::intrusive::pointer_traits::template - rebind_pointer::type - , Pointer - >::type pointer; - typedef typename if_c - < IsConst - , const value_type& - , value_type& - >::type reference; - - BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_CONTAINER_STATIC_ASSERT((new_deque_block_traits::value)); - return new_deque_block_traits::value; - } - - BOOST_CONSTEXPR inline static difference_type get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW - { return difference_type((get_block_size())); } - - class nat; - typedef typename dtl::if_c< IsConst - , new_deque_iterator - , nat>::type nonconst_iterator; - - typedef Pointer val_alloc_ptr; - typedef typename boost::intrusive::pointer_traits:: - template rebind_pointer::type index_pointer; - - Pointer m_cur; - index_pointer m_node; - - public: - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_cur() const { return m_cur; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_first() const { return *m_node; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_last() const { return *m_node + get_block_ssize(); } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline index_pointer get_node() const { return m_node; } - - inline new_deque_iterator(val_alloc_ptr x, index_pointer y) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x), m_node(y) - {} - - inline new_deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(), m_node() //Value initialization to achieve "null iterators" (N3644) - {} - - inline new_deque_iterator(const new_deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_node(x.get_node()) - {} - - inline new_deque_iterator(const nonconst_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_node(x.get_node()) - {} - - inline new_deque_iterator& operator=(const new_deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - { m_cur = x.get_cur(); m_node = x.get_node(); return *this; } - - inline nonconst_iterator unconst() const BOOST_NOEXCEPT_OR_NOTHROW - { - return nonconst_iterator(this->get_cur(), this->get_node()); - } - - inline reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->m_cur; } - - inline pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD difference_type operator-(const new_deque_iterator& x) const BOOST_NOEXCEPT_OR_NOTHROW - { - if(this->m_cur == x.m_cur){ //Includes when both are null - return 0; - } - BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); - return block_size * (this->m_node - x.m_node) + - (this->m_cur - this->get_first()) - (x.m_cur - x.get_first()); - } - - new_deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - ++this->m_cur; - const Pointer last = *m_node + get_block_ssize(); - if (BOOST_UNLIKELY(this->m_cur == last)) { - ++this->m_node; - this->m_cur = *this->m_node; - } - return *this; - } - - inline new_deque_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW - { - new_deque_iterator tmp(*this); - ++*this; - return tmp; - } - - new_deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - const Pointer first = *m_node; - if (BOOST_UNLIKELY(this->m_cur == first)) { - --this->m_node; - this->m_cur = *this->m_node; - this->m_cur += get_block_ssize() - 1; - } - else { - --this->m_cur; - } - return *this; - } - - inline new_deque_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW - { - new_deque_iterator tmp(*this); - --*this; - return tmp; - } - - new_deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - if (n){ - BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); - - const difference_type offset = n + (this->m_cur - *this->m_node); - - if (offset >= 0 && offset < block_size) - this->m_cur += difference_type(n); - else { - const difference_type node_offset = - offset > 0 ? (offset / block_size) - : (-difference_type((-offset - 1) / block_size) - 1); - this->m_node += node_offset; - this->m_cur = *this->m_node + (offset - node_offset * block_size); - } - } - return *this; - } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - new_deque_iterator operator+(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { new_deque_iterator tmp(*this); return tmp += n; } - - inline - new_deque_iterator& operator-=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return *this += -n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - new_deque_iterator operator-(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { new_deque_iterator tmp(*this); return tmp -= n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference operator[](difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); - - const difference_type offset = n + (this->m_cur - *this->m_node); - - if (offset >= 0 && offset < block_size) - return this->m_cur[difference_type(n)]; - else { - const difference_type node_offset = offset > 0 - ? (offset / block_size) - : (-difference_type((-offset - 1) / block_size) - 1); - return (this->m_node[node_offset]) [offset - node_offset * block_size]; - } - } - - //Comparisons - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator==(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur == r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator!=(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur != r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return (l.m_node == r.m_node) ? (l.m_cur < r.m_cur) : (l.m_node < r.m_node); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return r < l; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<=(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(r < l); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>=(const new_deque_iterator& l, const new_deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(l < r); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend new_deque_iterator operator+(difference_type n, new_deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW - { return x += n; } - - inline void priv_set_node(index_pointer new_node) BOOST_NOEXCEPT_OR_NOTHROW - { this->m_node = new_node; } -}; - -} //namespace dtl { - -template -struct new_deque_opt -{ - BOOST_STATIC_CONSTEXPR std::size_t block_bytes = BlockBytes; - 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"); -}; - -typedef new_deque_opt<0u, 0u> new_deque_null_opt; - -template -struct get_new_deque_opt -{ - typedef Options type; -}; - -template<> -struct get_new_deque_opt -{ - typedef new_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 new_deque_base -{ - BOOST_COPYABLE_AND_MOVABLE(new_deque_base) - public: - typedef allocator_traits val_alloc_traits_type; - typedef typename val_alloc_traits_type::value_type val_alloc_val; - typedef typename val_alloc_traits_type::pointer val_alloc_ptr; - typedef typename val_alloc_traits_type::const_pointer val_alloc_cptr; - typedef typename val_alloc_traits_type::reference val_alloc_ref; - typedef typename val_alloc_traits_type::const_reference val_alloc_cref; - typedef typename val_alloc_traits_type::difference_type val_alloc_diff; - typedef typename val_alloc_traits_type::size_type val_alloc_size; - typedef typename val_alloc_traits_type::template - portable_rebind_alloc::type ptr_alloc_t; - typedef allocator_traits ptr_alloc_traits_type; - typedef typename ptr_alloc_traits_type::value_type ptr_alloc_val; - typedef typename ptr_alloc_traits_type::pointer ptr_alloc_ptr; - typedef typename ptr_alloc_traits_type::const_pointer ptr_alloc_cptr; - typedef typename ptr_alloc_traits_type::reference ptr_alloc_ref; - typedef typename ptr_alloc_traits_type::const_reference ptr_alloc_cref; - typedef Allocator allocator_type; - typedef allocator_type stored_allocator_type; - typedef val_alloc_size size_type; - typedef val_alloc_diff difference_type; - typedef val_alloc_size stored_size_type; - - private: - typedef typename get_new_deque_opt::type options_type; - - protected: - typedef dtl::new_deque_iterator iterator; - typedef dtl::new_deque_iterator const_iterator; - - BOOST_CONSTEXPR inline static val_alloc_diff get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW - { return val_alloc_diff((get_block_size())); } - - BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW - { return new_deque_block_traits::value; } - - typedef new_deque_value_traits traits_t; - typedef ptr_alloc_t map_allocator_type; - - inline val_alloc_ptr prot_allocate_node() - { return this->alloc().allocate(get_block_size()); } - - inline void prot_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW - { this->alloc().deallocate(p, get_block_size()); } - - inline ptr_alloc_ptr prot_allocate_map(size_type n) - { return this->ptr_alloc().allocate(n); } - - inline void prot_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { this->ptr_alloc().deallocate(p, n); } - - inline new_deque_base(size_type num_elements, const allocator_type& a) - : members_(a) - { this->prot_initialize_map_and_nodes(num_elements); } - - inline explicit new_deque_base(const allocator_type& a) - : members_(a) - {} - - inline new_deque_base() - : members_() - {} - - inline explicit new_deque_base(BOOST_RV_REF(new_deque_base) x) - : members_( boost::move(x.ptr_alloc()) - , boost::move(x.alloc()) ) - {} - - ~new_deque_base() - { - if (this->members_.m_map) { - this->prot_destroy_nodes(this->prot_start_node(), this->prot_finish_node() + 1); - this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); - } - } - - private: - new_deque_base(const new_deque_base&); - - protected: - - void swap_members(new_deque_base &x) BOOST_NOEXCEPT_OR_NOTHROW - { - this->members_.swap(x.members_); - } - - void prot_initialize_map_and_nodes(size_type num_elements) - { - //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; - - //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); - this->members_.m_map = this->prot_allocate_map(this->members_.m_map_size); - - ptr_alloc_ptr nstart = this->members_.m_map + difference_type(this->members_.m_map_size - num_nodes) / 2; - ptr_alloc_ptr nfinish = nstart + difference_type(num_nodes); - - BOOST_CONTAINER_TRY { - this->prot_create_nodes(nstart, nfinish); - } - BOOST_CONTAINER_CATCH(...){ - this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = ptr_alloc_ptr(); - this->members_.m_map_size = 0; - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - - this->prot_start_to_node_first(nstart); - this->members_.m_finish = this->members_.m_start + num_elements; -// } - } - - void prot_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) - { - ptr_alloc_ptr cur = nstart; - BOOST_CONTAINER_TRY { - for (; cur < nfinish; ++cur) - *cur = this->prot_allocate_node(); - } - BOOST_CONTAINER_CATCH(...){ - this->prot_destroy_nodes(nstart, cur); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - - void prot_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) BOOST_NOEXCEPT_OR_NOTHROW - { - for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) - this->prot_deallocate_node(*n); - } - - void prot_clear_map() BOOST_NOEXCEPT_OR_NOTHROW - { - if (this->members_.m_map) { - this->prot_destroy_nodes(this->prot_start_node(), this->prot_finish_node() + 1); - this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = ptr_alloc_ptr(); - this->members_.m_map_size = 0u; - this->members_.m_start = 0u; - this->members_.m_finish = 0u; - } - } - - enum { InitialMapSize = 4 }; - - protected: - struct members_holder - : public ptr_alloc_t - , public allocator_type - { - friend class new_deque_base; - members_holder() - : map_allocator_type(), allocator_type() - , m_map(0), m_map_size(0) - , m_start(), m_finish() - {} - - explicit members_holder(const allocator_type &a) - : map_allocator_type(a), allocator_type(a) - , m_map(0), m_map_size(0) - , m_start(), m_finish() - {} - - template - members_holder(BOOST_FWD_REF(PtrAllocConvertible) pa, BOOST_FWD_REF(ValAllocConvertible) va) - : map_allocator_type(boost::forward(pa)) - , allocator_type (boost::forward(va)) - , m_map(0), m_map_size(0) - , m_start(), m_finish() - {} - - void swap(members_holder &x) BOOST_NOEXCEPT_OR_NOTHROW - { - ::boost::adl_move_swap(this->m_start, x.m_start); - ::boost::adl_move_swap(this->m_finish, x.m_finish); - ::boost::adl_move_swap(this->m_map, x.m_map); - ::boost::adl_move_swap(this->m_map_size, x.m_map_size); - } - - ptr_alloc_ptr m_map; - stored_size_type m_map_size; - private: - stored_size_type m_start; - stored_size_type m_finish; - } members_; - - inline ptr_alloc_t &ptr_alloc() BOOST_NOEXCEPT_OR_NOTHROW - { return members_; } - - inline const ptr_alloc_t &ptr_alloc() const BOOST_NOEXCEPT_OR_NOTHROW - { return members_; } - - inline allocator_type &alloc() BOOST_NOEXCEPT_OR_NOTHROW - { return members_; } - - inline const allocator_type &alloc() const BOOST_NOEXCEPT_OR_NOTHROW - { return members_; } - - static BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_node_last(ptr_alloc_ptr idx) - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - return *idx + (block_size - 1u); - } - - BOOST_CONTAINER_FORCEINLINE std::size_t prot_front_capacity() const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - return this->members_.m_start % block_size; - } - - BOOST_CONTAINER_FORCEINLINE std::size_t prot_back_capacity() const - { - //m_finish 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 = new_deque_block_traits::value; - return this->members_.m_map ? (block_size - 1u) - (this->members_.m_finish % block_size) : 0u; - } - - ////////////////////////// - // it_to_off / off_to_it - ////////////////////////// - - BOOST_CONTAINER_FORCEINLINE stored_size_type prot_it_to_off(const_iterator it) const - { - const ptr_alloc_ptr n = it.get_node(); - BOOST_ASSERT(!this->members_.m_map == !n); //Both should be null or both non-null - if (n) { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - return static_cast(std::size_t(n - this->members_.m_map)*block_size + std::size_t(it.get_cur() - it.get_first())); - } - else{ - return 0; - } - } - - BOOST_CONTAINER_FORCEINLINE iterator prot_off_to_it(std::size_t off) const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - const ptr_alloc_ptr node = this->members_.m_map + off/block_size; - return iterator(node ? *node + (off%block_size) : val_alloc_ptr(), node); - } - - stored_size_type prot_it_to_start_off(const_iterator it) const - { - const size_type off = this->prot_it_to_off(it); - BOOST_ASSERT(off >= this->members_.m_start); - return off - this->members_.m_start; - } - - ///////////// - // xxx_to_node - ///////////// - - BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_off_to_node(std::size_t off) const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - return this->members_.m_map + off/block_size; - } - - BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_start_node() const - { - return this->prot_off_to_node(this->members_.m_start); - } - - BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_finish_node() const - { - return this->prot_off_to_node(this->members_.m_finish); - } - - ///////////// - // xxx_to_cur - ///////////// - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_off_to_cur(std::size_t off) const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - const ptr_alloc_ptr node = this->members_.m_map + off/block_size; - return node ? *node + off%block_size : val_alloc_ptr(); - } - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_off_to_cur_unchecked(std::size_t off) const - { - BOOST_ASSERT(!!this->members_.m_map); - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - const ptr_alloc_ptr node = this->members_.m_map + off/block_size; - return *node + off%block_size; - } - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_start_cur_unchecked() const - { - return this->prot_off_to_cur_unchecked(this->members_.m_start); - } - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_finish_cur_unchecked() const - { - return this->prot_off_to_cur_unchecked(this->members_.m_finish); - } - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_last_cur_unchecked() const - { - BOOST_ASSERT(members_.m_start != members_.m_finish); - return this->prot_off_to_cur_unchecked(this->members_.m_finish-1u); - } - - BOOST_CONTAINER_FORCEINLINE const_iterator prot_start() const - { return this->prot_off_to_it(members_.m_start); } - - BOOST_CONTAINER_FORCEINLINE const_iterator prot_finish() const - { return this->prot_off_to_it(members_.m_finish); } - - BOOST_CONTAINER_FORCEINLINE const_iterator prot_nth(size_type n) const - { return this->prot_off_to_it(members_.m_start+n); } - - BOOST_CONTAINER_FORCEINLINE iterator prot_start() - { return this->prot_off_to_it(members_.m_start); } - - BOOST_CONTAINER_FORCEINLINE iterator prot_finish() - { return this->prot_off_to_it(members_.m_finish); } - - BOOST_CONTAINER_FORCEINLINE iterator prot_last() - { - BOOST_ASSERT(members_.m_start != members_.m_finish); - return this->prot_off_to_it(members_.m_finish-1u); - } - - BOOST_CONTAINER_FORCEINLINE iterator prot_nth(size_type n) - { return this->prot_off_to_it(members_.m_start+n); } - - BOOST_CONTAINER_FORCEINLINE std::size_t prot_size() const - { return size_type(this->members_.m_finish - this->members_.m_start); } - - BOOST_CONTAINER_FORCEINLINE bool prot_empty() const - { return this->members_.m_finish == this->members_.m_start; } - - BOOST_CONTAINER_FORCEINLINE void prot_inc_start() - { ++this->members_.m_start; } - - BOOST_CONTAINER_FORCEINLINE void prot_dec_start() - { --this->members_.m_start; } - - BOOST_CONTAINER_FORCEINLINE void prot_inc_finish() - { ++this->members_.m_finish; } - - BOOST_CONTAINER_FORCEINLINE void prot_dec_finish() - { --this->members_.m_finish; } - - BOOST_CONTAINER_FORCEINLINE void prot_dec_finish(std::size_t n) - { this->members_.m_finish = static_cast(this->members_.m_finish - n); } - - BOOST_CONTAINER_FORCEINLINE void prot_inc_finish(std::size_t n) - { this->members_.m_finish = static_cast(this->members_.m_finish + n); } - - BOOST_CONTAINER_FORCEINLINE void prot_dec_start(std::size_t n) - { this->members_.m_start = static_cast(this->members_.m_start - n); } - - BOOST_CONTAINER_FORCEINLINE void prot_inc_start(std::size_t n) - { this->members_.m_start = static_cast(this->members_.m_start + n); } - - BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_nth_to_cur(std::size_t n) const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - const size_type off = this->members_.m_start + n; - const ptr_alloc_ptr node = this->members_.m_map + off/block_size; - BOOST_ASSERT(node); - return *node + off%block_size; - } - - inline void prot_start_set_node(ptr_alloc_ptr new_start) - { - //iG: to-do: optimizable avoiding some division/remainder - std::size_t new_block_off = prot_it_to_off(iterator(*new_start, new_start)); - this->members_.m_start = static_cast(new_block_off + (this->members_.m_start % get_block_size())); - } - - inline void prot_finish_set_node(ptr_alloc_ptr new_finish) - { - //iG: to-do: optimizable avoiding some division/remainder - std::size_t new_block_off = prot_it_to_off(iterator(*new_finish, new_finish)); - this->members_.m_finish = static_cast(new_block_off + (this->members_.m_finish % get_block_size())); - } - - BOOST_CONTAINER_FORCEINLINE void prot_start_to_node_first(ptr_alloc_ptr new_start) - { - this->members_.m_start = this->prot_it_to_off(iterator(*new_start, new_start)); - } - - inline void prot_reset_finish_to_start() - { this->members_.m_finish = this->members_.m_start; } - - inline void prot_reset_start_to_finish() - { this->members_.m_start = this->members_.m_finish; } - - inline val_alloc_val *prot_push_back_simple_pos() const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - 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 std::size_t off = node ? this->members_.m_finish : last_in_block; - const std::size_t rem = off % block_size; - if(BOOST_LIKELY(rem != last_in_block)){ - return boost::movelib::to_raw_pointer(node[off/block_size]) + rem; - } - return 0; - } - - inline val_alloc_val *prot_push_front_simple_pos() const - { - BOOST_CONSTEXPR_OR_CONST std::size_t block_size = new_deque_block_traits::value; - //No need to check !m_map, as m_start is zero in that case - const std::size_t off = this->members_.m_start; - const std::size_t rem = off % block_size; - if(BOOST_LIKELY(rem != 0u)){ - return boost::movelib::to_raw_pointer(this->members_.m_map[off / block_size]) + (rem-1u); - } - return 0; - } - - BOOST_CONTAINER_FORCEINLINE bool prot_pop_back_simple_available() const - { - return (this->members_.m_finish % get_block_size()) != 0u; - } - - BOOST_CONTAINER_FORCEINLINE bool prot_pop_front_simple_available() const - { - return (this->members_.m_start % get_block_size()) != (get_block_size() - 1u); - } - -}; -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -//! A double-ended queue is a sequence that supports random access to elements, constant time insertion -//! 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 A The allocator used for all internal memory management, use void -//! for the default allocator -//! \tparam Options A type produced from \c boost::container::deque_options. -template -#else -template -#endif -class new_deque : protected new_deque_base::type, Options> -{ - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - private: - typedef new_deque_base::type, Options> Base; - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - typedef typename real_allocator::type ValAllocator; - typedef constant_iterator c_it; - - public: - - ////////////////////////////////////////////// - // - // types - // - ////////////////////////////////////////////// - - typedef T value_type; - typedef ValAllocator allocator_type; - typedef typename ::boost::container::allocator_traits::pointer pointer; - typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; - typedef typename ::boost::container::allocator_traits::reference reference; - typedef typename ::boost::container::allocator_traits::const_reference const_reference; - typedef typename ::boost::container::allocator_traits::size_type size_type; - typedef typename ::boost::container::allocator_traits::difference_type difference_type; - typedef BOOST_CONTAINER_IMPDEF(allocator_type) stored_allocator_type; - typedef BOOST_CONTAINER_IMPDEF(typename Base::iterator) iterator; - typedef BOOST_CONTAINER_IMPDEF(typename Base::const_iterator) const_iterator; - typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; - - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - - private: // Internal typedefs - - //`allocator_type::value_type` must match container's `value type`. If this - //assertion fails, please review your allocator definition. - BOOST_CONTAINER_STATIC_ASSERT((dtl::is_same::value_type>::value)); - - BOOST_COPYABLE_AND_MOVABLE(new_deque) - typedef typename Base::ptr_alloc_ptr index_pointer; - typedef allocator_traits allocator_traits_type; - - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - - using Base::get_block_ssize; - - public: - - using Base::get_block_size; - - - ////////////////////////////////////////////// - // - // construct/copy/destroy - // - ////////////////////////////////////////////// - - //! Effects: Default constructors a deque. - //! - //! Throws: If allocator_type's default constructor throws. - //! - //! Complexity: Constant. - inline new_deque() - BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) - : Base() - {} - - //! Effects: Constructs a deque taking the allocator as parameter. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - inline explicit new_deque(const allocator_type& a) BOOST_NOEXCEPT_OR_NOTHROW - : Base(a) - {} - - //! Effects: Constructs a deque - //! and inserts n value initialized values. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's value initialization throws. - //! - //! Complexity: Linear to n. - inline explicit new_deque(size_type n) - : Base(n, allocator_type()) - { - dtl::insert_value_initialized_n_proxy proxy; - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - //new_deque_base will deallocate in case of exception... - } - - //! Effects: Constructs a deque - //! and inserts n default initialized values. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's default initialization or copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: Non-standard extension - inline new_deque(size_type n, default_init_t) - : Base(n, allocator_type()) - { - dtl::insert_default_initialized_n_proxy proxy; - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - //new_deque_base will deallocate in case of exception... - } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts n value initialized values. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's value initialization throws. - //! - //! Complexity: Linear to n. - inline explicit new_deque(size_type n, const allocator_type &a) - : Base(n, a) - { - dtl::insert_value_initialized_n_proxy proxy; - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - //new_deque_base will deallocate in case of exception... - } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts n default initialized values. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's default initialization or copy constructor throws. - //! - //! Complexity: Linear to n. - //! - //! Note: Non-standard extension - inline new_deque(size_type n, default_init_t, const allocator_type &a) - : Base(n, a) - { - dtl::insert_default_initialized_n_proxy proxy; - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - //new_deque_base will deallocate in case of exception... - } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - inline new_deque(size_type n, const value_type& value) - : Base(n, allocator_type()) - { this->priv_fill_initialize(n, value); } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts n copies of value. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - inline new_deque(size_type n, const value_type& value, const allocator_type& a) - : Base(n, a) - { this->priv_fill_initialize(n, value); } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the deque. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's constructor taking a dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - inline new_deque(InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_convertible - ::type * = 0 - #endif - ) - : Base(allocator_type()) - { - this->priv_range_initialize(first, last); - } - - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts a copy of the range [first, last) in the deque. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's constructor taking a dereferenced InIt throws. - //! - //! Complexity: Linear to the range [first, last). - template - inline new_deque(InIt first, InIt last, const allocator_type& a - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_convertible - ::type * = 0 - #endif - ) - : Base(a) - { - this->priv_range_initialize(first, last); - } - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - //! Effects: Constructs a deque that will use a copy of allocator a - //! and inserts a copy of the range [il.begin(), il.end()) in the deque. - //! - //! Throws: If allocator_type's default constructor - //! throws or T's constructor taking a dereferenced std::initializer_list iterator throws. - //! - //! Complexity: Linear to the range [il.begin(), il.end()). - inline new_deque(std::initializer_list il, const allocator_type& a = allocator_type()) - : Base(a) - { - this->priv_range_initialize(il.begin(), il.end()); - } -#endif - - //! Effects: Copy constructs a deque. - //! - //! Postcondition: x == *this. - //! - //! Complexity: Linear to the elements x contains. - inline new_deque(const new_deque& x) - : Base(allocator_traits_type::select_on_container_copy_construction(x.alloc())) - { - if(x.size()){ - this->prot_initialize_map_and_nodes(x.size()); - this->priv_segmented_uninitialized_copy_alloc_n(x.begin(), x.size(), this->begin()); - } - } - - //! Effects: Move constructor. Moves x's resources to *this. - //! - //! Throws: If allocator_type's copy constructor throws. - //! - //! Complexity: Constant. - inline new_deque(BOOST_RV_REF(new_deque) x) BOOST_NOEXCEPT_OR_NOTHROW - : Base(BOOST_MOVE_BASE(Base, x)) - { this->swap_members(x); } - - //! Effects: Copy constructs a vector using the specified allocator. - //! - //! Postcondition: x == *this. - //! - //! Throws: If allocation - //! throws or T's copy constructor throws. - //! - //! Complexity: Linear to the elements x contains. - new_deque(const new_deque& x, const allocator_type &a) - : Base(a) - { - if(x.size()){ - this->prot_initialize_map_and_nodes(x.size()); - this->priv_segmented_uninitialized_copy_alloc_n(x.begin(), x.size(), this->begin()); - } - } - - //! Effects: Move constructor using the specified allocator. - //! Moves x's resources to *this if a == allocator_type(). - //! Otherwise copies values from x to *this. - //! - //! Throws: If allocation or T's copy constructor throws. - //! - //! Complexity: Constant if a == x.get_allocator(), linear otherwise. - new_deque(BOOST_RV_REF(new_deque) x, const allocator_type &a) - : Base(a) - { - if(x.alloc() == a){ - this->swap_members(x); - } - else{ - if(x.size()){ - this->prot_initialize_map_and_nodes(x.size()); - this->priv_segmented_uninitialized_move_alloc_n(x.begin(), x.size(), this->begin()); - } - } - } - - //! Effects: Destroys the deque. All stored values are destroyed - //! and used memory is deallocated. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements. - inline ~new_deque() BOOST_NOEXCEPT_OR_NOTHROW - { - this->prot_destroy_range(this->prot_start(), this->prot_finish()); - } - - //! Effects: Makes *this contain the same elements as x. - //! - //! Postcondition: this->size() == x.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in x. - new_deque& operator= (BOOST_COPY_ASSIGN_REF(new_deque) x) - { - if (BOOST_LIKELY(&x != this)){ - allocator_type &this_alloc = this->alloc(); - const allocator_type &x_alloc = x.alloc(); - dtl::bool_ flag; - if(flag && this_alloc != x_alloc){ - this->clear(); - this->shrink_to_fit(); - } - dtl::assign_alloc(this->alloc(), x.alloc(), flag); - dtl::assign_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - this->assign(x.cbegin(), x.cend()); - } - return *this; - } - - //! Effects: Move assignment. All x's values are transferred to *this. - //! - //! Throws: If allocator_traits_type::propagate_on_container_move_assignment - //! is false and (allocation throws or value_type's move constructor throws) - //! - //! Complexity: Constant if allocator_traits_type:: - //! propagate_on_container_move_assignment is true or - //! this->get>allocator() == x.get_allocator(). Linear otherwise. - new_deque& operator= (BOOST_RV_REF(new_deque) x) - BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value) - { - if (BOOST_LIKELY(this != &x)) { - //We know resources can be transferred at comiple time if both allocators are - //always equal or the allocator is going to be propagated - const bool can_steal_resources_alloc - = allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value; - dtl::bool_ flag; - this->priv_move_assign(boost::move(x), flag); - } - return *this; - } - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - //! Effects: Makes *this contain the same elements as il. - //! - //! Postcondition: this->size() == il.size(). *this contains a copy - //! of each of x's elements. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to the number of elements in il. - inline new_deque& operator=(std::initializer_list il) - { - this->assign(il.begin(), il.end()); - return *this; - } -#endif - - //! Effects: Assigns the n copies of val to *this. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - inline void assign(size_type n, const T& val) - { - dtl::insert_n_copies_proxy proxy(val); - this->priv_assign(n, proxy); - } - - //! Effects: Assigns the the range [first, last) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing InIt throws. - //! - //! Complexity: Linear to n. - template - void assign(InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_or - < void - , dtl::is_convertible - , dtl::is_not_input_iterator - >::type * = 0 - #endif - ) - { - iterator cur = this->begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ - *cur = *first; - } - if (first == last){ - this->erase(cur, this->cend()); - } - else{ - this->insert(this->cend(), first, last); - } - } - - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - template - void assign(FwdIt first, FwdIt last - , typename dtl::disable_if_or - < void - , dtl::is_convertible - , dtl::is_input_iterator - >::type * = 0 - ) - { - const size_type n = boost::container::iterator_udistance(first, last); - dtl::insert_range_proxy proxy(first); - this->priv_assign(n, proxy); - } - #endif - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - //! Effects: Assigns the the range [il.begin(), il.end()) to *this. - //! - //! Throws: If memory allocation throws or - //! T's constructor from dereferencing std::initializer_list iterator throws. - //! - //! Complexity: Linear to il.size(). - inline void assign(std::initializer_list il) - { this->assign(il.begin(), il.end()); } -#endif - - //! Effects: Returns a copy of the internal allocator. - //! - //! Throws: If allocator's copy constructor throws. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW - { return Base::alloc(); } - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW - { return Base::alloc(); } - - ////////////////////////////////////////////// - // - // iterators - // - ////////////////////////////////////////////// - - //! Effects: Returns a reference to the internal allocator. - //! - //! Throws: Nothing - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW - { return Base::alloc(); } - - //! Effects: Returns an iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - iterator begin() BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_start(); } - - //! Effects: Returns a const_iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_start(); } - - //! Effects: Returns an iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - iterator end() BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_finish(); } - - //! Effects: Returns a const_iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_finish(); } - - //! Effects: Returns a reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW - { return reverse_iterator(this->prot_finish()); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->prot_finish()); } - - //! Effects: Returns a reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW - { return reverse_iterator(this->prot_start()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->prot_start()); } - - //! Effects: Returns a const_iterator to the first element contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_start(); } - - //! Effects: Returns a const_iterator to the end of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_finish(); } - - //! Effects: Returns a const_reverse_iterator pointing to the beginning - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->prot_finish()); } - - //! Effects: Returns a const_reverse_iterator pointing to the end - //! of the reversed deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->prot_start()); } - - ////////////////////////////////////////////// - // - // capacity - // - ////////////////////////////////////////////// - - //! Effects: Returns true if the deque contains no elements. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - bool empty() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_empty(); } - - //! Effects: Returns the number of the elements contained in the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type size() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->prot_size(); } - - //! Effects: Returns the largest possible size of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW - { return allocator_traits_type::max_size(this->alloc()); } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are value initialized. - //! - //! Throws: If memory allocation throws, or T's constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size) - { - const size_type len = this->size(); - if (new_size < len) - this->priv_erase_last_n(len - new_size); - else{ - const size_type n = new_size - this->size(); - dtl::insert_value_initialized_n_proxy proxy; - this->priv_insert_back_aux_impl(n, proxy); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are default initialized. - //! - //! Throws: If memory allocation throws, or T's constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - //! - //! Note: Non-standard extension - void resize(size_type new_size, default_init_t) - { - const size_type len = size(); - if (new_size < len) - this->priv_erase_last_n(len - new_size); - else{ - const size_type n = new_size - this->size(); - dtl::insert_default_initialized_n_proxy proxy; - this->priv_insert_back_aux_impl(n, proxy); - } - } - - //! Effects: Inserts or erases elements at the end such that - //! the size becomes n. New elements are copy constructed from x. - //! - //! Throws: If memory allocation throws, or T's copy constructor throws. - //! - //! Complexity: Linear to the difference between size() and new_size. - void resize(size_type new_size, const value_type& x) - { - const size_type sz = this->size(); - if (new_size < sz) - this->priv_erase_last_n(sz - new_size); - else { - const size_type n = new_size - sz; - dtl::insert_n_copies_proxy proxy(x); - this->priv_insert_back_aux_impl(n, proxy); - } - } - - //! Effects: Tries to deallocate the excess of memory created - //! with previous allocations. The size of the deque is unchanged - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Constant. - void shrink_to_fit() - { - //This deque implementation already - //deallocates excess nodes when erasing - //so there is nothing to do except for - //empty deque - if(this->empty()){ - this->prot_clear_map(); - } - } - - ////////////////////////////////////////////// - // - // element access - // - ////////////////////////////////////////////// - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the first - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference front() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - return *this->prot_start_cur_unchecked(); - } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the first element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - return *this->prot_start_cur_unchecked(); - } - - //! Requires: !empty() - //! - //! Effects: Returns a reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference back() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - return *this->prot_last_cur_unchecked(); - } - - //! Requires: !empty() - //! - //! Effects: Returns a const reference to the last - //! element of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - return *this->prot_last_cur_unchecked(); - } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(this->size() > n); - return *this->prot_nth_to_cur(n); - } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(this->size() > n); - return *this->prot_nth_to_cur(n); - } - - //! Requires: size() >= n. - //! - //! Effects: Returns an iterator to the nth element - //! from the beginning of the container. Returns end() - //! if n == size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(this->size() >= n); - return this->prot_nth(n); - } - - //! Requires: size() >= n. - //! - //! Effects: Returns a const_iterator to the nth element - //! from the beginning of the container. Returns end() - //! if n == size(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(this->size() >= n); - return this->prot_nth(n); - } - - //! Requires: begin() <= p <= end(). - //! - //! Effects: Returns the index of the element pointed by p - //! and size() if p == end(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { - //Range checked priv_index_of - return this->priv_index_of(p); - } - - //! Requires: begin() <= p <= end(). - //! - //! Effects: Returns the index of the element pointed by p - //! and size() if p == end(). - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - //! - //! Note: Non-standard extension - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { - //Range checked priv_index_of - return this->priv_index_of(p); - } - - //! Requires: size() > n. - //! - //! Effects: Returns a reference to the nth element - //! from the beginning of the container. - //! - //! Throws: range_error if n >= size() - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference at(size_type n) - { - this->priv_throw_if_out_of_range(n); - return (*this)[n]; - } - - //! Requires: size() > n. - //! - //! Effects: Returns a const reference to the nth element - //! from the beginning of the container. - //! - //! Throws: range_error if n >= size() - //! - //! Complexity: Constant. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - const_reference at(size_type n) const - { - this->priv_throw_if_out_of_range(n); - return (*this)[n]; - } - - ////////////////////////////////////////////// - // - // modifiers - // - ////////////////////////////////////////////// - - #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the beginning of the deque. - //! - //! Returns: A reference to the created object. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time - template - reference emplace_front(BOOST_FWD_REF(Args)... args) - { - value_type *pr = this->prot_push_front_simple_pos(); - if(BOOST_LIKELY(pr != 0)){ - allocator_traits_type::construct - ( this->alloc() - , pr - , boost::forward(args)...); - this->prot_dec_start(); - return *pr; - } - else{ - typedef dtl::insert_nonmovable_emplace_proxy type; - return *this->priv_insert_front_aux_impl(1, type(boost::forward(args)...)); - } - } - - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... in the end of the deque. - //! - //! Returns: A reference to the created object. - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: Amortized constant time - template - reference emplace_back(BOOST_FWD_REF(Args)... args) - { - value_type *pr = this->prot_push_back_simple_pos(); - if(BOOST_LIKELY(pr != 0)){ - allocator_traits_type::construct - ( this->alloc() - , pr - , boost::forward(args)...); - this->prot_inc_finish(); - return *pr; - } - else{ - typedef dtl::insert_nonmovable_emplace_proxy type; - return *this->priv_insert_back_aux_impl(1, type(boost::forward(args)...)); - } - } - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Inserts an object of type T constructed with - //! std::forward(args)... before p - //! - //! Throws: If memory allocation throws or the in-place constructor throws. - //! - //! Complexity: If p is end(), amortized constant time - //! Linear time otherwise. - template - iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args) - { - const size_type elemsbefore = this->prot_it_to_start_off(p); - const size_type length = this->prot_size(); - - if (!elemsbefore) { - this->emplace_front(boost::forward(args)...); - return this->begin(); - } - else if (elemsbefore == length) { - this->emplace_back(boost::forward(args)...); - return this->prot_last(); - } - else { - typedef dtl::insert_emplace_proxy type; - return this->priv_insert_middle_aux_impl(elemsbefore, 1, type(boost::forward(args)...)); - } - } - - #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - #define BOOST_CONTAINER_DEQUE_EMPLACE_CODE(N) \ - BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ - reference emplace_front(BOOST_MOVE_UREF##N)\ - {\ - value_type *pr = this->prot_push_front_simple_pos();\ - if(BOOST_LIKELY(pr != 0)){\ - allocator_traits_type::construct\ - ( this->alloc(), pr BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - this->prot_dec_start();\ - return *pr;\ - }\ - else{\ - typedef dtl::insert_nonmovable_emplace_proxy##N\ - type;\ - return *priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\ - }\ - }\ - \ - BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ - reference emplace_back(BOOST_MOVE_UREF##N)\ - {\ - value_type *pr = this->prot_push_back_simple_pos();\ - if(BOOST_LIKELY(pr != 0)){\ - allocator_traits_type::construct\ - ( this->alloc(), pr BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - this->prot_inc_finish();\ - return *pr;\ - }\ - else{\ - typedef dtl::insert_nonmovable_emplace_proxy##N\ - type;\ - return *priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\ - }\ - }\ - \ - BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ - iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - {\ - const size_type elemsbefore = this->prot_it_to_start_off(p);\ - const size_type length = this->prot_size();\ - \ - if (!elemsbefore) {\ - this->emplace_front(BOOST_MOVE_FWD##N);\ - return this->begin();\ - }\ - else if (elemsbefore == length) {\ - this->emplace_back(BOOST_MOVE_FWD##N);\ - return this->prot_last();\ - }\ - else {\ - typedef dtl::insert_emplace_proxy_arg##N\ - type;\ - return this->priv_insert_middle_aux_impl(elemsbefore, 1, type(BOOST_MOVE_FWD##N));\ - }\ - }\ - // - BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEQUE_EMPLACE_CODE) - #undef BOOST_CONTAINER_DEQUE_EMPLACE_CODE - - #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the front of the deque. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_front(const T &x); - - //! Effects: Constructs a new element in the front of the deque - //! and moves the resources of x to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_front(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) - #endif - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: Inserts a copy of x at the end of the deque. - //! - //! Throws: If memory allocation throws or - //! T's copy constructor throws. - //! - //! Complexity: Amortized constant time. - void push_back(const T &x); - - //! Effects: Constructs a new element in the end of the deque - //! and moves the resources of x to this new element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: Amortized constant time. - void push_back(T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) - #endif - - #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a copy of x before p. - //! - //! Returns: an iterator to the inserted element. - //! - //! Throws: If memory allocation throws or x's copy constructor throws. - //! - //! Complexity: If p is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator p, const T &x); - - //! Requires: p must be a valid iterator of *this. - //! - //! Effects: Insert a new element before p with x's resources. - //! - //! Returns: an iterator to the inserted element. - //! - //! Throws: If memory allocation throws. - //! - //! Complexity: If p is end(), amortized constant time - //! Linear time otherwise. - iterator insert(const_iterator p, T &&x); - #else - BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) - #endif - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert n copies of x before pos. - //! - //! Returns: an iterator to the first inserted element or pos if n is 0. - //! - //! Throws: If memory allocation throws or T's copy constructor throws. - //! - //! Complexity: Linear to n. - inline iterator insert(const_iterator pos, size_type n, const value_type& x) - { - BOOST_ASSERT(this->priv_in_range_or_end(pos)); - dtl::insert_n_copies_proxy proxy(x); - return this->priv_insert_aux_impl(pos, n, proxy); - } - - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [first, last) range before pos. - //! - //! Returns: an iterator to the first inserted element or pos if first == last. - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced InIt throws or T's copy constructor throws. - //! - //! Complexity: Linear to distance [first, last). - template - iterator insert(const_iterator pos, InIt first, InIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_or - < void - , dtl::is_convertible - , dtl::is_not_input_iterator - >::type * = 0 - #endif - ) - { - BOOST_ASSERT(this->priv_in_range_or_end(pos)); - size_type n = 0; - iterator it(pos.unconst()); - for(;first != last; ++first, ++n){ - it = this->emplace(it, *first); - ++it; - } - it -= difference_type(n); - return it; - } - -#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) - //! Requires: pos must be a valid iterator of *this. - //! - //! Effects: Insert a copy of the [il.begin(), il.end()) range before pos. - //! - //! Returns: an iterator to the first inserted element or pos if il.begin() == il.end(). - //! - //! Throws: If memory allocation throws, T's constructor from a - //! dereferenced std::initializer_list throws or T's copy constructor throws. - //! - //! Complexity: Linear to distance [il.begin(), il.end()). - inline iterator insert(const_iterator pos, std::initializer_list il) - { - //Range check os pos is done in insert() - return insert(pos, il.begin(), il.end()); - } -#endif - - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - template - inline iterator insert(const_iterator p, FwdIt first, FwdIt last - #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - , typename dtl::disable_if_or - < void - , dtl::is_convertible - , dtl::is_input_iterator - >::type * = 0 - #endif - ) - { - BOOST_ASSERT(this->priv_in_range_or_end(p)); - dtl::insert_range_proxy proxy(first); - return this->priv_insert_aux_impl(p, boost::container::iterator_udistance(first, last), proxy); - } - #endif - - //! Effects: Removes the first element from the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_front() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - if (BOOST_LIKELY(this->prot_pop_front_simple_available())) { - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->prot_start_cur_unchecked()) - ); - this->prot_inc_start(); - } - else - this->priv_pop_front_aux(); - } - - //! Effects: Removes the last element from the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant time. - void pop_back() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!this->empty()); - if (BOOST_LIKELY(this->prot_pop_back_simple_available())) { - this->prot_dec_finish(); - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->prot_finish_cur_unchecked()) - ); - } - else - this->priv_pop_back_aux(); - } - - //! Effects: Erases the element at p. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the elements between pos and the - //! last element (if pos is near the end) or the first element - //! if(pos is near the beginning). - //! Constant if pos is the first or the last element. - iterator erase(const_iterator pos) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(this->priv_in_range(pos)); - iterator next = pos.unconst(); - ++next; - const size_type index = this->prot_it_to_start_off(pos); - - if (index < (this->size()/2)) { - this->priv_segmented_move_backward_n(pos.unconst(), index, next); - pop_front(); - return next; - } - else { - this->priv_segmented_move_n(next, this->size() - index - 1u, pos.unconst()); - pop_back(); - return pos.unconst(); - } - } - - //! Effects: Erases the elements pointed by [first, last). - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the distance between first and - //! last plus the elements between pos and the - //! last element (if pos is near the end) or the first element - //! if(pos is near the beginning). - iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(first == last || - (first < last && this->priv_in_range(first) && this->priv_in_range_or_end(last))); - const size_type n = static_cast(last - first); - if (n == this->prot_size()) { - this->clear(); - return this->end(); - } - else { - const size_type elems_before = this->prot_it_to_start_off(first); - if (elems_before < (this->size() - n) - elems_before) { - const iterator old_start = this->begin(); - 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_nodes(old_start.get_node(), new_start.m_node); - this->prot_inc_start(n); - } - else { - const iterator old_finish = this->end(); - iterator new_finish = this->priv_segmented_move_n(last.unconst(), this->prot_size() - n - elems_before, first.unconst()); - this->prot_destroy_range(new_finish, old_finish); - this->prot_destroy_nodes(new_finish.m_node + 1, old_finish.get_node() + 1); - this->prot_dec_finish(n); - } - return this->nth(elems_before); - } - } - - //! Effects: Swaps the contents of *this and x. - //! - //! Throws: Nothing. - //! - //! Complexity: Constant. - inline void swap(new_deque &x) - BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_swap::value - || allocator_traits_type::is_always_equal::value) - { - this->swap_members(x); - dtl::bool_ flag; - dtl::swap_alloc(this->alloc(), x.alloc(), flag); - dtl::swap_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - } - - //! Effects: Erases all the elements of the deque. - //! - //! Throws: Nothing. - //! - //! Complexity: Linear to the number of elements in the deque. - void clear() BOOST_NOEXCEPT_OR_NOTHROW - { - if (!this->empty()) { - const iterator start = this->prot_start(); - const iterator finish = this->prot_finish(); - const index_pointer start_node = start.get_node(); - const index_pointer finish_node = finish.get_node(); - for (index_pointer node = start_node + 1; node < finish_node; ++node) { - this->prot_destroy_range(*node, *node + get_block_ssize()); - this->prot_deallocate_node(*node); - } - - if (start_node != finish_node) { - this->prot_destroy_range(start.get_cur(), start.get_last()); - this->prot_destroy_range(finish.get_first(), finish.get_cur()); - this->prot_deallocate_node(finish.get_first()); - } - else - this->prot_destroy_range(start.get_cur(), finish.get_cur()); - - this->prot_reset_finish_to_start(); - } - } - - //! Effects: Returns true if x and y are equal - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator==(const new_deque& x, const new_deque& y) - { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } - - //! Effects: Returns true if x and y are unequal - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator!=(const new_deque& x, const new_deque& y) - { return !(x == y); } - - //! Effects: Returns true if x is less than y - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<(const new_deque& x, const new_deque& y) - { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - - //! Effects: Returns true if x is greater than y - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>(const new_deque& x, const new_deque& y) - { return y < x; } - - //! Effects: Returns true if x is equal or less than y - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<=(const new_deque& x, const new_deque& y) - { return !(y < x); } - - //! Effects: Returns true if x is equal or greater than y - //! - //! Complexity: Linear to the number of elements in the container. - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>=(const new_deque& x, const new_deque& y) - { return !(x < y); } - - //! Effects: x.swap(y) - //! - //! Complexity: Constant. - inline friend void swap(new_deque& x, new_deque& y) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) - { x.swap(y); } - - #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - private: - - template - void priv_assign(size_type n, InsertProxy proxy) - { - const size_type sz = this->prot_size(); - this->priv_segmented_proxy_copy_n_and_update(this->begin(), sz < n ? sz : n, proxy); - if (n > sz) { - this->priv_insert_back_aux_impl(n - sz, proxy); - } - else{ - this->priv_erase_last_n(sz - n); - } - } - - void priv_move_assign(BOOST_RV_REF(new_deque) x, dtl::bool_ /*steal_resources*/) - { - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - //Move allocator if needed - dtl::bool_ flag; - dtl::move_alloc(this->alloc(), x.alloc(), flag); - dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); - //Nothrow swap - this->swap_members(x); - } - - void priv_move_assign(BOOST_RV_REF(new_deque) x, dtl::bool_ /*steal_resources*/) - { - //We can't guarantee a compile-time equal allocator or propagation so fallback to runtime - //Resources can be transferred if both allocators are equal - if (this->alloc() == x.alloc()) { - this->priv_move_assign(boost::move(x), dtl::true_()); - } - else { - this->assign(boost::make_move_iterator(x.begin()), boost::make_move_iterator(x.end())); - } - } - - inline size_type priv_index_of(const_iterator p) const - { - BOOST_ASSERT(this->cbegin() <= p); - BOOST_ASSERT(p <= this->cend()); - return this->prot_it_to_start_off(p); - } - - void priv_erase_last_n(size_type n) - { - const size_type sz = this->prot_size(); - BOOST_ASSERT(n <= sz); - - if(sz) { - const iterator old_finish = this->prot_finish(); - const iterator new_finish = old_finish - difference_type(n); - this->prot_destroy_range(new_finish, old_finish); - this->prot_destroy_nodes(new_finish.get_node() + 1, old_finish.get_node() + 1); - this->prot_dec_finish(n); - } - } - - void priv_throw_if_out_of_range(size_type n) const - { - if (n >= this->size()) - throw_out_of_range("new_deque::at out of range"); - } - - inline bool priv_in_range(const_iterator pos) const - { - return (this->begin() <= pos) && (pos < this->end()); - } - - inline bool priv_in_range_or_end(const_iterator pos) const - { - return (this->begin() <= pos) && (pos <= this->end()); - } - - template - 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(::boost::forward(x))); - } - - template - void priv_push_back(BOOST_FWD_REF(U) u) - { - value_type *pr = this->prot_push_back_simple_pos(); - if(BOOST_LIKELY(pr != 0)){ - allocator_traits_type::construct - (this->alloc(), pr, boost::forward(u)); - this->prot_inc_finish(); - } - else{ - this->priv_insert_back_aux_impl(1, dtl::get_insert_value_proxy(::boost::forward(u))); - } - } - - template - BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u) - { - value_type *pr = this->prot_push_front_simple_pos(); - if(BOOST_LIKELY(pr != 0)){ - allocator_traits_type::construct - (this->alloc(), pr, boost::forward(u)); - this->prot_dec_start(); - } - else{ - this->priv_insert_front_aux_impl(1, dtl::get_insert_value_proxy(::boost::forward(u))); - } - } - - void prot_destroy_range(iterator start, iterator finish) - { - (void)start; (void)finish; - BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ - const index_pointer start_node = start.get_node(); - const index_pointer finish_node = finish.get_node(); - - //In a sane deque both should be null or non-null - BOOST_ASSERT(!start_node == !finish_node); - if(start_node){ - for (index_pointer node = start_node + 1; node < finish_node; ++node) { - this->prot_destroy_range(*node, *node + get_block_ssize()); - } - - if (start_node != finish_node) { - this->prot_destroy_range(start.get_cur(), start.get_last()); - this->prot_destroy_range(finish.get_first(), finish.get_cur()); - } - else - this->prot_destroy_range(start.get_cur(), finish.get_cur()); - } - } - } - - void prot_destroy_range(pointer p, pointer p2) - { - (void)p; (void)p2; - BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ - for(;p != p2; ++p){ - allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); - } - } - } - - template - iterator priv_insert_middle_aux_impl(const size_type elemsbefore, const size_type n, InsertProxy proxy) - { - typedef dtl::bool_::value> single_t; - BOOST_ASSERT(!single_t::value || n == 1); - - const size_type length = this->prot_size(); - if (elemsbefore < length / 2) { - this->priv_reserve_elements_at_front(n); - const iterator old_start = this->prot_start(); - iterator new_start = old_start; - priv_itsub(new_start, n, single_t()); - - BOOST_ASSERT(!single_t::value || elemsbefore >= 1); - - if(single_t::value || elemsbefore >= n) { - iterator start_n = old_start; - priv_itadd(start_n, n, single_t()); - BOOST_CONTAINER_TRY { - this->priv_segmented_uninitialized_move_alloc_n(old_start, n, new_start, single_t()); - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_nodes(new_start.m_node, old_start.m_node); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - - this->prot_dec_start(n); - iterator p = this->priv_segmented_move_n(start_n, elemsbefore-n, old_start); - this->priv_segmented_proxy_copy_n_and_update(p, n, proxy); - return p; - } - else { - const size_type mid_count = n - elemsbefore; - iterator mid_start = old_start - difference_type(mid_count); - - BOOST_CONTAINER_TRY { - this->priv_segmented_proxy_uninitialized_copy_n_and_update(mid_start, mid_count, proxy); - this->prot_dec_start(mid_count); - this->priv_segmented_uninitialized_move_alloc_n(old_start, elemsbefore, new_start); - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_nodes(new_start.m_node, old_start.get_node()); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - this->prot_dec_start(n - mid_count); - this->priv_segmented_proxy_copy_n_and_update(old_start, elemsbefore, proxy); - return mid_start; - } - } - else { - this->priv_reserve_elements_at_back(n); - const iterator old_finish = this->prot_finish(); - const size_type elemsafter = length - elemsbefore; - - BOOST_ASSERT(!single_t::value || elemsafter >= 1); - - if(single_t::value || elemsafter >= n) { - iterator finish_n = old_finish; - priv_itsub(finish_n, n, single_t()); - BOOST_CONTAINER_TRY { - this->priv_segmented_uninitialized_move_alloc_n(finish_n, n, old_finish, single_t()); - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_nodes(old_finish.get_node() + 1, (old_finish + difference_type(n)).m_node + 1); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - - this->prot_inc_finish(n); - const size_type move_n = elemsafter - n; - this->priv_segmented_move_backward_n(finish_n, move_n, old_finish); - finish_n -= difference_type(move_n); - this->priv_segmented_proxy_copy_n_and_update(finish_n, n, proxy); - return finish_n; - } - else { - const size_type raw_gap = n - elemsafter; - iterator pos = old_finish - difference_type(elemsafter); - - BOOST_CONTAINER_TRY{ - this->priv_segmented_uninitialized_move_alloc_n(pos, elemsafter, old_finish + difference_type(raw_gap)); - BOOST_CONTAINER_TRY{ - this->priv_segmented_proxy_copy_n_and_update(pos, elemsafter, proxy); - this->priv_segmented_proxy_uninitialized_copy_n_and_update(old_finish, raw_gap, proxy); - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_range(old_finish, old_finish + difference_type(elemsafter)); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_nodes(old_finish.get_node() + 1, (old_finish + difference_type(n)).m_node + 1); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - this->prot_inc_finish(n); - return pos; - } - } - } - - template - iterator priv_insert_aux_impl(const_iterator p, size_type n, InsertProxy proxy) - { - const size_type elemsbefore = this->prot_it_to_start_off(p); - const size_type length = this->prot_size(); - - if (!elemsbefore) { - return this->priv_insert_front_aux_impl(n, proxy); - } - else if (elemsbefore == length) { - return this->priv_insert_back_aux_impl(n, proxy); - } - else { - return this->priv_insert_middle_aux_impl(elemsbefore, n, proxy); - } - } - - template - void priv_segmented_proxy_uninitialized_copy_n_and_update(const iterator first, size_type n, InsertProxy &proxy) - { - BOOST_IF_CONSTEXPR (dtl::is_single_value_proxy::value) { - (void)n; - proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(first.get_cur()), 1u); - } - else{ - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - - BOOST_CONTAINER_TRY{ - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); - n -= cnt; - - while (n) { - ++current_node; - cnt = n < block_size ? n: block_size; - proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); - n -= cnt; - } - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_range(first, iterator(*current_node, current_node)); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - } - - - template - void priv_segmented_proxy_copy_n_and_update(const iterator first, size_type n, InsertProxy &proxy) - { - BOOST_IF_CONSTEXPR (dtl::is_single_value_proxy::value) { - (void)n; - proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(first.get_cur()), 1u); - } - else if(n){ //We might assign an empty range in a default constructed deque - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); - n -= cnt; - - while (n) { - ++current_node; - cnt = n < block_size ? n: block_size; - proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); - n -= cnt; - } - } - } - - template - void priv_insert_segmented_uninitialized_copy_n_and_update(const iterator first, size_type n, InsertProxy proxy) - { - BOOST_CONTAINER_TRY{ - this->priv_segmented_proxy_uninitialized_copy_n_and_update(first, n, proxy); - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_nodes(first.get_node() + 1, (first+difference_type(n)).get_node() + 1); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - - template - static BOOST_CONTAINER_FORCEINLINE void priv_itadd(It &it, size_type, dtl::bool_ /*single element*/) - { ++it; } - - template - static BOOST_CONTAINER_FORCEINLINE void priv_itadd(It &it, size_type n, dtl::bool_ /*!single element*/) - { it += difference_type(n); } - - template - static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type, dtl::bool_ /*single element*/) - { --it; } - - template - static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type n, dtl::bool_ /*!single element*/) - { it -= difference_type(n); } - - void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_ /*single element*/) - { - BOOST_ASSERT(n == 1); (void)n; - allocator_traits_type::construct - ( this->alloc() - , boost::movelib::to_raw_pointer(dest.get_cur()) - , boost::move(*first)); - } - - void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_ /*!single element*/) - { - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - - BOOST_CONTAINER_TRY{ - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); - n -= cnt; - - while (n) { - ++current_node; - 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); - n -= cnt; - } - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_range(first, iterator(*current_node, current_node)); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - - void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest) - { - this->priv_segmented_uninitialized_move_alloc_n(first, n, dest, dtl::bool_()); - } - - void priv_segmented_uninitialized_copy_alloc_n(const_iterator first, std::size_t n, iterator dest) - { - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - - BOOST_CONTAINER_TRY{ - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); - n -= cnt; - - while (n) { - ++current_node; - 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); - n -= cnt; - } - } - BOOST_CONTAINER_CATCH(...) { - this->prot_destroy_range(first.unconst(), iterator(*current_node, current_node)); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - - void priv_segmented_copy_n(const_iterator first, std::size_t n, iterator dest) - { - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - dest = ::boost::container::copy_n(boost::movelib::to_raw_pointer(cur), cnt, dest); - n -= cnt; - - while (n) { - ++current_node; - cnt = n < block_size ? n: block_size; - dest = ::boost::container::copy_n(boost::movelib::to_raw_pointer(*current_node), cnt, dest); - n -= cnt; - } - } - - static iterator priv_segmented_move_n(const_iterator first, std::size_t n, iterator dest) - { - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = first.get_node(); - const pointer cur = first.get_cur(); - const size_type block = block_size - size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(cur), cnt, dest); - n -= cnt; - - while (n) { - ++current_node; - cnt = n < block_size ? n: block_size; - dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(*current_node), cnt, dest); - n -= cnt; - } - return dest; - } - - static iterator priv_segmented_move_backward_n(iterator last, std::size_t n, iterator dest_last) - { - BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); - - index_pointer current_node = last.get_node(); - const pointer cur = last.get_cur(); - const size_type block = size_type(cur - *current_node); - size_type cnt = n < block ? n: block; - dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(cur), cnt, dest_last); - n -= cnt; - - while (n) { - --current_node; - 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); - n -= cnt; - } - return dest_last; - } - - template - iterator priv_insert_back_aux_impl(size_type n, InsertProxy proxy) - { - this->priv_reserve_elements_at_back(n); - const iterator old_finish = this->prot_finish(); - this->priv_insert_segmented_uninitialized_copy_n_and_update(old_finish, n, proxy); - this->prot_inc_finish(n); - return old_finish; - } - - template - iterator priv_insert_front_aux_impl(size_type n, InsertProxy proxy) - { - this->priv_reserve_elements_at_front(n); - const iterator old_start = this->prot_start(); - const iterator new_start = old_start - difference_type(n); - this->priv_insert_segmented_uninitialized_copy_n_and_update(new_start, n, proxy); - this->prot_dec_start(n); - return new_start; - } - - // Precondition: this->prot_start() and this->prot_finish() have already been initialized, - // but none of the deque's elements have yet been constructed. - void priv_fill_initialize(size_type n, const value_type& value) - { - dtl::insert_n_copies_proxy proxy(value); - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - } - - template - void priv_range_initialize(InIt first, InIt last, typename iterator_enable_if_tag::type* =0) - { - this->prot_initialize_map_and_nodes(0); - BOOST_CONTAINER_TRY { - for ( ; first != last; ++first) - this->emplace_back(*first); - } - BOOST_CONTAINER_CATCH(...){ - this->clear(); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - - template - void priv_range_initialize(FwdIt first, FwdIt last, typename iterator_disable_if_tag::type* =0) - { - const size_type n = boost::container::iterator_udistance(first, last); - this->prot_initialize_map_and_nodes(n); - - dtl::insert_range_proxy proxy(first); - this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); - } - - // Called only if this->prot_finish_cur() == this->prot_finish().get_first(). - void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW - { - index_pointer ip = this->prot_finish_node(); - this->prot_deallocate_node(*ip); - this->prot_dec_finish(); - --ip; - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->prot_node_last(ip)) - ); - } - - // Called only if this->prot_start_cur() == this->prot_start().get_last() - 1. Note that - // if the deque has at least one element (a precondition for this member - // function), and if this->prot_start_cur() == this->prot_start().get_last(), then the deque - // must have at least two nodes. - void priv_pop_front_aux() BOOST_NOEXCEPT_OR_NOTHROW - { - const index_pointer ip = this->prot_start_node(); - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->prot_node_last(ip)) - ); - this->prot_deallocate_node(*ip); - this->prot_inc_start(); - } - - void priv_reserve_elements_at_front(size_type n) - { - const size_type vacancies = this->prot_front_capacity(); - - if (n > vacancies){ //n == 0 handled in the else part - if(this->members_.m_map){ - size_type new_elems = n - vacancies; - size_type new_nodes = (new_elems + get_block_size() - 1u) / get_block_size(); - index_pointer start_node = this->prot_start_node(); - size_type s = (size_type)(start_node - this->members_.m_map); - if (new_nodes > s){ - this->priv_reallocate_map(new_nodes, true); - //Start node might have changed when reallocating the map - start_node = this->prot_start_node(); - } - - size_type i = 1; - BOOST_CONTAINER_TRY { - for (; i <= new_nodes; ++i) - start_node[-difference_type(i)] = this->prot_allocate_node(); - } - BOOST_CONTAINER_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->prot_deallocate_node(start_node[-difference_type(j)]); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - else { - this->prot_initialize_map_and_nodes(n); - this->prot_reset_start_to_finish(); - } - } - } - - void priv_reserve_elements_at_back(size_type n) - { - const size_type vacancies = this->prot_back_capacity(); - - if (n > vacancies){ - if(this->members_.m_map){ - size_type new_elems = size_type(n - vacancies); - size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); - 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)); - if (new_nodes + 1 > s){ - this->priv_reallocate_map(new_nodes, false); - //Finish node might have changed when reallocating the map - finish_node = this->prot_finish_node(); - } - - size_type i = 1; - BOOST_CONTAINER_TRY { - for (; i <= new_nodes; ++i) - finish_node[difference_type(i)] = this->prot_allocate_node(); - } - BOOST_CONTAINER_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->prot_deallocate_node(finish_node[difference_type(j)]); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - } - else{ - this->prot_initialize_map_and_nodes(n); - this->prot_reset_finish_to_start(); - } - } - } - - void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) - { - const index_pointer start_node = this->prot_start_node(); - const index_pointer finish_node = this->prot_finish_node(); - size_type old_num_nodes = size_type(finish_node - start_node + 1); - size_type new_num_nodes = old_num_nodes + nodes_to_add; - - index_pointer new_nstart; - if (this->members_.m_map_size > 2 * new_num_nodes) { - new_nstart = this->members_.m_map + difference_type(this->members_.m_map_size - new_num_nodes) / 2 - + difference_type(add_at_front ? nodes_to_add : 0u); - if (new_nstart < start_node) - boost::container::move(start_node, finish_node + 1, new_nstart); - else - boost::container::move_backward - (start_node, finish_node + 1, new_nstart + difference_type(old_num_nodes)); - } - else { - //Doubling size, but at least one spare slot on each end - size_type new_map_size = - 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); - 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(start_node, finish_node + 1, new_nstart); - this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); - - this->members_.m_map = new_map; - this->members_.m_map_size = new_map_size; - } - - this->prot_start_set_node(new_nstart); - this->prot_finish_set_node(new_nstart + difference_type(old_num_nodes - 1u)); - } - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -}; - -#ifndef BOOST_CONTAINER_NO_CXX17_CTAD -template -new_deque(InputIterator, InputIterator) -> new_deque::value_type>; -template -new_deque(InputIterator, InputIterator, Allocator const&) -> new_deque::value_type, Allocator>; -#endif - -} //namespace container -} //namespace boost - -#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -namespace boost { - -//!has_trivial_destructor_after_move<> == true_type -//!specialization for optimizations -template -struct has_trivial_destructor_after_move > -{ - typedef typename boost::container::new_deque::allocator_type allocator_type; - typedef typename ::boost::container::allocator_traits::pointer pointer; - BOOST_STATIC_CONSTEXPR bool value = ::boost::has_trivial_destructor_after_move::value && - ::boost::has_trivial_destructor_after_move::value; -}; - -} - -#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - -#include - -#endif // #ifndef BOOST_CONTAINER_NEW_DEQUE_HPP diff --git a/doc/container.qbk b/doc/container.qbk index 7d244f9..0ff9fa0 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1423,6 +1423,13 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_90_00 Boost 1.90 Release] +* Reimplemented [classref boost::container::deque]. The original implementation was based on + the SGI's original data structure (similar to libstdc++). Main changes: + * `sizeof(deque)` was 10 words, now is 4 words. Probably the lightest implementation around. + * `sizeof(deque::iterator)` now is is 2 words (similar to libc++ and MSVC).) + * Several internal algorithms were reimplemented to speed up the segmented nature of deque. + * The new implementation eases further deque-like variations and optimizations in the future. + * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/248 GitHub #248: ['"flat_map slow insertion introduced in boost-1.80.0"]]. * [@https://github.com/boostorg/container/pull/294 GitHub #294: ['"CMake: Add option to use header-only Boost::container"]]. diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index a452cfa..c6bdbdd 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// (C) Copyright Ion Gaztanaga 2025-2025. 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) // @@ -38,6 +38,7 @@ #include #include #include +#include // move #include #include @@ -61,8 +62,6 @@ namespace boost { namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -template -class deque; template struct deque_value_traits @@ -73,21 +72,28 @@ struct deque_value_traits }; template -struct deque_block_size +struct deque_block_traits { BOOST_CONTAINER_STATIC_ASSERT_MSG(!(BlockBytes && BlockSize), "BlockBytes and BlockSize can't be specified at the same time"); - BOOST_STATIC_CONSTEXPR std::size_t block_bytes = BlockBytes ? BlockBytes : 512u; - BOOST_STATIC_CONSTEXPR std::size_t value = BlockSize ? BlockSize : (sizeof(T) < block_bytes ? (block_bytes/sizeof(T)) : std::size_t(1)); + BOOST_STATIC_CONSTEXPR std::size_t default_block_bytes = 512u; + 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_block_size = default_block_start < default_min_block_size + ? default_min_block_size + : dtl::upper_power_of_2_ct::value; + BOOST_STATIC_CONSTEXPR std::size_t value = BlockSize ? BlockSize + : BlockBytes ? (BlockBytes-1u)/sizeof(T) + 1u + : default_block_size + ; }; namespace dtl { + // Class invariants: // For any nonsingular iterator i: // i.node is the address of an element in the map array. The // contents of i.node is a pointer to the beginning of a node. -// i.first == //(i.node) -// i.last == i.first + node_size // i.cur is a pointer in the range [i.first, i.last). NOTE: // the implication of this is that i.cur is always a dereferenceable // pointer, even if i is a past-the-end iterator. @@ -98,437 +104,11 @@ namespace dtl { // [start.cur, start.last) and [finish.first, finish.cur) are initialized // objects, and [start.first, start.cur) and [finish.cur, finish.last) // are uninitialized storage. -// [map, map + map_size) is a valid, non-empty range. +// [map, map + map_size) is a valid range. // [start.node, finish.node] is a valid range contained within // [map, map + map_size). // 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]. - -#define BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL 0 - -#if BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL == 0 -template -class deque_iterator -{ - public: - typedef std::random_access_iterator_tag iterator_category; - typedef typename boost::intrusive::pointer_traits::element_type value_type; - typedef typename boost::intrusive::pointer_traits::difference_type difference_type; - typedef typename boost::intrusive::pointer_traits::size_type size_type; - typedef typename if_c - < IsConst - , typename boost::intrusive::pointer_traits::template - rebind_pointer::type - , Pointer - >::type pointer; - typedef typename if_c - < IsConst - , const value_type& - , value_type& - >::type reference; - - class nat; - typedef typename dtl::if_c< IsConst - , deque_iterator - , nat>::type nonconst_iterator; - - typedef Pointer val_alloc_ptr; - typedef typename boost::intrusive::pointer_traits:: - template rebind_pointer::type index_pointer; - - Pointer m_cur; - Pointer m_first; - Pointer m_last; - index_pointer m_node; - - public: - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_cur() const { return m_cur; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_first() const { return m_first; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_last() const { return m_last; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline index_pointer get_node() const { return m_node; } - - inline 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) - {} - - inline deque_iterator(val_alloc_ptr x, index_pointer y, size_type block_size) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x), m_first(*y), m_last(*y + difference_type(block_size)), m_node(y) - {} - - inline deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(), m_first(), m_last(), m_node() //Value initialization to achieve "null iterators" (N3644) - {} - - inline deque_iterator(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_first(x.get_first()), m_last(x.get_last()), m_node(x.get_node()) - {} - - inline deque_iterator(const nonconst_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_first(x.get_first()), m_last(x.get_last()), m_node(x.get_node()) - {} - - inline deque_iterator(Pointer cur, Pointer first, Pointer last, index_pointer node) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(cur), m_first(first), m_last(last), m_node(node) - {} - - inline deque_iterator& operator=(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - { m_cur = x.get_cur(); m_first = x.get_first(); m_last = x.get_last(); m_node = x.get_node(); return *this; } - - inline deque_iterator unconst() const BOOST_NOEXCEPT_OR_NOTHROW - { - return deque_iterator(this->get_cur(), this->get_first(), this->get_last(), this->get_node()); - } - - inline reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->m_cur; } - - inline pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD difference_type operator-(const deque_iterator& x) const BOOST_NOEXCEPT_OR_NOTHROW - { - if(!this->m_cur && !x.m_cur){ - return 0; - } - const difference_type block_size = m_last - 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) { - 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; - } - - inline deque_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW - { - deque_iterator tmp(*this); - ++*this; - return tmp; - } - - deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - if (this->m_cur == this->m_first) { - 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; - return *this; - } - - inline deque_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW - { - deque_iterator tmp(*this); - --*this; - return tmp; - } - - deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - if (!n) - return *this; - BOOST_ASSERT(!!m_cur); - const difference_type offset = n + (this->m_cur - this->m_first); - const difference_type block_size = m_last - m_first; - BOOST_ASSERT(block_size); - if (offset >= 0 && offset < block_size) - this->m_cur += difference_type(n); - else { - const difference_type node_offset = - offset > 0 ? (offset / block_size) - : (-difference_type((-offset - 1) / block_size) - 1); - this->priv_set_node(this->m_node + node_offset, size_type(block_size)); - this->m_cur = this->m_first + (offset - node_offset * block_size); - } - return *this; - } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - deque_iterator operator+(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { deque_iterator tmp(*this); return tmp += n; } - - inline - deque_iterator& operator-=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return *this += -n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - deque_iterator operator-(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { deque_iterator tmp(*this); return tmp -= n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference operator[](difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return *(*this + n); } - - //Comparisons - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator==(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur == r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator!=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur != r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return (l.m_node == r.m_node) ? (l.m_cur < r.m_cur) : (l.m_node < r.m_node); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return r < l; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(r < l); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(l < r); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW - { return x += n; } - - inline void priv_set_node(index_pointer new_node, size_type block_size) BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_set_node(new_node, difference_type(block_size)); } - - inline 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 + block_size; - } -}; - -#elif BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL == 1 - -template -class deque_iterator -{ - public: - typedef std::random_access_iterator_tag iterator_category; - typedef typename boost::intrusive::pointer_traits::element_type value_type; - typedef typename boost::intrusive::pointer_traits::difference_type difference_type; - typedef typename boost::intrusive::pointer_traits::size_type size_type; - typedef typename if_c - < IsConst - , typename boost::intrusive::pointer_traits::template - rebind_pointer::type - , Pointer - >::type pointer; - typedef typename if_c - < IsConst - , const value_type& - , value_type& - >::type reference; - - BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW - { return deque_block_size::value; } - - BOOST_CONSTEXPR inline static difference_type get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW - { return difference_type((get_block_size())); } - - class nat; - typedef typename dtl::if_c< IsConst - , deque_iterator - , nat>::type nonconst_iterator; - - typedef Pointer val_alloc_ptr; - typedef typename boost::intrusive::pointer_traits:: - template rebind_pointer::type index_pointer; - - Pointer m_cur; - Pointer m_first; - index_pointer m_node; - - public: - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_cur() const { return m_cur; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_first() const { return m_first; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_last() const { return m_first + get_block_ssize(); } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline index_pointer get_node() const { return m_node; } - - inline deque_iterator(val_alloc_ptr x, index_pointer y, difference_type ) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x), m_first(*y), m_node(y) - {} - - inline deque_iterator(val_alloc_ptr x, index_pointer y, size_type ) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x), m_first(*y), m_node(y) - {} - - inline deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(), m_first(), m_node() //Value initialization to achieve "null iterators" (N3644) - {} - - inline deque_iterator(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_first(x.get_first()), m_node(x.get_node()) - {} - - inline deque_iterator(const nonconst_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x.get_cur()), m_first(x.get_first()), m_node(x.get_node()) - {} - - inline deque_iterator(Pointer cur, Pointer first, index_pointer node) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(cur), m_first(first), m_node(node) - {} - - inline deque_iterator& operator=(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW - { m_cur = x.get_cur(); m_first = x.get_first(); m_node = x.get_node(); return *this; } - - inline nonconst_iterator unconst() const BOOST_NOEXCEPT_OR_NOTHROW - { - return nonconst_iterator(this->get_cur(), this->get_first(), this->get_node()); - } - - inline reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW - { return *this->m_cur; } - - inline pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD difference_type operator-(const deque_iterator& x) const BOOST_NOEXCEPT_OR_NOTHROW - { - if(!this->m_cur && !x.m_cur){ - return 0; - } - const difference_type block_size = get_block_ssize(); - BOOST_ASSERT(block_size); - return block_size * (this->m_node - x.m_node - 1) + - (this->m_cur - this->m_first) + ((x.m_first+block_size) - x.m_cur); - } - - deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - ++this->m_cur; - const difference_type block_size = get_block_ssize(); - if (this->m_cur == (this->m_first+block_size)) { - - BOOST_ASSERT(block_size); - ++this->m_node; - this->m_first = *this->m_node; - this->m_cur = this->m_first; - } - return *this; - } - - inline deque_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW - { - deque_iterator tmp(*this); - ++*this; - return tmp; - } - - deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW - { - BOOST_ASSERT(!!m_cur); - if (this->m_cur == this->m_first) { - --this->m_node; - this->m_first = *this->m_node; - this->m_cur = this->m_first + get_block_ssize(); - } - --this->m_cur; - return *this; - } - - inline deque_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW - { - deque_iterator tmp(*this); - --*this; - return tmp; - } - - deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { - if (!n) - return *this; - BOOST_ASSERT(!!m_cur); - const difference_type offset = n + (this->m_cur - this->m_first); - const difference_type block_size = get_block_ssize(); - BOOST_ASSERT(block_size); - if (offset >= 0 && offset < block_size) - this->m_cur += difference_type(n); - else { - const difference_type node_offset = - offset > 0 ? (offset / block_size) - : (-difference_type((-offset - 1) / block_size) - 1); - this->m_node += node_offset; - this->m_first = *this->m_node; - this->m_cur = this->m_first + (offset - node_offset * block_size); - } - return *this; - } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - deque_iterator operator+(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { deque_iterator tmp(*this); return tmp += n; } - - inline - deque_iterator& operator-=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return *this += -n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - deque_iterator operator-(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { deque_iterator tmp(*this); return tmp -= n; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - reference operator[](difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return *(*this + n); } - - //Comparisons - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator==(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur == r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator!=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return l.m_cur != r.m_cur; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return (l.m_node == r.m_node) ? (l.m_cur < r.m_cur) : (l.m_node < r.m_node); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return r < l; } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator<=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(r < l); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend bool operator>=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW - { return !(l < r); } - - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline - friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW - { return x += n; } - - inline void priv_set_node(index_pointer new_node, size_type ) BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_set_node(new_node, difference_type()); } - - inline void priv_set_node(index_pointer new_node, difference_type) BOOST_NOEXCEPT_OR_NOTHROW - { - this->m_node = new_node; - this->m_first = *new_node; - } -}; - -#elif BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL == 2 - template class deque_iterator { @@ -551,8 +131,8 @@ class deque_iterator BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW { - BOOST_CONTAINER_STATIC_ASSERT((deque_block_size::value)); - return deque_block_size::value; + BOOST_CONTAINER_STATIC_ASSERT((deque_block_traits::value)); + return deque_block_traits::value; } BOOST_CONSTEXPR inline static difference_type get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW @@ -574,14 +154,10 @@ class deque_iterator BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_cur() const { return m_cur; } BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_first() const { return *m_node; } - BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_last() const { return *m_node + get_block_ssize(); } + BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline Pointer get_last() const { return *m_node + get_block_ssize(); } BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline index_pointer get_node() const { return m_node; } - inline deque_iterator(val_alloc_ptr x, index_pointer y, difference_type ) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(x), m_node(y) - {} - - inline deque_iterator(val_alloc_ptr x, index_pointer y, size_type ) BOOST_NOEXCEPT_OR_NOTHROW + inline deque_iterator(val_alloc_ptr x, index_pointer y) BOOST_NOEXCEPT_OR_NOTHROW : m_cur(x), m_node(y) {} @@ -597,10 +173,6 @@ class deque_iterator : m_cur(x.get_cur()), m_node(x.get_node()) {} - inline deque_iterator(Pointer cur, index_pointer node) BOOST_NOEXCEPT_OR_NOTHROW - : m_cur(cur), m_node(node) - {} - inline deque_iterator& operator=(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW { m_cur = x.get_cur(); m_node = x.get_node(); return *this; } @@ -617,21 +189,20 @@ class deque_iterator BOOST_CONTAINER_ATTRIBUTE_NODISCARD difference_type operator-(const deque_iterator& x) const BOOST_NOEXCEPT_OR_NOTHROW { - if(!this->m_cur && !x.m_cur){ + if(this->m_cur == x.m_cur){ //Includes when both are null return 0; } - const difference_type block_size = get_block_ssize(); - BOOST_ASSERT(block_size); - return block_size * (this->m_node - x.m_node - 1) + - (this->m_cur - this->get_first()) + (x.get_last() - x.m_cur); + BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); + return block_size * (this->m_node - x.m_node) + + (this->m_cur - this->get_first()) - (x.m_cur - x.get_first()); } deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_cur); ++this->m_cur; - if (this->m_cur == (this->get_last())) { - + const Pointer last = *m_node + get_block_ssize(); + if (BOOST_UNLIKELY(this->m_cur == last)) { ++this->m_node; this->m_cur = *this->m_node; } @@ -645,17 +216,30 @@ class deque_iterator return tmp; } +//Some GCC versions issue bogus warnings about array bounds here +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +# pragma GCC diagnostic ignored "-Warray-bounds" +#endif + deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_cur); - if (this->m_cur == this->get_first()) { + const Pointer first = *m_node; + if (BOOST_UNLIKELY(this->m_cur == first)) { --this->m_node; - this->m_cur = this->get_last(); + this->m_cur = *this->m_node; + this->m_cur += get_block_ssize() - 1; + } + else { + --this->m_cur; } - --this->m_cur; return *this; } +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif + inline deque_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW { deque_iterator tmp(*this); @@ -665,20 +249,20 @@ class deque_iterator deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW { - if (!n) - return *this; - BOOST_ASSERT(!!m_cur); - const difference_type offset = n + (this->m_cur - this->get_first()); - const difference_type block_size = get_block_ssize(); - BOOST_ASSERT(block_size); - if (offset >= 0 && offset < block_size) - this->m_cur += difference_type(n); - else { - const difference_type node_offset = - offset > 0 ? (offset / block_size) - : (-difference_type((-offset - 1) / block_size) - 1); - this->m_node += node_offset; - this->m_cur = this->get_first() + (offset - node_offset * block_size); + if (n){ + BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); + + const difference_type offset = n + (this->m_cur - *this->m_node); + + if (offset >= 0 && offset < block_size) + this->m_cur += difference_type(n); + else { + const difference_type node_offset = + offset > 0 ? (offset / block_size) + : (-difference_type((-offset - 1) / block_size) - 1); + this->m_node += node_offset; + this->m_cur = *this->m_node + (offset - node_offset * block_size); + } } return *this; } @@ -699,8 +283,10 @@ class deque_iterator reference operator[](difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!!m_cur); - const difference_type offset = n + (this->m_cur - this->get_first()); - const difference_type block_size = get_block_ssize(); + BOOST_CONSTEXPR_OR_CONST difference_type block_size = get_block_ssize(); + + const difference_type offset = n + (this->m_cur - *this->m_node); + if (offset >= 0 && offset < block_size) return this->m_cur[difference_type(n)]; else { @@ -740,20 +326,10 @@ class deque_iterator friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW { return x += n; } - inline void priv_set_node(index_pointer new_node, size_type ) BOOST_NOEXCEPT_OR_NOTHROW - { return this->priv_set_node(new_node, difference_type()); } - - inline void priv_set_node(index_pointer new_node, difference_type) BOOST_NOEXCEPT_OR_NOTHROW - { - this->m_node = new_node; - } + inline void priv_set_node(index_pointer new_node) BOOST_NOEXCEPT_OR_NOTHROW + { this->m_node = new_node; } }; -#else - -#error "Invalid BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL" - -#endif } //namespace dtl { template @@ -792,47 +368,43 @@ class deque_base typedef typename ptr_alloc_traits_type::const_pointer ptr_alloc_cptr; typedef typename ptr_alloc_traits_type::reference ptr_alloc_ref; typedef typename ptr_alloc_traits_type::const_reference ptr_alloc_cref; - typedef Allocator allocator_type; + typedef Allocator allocator_type; typedef allocator_type stored_allocator_type; typedef val_alloc_size size_type; typedef val_alloc_diff difference_type; + typedef val_alloc_size stored_size_type; private: - typedef typename get_deque_opt::type options_type; + typedef typename get_deque_opt::type options_type; protected: - #if BOOST_CONTAINER_DEQUE_LIGHTER_ITERATOR_LEVEL == 0 - typedef dtl::deque_iterator iterator; - typedef dtl::deque_iterator const_iterator; - #else typedef dtl::deque_iterator iterator; typedef dtl::deque_iterator const_iterator; - #endif BOOST_CONSTEXPR inline static val_alloc_diff get_block_ssize() BOOST_NOEXCEPT_OR_NOTHROW { return val_alloc_diff((get_block_size())); } BOOST_CONSTEXPR inline static size_type get_block_size() BOOST_NOEXCEPT_OR_NOTHROW - { return deque_block_size::value; } + { return deque_block_traits::value; } typedef deque_value_traits traits_t; typedef ptr_alloc_t map_allocator_type; - inline val_alloc_ptr priv_allocate_node() + inline val_alloc_ptr prot_allocate_node() { return this->alloc().allocate(get_block_size()); } - inline void priv_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW + inline void prot_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW { this->alloc().deallocate(p, get_block_size()); } - inline ptr_alloc_ptr priv_allocate_map(size_type n) + inline ptr_alloc_ptr prot_allocate_map(size_type n) { return this->ptr_alloc().allocate(n); } - inline void priv_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { this->ptr_alloc().deallocate(p, n); } + inline void prot_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { this->ptr_alloc().deallocate(p, n); } inline deque_base(size_type num_elements, const allocator_type& a) : members_(a) - { this->priv_initialize_map(num_elements); } + { this->prot_initialize_map_and_nodes(num_elements); } inline explicit deque_base(const allocator_type& a) : members_(a) @@ -850,8 +422,8 @@ class deque_base ~deque_base() { if (this->members_.m_map) { - this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->prot_destroy_nodes(this->prot_start_node(), this->prot_finish_node() + 1); + this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); } } @@ -862,104 +434,109 @@ class deque_base void swap_members(deque_base &x) BOOST_NOEXCEPT_OR_NOTHROW { - ::boost::adl_move_swap(this->members_.m_start, x.members_.m_start); - ::boost::adl_move_swap(this->members_.m_finish, x.members_.m_finish); - ::boost::adl_move_swap(this->members_.m_map, x.members_.m_map); - ::boost::adl_move_swap(this->members_.m_map_size, x.members_.m_map_size); + this->members_.swap(x.members_); } - void priv_initialize_map(size_type num_elements) + void prot_initialize_map_and_nodes(size_type num_elements) { -// if(num_elements){ - size_type num_nodes = num_elements / get_block_size() + 1; + //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; - 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); + //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); + this->members_.m_map = this->prot_allocate_map(this->members_.m_map_size); - ptr_alloc_ptr nstart = this->members_.m_map + difference_type(this->members_.m_map_size - num_nodes) / 2; - ptr_alloc_ptr nfinish = nstart + difference_type(num_nodes); + ptr_alloc_ptr nstart = this->members_.m_map + difference_type(this->members_.m_map_size - num_nodes) / 2; + ptr_alloc_ptr nfinish = nstart + difference_type(num_nodes); - BOOST_CONTAINER_TRY { - this->priv_create_nodes(nstart, nfinish); - } - BOOST_CONTAINER_CATCH(...){ - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = 0; - this->members_.m_map_size = 0; - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END + BOOST_CONTAINER_TRY { + this->prot_create_nodes(nstart, nfinish); + } + BOOST_CONTAINER_CATCH(...){ + this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = ptr_alloc_ptr(); + this->members_.m_map_size = 0; + BOOST_CONTAINER_RETHROW + } + BOOST_CONTAINER_CATCH_END - 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.get_first(); - this->members_.m_finish.m_cur = this->members_.m_finish.get_first() + difference_type(num_elements % get_block_size()); -// } + this->members_.m_start_off = this->prot_non_null_node_to_off(nstart); + this->members_.m_finish_off = this->members_.m_start_off + num_elements; } - void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + void prot_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) { ptr_alloc_ptr cur = nstart; BOOST_CONTAINER_TRY { for (; cur < nfinish; ++cur) - *cur = this->priv_allocate_node(); + *cur = this->prot_allocate_node(); } BOOST_CONTAINER_CATCH(...){ - this->priv_destroy_nodes(nstart, cur); + this->prot_destroy_nodes(nstart, cur); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END } - void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) BOOST_NOEXCEPT_OR_NOTHROW + void prot_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) BOOST_NOEXCEPT_OR_NOTHROW { for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) - this->priv_deallocate_node(*n); + this->prot_deallocate_node(*n); } - void priv_clear_map() BOOST_NOEXCEPT_OR_NOTHROW + void prot_clear_map() BOOST_NOEXCEPT_OR_NOTHROW { if (this->members_.m_map) { - this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); - this->members_.m_map = 0; - this->members_.m_map_size = 0; - this->members_.m_start = iterator(); - this->members_.m_finish = this->members_.m_start; + this->prot_destroy_nodes(this->prot_start_node(), this->prot_finish_node() + 1); + this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = ptr_alloc_ptr(); + this->members_.m_map_size = 0u; + this->members_.m_start_off = 0u; + this->members_.m_finish_off = 0u; } } - enum { InitialMapSize = 8 }; + enum { InitialMapSize = 4 }; protected: struct members_holder : public ptr_alloc_t , public allocator_type { + friend class deque_base; members_holder() : map_allocator_type(), allocator_type() - , m_map(0), m_map_size(0) - , m_start(), m_finish(m_start) + , m_map(), m_map_size() + , m_start_off(), m_finish_off() {} explicit members_holder(const allocator_type &a) : map_allocator_type(a), allocator_type(a) - , m_map(0), m_map_size(0) - , m_start(), m_finish(m_start) + , m_map(), m_map_size() + , m_start_off(), m_finish_off() {} template members_holder(BOOST_FWD_REF(PtrAllocConvertible) pa, BOOST_FWD_REF(ValAllocConvertible) va) : map_allocator_type(boost::forward(pa)) , allocator_type (boost::forward(va)) - , m_map(0), m_map_size(0) - , m_start(), m_finish(m_start) + , m_map(), m_map_size() + , m_start_off(), m_finish_off() {} - ptr_alloc_ptr m_map; - val_alloc_size m_map_size; - iterator m_start; - iterator m_finish; + void swap(members_holder &x) BOOST_NOEXCEPT_OR_NOTHROW + { + ::boost::adl_move_swap(this->m_map, x.m_map); + ::boost::adl_move_swap(this->m_map_size, x.m_map_size); + ::boost::adl_move_swap(this->m_start_off, x.m_start_off); + ::boost::adl_move_swap(this->m_finish_off, x.m_finish_off); + } + + ptr_alloc_ptr m_map; + stored_size_type m_map_size; + private: + stored_size_type m_start_off; + stored_size_type m_finish_off; } members_; inline ptr_alloc_t &ptr_alloc() BOOST_NOEXCEPT_OR_NOTHROW @@ -973,6 +550,231 @@ class deque_base inline const allocator_type &alloc() const BOOST_NOEXCEPT_OR_NOTHROW { return members_; } + + 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::value; + return *idx + (block_size - 1u); + } + + BOOST_CONTAINER_FORCEINLINE std::size_t prot_front_capacity() const + { + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + return this->members_.m_start_off % block_size; + } + + BOOST_CONTAINER_FORCEINLINE std::size_t 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 + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + return this->members_.m_map ? (block_size - 1u) - (this->members_.m_finish_off % block_size) : 0u; + } + + ////////////////////////// + // it_to_off / off_to_it + ////////////////////////// + + BOOST_CONTAINER_FORCEINLINE stored_size_type prot_it_to_off(const_iterator it) const + { + const ptr_alloc_ptr n = it.get_node(); + BOOST_ASSERT(!this->members_.m_map == !n); //Both should be null or both non-null + if (n) { + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + return static_cast(std::size_t(n - this->members_.m_map)*block_size + std::size_t(it.get_cur() - *n)); + } + else{ + return 0; + } + } + + 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::value; + const ptr_alloc_ptr node = this->members_.m_map + off/block_size; + return iterator(node ? *node + (off%block_size) : val_alloc_ptr(), node); + } + + stored_size_type prot_it_to_start_off(const_iterator it) const + { + const size_type off = this->prot_it_to_off(it); + BOOST_ASSERT(off >= this->members_.m_start_off); + return off - this->members_.m_start_off; + } + + ///////////// + // xxx_to_node + ///////////// + + 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::value; + return this->members_.m_map + off/block_size; + } + + BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_start_node() const + { + return this->prot_off_to_node(this->members_.m_start_off); + } + + BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr prot_finish_node() const + { + return this->prot_off_to_node(this->members_.m_finish_off); + } + + // + // xxx_to_cur_unchecked versions, faster but need non-default constructed deque + // + BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_off_to_cur_unchecked(std::size_t off) const + { + BOOST_ASSERT(!!this->members_.m_map); + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + const ptr_alloc_ptr node = this->members_.m_map + off/block_size; + return *node + off%block_size; + } + + BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_start_cur_unchecked() const + { + return this->prot_off_to_cur_unchecked(this->members_.m_start_off); + } + + BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_finish_cur_unchecked() const + { + return this->prot_off_to_cur_unchecked(this->members_.m_finish_off); + } + + BOOST_CONTAINER_FORCEINLINE val_alloc_ptr prot_last_cur_unchecked() const + { + BOOST_ASSERT(members_.m_start_off != members_.m_finish_off); + return this->prot_off_to_cur_unchecked(this->members_.m_finish_off-1u); + } + + // + // functions returning iterators to different positions + // + BOOST_CONTAINER_FORCEINLINE const_iterator prot_start() const + { return this->prot_off_to_it(members_.m_start_off); } + + BOOST_CONTAINER_FORCEINLINE iterator prot_start() + { return this->prot_off_to_it(members_.m_start_off); } + + BOOST_CONTAINER_FORCEINLINE const_iterator prot_finish() const + { return this->prot_off_to_it(members_.m_finish_off); } + + BOOST_CONTAINER_FORCEINLINE iterator prot_finish() + { return this->prot_off_to_it(members_.m_finish_off); } + + BOOST_CONTAINER_FORCEINLINE const_iterator prot_nth(size_type n) const + { return this->prot_off_to_it(members_.m_start_off+n); } + + BOOST_CONTAINER_FORCEINLINE iterator prot_nth(size_type n) + { return this->prot_off_to_it(members_.m_start_off+n); } + + BOOST_CONTAINER_FORCEINLINE iterator prot_back_it() + { + BOOST_ASSERT(members_.m_start_off != members_.m_finish_off); + return this->prot_off_to_it(members_.m_finish_off-1u); + } + + // + // size/empty + // + BOOST_CONTAINER_FORCEINLINE std::size_t prot_size() const + { return size_type(this->members_.m_finish_off - this->members_.m_start_off); } + + BOOST_CONTAINER_FORCEINLINE bool prot_empty() const + { return this->members_.m_finish_off == this->members_.m_start_off; } + + // + // Functions to move start/finish indexes + // + BOOST_CONTAINER_FORCEINLINE void prot_inc_start() + { ++this->members_.m_start_off; } + + BOOST_CONTAINER_FORCEINLINE void prot_dec_start() + { --this->members_.m_start_off; } + + BOOST_CONTAINER_FORCEINLINE void prot_inc_finish() + { ++this->members_.m_finish_off; } + + BOOST_CONTAINER_FORCEINLINE void prot_dec_finish() + { --this->members_.m_finish_off; } + + BOOST_CONTAINER_FORCEINLINE void prot_dec_finish(std::size_t n) + { this->members_.m_finish_off = static_cast(this->members_.m_finish_off - n); } + + BOOST_CONTAINER_FORCEINLINE void prot_inc_finish(std::size_t n) + { this->members_.m_finish_off = static_cast(this->members_.m_finish_off + n); } + + BOOST_CONTAINER_FORCEINLINE void prot_dec_start(std::size_t n) + { this->members_.m_start_off = static_cast(this->members_.m_start_off - n); } + + BOOST_CONTAINER_FORCEINLINE void prot_inc_start(std::size_t n) + { this->members_.m_start_off = static_cast(this->members_.m_start_off + n); } + + // + // Functions to obtain indexes from nodes + // + 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::value; + return static_cast(std::size_t(n - this->members_.m_map)*block_size); + } + + inline void prot_start_set_node(ptr_alloc_ptr new_start) + { + //iG: to-do: optimizable avoiding some division/remainder + std::size_t new_block_off = prot_non_null_node_to_off(new_start); + this->members_.m_start_off = static_cast(new_block_off + (this->members_.m_start_off % get_block_size())); + } + + inline void prot_finish_set_node(ptr_alloc_ptr new_finish) + { + //iG: to-do: optimizable avoiding some division/remainder + std::size_t new_block_off = prot_non_null_node_to_off(new_finish); + this->members_.m_finish_off = static_cast(new_block_off + (this->members_.m_finish_off % get_block_size())); + } + + inline void prot_reset_finish_to_start() + { this->members_.m_finish_off = this->members_.m_start_off; } + + inline void prot_reset_start_to_finish() + { this->members_.m_start_off = this->members_.m_finish_off; } + + inline val_alloc_val *prot_push_back_simple_pos() const + { + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + 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 std::size_t off = node ? this->members_.m_finish_off : last_in_block; + const std::size_t rem = off % block_size; + if(BOOST_LIKELY(rem != last_in_block)){ + return boost::movelib::to_raw_pointer(node[off/block_size]) + rem; + } + return 0; + } + + inline val_alloc_val *prot_push_front_simple_pos() const + { + BOOST_CONSTEXPR_OR_CONST std::size_t block_size = deque_block_traits::value; + //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 rem = off % block_size; + if(BOOST_LIKELY(rem != 0u)){ + return boost::movelib::to_raw_pointer(this->members_.m_map[off / block_size]) + (rem-1u); + } + return 0; + } + + BOOST_CONTAINER_FORCEINLINE bool prot_pop_back_simple_available() const + { + return (this->members_.m_finish_off % get_block_size()) != 0u; + } + + BOOST_CONTAINER_FORCEINLINE bool prot_pop_front_simple_available() const + { + return (this->members_.m_start_off % get_block_size()) != (get_block_size() - 1u); + } + }; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1076,7 +878,7 @@ class deque : protected deque_base::type, : Base(n, allocator_type()) { dtl::insert_value_initialized_n_proxy proxy; - proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); //deque_base will deallocate in case of exception... } @@ -1093,7 +895,7 @@ class deque : protected deque_base::type, : Base(n, allocator_type()) { dtl::insert_default_initialized_n_proxy proxy; - proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); //deque_base will deallocate in case of exception... } @@ -1108,7 +910,7 @@ class deque : protected deque_base::type, : Base(n, a) { dtl::insert_value_initialized_n_proxy proxy; - proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); //deque_base will deallocate in case of exception... } @@ -1125,7 +927,7 @@ class deque : protected deque_base::type, : Base(n, a) { dtl::insert_default_initialized_n_proxy proxy; - proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); //deque_base will deallocate in case of exception... } @@ -1138,7 +940,7 @@ class deque : protected deque_base::type, //! Complexity: Linear to n. inline deque(size_type n, const value_type& value) : Base(n, allocator_type()) - { this->priv_fill_initialize(value); } + { this->priv_fill_initialize(n, value); } //! Effects: Constructs a deque that will use a copy of allocator a //! and inserts n copies of value. @@ -1149,7 +951,7 @@ class deque : protected deque_base::type, //! Complexity: Linear to n. inline deque(size_type n, const value_type& value, const allocator_type& a) : Base(n, a) - { this->priv_fill_initialize(value); } + { this->priv_fill_initialize(n, value); } //! Effects: Constructs a deque that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the deque. @@ -1213,9 +1015,8 @@ class deque : protected deque_base::type, : Base(allocator_traits_type::select_on_container_copy_construction(x.alloc())) { if(x.size()){ - this->priv_initialize_map(x.size()); - boost::container::uninitialized_copy_alloc - (this->alloc(), x.begin(), x.end(), this->members_.m_start); + this->prot_initialize_map_and_nodes(x.size()); + this->priv_segmented_uninitialized_copy_alloc_n(x.begin(), x.size(), this->begin()); } } @@ -1240,9 +1041,8 @@ class deque : protected deque_base::type, : Base(a) { if(x.size()){ - this->priv_initialize_map(x.size()); - boost::container::uninitialized_copy_alloc - (this->alloc(), x.begin(), x.end(), this->members_.m_start); + this->prot_initialize_map_and_nodes(x.size()); + this->priv_segmented_uninitialized_copy_alloc_n(x.begin(), x.size(), this->begin()); } } @@ -1261,10 +1061,8 @@ class deque : protected deque_base::type, } else{ if(x.size()){ - this->priv_initialize_map(x.size()); - boost::container::uninitialized_copy_alloc - ( this->alloc(), boost::make_move_iterator(x.begin()) - , boost::make_move_iterator(x.end()), this->members_.m_start); + this->prot_initialize_map_and_nodes(x.size()); + this->priv_segmented_uninitialized_move_alloc_n(x.begin(), x.size(), this->begin()); } } } @@ -1277,7 +1075,7 @@ class deque : protected deque_base::type, //! Complexity: Linear to the number of elements. inline ~deque() BOOST_NOEXCEPT_OR_NOTHROW { - this->priv_destroy_range(this->members_.m_start, this->members_.m_finish); + this->prot_destroy_range(this->prot_start(), this->prot_finish()); } //! Effects: Makes *this contain the same elements as x. @@ -1353,7 +1151,8 @@ class deque : protected deque_base::type, //! Complexity: Linear to n. inline void assign(size_type n, const T& val) { - this->assign(c_it(val, n), c_it()); + dtl::insert_n_copies_proxy proxy(val); + this->priv_assign(n, proxy); } //! Effects: Assigns the the range [first, last) to *this. @@ -1395,16 +1194,9 @@ class deque : protected deque_base::type, >::type * = 0 ) { - const size_type len = boost::container::iterator_udistance(first, last); - if (len > size()) { - FwdIt mid = first; - boost::container::iterator_uadvance(mid, this->size()); - boost::container::copy(first, mid, begin()); - this->insert(this->cend(), mid, last); - } - else{ - this->erase(boost::container::copy(first, last, this->begin()), cend()); - } + const size_type n = boost::container::iterator_udistance(first, last); + dtl::insert_range_proxy proxy(first); + this->priv_assign(n, proxy); } #endif @@ -1463,7 +1255,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline iterator begin() BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_start; } + { return this->prot_start(); } //! Effects: Returns a const_iterator to the first element contained in the deque. //! @@ -1472,7 +1264,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_start; } + { return this->prot_start(); } //! Effects: Returns an iterator to the end of the deque. //! @@ -1481,7 +1273,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline iterator end() BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_finish; } + { return this->prot_finish(); } //! Effects: Returns a const_iterator to the end of the deque. //! @@ -1490,7 +1282,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_finish; } + { return this->prot_finish(); } //! Effects: Returns a reverse_iterator pointing to the beginning //! of the reversed deque. @@ -1500,7 +1292,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW - { return reverse_iterator(this->members_.m_finish); } + { return reverse_iterator(this->prot_finish()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed deque. @@ -1510,7 +1302,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->members_.m_finish); } + { return const_reverse_iterator(this->prot_finish()); } //! Effects: Returns a reverse_iterator pointing to the end //! of the reversed deque. @@ -1520,7 +1312,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW - { return reverse_iterator(this->members_.m_start); } + { return reverse_iterator(this->prot_start()); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed deque. @@ -1530,7 +1322,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->members_.m_start); } + { return const_reverse_iterator(this->prot_start()); } //! Effects: Returns a const_iterator to the first element contained in the deque. //! @@ -1539,7 +1331,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_start; } + { return this->prot_start(); } //! Effects: Returns a const_iterator to the end of the deque. //! @@ -1548,7 +1340,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_finish; } + { return this->prot_finish(); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed deque. @@ -1558,7 +1350,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->members_.m_finish); } + { return const_reverse_iterator(this->prot_finish()); } //! Effects: Returns a const_reverse_iterator pointing to the end //! of the reversed deque. @@ -1568,7 +1360,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW - { return const_reverse_iterator(this->members_.m_start); } + { return const_reverse_iterator(this->prot_start()); } ////////////////////////////////////////////// // @@ -1583,7 +1375,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline bool empty() const BOOST_NOEXCEPT_OR_NOTHROW - { return this->members_.m_finish == this->members_.m_start; } + { return this->prot_empty(); } //! Effects: Returns the number of the elements contained in the deque. //! @@ -1592,7 +1384,7 @@ class deque : protected deque_base::type, //! Complexity: Constant. BOOST_CONTAINER_ATTRIBUTE_NODISCARD inline size_type size() const BOOST_NOEXCEPT_OR_NOTHROW - { return size_type(this->members_.m_finish - this->members_.m_start); } + { return this->prot_size(); } //! Effects: Returns the largest possible size of the deque. //! @@ -1611,13 +1403,13 @@ class deque : protected deque_base::type, //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - const size_type len = size(); + const size_type len = this->size(); if (new_size < len) this->priv_erase_last_n(len - new_size); else{ const size_type n = new_size - this->size(); dtl::insert_value_initialized_n_proxy proxy; - priv_insert_back_aux_impl(n, proxy); + this->priv_insert_back_aux_impl(n, proxy); } } @@ -1637,7 +1429,7 @@ class deque : protected deque_base::type, else{ const size_type n = new_size - this->size(); dtl::insert_default_initialized_n_proxy proxy; - priv_insert_back_aux_impl(n, proxy); + this->priv_insert_back_aux_impl(n, proxy); } } @@ -1649,11 +1441,14 @@ class deque : protected deque_base::type, //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const value_type& x) { - const size_type len = size(); - if (new_size < len) - this->erase(this->members_.m_start + difference_type(new_size), this->members_.m_finish); - else - this->insert(this->members_.m_finish, new_size - len, x); + const size_type sz = this->size(); + if (new_size < sz) + this->priv_erase_last_n(sz - new_size); + else { + const size_type n = new_size - sz; + dtl::insert_n_copies_proxy proxy(x); + this->priv_insert_back_aux_impl(n, proxy); + } } //! Effects: Tries to deallocate the excess of memory created @@ -1669,7 +1464,7 @@ class deque : protected deque_base::type, //so there is nothing to do except for //empty deque if(this->empty()){ - this->priv_clear_map(); + this->prot_clear_map(); } } @@ -1691,7 +1486,7 @@ class deque : protected deque_base::type, reference front() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - return *this->members_.m_start; + return *this->prot_start_cur_unchecked(); } //! Requires: !empty() @@ -1706,7 +1501,7 @@ class deque : protected deque_base::type, const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - return *this->members_.m_start; + return *this->prot_start_cur_unchecked(); } //! Requires: !empty() @@ -1721,7 +1516,7 @@ class deque : protected deque_base::type, reference back() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - return *(end()-1); + return *this->prot_last_cur_unchecked(); } //! Requires: !empty() @@ -1736,7 +1531,7 @@ class deque : protected deque_base::type, const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - return *(cend()-1); + return *this->prot_last_cur_unchecked(); } //! Requires: size() > n. @@ -1751,7 +1546,7 @@ class deque : protected deque_base::type, reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->size() > n); - return this->members_.m_start[difference_type(n)]; + return *this->prot_nth(n); } //! Requires: size() > n. @@ -1766,7 +1561,7 @@ class deque : protected deque_base::type, const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->size() > n); - return this->members_.m_start[difference_type(n)]; + return *this->prot_nth(n); } //! Requires: size() >= n. @@ -1784,7 +1579,7 @@ class deque : protected deque_base::type, iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->size() >= n); - return iterator(this->begin()+difference_type(n)); + return this->prot_nth(n); } //! Requires: size() >= n. @@ -1802,7 +1597,7 @@ class deque : protected deque_base::type, const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(this->size() >= n); - return const_iterator(this->cbegin()+difference_type(n)); + return this->prot_nth(n); } //! Requires: begin() <= p <= end(). @@ -1888,14 +1683,14 @@ class deque : protected deque_base::type, template reference emplace_front(BOOST_FWD_REF(Args)... args) { - if(this->priv_push_front_simple_available()){ - reference r = *this->priv_push_front_simple_pos(); + value_type *pr = this->prot_push_front_simple_pos(); + if(BOOST_LIKELY(pr != 0)){ allocator_traits_type::construct ( this->alloc() - , this->priv_push_front_simple_pos() + , pr , boost::forward(args)...); - this->priv_push_front_simple_commit(); - return r; + this->prot_dec_start(); + return *pr; } else{ typedef dtl::insert_nonmovable_emplace_proxy type; @@ -1914,14 +1709,12 @@ class deque : protected deque_base::type, template reference emplace_back(BOOST_FWD_REF(Args)... args) { - if(this->priv_push_back_simple_available()){ - reference r = *this->priv_push_back_simple_pos(); + value_type *pr = this->prot_push_back_simple_pos(); + if(BOOST_LIKELY(pr != 0)){ allocator_traits_type::construct - ( this->alloc() - , this->priv_push_back_simple_pos() - , boost::forward(args)...); - this->priv_push_back_simple_commit(); - return r; + ( this->alloc(), pr, boost::forward(args)...); + this->prot_inc_finish(); + return *pr; } else{ typedef dtl::insert_nonmovable_emplace_proxy type; @@ -1941,18 +1734,20 @@ class deque : protected deque_base::type, template iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args) { - BOOST_ASSERT(this->priv_in_range_or_end(p)); - if(p == this->cbegin()){ + const size_type elemsbefore = this->prot_it_to_start_off(p); + const size_type length = this->prot_size(); + + if (!elemsbefore) { this->emplace_front(boost::forward(args)...); return this->begin(); } - else if(p == this->cend()){ + else if (elemsbefore == length) { this->emplace_back(boost::forward(args)...); - return (this->end()-1); + return this->prot_back_it(); } - else{ + else { typedef dtl::insert_emplace_proxy type; - return this->priv_insert_aux_impl(p, 1, type(boost::forward(args)...)); + return this->priv_insert_middle_aux_impl(elemsbefore, 1, type(boost::forward(args)...)); } } @@ -1962,12 +1757,12 @@ class deque : protected deque_base::type, BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ reference emplace_front(BOOST_MOVE_UREF##N)\ {\ - if(priv_push_front_simple_available()){\ - reference r = *this->priv_push_front_simple_pos();\ + value_type *pr = this->prot_push_front_simple_pos();\ + if(BOOST_LIKELY(pr != 0)){\ allocator_traits_type::construct\ - ( this->alloc(), this->priv_push_front_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - priv_push_front_simple_commit();\ - return r;\ + ( this->alloc(), pr BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + this->prot_dec_start();\ + return *pr;\ }\ else{\ typedef dtl::insert_nonmovable_emplace_proxy##N\ @@ -1979,12 +1774,12 @@ class deque : protected deque_base::type, BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ reference emplace_back(BOOST_MOVE_UREF##N)\ {\ - if(priv_push_back_simple_available()){\ - reference r = *this->priv_push_back_simple_pos();\ + value_type *pr = this->prot_push_back_simple_pos();\ + if(BOOST_LIKELY(pr != 0)){\ allocator_traits_type::construct\ - ( this->alloc(), this->priv_push_back_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - priv_push_back_simple_commit();\ - return r;\ + ( this->alloc(), pr BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + this->prot_inc_finish();\ + return *pr;\ }\ else{\ typedef dtl::insert_nonmovable_emplace_proxy##N\ @@ -1996,21 +1791,23 @@ class deque : protected deque_base::type, BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ - BOOST_ASSERT(this->priv_in_range_or_end(p));\ - if(p == this->cbegin()){\ + const size_type elemsbefore = this->prot_it_to_start_off(p);\ + const size_type length = this->prot_size();\ + \ + if (!elemsbefore) {\ this->emplace_front(BOOST_MOVE_FWD##N);\ return this->begin();\ }\ - else if(p == cend()){\ + else if (elemsbefore == length) {\ this->emplace_back(BOOST_MOVE_FWD##N);\ - return (--this->end());\ + return this->prot_back_it();\ }\ - else{\ + else {\ typedef dtl::insert_emplace_proxy_arg##N\ type;\ - return this->priv_insert_aux_impl(p, 1, type(BOOST_MOVE_FWD##N));\ + return this->priv_insert_middle_aux_impl(elemsbefore, 1, type(BOOST_MOVE_FWD##N));\ }\ - } + }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEQUE_EMPLACE_CODE) #undef BOOST_CONTAINER_DEQUE_EMPLACE_CODE @@ -2097,8 +1894,9 @@ class deque : protected deque_base::type, //! Complexity: Linear to n. inline iterator insert(const_iterator pos, size_type n, const value_type& x) { - //Range check of p is done by insert() - return this->insert(pos, c_it(x, n), c_it()); + BOOST_ASSERT(this->priv_in_range_or_end(pos)); + dtl::insert_n_copies_proxy proxy(x); + return this->priv_insert_aux_impl(pos, n, proxy); } //! Requires: pos must be a valid iterator of *this. @@ -2165,7 +1963,7 @@ class deque : protected deque_base::type, { BOOST_ASSERT(this->priv_in_range_or_end(p)); dtl::insert_range_proxy proxy(first); - return priv_insert_aux_impl(p, boost::container::iterator_udistance(first, last), proxy); + return this->priv_insert_aux_impl(p, boost::container::iterator_udistance(first, last), proxy); } #endif @@ -2177,12 +1975,12 @@ class deque : protected deque_base::type, void pop_front() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - if (this->members_.m_start.m_cur != this->members_.m_start.get_last() - 1) { + if (BOOST_LIKELY(this->prot_pop_front_simple_available())) { allocator_traits_type::destroy ( this->alloc() - , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) + , boost::movelib::to_raw_pointer(this->prot_start_cur_unchecked()) ); - ++this->members_.m_start.m_cur; + this->prot_inc_start(); } else this->priv_pop_front_aux(); @@ -2196,11 +1994,11 @@ class deque : protected deque_base::type, void pop_back() BOOST_NOEXCEPT_OR_NOTHROW { BOOST_ASSERT(!this->empty()); - if (this->members_.m_finish.m_cur != this->members_.m_finish.get_first()) { - --this->members_.m_finish.m_cur; + if (BOOST_LIKELY(this->prot_pop_back_simple_available())) { + this->prot_dec_finish(); allocator_traits_type::destroy ( this->alloc() - , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) + , boost::movelib::to_raw_pointer(this->prot_finish_cur_unchecked()) ); } else @@ -2220,16 +2018,18 @@ class deque : protected deque_base::type, BOOST_ASSERT(this->priv_in_range(pos)); iterator next = pos.unconst(); ++next; - size_type index = size_type(pos - this->members_.m_start); + const size_type index = this->prot_it_to_start_off(pos); + if (index < (this->size()/2)) { - boost::container::move_backward(this->begin(), pos.unconst(), next); + this->priv_segmented_move_backward_n(pos.unconst(), index, next); pop_front(); + return next; } else { - boost::container::move(next, this->end(), pos.unconst()); + this->priv_segmented_move_n(next, this->size() - index - 1u, pos.unconst()); pop_back(); + return pos.unconst(); } - return this->members_.m_start + difference_type(index); } //! Effects: Erases the elements pointed by [first, last). @@ -2244,28 +2044,28 @@ class deque : protected deque_base::type, { BOOST_ASSERT(first == last || (first < last && this->priv_in_range(first) && this->priv_in_range_or_end(last))); - if (first == this->members_.m_start && last == this->members_.m_finish) { + const size_type n = static_cast(last - first); + if (n == this->prot_size()) { this->clear(); - return this->members_.m_finish; + return this->end(); } else { - const size_type n = static_cast(last - first); - const size_type elems_before = static_cast(first - this->members_.m_start); + const size_type elems_before = this->prot_it_to_start_off(first); if (elems_before < (this->size() - n) - elems_before) { - boost::container::move_backward(begin(), first.unconst(), last.unconst()); - iterator new_start = this->members_.m_start + difference_type(n); - this->priv_destroy_range(this->members_.m_start, new_start); - this->priv_destroy_nodes(this->members_.m_start.m_node, new_start.m_node); - this->members_.m_start = new_start; + const iterator old_start = this->begin(); + 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_nodes(old_start.get_node(), new_start.m_node); + this->prot_inc_start(n); } else { - boost::container::move(last.unconst(), end(), first.unconst()); - iterator new_finish = this->members_.m_finish - difference_type(n); - this->priv_destroy_range(new_finish, this->members_.m_finish); - this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); - this->members_.m_finish = new_finish; + const iterator old_finish = this->end(); + iterator new_finish = this->priv_segmented_move_n(last.unconst(), this->prot_size() - n - elems_before, first.unconst()); + this->prot_destroy_range(new_finish, old_finish); + this->prot_destroy_nodes(new_finish.m_node + 1, old_finish.get_node() + 1); + this->prot_dec_finish(n); } - return this->members_.m_start + difference_type(elems_before); + return this->nth(elems_before); } } @@ -2291,24 +2091,25 @@ class deque : protected deque_base::type, //! Complexity: Linear to the number of elements in the deque. void clear() BOOST_NOEXCEPT_OR_NOTHROW { - if (this->members_.m_finish != this->members_.m_start) { - - 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 + get_block_ssize()); - this->priv_deallocate_node(*node); + if (!this->empty()) { + const iterator start = this->prot_start(); + const iterator finish = this->prot_finish(); + const index_pointer start_node = start.get_node(); + const index_pointer finish_node = finish.get_node(); + for (index_pointer node = start_node + 1; node < finish_node; ++node) { + this->prot_destroy_range(*node, *node + get_block_ssize()); + this->prot_deallocate_node(*node); } - if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.get_last()); - this->priv_destroy_range(this->members_.m_finish.get_first(), this->members_.m_finish.m_cur); - this->priv_deallocate_node(this->members_.m_finish.get_first()); + if (start_node != finish_node) { + this->prot_destroy_range(start.get_cur(), start.get_last()); + this->prot_destroy_range(finish.get_first(), finish.get_cur()); + this->prot_deallocate_node(finish.get_first()); } else - this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); + this->prot_destroy_range(start.get_cur(), finish.get_cur()); - this->members_.m_finish = this->members_.m_start; + this->prot_reset_finish_to_start(); } } @@ -2364,6 +2165,19 @@ class deque : protected deque_base::type, #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: + template + void priv_assign(size_type n, InsertProxy proxy) + { + const size_type sz = this->prot_size(); + this->priv_segmented_proxy_copy_n_and_update(this->begin(), sz < n ? sz : n, proxy); + if (n > sz) { + this->priv_insert_back_aux_impl(n - sz, proxy); + } + else{ + this->priv_erase_last_n(sz - n); + } + } + void priv_move_assign(BOOST_RV_REF(deque) x, dtl::bool_ /*steal_resources*/) { //Destroy objects but retain memory in case x reuses it in the future @@ -2392,19 +2206,20 @@ class deque : protected deque_base::type, { BOOST_ASSERT(this->cbegin() <= p); BOOST_ASSERT(p <= this->cend()); - return static_cast(p - this->cbegin()); + return this->prot_it_to_start_off(p); } void priv_erase_last_n(size_type n) { - if(n == this->size()) { - this->clear(); - } - else { - iterator new_finish = this->members_.m_finish - difference_type(n); - this->priv_destroy_range(new_finish, this->members_.m_finish); - this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); - this->members_.m_finish = new_finish; + const size_type sz = this->prot_size(); + BOOST_ASSERT(n <= sz); + + if(sz) { + const iterator old_finish = this->prot_finish(); + const iterator new_finish = old_finish - difference_type(n); + this->prot_destroy_range(new_finish, old_finish); + this->prot_destroy_nodes(new_finish.get_node() + 1, old_finish.get_node() + 1); + this->prot_dec_finish(n); } } @@ -2425,93 +2240,64 @@ class deque : protected deque_base::type, } template - 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) { - BOOST_ASSERT(this->priv_in_range_or_end(p)); - if (p == cbegin()){ - this->push_front(::boost::forward(x)); - return begin(); + return this->priv_insert_aux_impl(p, 1, dtl::get_insert_value_proxy(::boost::forward(x))); + } + + template + void priv_push_back(BOOST_FWD_REF(U) u) + { + value_type *pr = this->prot_push_back_simple_pos(); + if(BOOST_LIKELY(pr != 0)){ + allocator_traits_type::construct + (this->alloc(), pr, boost::forward(u)); + this->prot_inc_finish(); } - else if (p == cend()){ - this->push_back(::boost::forward(x)); - return --end(); - } - else { - return priv_insert_aux_impl - ( p, (size_type)1 - , dtl::get_insert_value_proxy(::boost::forward(x))); + else{ + this->priv_insert_back_aux_impl(1, dtl::get_insert_value_proxy(::boost::forward(u))); } } template - void priv_push_front(BOOST_FWD_REF(U) x) + BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u) { - if(this->priv_push_front_simple_available()){ + value_type *pr = this->prot_push_front_simple_pos(); + if(BOOST_LIKELY(pr != 0)){ allocator_traits_type::construct - ( this->alloc(), this->priv_push_front_simple_pos(), ::boost::forward(x)); - this->priv_push_front_simple_commit(); + (this->alloc(), pr, boost::forward(u)); + this->prot_dec_start(); } else{ - priv_insert_aux_impl - ( this->cbegin(), (size_type)1 - , dtl::get_insert_value_proxy(::boost::forward(x))); + this->priv_insert_front_aux_impl(1, dtl::get_insert_value_proxy(::boost::forward(u))); } } - template - void priv_push_back(BOOST_FWD_REF(U) x) + void prot_destroy_range(iterator start, iterator finish) { - if(this->priv_push_back_simple_available()){ - allocator_traits_type::construct - ( this->alloc(), this->priv_push_back_simple_pos(), ::boost::forward(x)); - this->priv_push_back_simple_commit(); - } - else{ - priv_insert_aux_impl - ( this->cend(), (size_type)1 - , dtl::get_insert_value_proxy(::boost::forward(x))); - } - } - - inline bool priv_push_back_simple_available() const - { - return this->members_.m_map && - (this->members_.m_finish.m_cur != (this->members_.m_finish.get_last() - 1)); - } - - inline T *priv_push_back_simple_pos() const - { - return boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur); - } - - inline void priv_push_back_simple_commit() - { - ++this->members_.m_finish.m_cur; - } - - inline bool priv_push_front_simple_available() const - { - return this->members_.m_map && - (this->members_.m_start.m_cur != this->members_.m_start.get_first()); - } - - inline T *priv_push_front_simple_pos() const - { return boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) - 1; } - - inline void priv_push_front_simple_commit() - { --this->members_.m_start.m_cur; } - - void priv_destroy_range(iterator p, iterator p2) - { - (void)p; (void)p2; + (void)start; (void)finish; BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ - for(;p != p2; ++p){ - allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); + const index_pointer start_node = start.get_node(); + const index_pointer finish_node = finish.get_node(); + + //In a sane deque both should be null or non-null + BOOST_ASSERT(!start_node == !finish_node); + if(start_node){ + for (index_pointer node = start_node + 1; node < finish_node; ++node) { + this->prot_destroy_range(*node, *node + get_block_ssize()); + } + + if (start_node != finish_node) { + this->prot_destroy_range(start.get_cur(), start.get_last()); + this->prot_destroy_range(finish.get_first(), finish.get_cur()); + } + else + this->prot_destroy_range(start.get_cur(), finish.get_cur()); } } } - void priv_destroy_range(pointer p, pointer p2) + void prot_destroy_range(pointer p, pointer p2) { (void)p; (void)p2; BOOST_IF_CONSTEXPR(!Base::traits_t::trivial_dctr){ @@ -2522,187 +2308,365 @@ class deque : protected deque_base::type, } template - iterator priv_insert_middle_aux_impl(const_iterator p, const size_type elemsbefore, const size_type length, const size_type n, InsertProxy proxy) + iterator priv_insert_middle_aux_impl(const size_type elemsbefore, const size_type n, InsertProxy proxy) { - if (!this->members_.m_map) { - this->priv_initialize_map(0); - p = this->cbegin(); - } - - iterator pos(p.unconst()); - const size_type pos_n = size_type(p - this->cbegin()); + typedef dtl::bool_::value> single_t; + BOOST_ASSERT(!single_t::value || n == 1); + const size_type length = this->prot_size(); if (elemsbefore < length / 2) { - const iterator new_start = this->priv_reserve_elements_at_front(n); - const iterator old_start = this->members_.m_start; - pos = this->members_.m_start + difference_type(elemsbefore); - if (elemsbefore >= n) { - const iterator start_n = this->members_.m_start + difference_type(n); + this->priv_reserve_elements_at_front(n); + const iterator old_start = this->prot_start(); + iterator new_start = old_start; + priv_itsub(new_start, n, single_t()); + + BOOST_ASSERT(!single_t::value || elemsbefore >= 1); + + if(single_t::value || elemsbefore >= n) { + iterator start_n = old_start; + priv_itadd(start_n, n, single_t()); BOOST_CONTAINER_TRY { - ::boost::container::uninitialized_move_alloc - (this->alloc(), this->members_.m_start, start_n, new_start); + this->priv_segmented_uninitialized_move_alloc_n(old_start, n, new_start, single_t()); } BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); + this->prot_destroy_nodes(new_start.m_node, old_start.m_node); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END - this->members_.m_start = new_start; - boost::container::move(start_n, pos, old_start); - proxy.copy_n_and_update(this->alloc(), pos - difference_type(n), n); + + this->prot_dec_start(n); + iterator p = this->priv_segmented_move_n(start_n, elemsbefore-n, old_start); + this->priv_segmented_proxy_copy_n_and_update(p, n, proxy); + return p; } else { const size_type mid_count = n - elemsbefore; - const iterator mid_start = old_start - difference_type(mid_count); + iterator mid_start = old_start - difference_type(mid_count); + BOOST_CONTAINER_TRY { - proxy.uninitialized_copy_n_and_update(this->alloc(), mid_start, mid_count); - this->members_.m_start = mid_start; - ::boost::container::uninitialized_move_alloc(this->alloc(), old_start, pos, new_start); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(mid_start, mid_count, proxy); + this->prot_dec_start(mid_count); + this->priv_segmented_uninitialized_move_alloc_n(old_start, elemsbefore, new_start); } BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); + this->prot_destroy_nodes(new_start.m_node, old_start.get_node()); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END - this->members_.m_start = new_start; - proxy.copy_n_and_update(this->alloc(), old_start, elemsbefore); + this->prot_dec_start(n - mid_count); + this->priv_segmented_proxy_copy_n_and_update(old_start, elemsbefore, proxy); + return mid_start; } } else { - const iterator new_finish = this->priv_reserve_elements_at_back(n); - const iterator old_finish = this->members_.m_finish; + this->priv_reserve_elements_at_back(n); + const iterator old_finish = this->prot_finish(); const size_type elemsafter = length - elemsbefore; - pos = old_finish - difference_type(elemsafter); - if (elemsafter >= n) { - iterator finish_n = old_finish - difference_type(n); + BOOST_ASSERT(!single_t::value || elemsafter >= 1); + + if(single_t::value || elemsafter >= n) { + iterator finish_n = old_finish; + priv_itsub(finish_n, n, single_t()); BOOST_CONTAINER_TRY { - ::boost::container::uninitialized_move_alloc(this->alloc(), finish_n, old_finish, old_finish); + this->priv_segmented_uninitialized_move_alloc_n(finish_n, n, old_finish, single_t()); } BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(this->members_.m_finish.m_node + 1, new_finish.m_node + 1); + this->prot_destroy_nodes(old_finish.get_node() + 1, (old_finish + difference_type(n)).m_node + 1); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END - this->members_.m_finish = new_finish; - boost::container::move_backward(pos, finish_n, old_finish); - proxy.copy_n_and_update(this->alloc(), pos, n); + this->prot_inc_finish(n); + const size_type move_n = elemsafter - n; + this->priv_segmented_move_backward_n(finish_n, move_n, old_finish); + finish_n -= difference_type(move_n); + this->priv_segmented_proxy_copy_n_and_update(finish_n, n, proxy); + return finish_n; } else { const size_type raw_gap = n - elemsafter; + iterator pos = old_finish - difference_type(elemsafter); + BOOST_CONTAINER_TRY{ - ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, old_finish + difference_type(raw_gap)); + this->priv_segmented_uninitialized_move_alloc_n(pos, elemsafter, old_finish + difference_type(raw_gap)); BOOST_CONTAINER_TRY{ - proxy.copy_n_and_update(this->alloc(), pos, elemsafter); - proxy.uninitialized_copy_n_and_update(this->alloc(), old_finish, raw_gap); + this->priv_segmented_proxy_copy_n_and_update(pos, elemsafter, proxy); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(old_finish, raw_gap, proxy); } BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_range(old_finish, old_finish + difference_type(elemsafter)); + this->prot_destroy_range(old_finish, old_finish + difference_type(elemsafter)); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END } BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(this->members_.m_finish.m_node + 1, new_finish.m_node + 1); + this->prot_destroy_nodes(old_finish.get_node() + 1, (old_finish + difference_type(n)).m_node + 1); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END - this->members_.m_finish = new_finish; + this->prot_inc_finish(n); + return pos; } } - return this->begin() + difference_type(pos_n); } template iterator priv_insert_aux_impl(const_iterator p, size_type n, InsertProxy proxy) { - iterator pos(p.unconst()); - const size_type elemsbefore = static_cast(pos - this->members_.m_start); - const size_type length = this->size(); + const size_type elemsbefore = this->prot_it_to_start_off(p); if (!elemsbefore) { return this->priv_insert_front_aux_impl(n, proxy); } - else if (elemsbefore == length) { + else if (elemsbefore == this->prot_size()) { return this->priv_insert_back_aux_impl(n, proxy); } else { - return this->priv_insert_middle_aux_impl(p, elemsbefore, length, n, proxy); + return this->priv_insert_middle_aux_impl(elemsbefore, n, proxy); } } + template + void priv_segmented_proxy_uninitialized_copy_n_and_update(const iterator first, size_type n, InsertProxy &proxy) + { + BOOST_IF_CONSTEXPR (dtl::is_single_value_proxy::value) { + (void)n; + proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(first.get_cur()), 1u); + } + else 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(); + + index_pointer current_node = first.get_node(); + + BOOST_CONTAINER_TRY{ + const pointer cur = first.get_cur(); + const size_type block = block_size - size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); + n -= cnt; + + while (n) { + ++current_node; + cnt = n < block_size ? n: block_size; + proxy.uninitialized_copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); + n -= cnt; + } + } + BOOST_CONTAINER_CATCH(...) { + this->prot_destroy_range(first, iterator(*current_node, current_node)); + BOOST_CONTAINER_RETHROW + } + BOOST_CONTAINER_CATCH_END + } + } + + + template + void priv_segmented_proxy_copy_n_and_update(const iterator first, size_type n, InsertProxy &proxy) + { + BOOST_IF_CONSTEXPR (dtl::is_single_value_proxy::value) { + (void)n; + proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(first.get_cur()), 1u); + } + else if (BOOST_LIKELY(n != 0)){ //We might assign an empty range in a default constructed deque + BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); + + index_pointer current_node = first.get_node(); + + const pointer cur = first.get_cur(); + const size_type block = block_size - size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt); + n -= cnt; + + while (n) { + ++current_node; + cnt = n < block_size ? n: block_size; + proxy.copy_n_and_update(this->alloc(), boost::movelib::to_raw_pointer(*current_node), cnt); + n -= cnt; + } + } + } + + template + void priv_insert_segmented_uninitialized_copy_n_and_update(const iterator first, size_type n, InsertProxy proxy) + { + BOOST_CONTAINER_TRY{ + this->priv_segmented_proxy_uninitialized_copy_n_and_update(first, n, proxy); + } + BOOST_CONTAINER_CATCH(...) { + this->prot_destroy_nodes(first.get_node() + 1, (first+difference_type(n)).get_node() + 1); + BOOST_CONTAINER_RETHROW + } + BOOST_CONTAINER_CATCH_END + } + + template + static BOOST_CONTAINER_FORCEINLINE void priv_itadd(It &it, size_type, dtl::bool_ /*single element*/) + { ++it; } + + template + static BOOST_CONTAINER_FORCEINLINE void priv_itadd(It &it, size_type n, dtl::bool_ /*!single element*/) + { it += difference_type(n); } + + template + static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type, dtl::bool_ /*single element*/) + { --it; } + + template + static BOOST_CONTAINER_FORCEINLINE void priv_itsub(It &it, size_type n, dtl::bool_ /*!single element*/) + { it -= difference_type(n); } + + void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_ /*single element*/) + { + BOOST_ASSERT(n == 1); (void)n; + allocator_traits_type::construct + ( this->alloc() + , boost::movelib::to_raw_pointer(dest.get_cur()) + , boost::move(*first)); + } + + void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest, dtl::bool_ /*!single element*/) + { + 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(); + + index_pointer current_node = first.get_node(); + + BOOST_CONTAINER_TRY{ + const pointer cur = first.get_cur(); + const size_type block = block_size - size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + dest = ::boost::container::uninitialized_move_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); + n -= cnt; + + while (n) { + ++current_node; + 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); + n -= cnt; + } + } + BOOST_CONTAINER_CATCH(...) { + this->prot_destroy_range(first, iterator(*current_node, current_node)); + BOOST_CONTAINER_RETHROW + } + BOOST_CONTAINER_CATCH_END + } + } + + BOOST_CONTAINER_FORCEINLINE void priv_segmented_uninitialized_move_alloc_n(iterator first, std::size_t n, iterator dest) + { + this->priv_segmented_uninitialized_move_alloc_n(first, n, dest, dtl::bool_()); + } + + void priv_segmented_uninitialized_copy_alloc_n(const_iterator first, std::size_t n, iterator dest) + { + 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(); + + index_pointer current_node = first.get_node(); + + BOOST_CONTAINER_TRY{ + const pointer cur = first.get_cur(); + const size_type block = block_size - size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + dest = ::boost::container::uninitialized_copy_alloc_n(this->alloc(), boost::movelib::to_raw_pointer(cur), cnt, dest); + n -= cnt; + + while (n) { + ++current_node; + 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); + n -= cnt; + } + } + BOOST_CONTAINER_CATCH(...) { + this->prot_destroy_range(first.unconst(), iterator(*current_node, current_node)); + BOOST_CONTAINER_RETHROW + } + BOOST_CONTAINER_CATCH_END + } + } + + static iterator priv_segmented_move_n(const_iterator first, std::size_t n, iterator dest) + { + index_pointer current_node = first.get_node(); + BOOST_ASSERT(current_node != index_pointer()); + + const pointer cur = first.get_cur(); + BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); + + const size_type block = block_size - size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(cur), cnt, dest); + n -= cnt; + + while (n) { + ++current_node; + cnt = n < block_size ? n: block_size; + dest = ::boost::container::move_n(boost::movelib::to_raw_pointer(*current_node), cnt, dest); + n -= cnt; + } + return dest; + } + + static iterator priv_segmented_move_backward_n(iterator last, std::size_t n, iterator dest_last) + { + index_pointer current_node = last.get_node(); + BOOST_ASSERT(current_node != index_pointer()); + + const pointer cur = last.get_cur(); + const size_type block = size_type(cur - *current_node); + size_type cnt = n < block ? n: block; + dest_last = ::boost::container::move_backward_n(boost::movelib::to_raw_pointer(cur), cnt, dest_last); + n -= cnt; + + BOOST_CONSTEXPR_OR_CONST size_type block_size = get_block_size(); + + while (n) { + --current_node; + 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); + n -= cnt; + } + return dest_last; + } + template iterator priv_insert_back_aux_impl(size_type n, InsertProxy proxy) { - if(!this->members_.m_map){ - this->priv_initialize_map(0); - } - - iterator new_finish = this->priv_reserve_elements_at_back(n); - BOOST_CONTAINER_TRY{ - proxy.uninitialized_copy_n_and_update(this->alloc(), this->members_.m_finish, n); - } - BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(this->members_.m_finish.m_node + 1, new_finish.m_node + 1); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - this->members_.m_finish = new_finish; - return iterator(this->members_.m_finish - difference_type(n)); + this->priv_reserve_elements_at_back(n); + const iterator old_finish = this->prot_finish(); + this->priv_insert_segmented_uninitialized_copy_n_and_update(old_finish, n, proxy); + this->prot_inc_finish(n); + return old_finish; } template iterator priv_insert_front_aux_impl(size_type n, InsertProxy proxy) { - if(!this->members_.m_map){ - this->priv_initialize_map(0); - } - - iterator new_start = this->priv_reserve_elements_at_front(n); - BOOST_CONTAINER_TRY{ - proxy.uninitialized_copy_n_and_update(this->alloc(), new_start, n); - } - BOOST_CONTAINER_CATCH(...) { - this->priv_destroy_nodes(new_start.m_node, this->members_.m_start.m_node); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END - - this->members_.m_start = new_start; + this->priv_reserve_elements_at_front(n); + const iterator old_start = this->prot_start(); + const iterator new_start = old_start - difference_type(n); + this->priv_insert_segmented_uninitialized_copy_n_and_update(new_start, n, proxy); + this->prot_dec_start(n); return new_start; } - inline iterator priv_fill_insert(const_iterator pos, size_type n, const value_type& x) - { - return this->insert(pos, c_it(x, n), c_it()); - } - - // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, + // Precondition: this->prot_start() and this->prot_finish() have already been initialized, // but none of the deque's elements have yet been constructed. - void priv_fill_initialize(const value_type& value) + void priv_fill_initialize(size_type n, const value_type& value) { - index_pointer cur = this->members_.m_start.m_node; - BOOST_CONTAINER_TRY { - for ( ; cur < this->members_.m_finish.m_node; ++cur){ - boost::container::uninitialized_fill_alloc - (this->alloc(), *cur, *cur + get_block_ssize(), value); - } - boost::container::uninitialized_fill_alloc - (this->alloc(), this->members_.m_finish.get_first(), this->members_.m_finish.m_cur, value); - } - BOOST_CONTAINER_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur, get_block_size())); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END + dtl::insert_n_copies_proxy proxy(value); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); } template void priv_range_initialize(InIt first, InIt last, typename iterator_enable_if_tag::type* =0) { - this->priv_initialize_map(0); + this->prot_initialize_map_and_nodes(0); BOOST_CONTAINER_TRY { for ( ; first != last; ++first) this->emplace_back(*first); @@ -2717,135 +2681,142 @@ class deque : protected deque_base::type, template void priv_range_initialize(FwdIt first, FwdIt last, typename iterator_disable_if_tag::type* =0) { - size_type n = 0; - n = boost::container::iterator_udistance(first, last); - this->priv_initialize_map(n); + const size_type n = boost::container::iterator_udistance(first, last); + this->prot_initialize_map_and_nodes(n); - index_pointer cur_node = this->members_.m_start.m_node; + dtl::insert_range_proxy proxy(first); + this->priv_segmented_proxy_uninitialized_copy_n_and_update(this->begin(), n, proxy); + } + + // Called only if this->prot_finish_cur() == this->prot_finish().get_first(). + void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW + { + index_pointer ip = this->prot_finish_node(); + this->prot_deallocate_node(*ip); + this->prot_dec_finish(); + --ip; + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->prot_node_last(ip)) + ); + } + + // Called only if this->prot_start_cur() == this->prot_start().get_last() - 1. Note that + // if the deque has at least one element (a precondition for this member + // function), and if this->prot_start_cur() == this->prot_start().get_last(), then the deque + // must have at least two nodes. + void priv_pop_front_aux() BOOST_NOEXCEPT_OR_NOTHROW + { + const index_pointer ip = this->prot_start_node(); + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->prot_node_last(ip)) + ); + this->prot_deallocate_node(*ip); + this->prot_inc_start(); + } + + void priv_allocate_nodes(index_pointer start, size_type n) + { + size_type i = 0; BOOST_CONTAINER_TRY { - for (; cur_node < this->members_.m_finish.m_node; ++cur_node) { - FwdIt mid = first; - boost::container::iterator_uadvance(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.get_first()); + for (; i < n; ++i) + start[i] = this->prot_allocate_node(); } - BOOST_CONTAINER_CATCH(...){ - this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node, get_block_size())); + BOOST_CONTAINER_CATCH(...) { + for (size_type j = 0; j < i; ++j) + this->prot_deallocate_node(start[j]); BOOST_CONTAINER_RETHROW } BOOST_CONTAINER_CATCH_END } - // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.get_first(). - void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW + void priv_reserve_elements_at_front(size_type n) { - this->priv_deallocate_node(this->members_.m_finish.get_first()); - 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.get_last() - 1; - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) - ); - } + const size_type vacancies = this->prot_front_capacity(); - // Called only if this->members_.m_start.m_cur == this->members_.m_start.get_last() - 1. Note that - // if the deque has at least one element (a precondition for this member - // function), and if this->members_.m_start.m_cur == this->members_.m_start.get_last(), then the deque - // must have at least two nodes. - void priv_pop_front_aux() BOOST_NOEXCEPT_OR_NOTHROW - { - allocator_traits_type::destroy - ( this->alloc() - , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) - ); - this->priv_deallocate_node(this->members_.m_start.get_first()); - 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.get_first(); - } - - iterator priv_reserve_elements_at_front(size_type n) - { - size_type vacancies = size_type(this->members_.m_start.m_cur - this->members_.m_start.get_first()); - if (n > vacancies){ - size_type new_elems = n-vacancies; - size_type new_nodes = (new_elems + get_block_size() - 1u) / 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); + if (n > vacancies){ //n == 0 handled in the else part + if(this->members_.m_map){ + size_type new_elems = size_type(n - vacancies); + size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); + index_pointer start_node = this->prot_start_node(); + size_type s = (size_type)(start_node - this->members_.m_map); + if (new_nodes > s){ + //Start node might have changed when reallocating the map + index_pointer finish_node; + this->priv_reallocate_map(new_nodes, true, start_node, finish_node); + (void) finish_node; + } + this->priv_allocate_nodes(start_node - difference_type(new_nodes), new_nodes); } - size_type i = 1; - BOOST_CONTAINER_TRY { - for (; i <= new_nodes; ++i) - *(this->members_.m_start.m_node - difference_type(i)) = this->priv_allocate_node(); + else { + this->prot_initialize_map_and_nodes(n); + this->prot_reset_start_to_finish(); } - BOOST_CONTAINER_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_start.m_node - difference_type(j))); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END } - return this->members_.m_start - difference_type(n); } - iterator priv_reserve_elements_at_back(size_type n) + void priv_reserve_elements_at_back(size_type n) { - size_type vacancies = size_type(this->members_.m_finish.get_last() - this->members_.m_finish.m_cur - 1); - if (n > vacancies){ - size_type new_elems = size_type(n - vacancies); - size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); - size_type s = (size_type)(this->members_.m_map_size - size_type(this->members_.m_finish.m_node - this->members_.m_map)); - if (new_nodes + 1 > s){ - this->priv_reallocate_map(new_nodes, false); + const size_type vacancies = this->prot_back_capacity(); + + if (n > vacancies){ //n == 0 handled in the else part + if(this->members_.m_map){ + size_type new_elems = size_type(n - vacancies); + size_type new_nodes = size_type(new_elems + get_block_size() - 1u)/get_block_size(); + 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)); + if (new_nodes + 1 > s){ + index_pointer start_node; + //Finish node might have changed when reallocating the map + this->priv_reallocate_map(new_nodes, false, start_node, finish_node); + (void) start_node; + } + this->priv_allocate_nodes(finish_node + 1, new_nodes); } - size_type i = 1; - BOOST_CONTAINER_TRY { - for (; i <= new_nodes; ++i) - *(this->members_.m_finish.m_node + difference_type(i)) = this->priv_allocate_node(); + else{ + this->prot_initialize_map_and_nodes(n); + this->prot_reset_finish_to_start(); } - BOOST_CONTAINER_CATCH(...) { - for (size_type j = 1; j < i; ++j) - this->priv_deallocate_node(*(this->members_.m_finish.m_node + difference_type(j))); - BOOST_CONTAINER_RETHROW - } - BOOST_CONTAINER_CATCH_END } - return this->members_.m_finish + difference_type(n); } - void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) + void priv_reallocate_map(size_type nodes_to_add, bool add_at_front, index_pointer &new_start_segment, index_pointer &new_finish_segment) { - size_type old_num_nodes = size_type(this->members_.m_finish.m_node - this->members_.m_start.m_node + 1); + const index_pointer start_node = this->prot_start_node(); + const index_pointer finish_node = this->prot_finish_node(); + size_type old_num_nodes = size_type(finish_node - start_node + 1); size_type new_num_nodes = old_num_nodes + nodes_to_add; index_pointer new_nstart; if (this->members_.m_map_size > 2 * new_num_nodes) { new_nstart = this->members_.m_map + difference_type(this->members_.m_map_size - new_num_nodes) / 2 + difference_type(add_at_front ? nodes_to_add : 0u); - if (new_nstart < this->members_.m_start.m_node) - boost::container::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + if (new_nstart < start_node) + boost::container::move(start_node, finish_node + 1, new_nstart); else boost::container::move_backward - (this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart + difference_type(old_num_nodes)); + (start_node, finish_node + 1, new_nstart + difference_type(old_num_nodes)); } else { + //Doubling size, but at least one spare slot on each end size_type new_map_size = - this->members_.m_map_size + dtl::max_value(this->members_.m_map_size, nodes_to_add) + 2; + this->members_.m_map_size + dtl::max_value(this->members_.m_map_size, nodes_to_add + 2u); - index_pointer new_map = this->priv_allocate_map(new_map_size); + 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(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); - this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + boost::container::move(start_node, finish_node + 1, new_nstart); + this->prot_deallocate_map(this->members_.m_map, this->members_.m_map_size); this->members_.m_map = new_map; this->members_.m_map_size = new_map_size; } - this->members_.m_start.priv_set_node(new_nstart, get_block_size()); - this->members_.m_finish.priv_set_node(new_nstart + difference_type(old_num_nodes - 1u), get_block_size()); + new_start_segment = new_nstart; + new_finish_segment = new_nstart + difference_type(old_num_nodes - 1u); + this->prot_start_set_node(new_start_segment); + this->prot_finish_set_node(new_finish_segment); } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index 13b168f..42c0664 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -654,14 +654,15 @@ using deque_options_t = typename boost::container::deque_options::ty #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)) +//!that will be allocated by some containers 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. +//!that will be allocated by some containersas BlockSize. +//!For some containers (like deque), a power of two value can improve performance. //!A value zero represents the default value. //! //!\tparam BlockBytes An unsigned integer value. diff --git a/test/deque_test.cpp b/test/deque_test.cpp index 023cfc0..61f6600 100644 --- a/test/deque_test.cpp +++ b/test/deque_test.cpp @@ -15,6 +15,7 @@ #include #include + #include "print_container.hpp" #include "check_equal_containers.hpp" #include "dummy_test_allocator.hpp" @@ -127,6 +128,11 @@ bool do_test() move_assign = boost::move(move_ctor); move_assign.swap(original); } + { + typedef deque MyCntDeque; + ::boost::movelib::unique_ptr const pcntdeque = ::boost::movelib::make_unique(); + pcntdeque->erase(pcntdeque->cbegin(), pcntdeque->cend()); + } //Alias deque types typedef deque MyCntDeque; @@ -172,10 +178,30 @@ bool do_test() stddeque.erase(stddeque.begin()++); if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + cntdeque.erase(cntdeque.erase(cntdeque.begin()++)); + stddeque.erase(stddeque.erase(stddeque.begin()++)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.erase(cntdeque.erase(cntdeque.begin()+3)); + stddeque.erase(stddeque.erase(stddeque.begin()+3)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.erase(cntdeque.erase(cntdeque.end()-2)); + stddeque.erase(stddeque.erase(stddeque.end()-2)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + + cntdeque.erase(cntdeque.erase(cntdeque.end()-4)); + stddeque.erase(stddeque.erase(stddeque.end()-4)); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + cntdeque.erase(cntdeque.begin()); stddeque.erase(stddeque.begin()); if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + cntdeque.erase(cntdeque.end()-1); + stddeque.erase(stddeque.end()-1); + if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; + { //Initialize values IntType aux_vect[50]; diff --git a/test/new_deque_test.cpp b/test/new_deque_test.cpp deleted file mode 100644 index 548390b..0000000 --- a/test/new_deque_test.cpp +++ /dev/null @@ -1,475 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// (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 -#include -#include -#include - -#include "../bench/new_deque.hpp" -#include - - -#include "print_container.hpp" -#include "check_equal_containers.hpp" -#include "dummy_test_allocator.hpp" -#include "movable_int.hpp" -#include -#include -#include -#include -#include -#include "emplace_test.hpp" -#include "propagate_allocator_test.hpp" -#include "vector_test.hpp" -#include "default_init_test.hpp" -#include "../../intrusive/test/iterator_test.hpp" - -using namespace boost::container; - -//Function to check if both sets are equal -template -bool deque_copyable_only(V1 &, V2 &, dtl::false_type) -{ - return true; -} - -//Function to check if both sets are equal -template -bool deque_copyable_only(V1 &cntdeque, V2 &stddeque, dtl::true_type) -{ - typedef typename V1::value_type IntType; - std::size_t size = cntdeque.size(); - stddeque.insert(stddeque.end(), 50u, 1); - cntdeque.insert(cntdeque.end(), 50u, IntType(1)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - { - IntType move_me(1); - stddeque.insert(stddeque.begin()+std::ptrdiff_t(size)/2, 50u, 1); - cntdeque.insert(cntdeque.begin()+std::ptrdiff_t(size/2), 50u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - { - IntType move_me(2); - cntdeque.assign(cntdeque.size()/2, boost::move(move_me)); - stddeque.assign(stddeque.size()/2, 2); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - { - IntType move_me(1); - stddeque.clear(); - cntdeque.clear(); - stddeque.insert(stddeque.begin(), 50u, 1); - cntdeque.insert(cntdeque.begin(), 50u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - stddeque.insert(stddeque.begin()+20, 50u, 1); - cntdeque.insert(cntdeque.begin()+20, 50u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - stddeque.insert(stddeque.begin()+20, 20u, 1); - cntdeque.insert(cntdeque.begin()+20, 20u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - { - IntType move_me(1); - stddeque.clear(); - cntdeque.clear(); - stddeque.insert(stddeque.end(), 50u, 1); - cntdeque.insert(cntdeque.end(), 50u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - stddeque.insert(stddeque.end()-20, 50u, 1); - cntdeque.insert(cntdeque.end()-20, 50u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - stddeque.insert(stddeque.end()-20, 20u, 1); - cntdeque.insert(cntdeque.end()-20, 20u, boost::move(move_me)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - - return true; -} - -//Test recursive structures -class recursive_deque -{ -public: - - recursive_deque (const recursive_deque &x) - : deque_(x.deque_) - {} - - recursive_deque & operator=(const recursive_deque &x) - { this->deque_ = x.deque_; return *this; } - - new_deque deque_; - new_deque::iterator it_; - new_deque::const_iterator cit_; - new_deque::reverse_iterator rit_; - new_deque::const_reverse_iterator crit_; -}; - -template -bool do_test() -{ - //Test for recursive types - { - new_deque recursive_deque_deque; - } - - { - //Now test move semantics - new_deque original; - new_deque move_ctor(boost::move(original)); - new_deque move_assign; - move_assign = boost::move(move_ctor); - move_assign.swap(original); - } - { - typedef new_deque MyCntDeque; - ::boost::movelib::unique_ptr const pcntdeque = ::boost::movelib::make_unique(); - pcntdeque->erase(pcntdeque->cbegin(), pcntdeque->cend()); - } - - //Alias deque types - typedef new_deque MyCntDeque; - typedef std::deque MyStdDeque; - const int max = 100; - { - ::boost::movelib::unique_ptr const pcntdeque = ::boost::movelib::make_unique(); - ::boost::movelib::unique_ptr const pstddeque = ::boost::movelib::make_unique(); - MyCntDeque &cntdeque = *pcntdeque; - MyStdDeque &stddeque = *pstddeque; - for(int i = 0; i < max*100; ++i){ - IntType move_me(i); - cntdeque.insert(cntdeque.end(), boost::move(move_me)); - stddeque.insert(stddeque.end(), i); - } - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.clear(); - stddeque.clear(); - - for(int i = 0; i < max*100; ++i){ - IntType move_me(i); - cntdeque.push_back(boost::move(move_me)); - stddeque.push_back(i); - } - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.clear(); - stddeque.clear(); - - for(int i = 0; i < max*100; ++i){ - IntType move_me(i); - cntdeque.push_front(boost::move(move_me)); - stddeque.push_front(i); - } - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - typename MyCntDeque::iterator it; - typename MyCntDeque::const_iterator cit = it; - (void)cit; - - cntdeque.erase(cntdeque.begin()++); - stddeque.erase(stddeque.begin()++); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.erase(cntdeque.begin()++)); - stddeque.erase(stddeque.erase(stddeque.begin()++)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.erase(cntdeque.begin()+3)); - stddeque.erase(stddeque.erase(stddeque.begin()+3)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.erase(cntdeque.end()-2)); - stddeque.erase(stddeque.erase(stddeque.end()-2)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.erase(cntdeque.end()-4)); - stddeque.erase(stddeque.erase(stddeque.end()-4)); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.begin()); - stddeque.erase(stddeque.begin()); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - cntdeque.erase(cntdeque.end()-1); - stddeque.erase(stddeque.end()-1); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - { - //Initialize values - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType move_me (-1); - aux_vect[i] = boost::move(move_me); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - - cntdeque.insert(cntdeque.end() - ,boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(aux_vect + 50)); - stddeque.insert(stddeque.end(), aux_vect2, aux_vect2 + 50); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - for(int i = 0; i < 50; ++i){ - IntType move_me (i); - aux_vect[i] = boost::move(move_me); - } - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = i; - } - - cntdeque.insert(cntdeque.begin()+std::ptrdiff_t(cntdeque.size()) - ,boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(aux_vect + 50)); - stddeque.insert(stddeque.begin()+std::ptrdiff_t(stddeque.size()), aux_vect2, aux_vect2 + 50); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - for(int i = 0, j = static_cast(cntdeque.size()); i < j; ++i){ - cntdeque.erase(cntdeque.begin()); - stddeque.erase(stddeque.begin()); - } - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - { - IntType aux_vect[50]; - for(int i = 0; i < 50; ++i){ - IntType move_me(-1); - aux_vect[i] = boost::move(move_me); - } - int aux_vect2[50]; - for(int i = 0; i < 50; ++i){ - aux_vect2[i] = -1; - } - cntdeque.insert(cntdeque.begin() - ,boost::make_move_iterator(&aux_vect[0]) - ,boost::make_move_iterator(aux_vect + 50)); - stddeque.insert(stddeque.begin(), aux_vect2, aux_vect2 + 50); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - } - - if(!deque_copyable_only(cntdeque, stddeque - ,dtl::bool_::value>())){ - return false; - } - - cntdeque.erase(cntdeque.begin()); - stddeque.erase(stddeque.begin()); - - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - for(int i = 0; i < max; ++i){ - IntType move_me(i); - cntdeque.insert(cntdeque.begin(), boost::move(move_me)); - stddeque.insert(stddeque.begin(), i); - } - if(!test::CheckEqualContainers(cntdeque, stddeque)) return false; - - //Test insertion from list - { - std::list l(50, int(1)); - cntdeque.insert(cntdeque.begin(), l.begin(), l.end()); - stddeque.insert(stddeque.begin(), l.begin(), l.end()); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; - cntdeque.assign(l.begin(), l.end()); - stddeque.assign(l.begin(), l.end()); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; - } - - cntdeque.resize(100); - stddeque.resize(100); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; - - cntdeque.resize(200); - stddeque.resize(200); - if(!test::CheckEqualContainers(cntdeque, stddeque)) return 1; - } - -#ifndef BOOST_CONTAINER_NO_CXX17_CTAD - //Check Constructor Template Auto Deduction - { - auto gold = MyStdDeque{ 1, 2, 3 }; - auto test = new_deque(gold.begin(), gold.end()); - if(!test::CheckEqualContainers(gold, test)) return false; - } - { - auto gold = MyStdDeque{ 1, 2, 3 }; - auto test = new_deque(gold.begin(), gold.end(), new_allocator()); - if(!test::CheckEqualContainers(gold, test)) return false; - } -#endif - - std::cout << std::endl << "Test OK!" << std::endl; - return true; -} - -template -struct GetAllocatorCont -{ - template - struct apply - { - typedef new_deque< ValueType - , typename allocator_traits - ::template portable_rebind_alloc::type - > type; - }; -}; - -template -int test_cont_variants() -{ - typedef typename GetAllocatorCont::template apply::type MyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveCont; - typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; - typedef typename GetAllocatorCont::template apply::type MyCopyCont; - typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; - - if (test::vector_test()) - return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) - return 1; - if (test::vector_test()) - return 1; - return 0; -} - -struct boost_container_new_deque; - -namespace boost { namespace container { namespace test { - -template<> -struct alloc_propagate_base -{ - template - struct apply - { - typedef boost::container::new_deque type; - }; -}; - -}}} //namespace boost::container::test - -int main () -{ - if(!do_test()) - return 1; - - if(!do_test()) - return 1; - - if(!do_test()) - return 1; - - if(!do_test()) - return 1; - - //Test non-copy-move operations - { - new_deque d; - d.emplace_back(); - d.emplace_front(1); - d.resize(10); - d.resize(1); - } - - //////////////////////////////////// - // Allocator implementations - //////////////////////////////////// - // std:allocator - if(test_cont_variants< std::allocator >()){ - std::cerr << "test_cont_variants< std::allocator > failed" << std::endl; - return 1; - } - - // boost::container::allocator - if(test_cont_variants< allocator >()){ - std::cerr << "test_cont_variants< allocator > failed" << std::endl; - return 1; - } - - //////////////////////////////////// - // Default init test - //////////////////////////////////// - if(!test::default_init_test< new_deque > >()){ - std::cerr << "Default init test failed" << std::endl; - return 1; - } - - //////////////////////////////////// - // Emplace testing - //////////////////////////////////// - const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE); - - if(!boost::container::test::test_emplace - < new_deque, Options>()) - return 1; - //////////////////////////////////// - // Allocator propagation testing - //////////////////////////////////// - if(!boost::container::test::test_propagate_allocator()) - return 1; - - //////////////////////////////////// - // Initializer lists testing - //////////////////////////////////// - if(!boost::container::test::test_vector_methods_with_initializer_list_as_argument_for - < boost::container::new_deque >()) { - return 1; - } - - //////////////////////////////////// - // Iterator testing - //////////////////////////////////// - { - typedef boost::container::new_deque cont_int; - for(std::size_t i = 1; i <= 10000; i*=10){ - cont_int a; - for (int j = 0; j < (int)i; ++j) - a.push_back((int)j); - boost::intrusive::test::test_iterator_random< cont_int >(a); - if(boost::report_errors() != 0) { - return 1; - } - } - } - - //////////////////////////////////// - // has_trivial_destructor_after_move testing - //////////////////////////////////// - // default allocator - { - typedef boost::container::new_deque cont; - typedef cont::allocator_type allocator_type; - typedef boost::container::allocator_traits::pointer pointer; - BOOST_CONTAINER_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) - , "has_trivial_destructor_after_move(std::allocator) test failed"); - } - // std::allocator - { - typedef boost::container::new_deque > cont; - typedef cont::allocator_type allocator_type; - typedef boost::container::allocator_traits::pointer pointer; - BOOST_CONTAINER_STATIC_ASSERT_MSG(!(boost::has_trivial_destructor_after_move::value != - boost::has_trivial_destructor_after_move::value && - boost::has_trivial_destructor_after_move::value) - , "has_trivial_destructor_after_move(std::allocator) test failed"); - } - - return 0; -}