diff --git a/bench/bench_vectors.cpp b/bench/bench_vectors.cpp new file mode 100644 index 0000000..e46c6c4 --- /dev/null +++ b/bench/bench_vectors.cpp @@ -0,0 +1,283 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning (disable : 4512) +#pragma warning (disable : 4267) +#pragma warning (disable : 4244) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include //std::allocator +#include //std::cout, std::endl +#include //std::strcmp +#include +#include + +//capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace test { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0 +#include + +using boost::timer::cpu_timer; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; + +namespace bc = boost::container; + +class MyInt +{ + int int_; + + public: + explicit MyInt(int i = 0) + : int_(i) + {} + + MyInt(const MyInt &other) + : int_(other.int_) + {} + + MyInt & operator=(const MyInt &other) + { + int_ = other.int_; + return *this; + } + + ~MyInt() + { + int_ = 0; + } +}; + +template::value> +struct capacity_wrapper +{ + static typename C::size_type get_capacity(const C &c) + { return c.capacity(); } + + static void set_reserve(C &c, typename C::size_type cp) + { c.reserve(cp); } +}; + +template +struct capacity_wrapper +{ + static typename C::size_type get_capacity(const C &) + { return 0u; } + + static void set_reserve(C &, typename C::size_type ) + { } +}; + +const std::size_t RangeSize = 5; + +struct insert_end_range +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int) + { c.insert(c.end(), &a[0], &a[0]+RangeSize); } + + const char *name() const + { return "insert_end_range"; } + + MyInt a[RangeSize]; +}; + +struct insert_end_repeated +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.insert(c.end(), RangeSize, MyInt(i)); } + + const char *name() const + { return "insert_end_repeated"; } + + MyInt a[RangeSize]; +}; + +struct push_back +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.push_back(MyInt(i)); } + + const char *name() const + { return "push_back"; } +}; + +struct emplace_back +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.emplace_back(MyInt(i)); } + + const char *name() const + { return "emplace_back"; } +}; + +struct insert_near_end_repeated +{ + + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), RangeSize, MyInt(i)); } + + const char *name() const + { return "insert_near_end_repeated"; } +}; + +struct insert_near_end_range +{ + std::size_t capacity_multiplier() const + { return RangeSize; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int) + { + c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), &a[0], &a[0]+RangeSize); + } + + const char *name() const + { return "insert_near_end_repeated"; } + + MyInt a[RangeSize]; +}; + +struct insert_near_end +{ + std::size_t capacity_multiplier() const + { return 1; } + + template + BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i) + { + typedef typename C::iterator it_t; + it_t it (c.end()); + it -= static_cast(!c.empty()); + c.insert(it, MyInt(i)); + } + + const char *name() const + { return "insert_near_end"; } +}; + + +template +void vector_test_template(unsigned int num_iterations, unsigned int num_elements, const char *cont_name) +{ + cpu_timer timer; + timer.resume(); + + + unsigned int capacity = 0; + Operation op; + typedef capacity_wrapper cpw_t; + const typename Container::size_type multiplier = op.capacity_multiplier(); + + for(unsigned int r = 0; r != num_iterations; ++r){ + Container c; + cpw_t::set_reserve(c, num_elements); + + for(unsigned e = 0, max = num_elements/multiplier; e != max; ++e){ + op(c, static_cast(e)); + } + + capacity = static_cast(cpw_t::get_capacity(c)); + } + + timer.stop(); + + + nanosecond_type nseconds = timer.elapsed().wall; + + std::cout << cont_name << "->" << op.name() <<" ns: " + << float(nseconds)/(num_iterations*num_elements) + << '\t' + << "Capacity: " << (unsigned int)capacity + << "\n"; +} + +template +void test_vectors() +{ + //#define SINGLE_TEST + #define SIMPLE_IT + #ifdef SINGLE_TEST + #ifdef NDEBUG + std::size_t numit [] = { 100 }; + #else + std::size_t numit [] = { 20 }; + #endif + std::size_t numele [] = { 10000 }; + #elif defined SIMPLE_IT + std::size_t numit [] = { 100 }; + std::size_t numele [] = { 10000 }; + #else + #ifdef NDEBUG + unsigned int numit [] = { 1000, 10000, 100000, 1000000 }; + #else + unsigned int numit [] = { 100, 1000, 10000, 100000 }; + #endif + unsigned int numele [] = { 10000, 1000, 100, 10 }; + #endif + + for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){ + vector_test_template< std::vector >, Operation >(numit[i], numele[i] , "std::vector "); + vector_test_template< bc::vector >, Operation >(numit[i], numele[i] , "vector "); + vector_test_template< bc::devector >, Operation >(numit[i], numele[i] , "devector "); + vector_test_template< bc::small_vector >, Operation >(numit[i], numele[i] , "small_vector "); + vector_test_template< std::deque >, Operation >(numit[i], numele[i] , "std::deque "); + vector_test_template< bc::deque >, Operation >(numit[i], numele[i] , "deque "); + } + + std::cout << "---------------------------------\n---------------------------------\n"; +} + +int main() +{ + //end + test_vectors(); + test_vectors(); + test_vectors(); + test_vectors(); + //near end + test_vectors(); + test_vectors(); + test_vectors(); + + return 0; +} diff --git a/doc/container.qbk b/doc/container.qbk index 64cc808..24f4314 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -47,12 +47,14 @@ In short, what does [*Boost.Container] offer? searches. * [classref boost::container::stable_vector stable_vector]: a std::list and std::vector hybrid container: vector-like random-access iterators and list-like iterator stability in insertions and erasures. - * [classref boost::container::static_vector static_vector ]: a vector-like container that internally embeds + * [classref boost::container::static_vector static_vector]: a vector-like container that internally embeds (statically allocates) all needed memory up to the maximum capacity. Maximum capacity can't be increased and it's specified at compile time. - * [classref boost::container::small_vector small_vector ]: a vector-like container that internally embeds + * [classref boost::container::small_vector small_vector]: a vector-like container that internally embeds (statically allocates) a minimum amount of memory, but dynamically allocates elements when capacity has to be increased. This minimum capacity is specified at compile time. + * [classref boost::container::devector devector]: is a hybrid of the standard vector and deque containers. + It offers cheap (amortized constant time) insertion at both the front and back ends. * [classref boost::container::slist slist]: the classic pre-standard singly linked list implementation offering constant-time `size()`. Note that C++11 `forward_list` has no `size()`. @@ -458,6 +460,21 @@ erasure times considerably. Flat associative containers have the following attri [endsect] +[section:devector ['devector]] + +`devector` is a hybrid of the standard vector and deque containers originally written by Thaler Benedek. +It offers cheap (amortized constant time) insertion at both the front and back ends, +while also providing the regular features of `vector`, in particular the contiguous underlying memory. + +Unlike `vector`, devector can have free capacity both before and after the elements. This enables efficient +implementation of methods that modify the devector at the front. In general, `devector`'s available methods +are a superset of those of `vector` with identical behaviour, barring a couple of iterator invalidation +guarantees that differ. + +The overhead for devector is one extra `size_t` per container: Usually sizeof(devector) == 4*sizeof(T*). + +[endsect] + [section:slist ['slist]] When the standard template library was designed, it contained a singly linked list called `slist`. @@ -1306,6 +1323,10 @@ use [*Boost.Container]? There are several reasons for that: * `static_vector` was based on Andrew Hundt's and Adam Wulkiewicz's high-performance `varray` class. Many performance improvements of `vector` were also inspired by their implementation. Thanks! +* `devector` is based on Thaler Benedek's high-performance `devector` implementation, then + adapted for [*Boost.Container]. Also inspired by similar implemenations by Orson Peters and Lars Hagen. + Thanks for such a great code and documentation! + * Howard Hinnant's help and advices were essential when implementing move semantics, improving allocator support or implementing small string optimization. Thanks Howard for your wonderful standard library implementations. diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index fb4d7bd..7855257 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -26,6 +26,7 @@ //! - boost::container::static_vector //! - boost::container::small_vector_base //! - boost::container::small_vector +//! - boost::container::devector //! - boost::container::slist //! - boost::container::list //! - boost::container::set @@ -122,6 +123,11 @@ template < class T , class Options = void > class small_vector; +template +class devector; + template diff --git a/include/boost/container/container_fwd.hpp.bak b/include/boost/container/container_fwd.hpp.bak new file mode 100644 index 0000000..9d419f7 --- /dev/null +++ b/include/boost/container/container_fwd.hpp.bak @@ -0,0 +1,389 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2014. 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_CONTAINER_FWD_HPP +#define BOOST_CONTAINER_CONTAINER_FWD_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//! \file +//! This header file forward declares the following containers: +//! - boost::container::vector +//! - boost::container::stable_vector +//! - boost::container::static_vector +//! - boost::container::small_vector_base +//! - boost::container::small_vector +//! - boost::container::slist +//! - boost::container::list +//! - boost::container::set +//! - boost::container::multiset +//! - boost::container::map +//! - boost::container::multimap +//! - boost::container::flat_set +//! - boost::container::flat_multiset +//! - boost::container::flat_map +//! - boost::container::flat_multimap +//! - boost::container::basic_string +//! - boost::container::string +//! - boost::container::wstring +//! +//! Forward declares the following allocators: +//! - boost::container::allocator +//! - boost::container::node_allocator +//! - boost::container::adaptive_pool +//! +//! Forward declares the following polymorphic resource classes: +//! - boost::container::pmr::memory_resource +//! - boost::container::pmr::polymorphic_allocator +//! - boost::container::pmr::monotonic_buffer_resource +//! - boost::container::pmr::pool_options +//! - boost::container::pmr::unsynchronized_pool_resource +//! - boost::container::pmr::synchronized_pool_resource +//! +//! And finally it defines the following types + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//Std forward declarations +#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP + #include +#endif + +namespace boost{ +namespace intrusive{ +namespace detail{ + //Create namespace to avoid compilation errors +}}} + +namespace boost{ namespace container{ namespace dtl{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +namespace boost{ namespace container{ namespace pmr{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +#include + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +struct pair; + +template +class new_allocator; + +template +class vector; + +template +class stable_vector; + +template < class T + , std::size_t Capacity + , class Options = void> +class static_vector; + +template < class T + , class Allocator = void + , class Options = void > +class small_vector_base; + +template < class T + , std::size_t N + , class Allocator = void + , class Options = void > +class small_vector; + +template +class devector; + +template +class deque; + +template +class list; + +template +class slist; + +template + ,class Allocator = void + ,class Options = void> +class set; + +template + ,class Allocator = void + ,class Options = void > +class multiset; + +template + ,class Allocator = void + ,class Options = void > +class map; + +template + ,class Allocator = void + ,class Options = void > +class multimap; + +template + ,class Allocator = void > +class flat_set; + +template + ,class Allocator = void > +class flat_multiset; + +template + ,class Allocator = void > +class flat_map; + +template + ,class Allocator = void > +class flat_multimap; + +#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + +//! Alias templates for small_flat_[multi]{set|map} using small_vector as container + +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_set = flat_set>; + +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_multiset = flat_multiset>; + +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_map = flat_map, N, SmallVectorAllocator, SmallVectorOptions>>; + +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +using small_flat_multimap = flat_multimap, N, SmallVectorAllocator, SmallVectorOptions>>; + +#endif // #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES + + +//! A portable metafunction to obtain a small_flat_set +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_set_of +{ + typedef flat_set > type; +}; + +//! A portable metafunction to obtain a small_flat_multiset +template < class Key + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multiset_of +{ + typedef flat_multiset > type; +}; + +//! A portable metafunction to obtain a small_flat_map +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_map_of +{ + typedef flat_map, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + +//! A portable metafunction to obtain a small_flat_multimap +template < class Key + , class T + , std::size_t N + , class Compare = std::less + , class SmallVectorAllocator = void + , class SmallVectorOptions = void > +struct small_flat_multimap_of +{ + typedef flat_multimap, N, SmallVectorAllocator, SmallVectorOptions> > type; +}; + +template + ,class Allocator = void > +class basic_string; + +typedef basic_string string; +typedef basic_string wstring; + +static const std::size_t ADP_nodes_per_block = 256u; +static const std::size_t ADP_max_free_blocks = 2u; +static const std::size_t ADP_overhead_percent = 1u; +static const std::size_t ADP_only_alignment = 0u; + +template < class T + , std::size_t NodesPerBlock = ADP_nodes_per_block + , std::size_t MaxFreeBlocks = ADP_max_free_blocks + , std::size_t OverheadPercent = ADP_overhead_percent + , unsigned Version = 2 + > +class adaptive_pool; + +template < class T + , unsigned Version = 2 + , unsigned int AllocationDisableMask = 0> +class allocator; + +static const std::size_t NodeAlloc_nodes_per_block = 256u; + +template + < class T + , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block + , std::size_t Version = 2> +class node_allocator; + +namespace pmr { + +class memory_resource; + +template +class polymorphic_allocator; + +class monotonic_buffer_resource; + +struct pool_options; + +template +class resource_adaptor_imp; + +class unsynchronized_pool_resource; + +class synchronized_pool_resource; + +} //namespace pmr { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the input range is +//! guaranteed to be ordered +struct ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered +static const ordered_range_t ordered_range = ordered_range_t(); + +//! Type used to tag that the input range is +//! guaranteed to be ordered and unique +struct ordered_unique_range_t + : public ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered and unique +static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t(); + +//! Type used to tag that the inserted values +//! should be default initialized +struct default_init_t +{}; + +//! Value used to tag that the inserted values +//! should be default initialized +static const default_init_t default_init = default_init_t(); +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the inserted values +//! should be value initialized +struct value_init_t +{}; + +//! Value used to tag that the inserted values +//! should be value initialized +static const value_init_t value_init = value_init_t(); + +namespace container_detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)ordered_range; + (void)ordered_unique_range; + (void)default_init; + } +}; + +} //detail_really_deep_namespace { + + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +}} //namespace boost { namespace container { + +#endif //#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index c346360..8e62a61 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -130,7 +130,8 @@ void flat_tree_container_inplace_merge //is_contiguous_container == true value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin()); value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); - boost::movelib::adaptive_merge(braw, iraw, eraw, comp, eraw, dest.capacity()- dest.size()); + boost::movelib::adaptive_merge + (braw, iraw, eraw, comp, eraw, back_free_capacity::get(dest)); } template @@ -152,7 +153,8 @@ void flat_tree_container_inplace_sort_ending //is_contiguous_container == true typedef typename SequenceContainer::value_type value_type; value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it); value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end()); - boost::movelib::adaptive_sort(iraw, eraw, comp, eraw, dest.capacity()- dest.size()); + boost::movelib::adaptive_sort + (iraw, eraw, comp, eraw, back_free_capacity::get(dest)); } template @@ -984,10 +986,7 @@ class flat_tree ret.first = this->nth(data.position - this->cbegin()); } else{ - typedef typename emplace_functor_type::type func_t; - typedef emplace_iterator it_t; - func_t func(try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); } return ret; } @@ -1053,10 +1052,7 @@ class flat_tree ret.first = this->nth(data.position - this->cbegin());\ }\ else{\ - typedef typename emplace_functor_type::type func_t;\ - typedef emplace_iterator it_t;\ - func_t func(try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\ + ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ }\ return ret;\ }\ @@ -1080,10 +1076,7 @@ class flat_tree ret.first->second = boost::forward(obj); } else{ - typedef typename emplace_functor_type::type func_t; - typedef emplace_iterator it_t; - func_t func(boost::forward(key), boost::forward(obj)); - ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.emplace(data.position, boost::forward(key), boost::forward(obj)); } return ret; } diff --git a/include/boost/container/detail/guards_dended.hpp b/include/boost/container/detail/guards_dended.hpp new file mode 100644 index 0000000..db5e1d0 --- /dev/null +++ b/include/boost/container/detail/guards_dended.hpp @@ -0,0 +1,198 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Benedek Thaler 2015-2016 +// (C) Copyright Ion Gaztanaga 2019-2020. 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://erenon.hu/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_GUARDS_HPP +#define BOOST_CONTAINER_DETAIL_GUARDS_HPP + +#include +#include + +#include // BOOST_MOVABLE_BUT_NOT_COPYABLE + +// move/detail +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif + +#include + +namespace boost { +namespace container { +namespace detail { + +class null_construction_guard +{ +public: + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + template + null_construction_guard(Args&&...) {} + + #else + + #define NULL_CONSTRUCTION_GUARD_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE null_construction_guard(BOOST_MOVE_UREFANON##N)\ + {}\ + // + BOOST_MOVE_ITERATE_0TO9(NULL_CONSTRUCTION_GUARD_CODE) + #undef NULL_CONSTRUCTION_GUARD_CODE + #endif + + void release() {} + void extend() {} +}; + +template +class construction_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(construction_guard) + +public: + construction_guard() + : _alloc_ptr() + , _elem_count() + , _allocator() + {} + + construction_guard(pointer alloc_ptr, Allocator& allocator) + :_alloc_ptr(alloc_ptr) + , _elem_count(0) + , _allocator(&allocator) + {} + + construction_guard(BOOST_RV_REF(construction_guard) rhs) + :_alloc_ptr(rhs._alloc_ptr) + , _elem_count(rhs._elem_count) + , _allocator(rhs._allocator) + { + rhs._elem_count = 0; + } + + ~construction_guard() + { + while (_elem_count) { + --_elem_count; + boost::container::allocator_traits::destroy(*_allocator, _alloc_ptr++); + } + } + + void release() + { + _elem_count = 0; + } + + void extend() + { + ++_elem_count; + } + +private: + pointer _alloc_ptr; + size_type _elem_count; + Allocator* _allocator; +}; + + +/** + * Has two ranges + * + * On success, destroys the first range (src), + * on failure, destroys the second range (dst). + * + * Can be used when copying/moving a range + */ +template +class nand_construction_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + construction_guard _src; + construction_guard _dst; + bool _dst_released; + + public: + nand_construction_guard() + : _src() + , _dst() + , _dst_released(false) + {} + + nand_construction_guard( pointer src, Allocator& src_alloc + , pointer dst, Allocator& dst_alloc) + :_src(src, src_alloc), + _dst(dst, dst_alloc), + _dst_released(false) + {} + + void extend() + { + _src.extend(); + _dst.extend(); + } + + void release() // on success + { + _dst.release(); + _dst_released = true; + } + + ~nand_construction_guard() + { + if (! _dst_released) { _src.release(); } + } +}; + + +template +class allocation_guard +{ + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(allocation_guard) + +public: + allocation_guard(pointer alloc_ptr, size_type alloc_size, Allocator& allocator) + :_alloc_ptr(alloc_ptr), + _alloc_size(alloc_size), + _allocator(allocator) + {} + + ~allocation_guard() + { + if (_alloc_ptr) + { + boost::container::allocator_traits::deallocate(_allocator, _alloc_ptr, _alloc_size); + } + } + + void release() + { + _alloc_ptr = 0; + } + +private: + pointer _alloc_ptr; + size_type _alloc_size; + Allocator& _allocator; +}; + +}}} // namespace boost::container::detail + +#include + +#endif // BOOST_CONTAINER_DETAIL_GUARDS_HPP diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp new file mode 100644 index 0000000..2b56829 --- /dev/null +++ b/include/boost/container/devector.hpp @@ -0,0 +1,2951 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Benedek Thaler 2015-2016 +// (C) Copyright Ion Gaztanaga 2019-2020. 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_DEVECTOR_HPP +#define BOOST_CONTAINER_DEVECTOR_HPP + +#include +#include + +//#include +#include // memcpy + +#include +#include + +#include +#include //new_allocator +#include //allocator_traits +#include //equal() +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// move +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include + +//std +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#include //for std::initializer_list +#endif + +namespace boost { +namespace container { + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +struct growth_factor_60; + +template +struct get_devector_opt +{ + typedef devector_opt< typename default_if_void::type + , typename default_if_void::type + > type; +}; + +template +struct get_devector_opt +{ + typedef vector_opt type; +}; + +#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +struct reserve_only_tag_t {}; +//struct unsafe_uninitialized_tag_t {}; + +/** + * A vector-like sequence container providing front and back operations + * (e.g: `push_front`/`pop_front`/`push_back`/`pop_back`) with amortized constant complexity + * and unsafe methods geared towards additional performance. + * + * Models the [SequenceContainer], [ReversibleContainer], and [AllocatorAwareContainer] concepts. + * + * **Requires**: + * - `T` shall be [MoveInsertable] into the devector. + * - `T` shall be [Erasable] from any `devector`. + * - `GrowthFactor`, and `Allocator` must model the concepts with the same names or be void. + * + * **Definition**: `T` is `NothrowConstructible` if it's either nothrow move constructible or + * nothrow copy constructible. + * + * **Definition**: `T` is `NothrowAssignable` if it's either nothrow move assignable or + * nothrow copy assignable. + * + * **Exceptions**: The exception specifications assume `T` is nothrow [Destructible]. + * + * Most methods providing the strong exception guarantee assume `T` either has a move + * constructor marked noexcept or is [CopyInsertable] into the devector. If it isn't true, + * and the move constructor throws, the guarantee is waived and the effects are unspecified. + * + * In addition to the exceptions specified in the **Throws** clause, the following operations + * of `T` can throw when any of the specified concept is required: + * - [DefaultInsertable][]: Default constructor + * - [MoveInsertable][]: Move constructor + * - [CopyInsertable][]: Copy constructor + * - [DefaultConstructible][]: Default constructor + * - [EmplaceConstructible][]: Constructor selected by the given arguments + * - [MoveAssignable][]: Move assignment operator + * - [CopyAssignable][]: Copy assignment operator + * + * Furthermore, not `noexcept` methods throws whatever the allocator throws + * if memory allocation fails. Such methods also throw `length_error` if the capacity + * exceeds `max_size()`. + * + * **Remark**: If a method invalidates some iterators, it also invalidates references + * and pointers to the elements pointed by the invalidated iterators. + * + * **Policies**: + * + * @ref devector_growth_policy models the `GrowthFactor` concept. + * + * [SequenceContainer]: http://en.cppreference.com/w/cpp/concept/SequenceContainer + * [ReversibleContainer]: http://en.cppreference.com/w/cpp/concept/ReversibleContainer + * [AllocatorAwareContainer]: http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer + * [DefaultInsertable]: http://en.cppreference.com/w/cpp/concept/DefaultInsertable + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [Erasable]: http://en.cppreference.com/w/cpp/concept/Erasable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + * [Destructible]: http://en.cppreference.com/w/cpp/concept/Destructible + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ +template < typename T, class A BOOST_CONTAINER_DOCONLY(= void), class Options BOOST_CONTAINER_DOCONLY(= void)> +class devector +{ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::allocator_traits + ::type> allocator_traits_type; + typedef typename allocator_traits_type::size_type alloc_size_type; + typedef typename get_devector_opt::type options_type; + typedef typename options_type::growth_factor_type growth_factor_type; + typedef typename options_type::stored_size_type stored_size_type; + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + // Standard Interface Types: + typedef T value_type; + typedef BOOST_CONTAINER_IMPDEF + (typename real_allocator::type) allocator_type; + typedef allocator_type stored_allocator_type; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::reference reference; + typedef typename allocator_traits::const_reference const_reference; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::difference_type difference_type; + typedef pointer iterator; + typedef const_pointer 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: + BOOST_COPYABLE_AND_MOVABLE(devector) + + // Guard to deallocate buffer on exception + typedef typename detail::allocation_guard allocation_guard; + + // Random access pseudo iterator always yielding to the same result + typedef constant_iterator cvalue_iterator; + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + // Standard Interface + public: + // construct/copy/destroy + + /** + * **Effects**: Constructs an empty devector. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == 0`. + * + * **Complexity**: Constant. + */ + devector() BOOST_NOEXCEPT + : m_() + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == 0`. + * + * **Complexity**: Constant. + */ + explicit devector(const allocator_type& allocator) BOOST_NOEXCEPT + : m_(allocator) + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator + * and reserves `n` slots as if `reserve(n)` was called. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() >= n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Constant. + */ + devector(size_type n, reserve_only_tag_t, const allocator_type& allocator = allocator_type()) + : m_(allocator, this->allocate(n), 0u, 0u, n) + {} + + /** + * **Effects**: Constructs an empty devector, using the specified allocator + * and reserves `front_cap + back_cap` slots as if `reserve_front(front_cap)` and + * `reserve_back(back_cap)` was called. + * + * **Postcondition**: `empty() && front_free_capacity() == front_cap + * && back_free_capacity() >= back_cap`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Constant. + */ + devector(size_type front_cap, size_type back_cap, reserve_only_tag_t, const allocator_type& allocator = allocator_type()) + : m_(allocator, this->allocate(front_cap + back_cap), front_cap, front_cap, front_cap + back_cap) + {} + + /** + * [DefaultInsertable]: http://en.cppreference.com/w/cpp/concept/DefaultInsertable + * + * **Effects**: Constructs a devector with `n` default-inserted elements using the specified allocator. + * + * **Requires**: `T` shall be [DefaultInsertable] into `*this`. + * + * **Postcondition**: `size() == n && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `n`. + */ + explicit devector(size_type n, const allocator_type& allocator = allocator_type()) + : m_(allocator, n ? allocate(n): pointer(), 0u, n, n) + { + // Cannot use construct_from_range/constant_iterator and copy_range, + // because we are not allowed to default construct T + allocation_guard buffer_guard(m_.buffer, m_.capacity, get_allocator_ref()); + detail::construction_guard copy_guard(m_.buffer, get_allocator_ref()); + + for (size_type i = 0; i < n; ++i) + { + this->alloc_construct(m_.buffer + i); + copy_guard.extend(); + } + + copy_guard.release(); + buffer_guard.release(); + + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Constructs a devector with `n` copies of `value`, using the specified allocator. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `size() == n && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `n`. + */ + devector(size_type n, const T& value, const allocator_type& allocator = allocator_type()) + : m_(allocator, n ? allocate(n): pointer(), 0u, n, n) + { + construct_from_range(cvalue_iterator(value, n), cvalue_iterator()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Constructs a devector equal to the range `[first,last)`, using the specified allocator. + * + * **Requires**: `T` shall be [EmplaceConstructible] into `*this` from `*first`. If the specified + * iterator does not meet the forward iterator requirements, `T` shall also be [MoveInsertable] + * into `*this`. + * + * **Postcondition**: `size() == boost::container::iterator_distance(first, last) + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Makes only `N` calls to the copy constructor of `T` (where `N` is the distance between `first` + * and `last`), at most one allocation and no reallocations if iterators first and last are of forward, + * bidirectional, or random access categories. It makes `O(N)` calls to the copy constructor of `T` + * and `O(log(N)) reallocations if they are just input iterators. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + template + devector(InputIterator first, InputIterator last, const allocator_type& allocator = allocator_type() + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + while (first != last) { + this->emplace_back(*first++); + } + + BOOST_ASSERT(invariants_ok()); + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + devector(ForwardIterator first, ForwardIterator last, const allocator_type& allocator = allocator_type() + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + const size_type n = boost::container::iterator_distance(first, last); + m_.buffer = n ? allocate(n) : pointer(); + m_.front_idx = 0u; + m_.set_back_idx(n); + m_.set_capacity(n); + construct_from_range(first, last); + BOOST_ASSERT(invariants_ok()); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Copy constructs a devector. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size() && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `x`. + */ + devector(const devector& x) + : m_( allocator_traits_type::select_on_container_copy_construction(x.get_allocator_ref()) + , pointer(), 0u, 0u, 0u) + { + const size_type n = x.size(); + m_.buffer = n ? allocate(n) : pointer(); + m_.front_idx = 0u; + //this->allocate(n) will take care of overflows + m_.set_back_idx(n); + m_.set_capacity(n); + this->construct_from_range(x.begin(), x.end()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Copy constructs a devector, using the specified allocator. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size() && front_free_capacity() == 0`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `x`. + */ + devector(const devector& x, const allocator_type& allocator) + : m_(allocator, pointer(), 0u, 0u, 0u) + { + const size_type n = x.size(); + m_.buffer = n ? this->allocate(n) : pointer(); + m_.front_idx = 0u; + //this->allocate(n) will take care of overflows + m_.set_back_idx(n); + m_.set_capacity(n); + this->construct_from_range(x.begin(), x.end()); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Moves `rhs`'s resources to `*this`. + * + * **Throws**: Nothing. + * + * **Postcondition**: `rhs` is left in an unspecified but valid state. + * + * **Exceptions**: Strong exception guarantee if not `noexcept`. + * + * **Complexity**: Constant. + */ + devector(BOOST_RV_REF(devector) rhs) BOOST_NOEXCEPT_OR_NOTHROW + : m_(::boost::move(rhs.get_allocator_ref()), rhs.m_.buffer, rhs.m_.front_idx, rhs.m_.back_idx, rhs.capacity()) + { + // buffer is already acquired, reset rhs + rhs.m_.capacity = 0u; + rhs.m_.buffer = pointer(); + rhs.m_.front_idx = 0; + rhs.m_.back_idx = 0; + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(rhs.invariants_ok()); + } + + /** + * **Effects**: Moves `rhs`'s resources to `*this`, using the specified allocator. + * + * **Throws**: If allocation or T's move constructor throws. + * + * **Postcondition**: `rhs` is left in an unspecified but valid state. + * + * **Exceptions**: Strong exception guarantee if not `noexcept`. + * + * **Complexity**: Linear if allocator != rhs.get_allocator(), otherwise constant. + */ + devector(BOOST_RV_REF(devector) rhs, const allocator_type& allocator) + : m_(allocator, rhs.m_.buffer, rhs.m_.front_idx, rhs.m_.back_idx, rhs.capacity()) + { + // TODO should move elems-by-elems if the two allocators differ + // buffer is already acquired, reset rhs + rhs.m_.capacity = 0u; + rhs.m_.buffer = pointer(); + rhs.m_.front_idx = 0; + rhs.m_.back_idx = 0; + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(rhs.invariants_ok()); + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** + * **Equivalent to**: `devector(il.begin(), il.end())` or `devector(il.begin(), il.end(), allocator)`. + */ + devector(const std::initializer_list& il, const allocator_type& allocator = allocator_type()) + : devector(il.begin(), il.end(), allocator) + {} + #endif + + /** + * **Effects**: Destroys the devector. All stored values are destroyed and + * used memory, if any, deallocated. + * + * **Complexity**: Linear in the size of `*this`. + */ + ~devector() BOOST_NOEXCEPT + { + destroy_elements(m_.buffer + m_.front_idx, m_.buffer + m_.back_idx); + deallocate_buffer(); + } + + /** + * **Effects**: Copies elements of `x` to `*this`. Previously + * held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Postcondition**: `this->size() == x.size()`, the elements of + * `*this` are copies of elements in `x` in the same order. + * + * **Returns**: `*this`. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and the allocator is allowed to be propagated + * ([propagate_on_container_copy_assignment] is true), + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `x` and `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [propagate_on_container_copy_assignment]: http://en.cppreference.com/w/cpp/memory/allocator_traits + */ + + BOOST_CONTAINER_FORCEINLINE devector& operator=(BOOST_COPY_ASSIGN_REF(devector) rhs) + { + const devector &x = rhs; + if (this == &x) { return *this; } // skip self + + BOOST_IF_CONSTEXPR(allocator_traits_type::propagate_on_container_copy_assignment::value) + { + allocator_type &this_alloc = this->get_allocator_ref(); + const allocator_type &other_alloc = x.get_allocator_ref(); + if (this_alloc != other_alloc) + { + // new allocator cannot free existing storage + this->clear(); + this->deallocate_buffer(); + m_.capacity = 0u; + m_.buffer = pointer(); + } + + this_alloc = other_alloc; + } + + size_type n = x.size(); + if (capacity() >= n) + { + this->overwrite_buffer(x.begin(), x.end()); + } + else + { + this->allocate_and_copy_range(x.begin(), x.end()); + } + + BOOST_ASSERT(invariants_ok()); + + return *this; + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Moves elements of `x` to `*this`. Previously + * held elements get move/copy assigned to or destroyed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Postcondition**: `x` is left in an unspecified but valid state. + * + * **Returns**: `*this`. + * + * **Exceptions**: Basic exception guarantee if not `noexcept`. + * + * **Complexity**: Constant if allocator_traits_type:: + * propagate_on_container_move_assignment is true or + * this->get>allocator() == x.get_allocator(). Linear otherwise. + */ + devector& operator=(BOOST_RV_REF(devector) x) + BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value) + { + BOOST_CONSTEXPR_OR_CONST bool copy_alloc = allocator_traits_type::propagate_on_container_move_assignment::value; + + BOOST_IF_CONSTEXPR (copy_alloc || get_allocator_ref() == x.get_allocator_ref()) + { + this->clear(); + this->deallocate_buffer(); + + if (copy_alloc) + { + this->get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + m_.capacity = x.m_.capacity; + m_.buffer = x.m_.buffer; + m_.front_idx = x.m_.front_idx; + m_.back_idx = x.m_.back_idx; + + // leave x in valid state + x.m_.capacity = 0u; + x.m_.buffer = pointer(); + x.m_.back_idx = x.m_.front_idx = 0; + } + else + { + // if the allocator shouldn't be copied and they do not compare equal + // we can't steal memory. + + move_iterator xbegin = boost::make_move_iterator(x.begin()); + move_iterator xend = boost::make_move_iterator(x.end()); + + if (copy_alloc) + { + get_allocator_ref() = boost::move(x.get_allocator_ref()); + } + + if (capacity() >= x.size()) + { + overwrite_buffer(xbegin, xend); + } + else + { + allocate_and_copy_range(xbegin, xend); + } + } + + BOOST_ASSERT(invariants_ok()); + + return *this; + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** + * **Effects**: Copies elements of `il` to `*this`. Previously + * held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and [CopyAssignable]. + * + * **Postcondition**: `this->size() == il.size()`, the elements of + * `*this` are copies of elements in `il` in the same order. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `T` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Returns**: `*this`. + * + * **Complexity**: Linear in the size of `il` and `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + devector& operator=(std::initializer_list il) + { + assign(il.begin(), il.end()); + return *this; + } + #endif + + /** + * **Effects**: Replaces elements of `*this` with a copy of `[first,last)`. + * Previously held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [EmplaceConstructible] from `*first`. If the specified iterator + * does not meet the forward iterator requirements, `T` shall be also [MoveInsertable] into `*this`. + * + * **Precondition**: `first` and `last` are not iterators into `*this`. + * + * **Postcondition**: `size() == N`, where `N` is the distance between `first` and `last`. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `*first` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the distance between `first` and `last`. + * Makes a single reallocation at most if the iterators `first` and `last` + * are of forward, bidirectional, or random access categories. It makes + * `O(log(N))` reallocations if they are just input iterators. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + template + void assign(InputIterator first, InputIterator last + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + { + first = overwrite_buffer_impl(first, last, dtl::false_()); + while (first != last) + { + this->emplace_back(*first++); + } + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + void assign(ForwardIterator first, ForwardIterator last + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + { + const size_type n = boost::container::iterator_distance(first, last); + + if (capacity() >= n) + { + overwrite_buffer(first, last); + } + else + { + allocate_and_copy_range(first, last); + } + + BOOST_ASSERT(invariants_ok()); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + /** + * **Effects**: Replaces elements of `*this` with `n` copies of `u`. + * Previously held elements get copy assigned to or destroyed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and + * [CopyAssignable]. + * + * **Precondition**: `u` is not a reference into `*this`. + * + * **Postcondition**: `size() == n` and the elements of + * `*this` are copies of `u`. + * + * **Exceptions**: Strong exception guarantee if `T` is nothrow copy assignable + * from `u` and `NothrowConstructible`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in `n` and the size of `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + void assign(size_type n, const T& u) + { + cvalue_iterator first(u, n); + cvalue_iterator last; + + assign(first, last); + } + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** **Equivalent to**: `assign(il.begin(), il.end())`. */ + void assign(std::initializer_list il) + { + assign(il.begin(), il.end()); + } + #endif + + /** + * **Returns**: A copy of the allocator associated with the container. + * + * **Complexity**: Constant. + */ + allocator_type get_allocator() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + const allocator_type &get_stored_allocator() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + allocator_type &get_stored_allocator() BOOST_NOEXCEPT + { + return static_cast(m_); + } + + // iterators + + /** + * **Returns**: A iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + iterator begin() BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: A constant iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_iterator begin() const BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: An iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + iterator end() BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A constant iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + const_iterator end() const BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A reverse iterator pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + reverse_iterator rbegin() BOOST_NOEXCEPT + { + return reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A constant reverse iterator + * pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator rbegin() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + reverse_iterator rend() BOOST_NOEXCEPT + { + return reverse_iterator(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator rend() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant iterator pointing to the first element in the devector, + * or the past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_iterator cbegin() const BOOST_NOEXCEPT + { + return m_.buffer + m_.front_idx; + } + + /** + * **Returns**: A constant iterator pointing past the last element of the container. + * + * **Complexity**: Constant. + */ + const_iterator cend() const BOOST_NOEXCEPT + { + return m_.buffer + m_.back_idx; + } + + /** + * **Returns**: A constant reverse iterator + * pointing to the first element in the reversed devector, + * or the reverse past the end iterator if the devector is empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator crbegin() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.back_idx); + } + + /** + * **Returns**: A constant reverse iterator pointing past the last element in the + * reversed container, or to the beginning of the reversed container if it's empty. + * + * **Complexity**: Constant. + */ + const_reverse_iterator crend() const BOOST_NOEXCEPT + { + return const_reverse_iterator(m_.buffer + m_.front_idx); + } + + // capacity + + /** + * **Returns**: True, if `size() == 0`, false otherwise. + * + * **Complexity**: Constant. + */ + bool empty() const BOOST_NOEXCEPT + { + return m_.front_idx == m_.back_idx; + } + + /** + * **Returns**: The number of elements the devector contains. + * + * **Complexity**: Constant. + */ + size_type size() const BOOST_NOEXCEPT + { + return m_.back_idx - m_.front_idx; + } + + /** + * **Returns**: The maximum number of elements the devector could possibly hold. + * + * **Complexity**: Constant. + */ + size_type max_size() const BOOST_NOEXCEPT + { + size_type alloc_max = allocator_traits_type::max_size(get_allocator_ref()); + size_type size_type_max = (size_type)-1; + return (alloc_max <= size_type_max) ? size_type(alloc_max) : size_type_max; + } + + /** + * **Returns**: The total number of elements that the devector can hold without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type capacity() const BOOST_NOEXCEPT + { + return m_.capacity; + } + + /** + * **Returns**: The total number of elements that can be pushed to the front of the + * devector without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type front_free_capacity() const BOOST_NOEXCEPT + { + return m_.front_idx; + } + + /** + * **Returns**: The total number of elements that can be pushed to the back of the + * devector without requiring reallocation. + * + * **Complexity**: Constant. + */ + size_type back_free_capacity() const BOOST_NOEXCEPT + { + return m_.capacity - m_.back_idx; + } + + /** **Equivalent to**: `resize_back(sz)` */ + void resize(size_type sz) { resize_back(sz); } + + /** **Equivalent to**: `resize_back(sz, c)` */ + void resize(size_type sz, const T& c) { resize_back(sz, c); } + + /** + * **Effects**: If `sz` is greater than the size of `*this`, + * additional value-initialized elements are inserted + * to the front. Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the front. + * + * **Requires**: T shall be [MoveInsertable] into *this and [DefaultConstructible]. + * + * **Postcondition**: `sz == size()`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + */ + void resize_front(size_type sz) + { + resize_front_impl(sz); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: If `sz` is greater than the size of `*this`, + * copies of `c` are inserted to the front. + * Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the front. + * + * **Postcondition**: `sz == size()`. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + */ + void resize_front(size_type sz, const T& c) + { + resize_front_impl(sz, c); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: If `sz` is greater than the size of `*this`, + * additional value-initialized elements are inserted + * to the back. Invalidates iterators if reallocation is needed. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the back. + * + * **Requires**: T shall be [MoveInsertable] into *this and [DefaultConstructible]. + * + * **Postcondition**: `sz == size()`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [DefaultConstructible]: http://en.cppreference.com/w/cpp/concept/DefaultConstructible + */ + void resize_back(size_type sz) + { + resize_back_impl(sz); + BOOST_ASSERT(invariants_ok()); + } + + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: If `sz` is greater than the size of `*this`, + * copies of `c` are inserted to the back. + * If `sz` is smaller than than the size of `*this`, + * elements are popped from the back. + * + * **Postcondition**: `sz == size()`. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of `*this` and `sz`. + */ + void resize_back(size_type sz, const T& c) + { + resize_back_impl(sz, c); + BOOST_ASSERT(invariants_ok()); + } + + // unsafe uninitialized resize methods + + /** + * **Unsafe method**, use with care. + * + * **Effects**: Changes the size of the devector without properly + * initializing the extra or destroying the superfluous elements. + * If `n < size()`, elements are removed from the front without + * getting destroyed; if `n > size()`, uninitialized elements are added + * before the first element at the front. + * Invalidates iterators if reallocation is needed. + * + * **Postcondition**: `size() == n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `size()` if `capacity() < n`, constant otherwise. + * + * **Remarks**: The devector does not keep track of initialization of the elements: + * Elements without a trivial destructor must be manually destroyed before shrinking, + * elements without a trivial constructor must be initialized after growing. + */ +/* + void unsafe_uninitialized_resize_front(size_type n) + { + if (n > size()) + { + unsafe_uninitialized_grow_front(n); + } + else + { + unsafe_uninitialized_shrink_front(n); + } + } +*/ + /** + * **Unsafe method**, use with care. + * + * **Effects**: Changes the size of the devector without properly + * initializing the extra or destroying the superfluous elements. + * If `n < size()`, elements are removed from the back without + * getting destroyed; if `n > size()`, uninitialized elements are added + * after the last element at the back. + * Invalidates iterators if reallocation is needed. + * + * **Postcondition**: `size() == n`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in `size()` if `capacity() < n`, constant otherwise. + * + * **Remarks**: The devector does not keep track of initialization of the elements: + * Elements without a trivial destructor must be manually destroyed before shrinking, + * elements without a trivial constructor must be initialized after growing. + */ +/* + void unsafe_uninitialized_resize_back(size_type n) + { + if (n > size()) + { + unsafe_uninitialized_grow_back(n); + } + else + { + unsafe_uninitialized_shrink_back(n); + } + } +*/ + // reserve promise: + // after reserve_[front,back](n), n - size() push_[front,back] will not allocate + + /** **Equivalent to**: `reserve_back(new_capacity)` */ + void reserve(size_type new_capacity) { reserve_back(new_capacity); } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Ensures that `n` elements can be pushed to the front + * without requiring reallocation, where `n` is `new_capacity - size()`, + * if `n` is positive. Otherwise, there are no effects. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Complexity**: Linear in the size of *this. + * + * **Exceptions**: Strong exception guarantee. + * + * **Throws**: `length_error` if `new_capacity > max_size()`. + */ + void reserve_front(size_type new_capacity) + { + if (front_capacity() >= new_capacity) { return; } + + reallocate_at(new_capacity + back_free_capacity(), new_capacity - size()); + + BOOST_ASSERT(invariants_ok()); + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Ensures that `n` elements can be pushed to the back + * without requiring reallocation, where `n` is `new_capacity - size()`, + * if `n` is positive. Otherwise, there are no effects. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Complexity**: Linear in the size of *this. + * + * **Exceptions**: Strong exception guarantee. + * + * **Throws**: length_error if `new_capacity > max_size()`. + */ + void reserve_back(size_type new_capacity) + { + if (back_capacity() >= new_capacity) { return; } + + reallocate_at(new_capacity + front_free_capacity(), m_.front_idx); + + BOOST_ASSERT(invariants_ok()); + } + + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Reduces `capacity()` to `size()`. Invalidates iterators. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Linear in the size of *this. + */ + void shrink_to_fit() + { + if(this->front_capacity() || this->back_capacity()) + this->reallocate_at(size(), 0); + } + + // element access: + + /** + * **Returns**: A reference to the `n`th element in the devector. + * + * **Precondition**: `n < size()`. + * + * **Complexity**: Constant. + */ + reference operator[](size_type n) BOOST_NOEXCEPT + { + BOOST_ASSERT(n < size()); + + return *(begin() + n); + } + + /** + * **Returns**: A constant reference to the `n`th element in the devector. + * + * **Precondition**: `n < size()`. + * + * **Complexity**: Constant. + */ + const_reference operator[](size_type n) const BOOST_NOEXCEPT + { + BOOST_ASSERT(n < size()); + + return *(begin() + n); + } + + /** + * **Returns**: A reference to the `n`th element in the devector. + * + * **Throws**: `std::out_of_range`, if `n >= size()`. + * + * **Complexity**: Constant. + */ + reference at(size_type n) + { + if (size() <= n) + throw_out_of_range("devector::at out of range"); + return (*this)[n]; + } + + /** + * **Returns**: A constant reference to the `n`th element in the devector. + * + * **Throws**: `std::out_of_range`, if `n >= size()`. + * + * **Complexity**: Constant. + */ + const_reference at(size_type n) const + { + if (size() <= n) + throw_out_of_range("devector::at out of range"); + return (*this)[n]; + } + + /** + * **Returns**: A reference to the first element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + reference front() BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A constant reference to the first element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + const_reference front() const BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.front_idx); + } + + /** + * **Returns**: A reference to the last element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + reference back() BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.back_idx -1); + } + + /** + * **Returns**: A constant reference to the last element in the devector. + * + * **Precondition**: `!empty()`. + * + * **Complexity**: Constant. + */ + const_reference back() const BOOST_NOEXCEPT + { + BOOST_ASSERT(!empty()); + + return *(m_.buffer + m_.back_idx -1); + } + + /** + * **Returns**: A pointer to the underlying array serving as element storage. + * The range `[data(); data() + size())` is always valid. For a non-empty devector, + * `data() == &front()`. + * + * **Complexity**: Constant. + */ + T* data() BOOST_NOEXCEPT + { + return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; + } + + /** + * **Returns**: A constant pointer to the underlying array serving as element storage. + * The range `[data(); data() + size())` is always valid. For a non-empty devector, + * `data() == &front()`. + * + * **Complexity**: Constant. + */ + const T* data() const BOOST_NOEXCEPT + { + return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; + } + + // modifiers: + + /** + * **Effects**: Pushes a new element to the front of the devector. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [EmplaceConstructible] from `args` and [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + void emplace_front(Args&&... args) + { + if (front_free_capacity()) // fast path + { + this->alloc_construct(m_.buffer + m_.front_idx - 1, boost::forward(args)...); + --m_.front_idx; + } + else + { + this->emplace_reallocating_slow_path(true, 0, boost::forward(args)...); + } + + BOOST_ASSERT(invariants_ok()); + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void emplace_front(BOOST_MOVE_UREF##N)\ + {\ + if (front_free_capacity())\ + {\ + this->alloc_construct(m_.buffer + m_.front_idx - 1 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + --m_.front_idx;\ + }\ + else\ + {\ + this->emplace_reallocating_slow_path(true, 0 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + \ + BOOST_ASSERT(invariants_ok());\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE_FRONT + + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Pushes the copy of `x` to the front of the devector. + * Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + */ + void push_front(const T& x); + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Move constructs a new element at the front of the devector using `x`. + * Invalidates iterators if reallocation is needed. + * (`front_free_capacity() == 0`) + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee, not regarding the state of `x`. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `front_free_capacity() > 0`) + */ + void push_front(T&& x); + + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + /** + * **Effects**: Removes the first element of `*this`. + * + * **Precondition**: `!empty()`. + * + * **Postcondition**: `front_free_capacity()` is incremented by 1. + * + * **Complexity**: Constant. + */ + void pop_front() BOOST_NOEXCEPT + { + BOOST_ASSERT(! empty()); + allocator_traits_type::destroy(get_allocator_ref(), m_.buffer + m_.front_idx); + ++m_.front_idx; + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Pushes a new element to the back of the devector. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [EmplaceConstructible] from `args` and [MoveInsertable] into `*this`, + * and [MoveAssignable]. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + BOOST_CONTAINER_FORCEINLINE void emplace_back(Args&&... args) + { + if (this->back_free_capacity()){ + this->alloc_construct(m_.buffer + m_.back_idx, boost::forward(args)...); + ++m_.back_idx; + } + else { + this->emplace_reallocating_slow_path(false, size(), boost::forward(args)...); + } + BOOST_ASSERT(invariants_ok()); + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_MOVE_UREF##N)\ + {\ + if (this->back_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.back_idx BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ++m_.back_idx;\ + }\ + else {\ + this->emplace_reallocating_slow_path(false, size() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + BOOST_ASSERT(invariants_ok());\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE_BACK + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * + * **Effects**: Pushes the copy of `x` to the back of the devector. + * Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [CopyInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + */ + void push_back(const T& x); + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: Move constructs a new element at the back of the devector using `x`. + * Invalidates iterators if reallocation is needed. + * (`back_free_capacity() == 0`) + * + * **Requires**: `T` shall be [MoveInsertable] into `*this`. + * + * **Exceptions**: Strong exception guarantee, not regarding the state of `x`. + * + * **Complexity**: Amortized constant in the size of `*this`. + * (Constant, if `back_free_capacity() > 0`) + */ + void push_back(T&& x); + + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + /** + * **Effects**: Removes the last element of `*this`. + * + * **Precondition**: `!empty()`. + * + * **Postcondition**: `back_free_capacity()` is incremented by 1. + * + * **Complexity**: Constant. + */ + void pop_back() BOOST_NOEXCEPT + { + BOOST_ASSERT(! empty()); + --m_.back_idx; + allocator_traits_type::destroy(get_allocator_ref(), m_.buffer + m_.back_idx); + BOOST_ASSERT(invariants_ok()); + } + + /** + * **Effects**: Constructs a new element before the element pointed by `position`. + * The element is constructed in-place, using the perfect forwarded `args` + * as constructor arguments. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [EmplaceConstructible], and [MoveInsertable] into `*this`, + * and [MoveAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + iterator emplace(const_iterator position, Args&&... args) + { + BOOST_ASSERT(position >= begin()); + BOOST_ASSERT(position <= end()); + + if (position == end() && back_free_capacity()) // fast path + { + this->alloc_construct(m_.buffer + m_.back_idx, boost::forward(args)...); + ++m_.back_idx; + return end() - 1; + } + else if (position == begin() && front_free_capacity()) // secondary fast path + { + this->alloc_construct(m_.buffer + (m_.front_idx - 1), boost::forward(args)...); + --m_.front_idx; + return begin(); + } + else + { + size_type new_elem_index = position - begin(); + return this->emplace_slow_path(new_elem_index, boost::forward(args)...); + } + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_EMPLACE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + BOOST_ASSERT(position >= begin());\ + BOOST_ASSERT(position <= end());\ + \ + if (position == end() && back_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.back_idx BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ++m_.back_idx;\ + return end() - 1;\ + }\ + else if (position == begin() && front_free_capacity()){\ + this->alloc_construct(m_.buffer + m_.front_idx - 1 BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + --m_.front_idx;\ + return begin();\ + }\ + else{\ + size_type new_elem_index = position - begin();\ + return this->emplace_slow_path(new_elem_index BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_EMPLACE) + #undef BOOST_CONTAINER_DEVECTOR_EMPLACE + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + /** + * **Effects**: Copy constructs a new element before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, const T &x); + + /** + * **Effects**: Move constructs a new element before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [MoveInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the newly constructed element. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable` (not regarding the state of `x`), + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this`. + * + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) + #endif + + /** + * **Effects**: Copy constructs `n` elements before the element pointed by `position`, + * using `x` as constructor argument. Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [CopyInsertable] into `*this` and and [CopyAssignable]. + * + * **Returns**: Iterator pointing to the first inserted element, or `position`, if `n` is zero. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Complexity**: Linear in the size of `*this` and `n`. + * + * [CopyInsertable]: http://en.cppreference.com/w/cpp/concept/CopyInsertable + * [CopyAssignable]: http://en.cppreference.com/w/cpp/concept/CopyAssignable + */ + iterator insert(const_iterator position, size_type n, const T& x) + { + cvalue_iterator first(x, n); + cvalue_iterator last = first + n; + return insert_range(position, first, last); + } + + /** + * **Effects**: Copy constructs elements before the element pointed by position + * using each element in the rage pointed by `first` and `last` as constructor arguments. + * Invalidates iterators if reallocation is needed. + * + * **Requires**: `T` shall be [EmplaceConstructible] into `*this` from `*first`. If the specified iterator + * does not meet the forward iterator requirements, `T` shall also be [MoveInsertable] into `*this` + * and [MoveAssignable]. + * + * **Precondition**: `first` and `last` are not iterators into `*this`. + * + * **Returns**: Iterator pointing to the first inserted element, or `position`, if `first == last`. + * + * **Complexity**: Linear in the size of `*this` and `N` (where `N` is the distance between `first` and `last`). + * Makes only `N` calls to the constructor of `T` and no reallocations if iterators `first` and `last` + * are of forward, bidirectional, or random access categories. It makes 2N calls to the copy constructor of `T` + * and allocates memory twice at most if they are just input iterators. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowConstructible` + * and `NothrowAssignable`, Basic exception guarantee otherwise. + * + * **Remarks**: Each iterator in the range `[first,last)` shall be dereferenced exactly once, + * unless an exception is thrown. + * + * [EmplaceConstructible]: http://en.cppreference.com/w/cpp/concept/EmplaceConstructible + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + */ + template + iterator insert(const_iterator position, InputIterator first, InputIterator last + //Input iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_not_input_iterator + >::type * = 0) + ) + { + if (position == end()) + { + size_type insert_index = size(); + + for (; first != last; ++first) + { + this->emplace_back(*first); + } + + return begin() + insert_index; + } + else + { + const size_type insert_index = static_cast(position - this->cbegin()); + const size_type old_size = static_cast(this->size()); + + for (; first != last; ++first) { + this->emplace_back(*first); + } + iterator rit (this->begin() + insert_index); + boost::movelib::rotate_gcd(rit, this->begin() + old_size, this->begin() + this->size()); + return rit; + } + } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + iterator insert(const_iterator position, ForwardIterator first, ForwardIterator last + //Other iterators + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or + < void + BOOST_MOVE_I dtl::is_convertible + BOOST_MOVE_I dtl::is_input_iterator + >::type * = 0) + ) + { + return insert_range(position, first, last); + } + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + /** **Equivalent to**: `insert(position, il.begin(), il.end())` */ + iterator insert(const_iterator position, std::initializer_list il) + { + return insert_range(position, il.begin(), il.end()); + } + #endif + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the element pointed by `position` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `position` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element immediately following the erased element + * prior to its erasure. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this`. + */ + iterator erase(const_iterator position) + { + return erase(position, position + 1); + } + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the range `[first,last)` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `[first,last)` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element pointed to by `last` prior to any elements + * being erased. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this` + * plus the distance between `first` and `last`. + */ + iterator erase(const_iterator first, const_iterator last) + { + iterator nc_first = begin() + (first - begin()); + iterator nc_last = begin() + (last - begin()); + return erase(nc_first, nc_last); + } + + /** + * [MoveAssignable]: http://en.cppreference.com/w/cpp/concept/MoveAssignable + * + * **Effects**: Destroys the range `[first,last)` and removes it from the devector. + * Invalidates iterators. + * + * **Requires**: `T` shall be [MoveAssignable]. + * + * **Precondition**: `[first,last)` must be in the range of `[begin(), end())`. + * + * **Returns**: Iterator pointing to the element pointed to by `last` prior to any elements + * being erased. If no such element exists, `end()` is returned. + * + * **Exceptions**: Strong exception guarantee if `T` is `NothrowAssignable`, + * Basic exception guarantee otherwise. + * + * **Complexity**: Linear in half the size of `*this`. + */ + iterator erase(iterator first, iterator last) + { + size_type front_distance = last - begin(); + size_type back_distance = end() - first; + size_type n = boost::container::iterator_distance(first, last); + + if (front_distance < back_distance) + { + // move n to the right + boost::container::move_backward(begin(), first, last); + + for (iterator i = begin(); i != begin() + n; ++i) + { + allocator_traits_type::destroy(get_allocator_ref(), i); + } + //n is always less than max stored_size_type + m_.set_front_idx(m_.front_idx + n); + + BOOST_ASSERT(invariants_ok()); + return last; + } + else { + // move n to the left + boost::container::move(last, end(), first); + + for (iterator i = end() - n; i != end(); ++i) + { + allocator_traits_type::destroy(get_allocator_ref(), i); + } + //n is always less than max stored_size_type + m_.set_back_idx(m_.back_idx - n); + + BOOST_ASSERT(invariants_ok()); + return first; + } + } + + /** + * [MoveInsertable]: http://en.cppreference.com/w/cpp/concept/MoveInsertable + * + * **Effects**: exchanges the contents of `*this` and `b`. + * + * **Requires**: instances of `T` must be swappable by unqualified call of `swap` + * and `T` must be [MoveInsertable] into `*this`. + * + * **Precondition**: The allocators should allow propagation or should compare equal. + * + * **Exceptions**: Basic exceptions guarantee if not `noexcept`. + * + * **Complexity**: Constant. + */ + void swap(devector& b) + BOOST_NOEXCEPT_IF( allocator_traits_type::propagate_on_container_swap::value + || allocator_traits_type::is_always_equal::value) + { + BOOST_CONSTEXPR_OR_CONST bool propagate_alloc = allocator_traits_type::propagate_on_container_swap::value; + BOOST_ASSERT(propagate_alloc || get_allocator_ref() == b.get_allocator_ref()); // else it's undefined behavior + + swap_big_big(*this, b); + + // swap indices + boost::adl_move_swap(m_.front_idx, b.m_.front_idx); + boost::adl_move_swap(m_.back_idx, b.m_.back_idx); + + //And now swap the allocator + dtl::swap_alloc(this->get_allocator_ref(), b.get_allocator_ref(), dtl::bool_()); + + BOOST_ASSERT( invariants_ok()); + BOOST_ASSERT(b.invariants_ok()); + } + + /** + * **Effects**: Destroys all elements in the devector. + * Invalidates all references, pointers and iterators to the + * elements of the devector. + * + * **Postcondition**: `empty() && front_free_capacity() == 0 + * && back_free_capacity() == old capacity`. + * + * **Complexity**: Linear in the size of `*this`. + * + * **Remarks**: Does not free memory. + */ + void clear() BOOST_NOEXCEPT + { + destroy_elements(begin(), end()); + m_.front_idx = m_.back_idx = 0; + } + + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const devector& x, const devector& y) + { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const devector& x, const devector& y) + { return !(x == y); } + + friend bool operator< (const devector& x, const devector& y) + { return boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const devector& x, const devector& y) + { return y < x; } + + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const devector& x, const devector& y) + { return !(y < x); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const devector& x, const devector& y) + { return !(x < y); } + + BOOST_CONTAINER_FORCEINLINE friend void swap(devector& x, devector& y) + { x.swap(y); } + + private: + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + T* raw_begin() BOOST_NOEXCEPT + { return boost::movelib::to_raw_pointer(m_.buffer) + m_.front_idx; } + + T* raw_end() BOOST_NOEXCEPT + { return boost::movelib::to_raw_pointer(m_.buffer) + m_.back_idx; } + + + template + BOOST_CONTAINER_FORCEINLINE void priv_push_front(BOOST_FWD_REF(U) u) + { + this->emplace_front(boost::forward(u)); + } + + template + BOOST_CONTAINER_FORCEINLINE void priv_push_back(BOOST_FWD_REF(U) u) + { + this->emplace_back(boost::forward(u)); + } + + template + BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator pos, BOOST_FWD_REF(U) u) + { + return this->emplace(pos, boost::forward(u)); + } + + // allocator_type wrappers + + BOOST_CONTAINER_FORCEINLINE allocator_type& get_allocator_ref() BOOST_NOEXCEPT + { + return static_cast(m_); + } + + BOOST_CONTAINER_FORCEINLINE const allocator_type& get_allocator_ref() const BOOST_NOEXCEPT + { + return static_cast(m_); + } + + pointer allocate(size_type capacity) + { + //First detect overflow on smaller stored_size_types + if (capacity > stored_size_type(-1)){ + boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); + } + //(clamp_by_stored_size_type)(prefer_in_recvd_out_size, stored_size_type()); + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + ++m_.capacity_alloc_count; + #endif // BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + return allocator_traits_type::allocate(get_allocator_ref(), capacity); + } + + void destroy_elements(pointer begin, pointer end) + { + for (; begin != end; ++begin) + { + allocator_traits_type::destroy(get_allocator_ref(), begin); + } + } + + void deallocate_buffer() + { + if (m_.buffer) + { + allocator_traits_type::deallocate(get_allocator_ref(), m_.buffer, m_.capacity); + } + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + BOOST_CONTAINER_FORCEINLINE void alloc_construct(pointer dst, Args&&... args) + { + allocator_traits_type::construct( + get_allocator_ref(), + dst, + boost::forward(args)... + ); + } + + template + void construct_n(pointer buffer, size_type n, Args&&... args) + { + detail::construction_guard ctr_guard(buffer, get_allocator_ref()); + guarded_construct_n(buffer, n, ctr_guard, boost::forward(args)...); + ctr_guard.release(); + } + + template + void guarded_construct_n(pointer buffer, size_type n, detail::construction_guard& ctr_guard, Args&&... args) + { + for (size_type i = 0; i < n; ++i) { + this->alloc_construct(buffer + i, boost::forward(args)...); + ctr_guard.extend(); + } + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE void alloc_construct(pointer dst BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits_type::construct(\ + get_allocator_ref(), dst BOOST_MOVE_I##N BOOST_MOVE_FWD##N );\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void construct_n(pointer buffer, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + detail::construction_guard ctr_guard(buffer, get_allocator_ref());\ + guarded_construct_n(buffer, n, ctr_guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ctr_guard.release();\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void guarded_construct_n(pointer buffer, size_type n, detail::construction_guard& ctr_guard BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + for (size_type i = 0; i < n; ++i) {\ + this->alloc_construct(buffer + i BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ctr_guard.extend();\ + }\ + } + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT) + #undef BOOST_CONTAINER_DEVECTOR_ALLOC_CONSTRUCT + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + size_type front_capacity() const + { + return m_.back_idx; + } + + size_type back_capacity() const + { + return m_.capacity - m_.front_idx; + } + + size_type calculate_new_capacity(size_type requested_capacity) + { + size_type max = allocator_traits_type::max_size(this->get_allocator_ref()); + (clamp_by_stored_size_type)(max, stored_size_type()); + const size_type remaining_additional_cap = max - size_type(m_.capacity); + const size_type min_additional_cap = requested_capacity - size_type(m_.capacity); + if ( remaining_additional_cap < min_additional_cap ) + boost::container::throw_length_error("devector: get_next_capacity, max size exceeded"); + + return growth_factor_type()( size_type(m_.capacity), min_additional_cap, max); + } + + void buffer_move_or_copy(pointer dst) + { + detail::construction_guard guard(dst, get_allocator_ref()); + + buffer_move_or_copy(dst, guard); + + guard.release(); + } + + void buffer_move_or_copy(pointer dst, detail::construction_guard& guard) + { + opt_move_or_copy(begin(), end(), dst, guard); + + destroy_elements(data(), data() + size()); + deallocate_buffer(); + } + + void opt_move_or_copy(pointer begin, pointer end, pointer dst) + { + typedef typename dtl::if_c + < boost::move_detail::is_nothrow_copy_constructible::value || boost::is_nothrow_move_constructible::value + , detail::null_construction_guard + , detail::construction_guard + >::type guard_t; + + guard_t guard(dst, get_allocator_ref()); + + opt_move_or_copy(begin, end, dst, guard); + + guard.release(); + } + + template + void opt_move_or_copy(pointer begin, pointer end, pointer dst, Guard& guard) + { + // if trivial copy and default allocator, memcpy + boost::container::uninitialized_move_alloc(get_allocator_ref(), begin, end, dst); + guard.extend(); + } + + template + void opt_copy(Iterator begin, Iterator end, pointer dst) + { + typedef typename dtl::if_c + < boost::move_detail::is_nothrow_copy_constructible::value + , detail::null_construction_guard + , detail::construction_guard + >::type guard_t; + + guard_t guard(dst, get_allocator_ref()); + + opt_copy(begin, end, dst, guard); + + guard.release(); + } + + template + void opt_copy(Iterator begin, Iterator end, pointer dst, Guard& guard) + { + while (begin != end) + { + this->alloc_construct(dst++, *begin++); + guard.extend(); + } + } + + template + void opt_copy(const_pointer begin, const_pointer end, pointer dst, Guard& guard) + { + // if trivial copy and default allocator, memcpy + boost::container::uninitialized_copy_alloc(get_allocator_ref(), begin, end, dst); + guard.extend(); + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + template + void resize_front_impl(size_type sz , Args&&... args) + { + if (sz > size()) + { + const size_type n = sz - size(); + + if (sz <= front_capacity()) + { + construct_n(m_.buffer + m_.front_idx - n, n, boost::forward(args)...); + m_.set_front_idx(m_.front_idx - n); + } + else + { + resize_front_slow_path(sz, n, boost::forward(args)...); + } + } + else { + while (this->size() > sz) + { + this->pop_front(); + } + } + } + + template + void resize_front_slow_path(size_type sz, size_type n, Args&&... args) + { + const size_type new_capacity = calculate_new_capacity(sz + back_free_capacity()); + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + const size_type new_old_elem_index = new_capacity - size(); + const size_type new_elem_index = new_old_elem_index - n; + + detail::construction_guard guard(new_buffer + new_elem_index, get_allocator_ref()); + guarded_construct_n(new_buffer + new_elem_index, n, guard, boost::forward(args)...); + + buffer_move_or_copy(new_buffer + new_old_elem_index, guard); + + guard.release(); + new_buffer_guard.release(); + + m_.buffer = new_buffer; + m_.set_capacity(new_capacity); + m_.set_back_idx(new_old_elem_index + m_.back_idx - m_.front_idx); + m_.set_front_idx(new_elem_index); + } + + template + void resize_back_impl(size_type sz, Args&&... args) + { + if (sz > size()) + { + const size_type n = sz - size(); + + if (sz <= back_capacity()) + { + construct_n(m_.buffer + m_.back_idx, n, boost::forward(args)...); + m_.set_back_idx(m_.back_idx + n); + } + else + { + resize_back_slow_path(sz, n, boost::forward(args)...); + } + } + else + { + while (size() > sz) + { + pop_back(); + } + } + } + + template + void resize_back_slow_path(size_type sz, size_type n, Args&&... args) + { + const size_type new_capacity = calculate_new_capacity(sz + front_free_capacity()); + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + detail::construction_guard guard(new_buffer + m_.back_idx, get_allocator_ref()); + guarded_construct_n(new_buffer + m_.back_idx, n, guard, boost::forward(args)...); + + buffer_move_or_copy(new_buffer + m_.front_idx); + + guard.release(); + new_buffer_guard.release(); + + m_.buffer = new_buffer; + m_.set_capacity(new_capacity); + m_.set_back_idx(m_.back_idx + n); + } + + template + iterator emplace_slow_path(size_type new_elem_index, Args&&... args) + { + pointer position = begin() + new_elem_index; + + // prefer moving front to access memory forward if there are less elems to move + bool prefer_move_front = new_elem_index <= size()/2; + + if (front_free_capacity() && (!back_free_capacity() || prefer_move_front)) + { + BOOST_ASSERT(size() >= 1); + + // move things closer to the front a bit + + // avoid invalidating any reference in args later + T tmp(boost::forward(args)...); + + // construct at front - 1 from front (no guard) + this->alloc_construct(begin() - 1, boost::move(*begin())); + + // move front half left + boost::move(begin() + 1, position, begin()); + --m_.front_idx; + + // move assign new elem before pos + --position; + *position = boost::move(tmp); + + return position; + } + else if (back_free_capacity()) { + BOOST_ASSERT(size() >= 1); + + // move things closer to the end a bit + + // avoid invalidating any reference in args later + T tmp(boost::forward(args)...); + + // construct at back + 1 from back (no guard) + this->alloc_construct(end(), boost::move(back())); + + // move back half right + boost::container::move_backward(position, end() - 1, end()); + ++m_.back_idx; + + // move assign new elem to pos + *position = boost::move(tmp); + + return position; + } + else + { + return emplace_reallocating_slow_path(prefer_move_front, new_elem_index, boost::forward(args)...); + } + } + + template + pointer emplace_reallocating_slow_path(bool make_front_free, size_type new_elem_index, Args&&... args) + { + // reallocate + size_type new_capacity = calculate_new_capacity(capacity() + 1); + pointer new_buffer = allocate(new_capacity); + + // guard allocation + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + size_type new_front_index = (make_front_free) + ? new_capacity - back_free_capacity() - size() - 1 + : m_.front_idx; + + iterator new_begin = new_buffer + new_front_index; + iterator new_position = new_begin + new_elem_index; + iterator old_position = begin() + new_elem_index; + + // construct new element (and guard it) + this->alloc_construct(new_position, boost::forward(args)...); + + detail::construction_guard second_half_guard(new_position, get_allocator_ref()); + second_half_guard.extend(); + + // move front-pos (possibly guarded) + detail::construction_guard first_half_guard(new_begin, get_allocator_ref()); + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard); + + // move pos+1-end (possibly guarded) + opt_move_or_copy(old_position, end(), new_position + 1, second_half_guard); + + // cleanup + destroy_elements(begin(), end()); + deallocate_buffer(); + + // release alloc and other guards + second_half_guard.release(); + first_half_guard.release(); + new_buffer_guard.release(); + + // rebind members + m_.set_capacity(new_capacity); + m_.buffer = new_buffer; + m_.set_back_idx(new_front_index + size() + 1); + m_.set_front_idx(new_front_index); + + return new_position; + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_DEVECTOR_SLOW_PATH(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_front_impl(size_type sz BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + if (sz > size())\ + {\ + const size_type n = sz - size();\ + if (sz <= front_capacity()){\ + construct_n(m_.buffer + m_.front_idx - n, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + m_.set_front_idx(m_.front_idx - n);\ + }\ + else\ + {\ + resize_front_slow_path(sz, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + else {\ + while (this->size() > sz)\ + {\ + this->pop_front();\ + }\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_front_slow_path(size_type sz, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + const size_type new_capacity = calculate_new_capacity(sz + back_free_capacity());\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + \ + const size_type new_old_elem_index = new_capacity - size();\ + const size_type new_elem_index = new_old_elem_index - n;\ + \ + detail::construction_guard guard(new_buffer + new_elem_index, get_allocator_ref());\ + guarded_construct_n(new_buffer + new_elem_index, n, guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + \ + buffer_move_or_copy(new_buffer + new_old_elem_index, guard);\ + \ + guard.release();\ + new_buffer_guard.release();\ + m_.buffer = new_buffer;\ + m_.set_capacity(new_capacity);\ + m_.set_back_idx(new_old_elem_index + m_.back_idx - m_.front_idx);\ + m_.set_front_idx(new_elem_index);\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_back_impl(size_type sz BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + if (sz > size())\ + {\ + const size_type n = sz - size();\ + \ + if (sz <= back_capacity())\ + {\ + construct_n(m_.buffer + m_.back_idx, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + m_.set_back_idx(m_.back_idx + n);\ + }\ + else\ + {\ + resize_back_slow_path(sz, n BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + else\ + {\ + while (size() > sz)\ + {\ + pop_back();\ + }\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + void resize_back_slow_path(size_type sz, size_type n BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + const size_type new_capacity = calculate_new_capacity(sz + front_free_capacity());\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + \ + detail::construction_guard guard(new_buffer + m_.back_idx, get_allocator_ref());\ + guarded_construct_n(new_buffer + m_.back_idx, n, guard BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + \ + buffer_move_or_copy(new_buffer + m_.front_idx);\ + \ + guard.release();\ + new_buffer_guard.release();\ + \ + m_.buffer = new_buffer;\ + m_.set_capacity(new_capacity);\ + m_.set_back_idx(m_.back_idx + n);\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + iterator emplace_slow_path(size_type new_elem_index BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + pointer position = begin() + new_elem_index;\ + \ + bool prefer_move_front = new_elem_index <= size()/2;\ + \ + if (front_free_capacity() && (!back_free_capacity() || prefer_move_front))\ + {\ + BOOST_ASSERT(size() >= 1);\ + typename dtl::aligned_storage::value>::type v;\ + T *vp = reinterpret_cast(v.data);\ + allocator_traits_type::construct(get_stored_allocator(), vp BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + T &tmp = *vp;\ + dtl::value_destructor on_exit(get_stored_allocator(), tmp); (void)on_exit;\ + \ + this->alloc_construct(begin() - 1, boost::move(*begin()));\ + boost::move(begin() + 1, position, begin());\ + --m_.front_idx;\ + --position;\ + *position = boost::move(tmp);\ + return position;\ + }\ + else if (back_free_capacity()) {\ + BOOST_ASSERT(size() >= 1);\ + typename dtl::aligned_storage::value>::type v;\ + T *vp = reinterpret_cast(v.data);\ + allocator_traits_type::construct(get_stored_allocator(), vp BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + T &tmp = *vp;\ + dtl::value_destructor on_exit(get_stored_allocator(), tmp); (void)on_exit;\ + this->alloc_construct(end(), boost::move(back()));\ + boost::container::move_backward(position, end() - 1, end());\ + ++m_.back_idx;\ + *position = boost::move(tmp);\ + return position;\ + }\ + else {\ + return emplace_reallocating_slow_path(prefer_move_front, new_elem_index BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + pointer emplace_reallocating_slow_path(bool make_front_free, size_type new_elem_index BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + size_type new_capacity = calculate_new_capacity(capacity() + 1);\ + pointer new_buffer = allocate(new_capacity);\ + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref());\ + size_type new_front_index = (make_front_free)\ + ? new_capacity - back_free_capacity() - size() - 1\ + : m_.front_idx;\ + iterator new_begin = new_buffer + new_front_index;\ + iterator new_position = new_begin + new_elem_index;\ + iterator old_position = begin() + new_elem_index;\ + this->alloc_construct(new_position BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + detail::construction_guard second_half_guard(new_position, get_allocator_ref());\ + second_half_guard.extend();\ + detail::construction_guard first_half_guard(new_begin, get_allocator_ref());\ + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard);\ + opt_move_or_copy(old_position, end(), new_position + 1, second_half_guard);\ + destroy_elements(begin(), end());\ + deallocate_buffer();\ + second_half_guard.release();\ + first_half_guard.release();\ + new_buffer_guard.release();\ + m_.set_capacity(new_capacity);\ + m_.buffer = new_buffer;\ + m_.set_back_idx(new_front_index + size() + 1);\ + m_.set_front_idx(new_front_index);\ + return new_position;\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEVECTOR_SLOW_PATH) + #undef BOOST_CONTAINER_DEVECTOR_SLOW_PATH + + #endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) +/* + void unsafe_uninitialized_grow_front(size_type n) + { + BOOST_ASSERT(n >= size()); + + size_type need = n - size(); + + if (need > front_free_capacity()) + { + reallocate_at(n + back_free_capacity(), need); + } + + m_.set_front_idx(m_.front_idx - need); + } + + void unsafe_uninitialized_shrink_front(size_type n) + { + BOOST_ASSERT(n <= size()); + + size_type doesnt_need = size() - n; + m_.set_front_idx(m_.front_idx + doesnt_need); + } + + void unsafe_uninitialized_grow_back(size_type n) + { + BOOST_ASSERT(n >= size()); + + size_type need = n - size(); + + if (need > back_free_capacity()) + { + reallocate_at(n + front_free_capacity(), front_free_capacity()); + } + + m_.set_back_idx(m_.back_idx + need); + } + + void unsafe_uninitialized_shrink_back(size_type n) + { + BOOST_ASSERT(n <= size()); + + size_type doesnt_need = size() - n; + m_.set_back_idx(m_.back_idx - doesnt_need); + } +*/ + + void reallocate_at(size_type new_capacity, size_type buffer_offset) + { + pointer new_buffer = allocate(new_capacity); + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + buffer_move_or_copy(new_buffer + buffer_offset); + + new_buffer_guard.release(); + + m_.buffer = new_buffer; + //Safe cast, allocate() will handle stored_size_type overflow + m_.set_capacity(new_capacity); + m_.set_back_idx(m_.back_idx - m_.front_idx + buffer_offset); + m_.set_front_idx(buffer_offset); + + BOOST_ASSERT(invariants_ok()); + } + + template + iterator insert_range(const_iterator position, ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + + if (position == end() && back_free_capacity() >= n) {// fast path + iterator r(this->end()); + boost::container::uninitialized_copy_alloc(get_allocator_ref(), first, last, this->raw_end()); + m_.set_back_idx(m_.back_idx + n); + return r; + } + else if (position == begin() && front_free_capacity() >= n) { // secondary fast path + boost::container::uninitialized_copy_alloc(get_allocator_ref(), first, last, this->raw_begin() - n); + m_.set_front_idx(m_.front_idx - n); + return begin(); + } + else { + return insert_range_slow_path(position, first, last); + } + } + + template + iterator insert_range_slow_path(const_iterator position, ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + size_type index = position - begin(); + + if (front_free_capacity() + back_free_capacity() >= n) { + // if we move enough, it can be done without reallocation + + iterator middle = begin() + index; + n -= insert_range_slow_path_near_front(middle, first, n); + + if (n) { + insert_range_slow_path_near_back(middle, first, n); + } + + BOOST_ASSERT(first == last); + return begin() + index; + } + else { + const bool prefer_move_front = 2 * index <= size(); + return insert_range_reallocating_slow_path(prefer_move_front, index, first, n); + } + } + + template + size_type insert_range_slow_path_near_front(iterator position, Iterator& first, size_type n) + { + size_type n_front = dtl::min_value(front_free_capacity(), n); + iterator new_begin = begin() - n_front; + iterator ctr_pos = new_begin; + detail::construction_guard ctr_guard(ctr_pos, get_allocator_ref()); + + while (ctr_pos != begin()) { + this->alloc_construct(ctr_pos++, *(first++)); + ctr_guard.extend(); + } + + boost::movelib::rotate_gcd(new_begin, ctr_pos, position); + m_.set_front_idx(m_.front_idx - n_front); + + ctr_guard.release(); + + BOOST_ASSERT(invariants_ok()); + + return n_front; + } + + template + size_type insert_range_slow_path_near_back(iterator position, Iterator& first, size_type n) + { + const size_type n_back = dtl::min_value(back_free_capacity(), n); + iterator ctr_pos = end(); + + detail::construction_guard ctr_guard(ctr_pos, get_allocator_ref()); + + for (size_type i = 0; i < n_back; ++i) { + this->alloc_construct(ctr_pos++, *first++); + ctr_guard.extend(); + } + + boost::movelib::rotate_gcd(position, end(), ctr_pos); + m_.set_back_idx(m_.back_idx + n_back); + + ctr_guard.release(); + + BOOST_ASSERT(invariants_ok()); + + return n_back; + } + + template + iterator insert_range_reallocating_slow_path + (bool make_front_free, size_type new_elem_index, Iterator elems, size_type n) + { + // reallocate + const size_type new_capacity = calculate_new_capacity(capacity() + n); + pointer new_buffer = allocate(new_capacity); + + // guard allocation + allocation_guard new_buffer_guard(new_buffer, new_capacity, get_allocator_ref()); + + const size_type new_front_index = (make_front_free) + ? new_capacity - back_free_capacity() - size() - n + : m_.front_idx; + + const iterator new_begin = new_buffer + new_front_index; + const iterator new_position = new_begin + new_elem_index; + const iterator old_position = begin() + new_elem_index; + + // construct new element (and guard it) + iterator second_half_position = new_position; + detail::construction_guard second_half_guard(second_half_position, get_allocator_ref()); + + for (size_type i = 0; i < n; ++i) { + this->alloc_construct(second_half_position++, *(elems++)); + second_half_guard.extend(); + } + + // move front-pos (possibly guarded) + detail::construction_guard first_half_guard(new_begin, get_allocator_ref()); + opt_move_or_copy(begin(), old_position, new_begin, first_half_guard); + + // move pos+1-end (possibly guarded) + opt_move_or_copy(old_position, end(), second_half_position, second_half_guard); + + // cleanup + destroy_elements(begin(), end()); + deallocate_buffer(); + + // release alloc and other guards + second_half_guard.release(); + first_half_guard.release(); + new_buffer_guard.release(); + + // rebind members + m_.set_capacity(new_capacity); + m_.buffer = new_buffer; + m_.set_back_idx(new_front_index + size() + n); + m_.set_front_idx(new_front_index); + + return new_position; + } + + template + void construct_from_range(Iterator begin, Iterator end) + { + allocation_guard buffer_guard(m_.buffer, m_.capacity, get_allocator_ref()); + opt_copy(begin, end, m_.buffer); + + buffer_guard.release(); + } + + template + void allocate_and_copy_range(ForwardIterator first, ForwardIterator last) + { + size_type n = boost::container::iterator_distance(first, last); + + pointer new_buffer = n ? allocate(n) : pointer(); + allocation_guard new_buffer_guard(new_buffer, n, get_allocator_ref()); + + opt_copy(first, last, new_buffer); + + destroy_elements(begin(), end()); + deallocate_buffer(); + + m_.set_capacity(n); + m_.buffer = new_buffer; + m_.front_idx = 0; + m_.set_back_idx(n); + + new_buffer_guard.release(); + } + + static void swap_big_big(devector& a, devector& b) BOOST_NOEXCEPT + { + boost::adl_move_swap(a.m_.capacity, b.m_.capacity); + boost::adl_move_swap(a.m_.buffer, b.m_.buffer); + } + + template + void overwrite_buffer_impl(ForwardIterator first, ForwardIterator last, dtl::true_) + { + const size_type n = boost::container::iterator_distance(first, last); + + BOOST_ASSERT(capacity() >= n); + boost::container::uninitialized_copy_alloc_n + ( get_allocator_ref(), boost::movelib::iterator_to_raw_pointer(first) + , n, boost::movelib::iterator_to_raw_pointer(m_.buffer)); + m_.front_idx = 0; + m_.set_back_idx(n); + } + + template + InputIterator overwrite_buffer_impl(InputIterator first, InputIterator last, dtl::false_) + { + pointer pos = m_.buffer; + detail::construction_guard front_guard(pos, get_allocator_ref()); + + while (first != last && pos != begin()) { + this->alloc_construct(pos++, *first++); + front_guard.extend(); + } + + while (first != last && pos != end()) { + *pos++ = *first++; + } + + detail::construction_guard back_guard(pos, get_allocator_ref()); + + iterator capacity_end = m_.buffer + capacity(); + while (first != last && pos != capacity_end) { + this->alloc_construct(pos++, *first++); + back_guard.extend(); + } + + pointer destroy_after = dtl::min_value(dtl::max_value(begin(), pos), end()); + destroy_elements(destroy_after, end()); + + front_guard.release(); + back_guard.release(); + + m_.front_idx = 0; + m_.set_back_idx(pos - begin()); + return first; + } + + template + BOOST_CONTAINER_FORCEINLINE void overwrite_buffer(ForwardIterator first, ForwardIterator last) + { + this->overwrite_buffer_impl(first, last, + dtl::bool_::value>()); + } + + bool invariants_ok() + { + return (!m_.capacity || m_.buffer) + && m_.front_idx <= m_.back_idx + && m_.back_idx <= m_.capacity; + } + + struct impl : allocator_type + { + impl() + : allocator_type(), buffer(), front_idx(), back_idx(), capacity() + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + explicit impl(const allocator_type &a) + : allocator_type(a), buffer(), front_idx(), back_idx(), capacity() + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + impl(const allocator_type &a, pointer p, size_type f, size_type b, size_type c) + : allocator_type(a), buffer(p) + //static cast sizes, as the allocation function will take care of overflows + , front_idx(static_cast(f)) + , back_idx(static_cast(b)) + , capacity(static_cast(c)) + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + impl(BOOST_RV_REF(allocator_type) a, pointer p, size_type f, size_type b, size_type c) + : allocator_type(boost::move(a)), buffer(p) + //static cast sizes, as the allocation function will take care of overflows + , front_idx(static_cast(f)) + , back_idx(static_cast(b)) + , capacity(static_cast(c)) + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + , capacity_alloc_count() + #endif + {} + + void set_back_idx(size_type bi) + { back_idx = static_cast(bi);} + + void set_front_idx(size_type fi) + { front_idx = static_cast(fi);} + + void set_capacity(size_type c) + { capacity = static_cast(c);} + + pointer buffer; + stored_size_type front_idx; + stored_size_type back_idx; + stored_size_type capacity; + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + size_type capacity_alloc_count; + #endif + } m_; + + + #ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + public: + void reset_alloc_stats() + { + m_.capacity_alloc_count = 0; + } + + size_type get_alloc_count() const + { + return m_.capacity_alloc_count; + } + + #endif // ifdef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + + #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +}; + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_DEVECTOR_HPP diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index ce85668..893c0df 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -215,6 +215,13 @@ class default_next_capacity; typedef vector_opt vector_null_opt; +template +struct devector_opt + : vector_opt +{}; + +typedef devector_opt devector_null_opt; + #else //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //!This growth factor argument specifies that the container should increase it's @@ -442,6 +449,40 @@ using static_vector_options_t = typename boost::container::static_vector_options #endif +//! Helper metafunction to combine options into a single type to be used +//! by \c boost::container::devector. +//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct devector_options +{ + /// @cond + typedef typename ::boost::intrusive::pack_options + < devector_null_opt, + #if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef devector_opt< typename packed_options::growth_factor_type + , typename packed_options::stored_size_type> implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +//! Helper alias metafunction to combine options into a single type to be used +//! by \c boost::container::devector. +//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size +template +using devector_options_t = typename boost::container::devector_options::type; + +#endif //////////////////////////////////////////////////////////////// // diff --git a/include/boost/container/pmr/devector.hpp b/include/boost/container/pmr/devector.hpp new file mode 100644 index 0000000..2ae9b0b --- /dev/null +++ b/include/boost/container/pmr/devector.hpp @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. 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_PMR_VECTOR_HPP +#define BOOST_CONTAINER_PMR_VECTOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { +namespace pmr { + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template < + typename T, + typename GrowthPolicy = growth_factor_60 +> +using devector = boost::container::devector >; + +#endif + +//! A portable metafunction to obtain a vector +//! that uses a polymorphic allocator +template < + typename T, + typename GrowthPolicy = growth_factor_60 +> +struct devector_of +{ + typedef boost::container::devector + < T, GrowthPolicy, polymorphic_allocator > type; +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_PMR_VECTOR_HPP diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 7693348..5b97c4c 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -39,10 +39,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_set_test", "flat_set_t ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -383,10 +379,6 @@ Global {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32 - {58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32 {58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32 diff --git a/test/devector_options_test.cpp b/test/devector_options_test.cpp new file mode 100644 index 0000000..8c8e29f --- /dev/null +++ b/test/devector_options_test.cpp @@ -0,0 +1,121 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +using namespace boost::container; + +template +void test_stored_size_type_impl() +{ + DevectorType v; + typedef typename DevectorType::size_type size_type; + typedef typename DevectorType::value_type value_type; + size_type const max = Unsigned(-1); + v.resize(5); + v.resize(max); + BOOST_TEST_THROWS(v.resize(max+1), std::exception); + BOOST_TEST_THROWS(v.push_back(value_type(1)), std::exception); + BOOST_TEST_THROWS(v.insert(v.begin(), value_type(1)), std::exception); + BOOST_TEST_THROWS(v.emplace(v.begin(), value_type(1)),std::exception); + BOOST_TEST_THROWS(v.reserve(max+1), std::exception); + BOOST_TEST_THROWS(DevectorType v2(max+1), std::exception); +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< stored_size >; + #else + typedef typename devector_options + < stored_size >::type options_t; + #endif + + //Test first with a typical allocator + { + typedef devector, options_t> devector_t; + test_stored_size_type_impl(); + } + //Test with a V2 allocator + { + typedef devector, options_t> devector_t; + test_stored_size_type_impl(); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + old_capacity/2); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = devector_options_t< growth_factor >; + #else + typedef devector_options + < growth_factor >::type options_t; + #endif + + devector, options_t> v; + + v.resize(5); + v.resize(v.capacity()); + std::size_t old_capacity = v.capacity(); + v.push_back(0); + std::size_t new_capacity = v.capacity(); + BOOST_TEST(new_capacity == 2*old_capacity); +} + +int main() +{ + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + test_stored_size_type(); + test_stored_size_type(); + return ::boost::report_errors(); +} diff --git a/test/devector_test.cpp b/test/devector_test.cpp new file mode 100644 index 0000000..88ef964 --- /dev/null +++ b/test/devector_test.cpp @@ -0,0 +1,3932 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. 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 // memcmp +#include +#include +#include +#include +#include +#include +#include +#include "dummy_test_allocator.hpp" +#include "propagate_allocator_test.hpp" +#include "check_equal_containers.hpp" +#include "movable_int.hpp" + +#include + +#define BOOST_CONTAINER_DEVECTOR_ALLOC_STATS +#include +#undef BOOST_CONTAINER_DEVECTOR_ALLOC_STATS + +#include "test_util.hpp" +#include "test_elem.hpp" +#include "input_iterator.hpp" + +using namespace boost::container; + +struct boost_container_devector; + +#ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4127) // conditional expression is constant +#endif + +namespace boost { +namespace container { +namespace test { + +template<> +struct alloc_propagate_base +{ + template + struct apply + { + typedef devector type; + }; +}; + +}}} //namespace boost::container::test { + +struct different_growth_policy +{ + template + static SizeType new_capacity(SizeType capacity) + { + return (capacity) ? capacity * 4u : 32u; + } +}; + +// END HELPERS + +template void test_constructor_default() +{ + Devector a; + + BOOST_TEST(a.empty()); + BOOST_TEST(a.get_alloc_count() == 0u); + BOOST_TEST(a.capacity() == 0u); +} + +template void test_constructor_allocator() +{ + typename Devector::allocator_type alloc_template; + + Devector a(alloc_template); + + BOOST_TEST(a.empty()); + BOOST_TEST(a.get_alloc_count() == 0u); + BOOST_TEST(a.capacity() == 0u); +} + +template void test_constructor_reserve_only() +{ + { + Devector a(16, reserve_only_tag_t()); + BOOST_TEST(a.size() == 0u); + BOOST_TEST(a.capacity() >= 16u); + } + + { + Devector b(0, reserve_only_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} + +template void test_constructor_reserve_only_front_back() +{ + { + Devector a(8, 8, reserve_only_tag_t()); + BOOST_TEST(a.size() == 0u); + BOOST_TEST(a.capacity() >= 16u); + + for (int i = 8; i; --i) + { + a.emplace_front(i); + } + + for (int i = 9; i < 17; ++i) + { + a.emplace_back(i); + } + + const int expected [] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + } + + { + Devector b(0, 0, reserve_only_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} + +template void test_constructor_n() +{ + typedef typename Devector::value_type T; + + { + Devector a(8); + const int expected [] = {0, 0, 0, 0, 0, 0, 0, 0}; + test_equal_range(a, expected); + } + + { + Devector b(0); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_default_constructible::value) + { + test_elem_throw::on_ctor_after(4); + BOOST_TEST_THROWS(Devector(8), test_exception); + BOOST_TEST(test_elem_base::no_living_elem()); + test_elem_throw::do_not_throw(); + } +} + +template void test_constructor_n_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + test_elem_throw::on_copy_after(4); + const T x(404); + BOOST_TEST_THROWS(Devector(8, x), test_exception); + test_elem_throw::do_not_throw(); +} + + +template void test_constructor_n_copy_throwing(dtl::false_) +{} + +template void test_constructor_n_copy() +{ + typedef typename Devector::value_type T; + { + const T x(9); + Devector a(8, x); + const int expected [] = {9, 9, 9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { + const T x(9); + Devector b(0, x); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + test_constructor_n_copy_throwing + (dtl::bool_::value>()); + + BOOST_TEST(test_elem_base::no_living_elem()); +} + +template void test_constructor_input_range() +{ + typedef typename Devector::value_type T; + { + devector expected; get_range >(16, expected); + devector input = expected; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a(input_begin, input_end); + BOOST_TEST(a == expected); + } + + { // empty range + devector input; + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector b(input_begin, input_begin); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_TEST(test_elem_base::no_living_elem()); +/* //if move_if_noexcept is implemented + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + devector input; get_range >(16, input); + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + test_elem_throw::on_copy_after(4); + + BOOST_TEST_THROWS(Devector c(input_begin, input_end), test_exception); + } + + BOOST_TEST(test_elem_base::no_living_elem()); +*/ +} + + +void test_constructor_forward_range_throwing(dtl::true_) +{} + +void test_constructor_forward_range_throwing(dtl::false_) +{} + +template void test_constructor_forward_range() +{ + typedef typename Devector::value_type T; + boost::container::list ncx; + ncx.emplace_back(1); + ncx.emplace_back(2); + ncx.emplace_back(3); + ncx.emplace_back(4); + ncx.emplace_back(5); + ncx.emplace_back(6); + ncx.emplace_back(7); + ncx.emplace_back(8); + const boost::container::list &x = ncx; + + { + Devector a(x.begin(), x.end()); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + a.reset_alloc_stats(); + } + + { + Devector b(x.begin(), x.begin()); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector c(x.begin(), x.end()), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_constructor_pointer_range() +{ + typedef typename Devector::value_type T; + + boost::container::vector x; get_range >(8, x); + const T* xbeg = x.data(); + const T* xend = x.data() + x.size(); + + { + Devector a(xbeg, xend); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() <= 1u); + } + + { + Devector b(xbeg, xbeg); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector c(xbeg, xend), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_copy_constructor() +{ + typedef typename Devector::value_type T; + + { + Devector a; + Devector b(a); + + test_equal_range(b); + BOOST_TEST(b.get_alloc_count() == 0u); + } + + { + Devector a; get_range(8, a); + Devector b(a); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(b.get_alloc_count() <= 1u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector a; get_range(8, a); + + test_elem_throw::on_copy_after(4); + BOOST_TEST_THROWS(Devector b(a), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_move_constructor() +{ + { // empty + Devector a; + Devector b(boost::move(a)); + + BOOST_TEST(a.empty()); + BOOST_TEST(b.empty()); + } + + { // maybe small + Devector a; get_range(1, 5, 5, 9, a); + Devector b(boost::move(a)); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + + // a is unspecified but valid state + a.clear(); + BOOST_TEST(a.empty()); + } + + { // big + Devector a; get_range(32, a); + Devector b(boost::move(a)); + + boost::container::vector expected; get_range >(32, expected); + test_equal_range(b, expected); + + // a is unspecified but valid state + a.clear(); + BOOST_TEST(a.empty()); + } +} + +template void test_destructor() +{ + Devector a; + + Devector b; get_range(3, b); +} + +template void test_assignment() +{ + typedef typename Devector::value_type T; + const typename Devector::size_type alloc_count = + boost::container::allocator_traits + < typename Devector::allocator_type >::propagate_on_container_copy_assignment::value; + + { // assign to empty (maybe small) + Devector a; + Devector c; get_range(6, c); + Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + const Devector b; + + a = b; + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + Devector c; get_range(6, c); + const Devector &b = c; + + a = b; + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + Devector c; get_range(12, c); + const Devector &b = c; + + a = b; + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == alloc_count); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + Devector c; get_range(12, c); + const Devector &b = c; + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a = b, test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + } +} + +template void test_move_assignment_throwing(dtl::true_) +// move should be used on the slow path +{ + Devector a; get_range(11, 15, 15, 19, a); + Devector b; get_range(6, b); + + test_elem_throw::on_copy_after(3); + a = boost::move(b); + test_elem_throw::do_not_throw(); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + b.clear(); + test_equal_range(b); +} + +template void test_move_assignment_throwing(dtl::false_) +{} + +template void test_move_assignment() +{ + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + Devector b; get_range(6, b); + + a = boost::move(b); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + // b is in unspecified but valid state + b.clear(); + test_equal_range(b); + } + + { // assign from empty + Devector a; get_range(6, a); + Devector b; + + a = boost::move(b); + + test_equal_range(a); + test_equal_range(b); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + Devector b; get_range(6, b); + + a = boost::move(b); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + + b.clear(); + test_equal_range(b); + } + + test_move_assignment_throwing + (boost::move_detail::bool_::value>()); +} + +template void test_il_assignment() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + a = {1, 2, 3, 4, 5, 6 }; + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign from empty + Devector a; get_range(6, a); + a = {}; + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + + try + { + a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + BOOST_TEST(false); + } catch(const test_exception&) {} + test_elem_throw::do_not_throw(); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + #endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_assign_input_range() +{ + typedef typename Devector::value_type T; + + { // assign to empty, keep it small + devector expected; get_range(1, 13, 13, 25, expected); + devector input = expected; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; + a.reset_alloc_stats(); + a.assign(input_begin, input_end); + + BOOST_TEST(a == expected); + } + + { // assign to empty (maybe small) + devector input; get_range >(6, input); + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; + + a.assign(input_begin, input_end); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector a; get_range(6, a); + a.assign(input_begin, input_begin); + + test_equal_range(a); + } + + { // assign to non-empty + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.assign(input_begin, input_end); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assignment overlaps contents + devector input; get_range >(6, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assignment exceeds contents + devector input; get_range >(12, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + + devector input; get_range >(12, input); + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.end()); + + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_forward_range_throwing(dtl::false_) +{} + +template void test_assign_forward_range() +{ + typedef typename Devector::value_type T; + typedef boost::container::list List; + + boost::container::list x; + typedef typename List::iterator list_iterator; + x.emplace_back(1); + x.emplace_back(2); + x.emplace_back(3); + x.emplace_back(4); + x.emplace_back(5); + x.emplace_back(6); + x.emplace_back(7); + x.emplace_back(8); + x.emplace_back(9); + x.emplace_back(10); + x.emplace_back(11); + x.emplace_back(12); + + list_iterator one = x.begin(); + list_iterator six = one; + list_iterator twelve = one; + + iterator_advance(six, 6); + iterator_advance(twelve, 12); + + { // assign to empty (maybe small) + Devector a; + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(one, one); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(one, twelve); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + BOOST_IF_CONSTEXPR(! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(one, twelve), test_exception); + test_elem_throw::do_not_throw(); + + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_pointer_range() +{ + typedef typename Devector::value_type T; + + boost::container::vector x; get_range >(12, x); + const T* one = x.data(); + const T* six = one + 6; + const T* twelve = one + 12; + + { // assign to empty (maybe small) + Devector a; + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(one, one); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(one, six); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(one, twelve); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(one, twelve), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_n() +{ + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign(0, T(404)); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign(6, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign(12, T(9)); + + const int expected[] = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign(32, T(9)), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected); + } +} + +template void test_assign_il() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + + { // assign to empty (maybe small) + Devector a; + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign from empty + Devector a; get_range(6, a); + + a.assign({}); + + test_equal_range(a); + } + + { // assign to non-empty + Devector a; get_range(11, 15, 15, 19, a); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + + { // assign to free front + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(8); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment overlaps contents + Devector a; get_range(11, 15, 15, 19, a); + a.reserve_front(12); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // assignment exceeds contents + Devector a; get_range(11, 13, 13, 15, a); + a.reserve_front(8); + a.reserve_back(8); + a.reset_alloc_stats(); + + a.assign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // strong guarantee if reallocation is needed (no guarantee otherwise) + Devector a; get_range(6, a); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(a.assign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(a, {1, 2, 3, 4, 5, 6}); + } + #endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_get_allocator() +{ + Devector a; + (void) a.get_allocator(); +} + +template void test_begin_end() +{ + boost::container::vector expected; get_range >(10, expected); + { + Devector actual; get_range(10, actual); + + BOOST_TEST(boost::algorithm::equal(expected.begin(), expected.end(), actual.begin(), actual.end())); + BOOST_TEST(boost::algorithm::equal(expected.rbegin(), expected.rend(), actual.rbegin(), actual.rend())); + BOOST_TEST(boost::algorithm::equal(expected.cbegin(), expected.cend(), actual.cbegin(), actual.cend())); + BOOST_TEST(boost::algorithm::equal(expected.crbegin(), expected.crend(), actual.crbegin(), actual.crend())); + } + + { + Devector cactual; get_range(10, cactual); + + BOOST_TEST(boost::algorithm::equal(expected.begin(), expected.end(), cactual.begin(), cactual.end())); + BOOST_TEST(boost::algorithm::equal(expected.rbegin(), expected.rend(), cactual.rbegin(), cactual.rend())); + } +} + +template void test_empty() +{ + typedef typename Devector::value_type T; + + Devector a; + BOOST_TEST(a.empty()); + + a.push_front(T(1)); + BOOST_TEST(! a.empty()); + + a.pop_back(); + BOOST_TEST(a.empty()); + + Devector b(16, reserve_only_tag_t()); + BOOST_TEST(b.empty()); + + Devector c; get_range(3, c); + BOOST_TEST(! c.empty()); +} + +//template +//using gp_devector = devector; + +void test_max_size() +{/* + gp_devector a; + BOOST_TEST(a.max_size() == (std::numeric_limits::max)()); + + gp_devector b; + BOOST_TEST(b.max_size() == (std::numeric_limits::max)()); + + gp_devector c; + BOOST_TEST(c.max_size() >= b.max_size()); + + gp_devector d; + BOOST_TEST(d.max_size() >= c.max_size()); +*/ +} + +void test_exceeding_max_size() +{/* + using Devector = gp_devector; + + Devector a((std::numeric_limits::max)()); + BOOST_TEST_THROWS(a.emplace_back(404), std::length_error); +*/ +} + +template void test_size() +{ + typedef typename Devector::value_type T; + + Devector a; + BOOST_TEST(a.size() == 0u); + + a.push_front(T(1)); + BOOST_TEST(a.size() == 1u); + + a.pop_back(); + BOOST_TEST(a.size() == 0u); + + Devector b(16, reserve_only_tag_t()); + BOOST_TEST(b.size() == 0u); + + Devector c; get_range(3, c); + BOOST_TEST(c.size() == 3u); +} + +template void test_capacity() +{ + Devector a; + BOOST_TEST(a.capacity() == 0u); + + Devector b(128, reserve_only_tag_t()); + BOOST_TEST(b.capacity() >= 128u); + + Devector c; get_range(10, c); + BOOST_TEST(c.capacity() >= 10u); +} + +template void test_resize_front_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector d; get_range(5, d); + boost::container::vector d_origi; get_range >(5, d_origi); + iterator origi_begin = d.begin(); + + test_elem_throw::on_ctor_after(3); + BOOST_TEST_THROWS(d.resize_front(256), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(d, d_origi); + BOOST_TEST(origi_begin == d.begin()); +} + +template void test_resize_front_throwing(dtl::false_) +{} + + +template void test_resize_front() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_front(8); + const int expected [] = {0, 0, 0, 1, 2, 3, 4, 5}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_front(16); + b.resize_front(8); + const int expected [] = {0, 0, 0, 1, 2, 3, 4, 5}; + test_equal_range(b, expected); + } + /* + // size < required, move would throw + if (! boost::is_nothrow_move_constructible::value && std::is_copy_constructible::value) + { + Devector c; get_range(5, c); + + test_elem_throw::on_move_after(3); + c.resize_front(8); // shouldn't use the throwing move + test_elem_throw::do_not_throw(); + + test_equal_range(c, {0, 0, 0, 1, 2, 3, 4, 5}); + } + */ + + test_resize_front_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_front(4); + const int expected [] = {3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128); + Devector g; + g.resize_front(128); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_front(6); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } +} + +template void test_resize_front_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_front(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + } + + // size < required, copy throws, but later + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(7); + BOOST_TEST_THROWS(c.resize_front(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } +} + +template void test_resize_front_copy_throwing(dtl::false_) +{} + +template void test_resize_front_copy() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_front(8, T(9)); + const int expected [] = {9, 9, 9, 1, 2, 3, 4, 5}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_front(16); + b.resize_front(8, T(9)); + const int expected [] = {9, 9, 9, 1, 2, 3, 4, 5}; + test_equal_range(b, expected); + } + + test_resize_front_copy_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_front(4, T(404)); + const int expected[] = {3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128, 9); + Devector g; + g.resize_front(128, T(9)); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_front(6, T(9)); + const int expected[] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, tmp is already inserted + { + Devector f; get_range(8, f); + const T& tmp = *(f.begin() + 1); + f.resize_front(16, tmp); + const int expected[] = {2,2,2,2,2,2,2,2,1,2,3,4,5,6,7,8}; + test_equal_range(f, expected); + } +} + +template void test_resize_back_throwing(dtl::true_) +// size < required, constructor throws +{ + typedef typename Devector::iterator iterator; + + Devector d; get_range(5, d); + boost::container::vector d_origi; get_range >(5, d_origi); + iterator origi_begin = d.begin(); + + test_elem_throw::on_ctor_after(3); + BOOST_TEST_THROWS(d.resize_back(256), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(d, d_origi); + BOOST_TEST(origi_begin == d.begin()); +} + +template void test_resize_back_throwing(dtl::false_) +{} + +template void test_resize_back() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_back(8); + const int expected [] = {1, 2, 3, 4, 5, 0, 0, 0}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_back(16); + b.resize_back(8); + const int expected [] = {1, 2, 3, 4, 5, 0, 0, 0}; + test_equal_range(b, expected); + } + /* + // size < required, move would throw + if (! boost::is_nothrow_move_constructible::value && std::is_copy_constructible::value) + { + Devector c; get_range(5, c); + + test_elem_throw::on_move_after(3); + c.resize_back(8); // shouldn't use the throwing move + test_elem_throw::do_not_throw(); + + test_equal_range(c, {1, 2, 3, 4, 5, 0, 0, 0}); + } + */ + + test_resize_back_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_back(4); + const int expected [] = {1, 2, 3, 4}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128); + Devector g; + g.resize_back(128); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_back(6); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } +} + +template void test_resize_back_copy_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + } + + // size < required, copy throws, but later + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(7); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } + + // size < required, copy throws + { + Devector c; get_range(5, c); + boost::container::vector c_origi; get_range >(5, c_origi); + iterator origi_begin = c.begin(); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(c.resize_back(256, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + test_equal_range(c, c_origi); + BOOST_TEST(origi_begin == c.begin()); + } +} + +template void test_resize_back_copy_throwing(dtl::false_) +{} + +template void test_resize_back_copy() +{ + typedef typename Devector::value_type T; + + // size < required, alloc needed + { + Devector a; get_range(5, a); + a.resize_back(8, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(a, expected); + } + + // size < required, but capacity provided + { + Devector b; get_range(5, b); + b.reserve_back(16); + b.resize_back(8, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(b, expected); + } + + test_resize_back_copy_throwing + (dtl::bool_::value>()); + + // size >= required + { + Devector e; get_range(6, e); + e.resize_back(4, T(404)); + const int expected [] = {1, 2, 3, 4}; + test_equal_range(e, expected); + } + + // size < required, does not fit front small buffer + { + boost::container::vector expected(128, 9); + Devector g; + g.resize_back(128, T(9)); + test_equal_range(g, expected); + } + + // size = required + { + Devector e; get_range(6, e); + e.resize_back(6, T(9)); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(e, expected); + } + + // size < required, tmp is already inserted + { + Devector f; get_range(8, f); + const T& tmp = *(f.begin() + 1); + f.resize_back(16, tmp); + const int expected [] = {1,2,3,4,5,6,7,8,2,2,2,2,2,2,2,2}; + test_equal_range(f, expected); + } +} + +/* +template void test_constructor_unsafe_uninitialized() +{ + typedef typename Devector::value_type T; + + { + Devector a(8, unsafe_uninitialized_tag_t()); + BOOST_TEST(a.size() == 8u); + + for (int i = 0; i < 8; ++i) + { + new (a.data() + i) T(i+1); + } + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + } + + { + Devector b(0, unsafe_uninitialized_tag_t()); + BOOST_TEST(b.get_alloc_count() == 0u); + } +} +*/ + +/* +template void test_unsafe_uninitialized_resize_front() +{ + typedef typename Devector::value_type T; + + { // noop + Devector a; get_range(8, a); + a.reset_alloc_stats(); + + a.unsafe_uninitialized_resize_front(a.size()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(a, expected); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // grow (maybe has enough capacity) + Devector b; get_range(0, 0, 5, 9, b); + + b.unsafe_uninitialized_resize_front(8); + + for (int i = 0; i < 4; ++i) + { + new (b.data() + i) T(i+1); + } + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + } + + { // shrink uninitialized + Devector c; get_range(8, c); + + c.unsafe_uninitialized_resize_front(16); + c.unsafe_uninitialized_resize_front(8); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(c, expected ); + } + + if (std::is_trivially_destructible::value) + { + // shrink + Devector d; get_range(8, d); + + d.unsafe_uninitialized_resize_front(4); + + test_equal_range(d, {5, 6, 7, 8}); + } +} + +template void test_unsafe_uninitialized_resize_back() +{ + typedef typename Devector::value_type T; + + { // noop + Devector a; get_range(8, a); + a.reset_alloc_stats(); + + a.unsafe_uninitialized_resize_back(a.size()); + + test_equal_range(a, {1, 2, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(a.get_alloc_count() == 0u); + } + + { // grow (maybe has enough capacity) + Devector b; get_range(1, 5, 0, 0, b); + + b.unsafe_uninitialized_resize_back(8); + + for (int i = 0; i < 4; ++i) + { + new (b.data() + 4 + i) T(i+5); + } + + test_equal_range(b, {1, 2, 3, 4, 5, 6, 7, 8}); + } + + { // shrink uninitialized + Devector c; get_range(8, c); + + c.unsafe_uninitialized_resize_back(16); + c.unsafe_uninitialized_resize_back(8); + + test_equal_range(c, {1, 2, 3, 4, 5, 6, 7, 8}); + } + + if (std::is_trivially_destructible::value) + { + // shrink + Devector d; get_range(8, d); + + d.unsafe_uninitialized_resize_back(4); + + test_equal_range(d, {1, 2, 3, 4}); + } +} +*/ + +template void test_reserve_front() +{ + typedef typename Devector::value_type value_type; + Devector a; + + a.reserve_front(100); + for (unsigned i = 0; i < 100u; ++i) + { + a.push_front(value_type(i)); + } + + BOOST_TEST(a.get_alloc_count() == 1u); + + Devector b; + b.reserve_front(4); + b.reserve_front(6); + b.reserve_front(4); + b.reserve_front(8); + b.reserve_front(16); +} + +template void test_reserve_back() +{ + Devector a; + typedef typename Devector::value_type value_type; + a.reserve_back(100); + for (unsigned i = 0; i < 100; ++i) + { + a.push_back(value_type(i)); + } + + BOOST_TEST(a.get_alloc_count() == 1u); + + Devector b; + b.reserve_back(4); + b.reserve_back(6); + b.reserve_back(4); + b.reserve_back(8); + b.reserve_back(16); +} + +template +void test_shrink_to_fit_always() +{ + Devector a; + a.reserve(100); + + a.push_back(1); + a.push_back(2); + a.push_back(3); + + a.shrink_to_fit(); + + boost::container::vector expected; + expected.push_back(1); + expected.push_back(2); + expected.push_back(3); + test_equal_range(a, expected); + + std::size_t exp_capacity = 3u; + BOOST_TEST(a.capacity() == exp_capacity); +} + +template +void test_shrink_to_fit_never() +{ + Devector a; + a.reserve(100); + + a.push_back(1); + a.push_back(2); + a.push_back(3); + + a.shrink_to_fit(); + + boost::container::vector expected; + expected.emplace_back(1); + expected.emplace_back(2); + expected.emplace_back(3); + test_equal_range(a, expected); + BOOST_TEST(a.capacity() == 100u); +} + +void shrink_to_fit() +{ + typedef devector devector_u_shr; + typedef devector small_devector_u_shr; + test_shrink_to_fit_always(); + test_shrink_to_fit_always(); +} + +template void test_index_operator() +{ + typedef typename Devector::value_type T; + + { // non-const [] + Devector a; get_range(5, a); + + BOOST_TEST(a[0] == 1); + BOOST_TEST(a[4] == 5); + BOOST_TEST(&a[3] == &a[0] + 3); + + a[0] = T(100); + BOOST_TEST(a[0] == 100); + } + + { // const [] + Devector b; get_range(5, b); + const Devector &a = b; + + BOOST_TEST(a[0] == 1); + BOOST_TEST(a[4] == 5); + BOOST_TEST(&a[3] == &a[0] + 3); + } +} + +template void test_at() +{ + typedef typename Devector::value_type T; + + { // non-const at + Devector a; get_range(3, a); + + BOOST_TEST(a.at(0) == 1); + a.at(0) = T(100); + BOOST_TEST(a.at(0) == 100); + + BOOST_TEST_THROWS(a.at(3), std::out_of_range); + } + + { // const at + Devector b; get_range(3, b); + const Devector &a = b; + + BOOST_TEST(a.at(0) == 1); + + BOOST_TEST_THROWS(a.at(3), std::out_of_range); + } +} + +template void test_front() +{ + typedef typename Devector::value_type T; + + { // non-const front + Devector a; get_range(3, a); + BOOST_TEST(a.front() == 1); + a.front() = T(100); + BOOST_TEST(a.front() == 100); + } + + { // const front + Devector b; get_range(3, b); const Devector &a = b; + BOOST_TEST(a.front() == 1); + } +} + +template void test_back() +{ + typedef typename Devector::value_type T; + + { // non-const back + Devector a; get_range(3, a); + BOOST_TEST(a.back() == 3); + a.back() = T(100); + BOOST_TEST(a.back() == 100); + } + + { // const back + Devector b; get_range(3, b); const Devector &a = b; + BOOST_TEST(a.back() == 3); + } +} + +void test_data() +{ + unsigned c_array[] = {1, 2, 3, 4}; + + { // non-const data + devector a(c_array, c_array + 4); + BOOST_TEST(a.data() == &a.front()); + + BOOST_TEST(std::memcmp(c_array, a.data(), 4 * sizeof(unsigned)) == 0); + + *(a.data()) = 100; + BOOST_TEST(a.front() == 100u); + } + + { // const data + const devector a(c_array, c_array + 4); + BOOST_TEST(a.data() == &a.front()); + + BOOST_TEST(std::memcmp(c_array, a.data(), 4 * sizeof(unsigned)) == 0); + } +} + +template void test_emplace_front(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(b.emplace_front(404), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_emplace_front(dtl::false_) +{ +} + +template void test_emplace_front() +{ + typedef typename Devector::value_type T; + + { + Devector a; + + a.emplace_front(3); + a.emplace_front(2); + a.emplace_front(1); + + boost::container::vector expected; get_range >(3, expected); + + test_equal_range(a, expected); + } + + test_emplace_front + (dtl::bool_::value>()); +} + +template void test_push_front() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_front(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.push_front(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } + + // test when tmp is already inserted + { + Devector c; get_range(4, c); + const T& tmp = *(c.begin() + 1); + c.push_front(tmp); + const int expected[] = {2, 1, 2, 3, 4}; + test_equal_range(c, expected); + } +} + +template void test_push_front_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_move_after(1); + BOOST_TEST_THROWS(b.push_front(T(404)), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_front_rvalue_throwing(dtl::false_) +{} + +template void test_push_front_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 16; i > 0; --i) + { + T elem(i); + a.push_front(boost::move(elem)); + } + + test_equal_range(a, expected); + } + + test_push_front_rvalue_throwing(dtl::bool_::value>()); +} + +template void test_pop_front() +{ + { + Devector a; + a.emplace_front(1); + a.pop_front(); + BOOST_TEST(a.empty()); + } + + { + Devector b; + + b.emplace_back(2); + b.pop_front(); + BOOST_TEST(b.empty()); + + b.emplace_front(3); + b.pop_front(); + BOOST_TEST(b.empty()); + } + + { + Devector c; get_range(20, c); + for (int i = 0; i < 20; ++i) + { + BOOST_TEST(!c.empty()); + c.pop_front(); + } + BOOST_TEST(c.empty()); + } +} + +template void test_emplace_back_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(b.emplace_back(404), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_emplace_back_throwing(dtl::false_) +{} + +template void test_emplace_back() +{ + typedef typename Devector::value_type T; + + { + Devector a; + + a.emplace_back(1); + a.emplace_back(2); + a.emplace_back(3); + + boost::container::vector expected; get_range >(3, expected); + + test_equal_range(a, expected); + } + + test_emplace_back_throwing + (dtl::bool_::value>()); +} + +template void test_push_back_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.push_back(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_back_throwing(dtl::false_) +{} + +template void test_push_back() +{ + typedef typename Devector::value_type T; + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_back(elem); + } + + test_equal_range(a, expected); + } + + test_push_back_throwing(dtl::bool_::value>()); + + // test when tmp is already inserted + { + Devector c; get_range(4, c); + const T& tmp = *(c.begin() + 1); + c.push_back(tmp); + const int expected[] = {1, 2, 3, 4, 2}; + test_equal_range(c, expected); + } +} + +template void test_push_back_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector b; get_range(4, b); + iterator origi_begin = b.begin(); + + test_elem_throw::on_move_after(1); + BOOST_TEST_THROWS(b.push_back(T(404)), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); +} + +template void test_push_back_rvalue_throwing(dtl::false_) +{} + +template void test_push_back_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + + for (int i = 1; i <= 16; ++i) + { + T elem(i); + a.push_back(boost::move(elem)); + } + + test_equal_range(a, expected); + } + + test_push_back_rvalue_throwing(dtl::bool_::value>()); +} + +/* +template void test_unsafe_push_front() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + a.reserve_front(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_front(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + b.reserve_front(5); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.unsafe_push_front(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } +} + +template void test_unsafe_push_front_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + std::reverse(expected.begin(), expected.end()); + Devector a; + a.reserve_front(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_front(boost::move(elem)); + } + + test_equal_range(a, expected); + } +} +*/ +/* +template void test_unsafe_push_back() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + a.reserve(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_back(elem); + } + + test_equal_range(a, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + Devector b; get_range(4, b); + b.reserve(5); + iterator origi_begin = b.begin(); + + const T elem(404); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(b.unsafe_push_back(elem), test_exception); + test_elem_throw::do_not_throw(); + + iterator new_begin = b.begin(); + + BOOST_TEST(origi_begin == new_begin); + BOOST_TEST(b.size() == 4u); + } +} + +template void test_unsafe_push_back_rvalue() +{ + typedef typename Devector::value_type T; + + { + boost::container::vector expected; get_range >(16, expected); + Devector a; + a.reserve(16); + + for (std::size_t i = 1; i <= 16; ++i) + { + T elem(i); + a.unsafe_push_back(boost::move(elem)); + } + + test_equal_range(a, expected); + } +} +*/ +template void test_pop_back() +{ + { + Devector a; + a.emplace_back(1); + a.pop_back(); + BOOST_TEST(a.empty()); + } + + { + Devector b; + + b.emplace_front(2); + b.pop_back(); + BOOST_TEST(b.empty()); + + b.emplace_back(3); + b.pop_back(); + BOOST_TEST(b.empty()); + } + + { + Devector c; get_range(20, c); + for (int i = 0; i < 20; ++i) + { + BOOST_TEST(!c.empty()); + c.pop_back(); + } + BOOST_TEST(c.empty()); + } +} + +template void test_emplace_throwing(dtl::true_) +{ + typedef typename Devector::iterator iterator; + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(j.emplace(j.begin() + 2, 404), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_emplace_throwing(dtl::false_) +{} + + +template void test_emplace() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.emplace(a.begin(), 123); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.emplace(b.end(), 123); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.emplace(c.begin(), 123); + const int expected [] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.emplace(d.end(), 123); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.emplace(e.begin() + 5, 123); + const int expected [] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.emplace(f.begin() + 1, 123); + const int expected [] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.emplace(g.end() - 1, 123); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.emplace(h.begin() + 7, 123); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.emplace(i.begin(), 1); + i.emplace(i.end(), 10); + for (int j = 2; j < 10; ++j) + { + i.emplace(i.begin() + (j-1), j); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_emplace_throwing + (dtl::bool_::value>()); +} + +template void test_insert_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + T test_elem(123); + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_copy_after(1); + BOOST_TEST_THROWS(j.insert(j.begin() + 2, test_elem), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_insert_throwing(dtl::false_) +{} + +template void test_insert() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + T test_elem(123); + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.insert(a.begin(), test_elem); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.insert(b.end(), test_elem); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.insert(c.begin(), test_elem); + const int expected[] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.insert(d.end(), test_elem); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.insert(e.begin() + 5, test_elem); + const int expected[] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.insert(f.begin() + 1, test_elem); + const int expected[] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.insert(g.end() - 1, test_elem); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.insert(h.begin() + 7, test_elem); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.insert(i.begin(), T(1)); + i.insert(i.end(), T(10)); + for (int j = 2; j < 10; ++j) + { + i.insert(i.begin() + (j-1), T(j)); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_insert_throwing + (dtl::bool_::value>()); + + // test when tmp is already inserted and there's free capacity + { + Devector c; get_range(6, c); + c.pop_back(); + const T& tmp = *(c.begin() + 2); + c.insert(c.begin() + 1, tmp); + const int expected[] = {1, 3, 2, 3, 4, 5}; + test_equal_range(c, expected); + } + + // test when tmp is already inserted and maybe there's no free capacity + { + Devector c; get_range(6, c); + const T& tmp = *(c.begin() + 2); + c.insert(c.begin() + 1, tmp); + const int expected[] = {1, 3, 2, 3, 4, 5, 6}; + test_equal_range(c, expected); + } +} + +template void test_insert_rvalue_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + Devector j; get_range(4, j); + iterator origi_begin = j.begin(); + + test_elem_throw::on_ctor_after(1); + BOOST_TEST_THROWS(j.insert(j.begin() + 2, T(404)), test_exception); + test_elem_throw::do_not_throw(); + + const int expected[] = {1, 2, 3, 4}; + test_equal_range(j, expected); + BOOST_TEST(origi_begin == j.begin()); +} + +template void test_insert_rvalue_throwing(dtl::false_) +{} + + +template void test_insert_rvalue() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; get_range(16, a); + typename Devector::iterator it = a.insert(a.begin(), T(123)); + const int expected[] = {123, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected); + BOOST_TEST(*it == 123); + } + + { + Devector b; get_range(16, b); + typename Devector::iterator it = b.insert(b.end(), T(123)); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 123}; + test_equal_range(b, expected); + BOOST_TEST(*it == 123); + } + + { + Devector c; get_range(16, c); + c.pop_front(); + typename Devector::iterator it = c.insert(c.begin(), T(123)); + const int expected[] = {123, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(c, expected); + BOOST_TEST(*it == 123); + } + + { + Devector d; get_range(16, d); + d.pop_back(); + typename Devector::iterator it = d.insert(d.end(), T(123)); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 123}; + test_equal_range(d, expected); + BOOST_TEST(*it == 123); + } + + { + Devector e; get_range(16, e); + typename Devector::iterator it = e.insert(e.begin() + 5, T(123)); + const int expected[] = {1, 2, 3, 4, 5, 123, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(e, expected); + BOOST_TEST(*it == 123); + } + + { + Devector f; get_range(16, f); + f.pop_front(); + f.pop_back(); + iterator valid = f.begin() + 1; + typename Devector::iterator it = f.insert(f.begin() + 1, T(123)); + const int expected[] = {2, 123, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(f, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 3); + } + + { + Devector g; get_range(16, g); + g.pop_front(); + g.pop_back(); + iterator valid = g.end() - 2; + typename Devector::iterator it = g.insert(g.end() - 1, T(123)); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 123, 15}; + test_equal_range(g, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 14); + } + + { + Devector h; get_range(16, h); + h.pop_front(); + h.pop_back(); + iterator valid = h.begin() + 7; + typename Devector::iterator it = h.insert(h.begin() + 7, T(123)); + const int expected[] = {2, 3, 4, 5, 6, 7, 8, 123, 9, 10, 11, 12, 13, 14, 15}; + test_equal_range(h, expected); + BOOST_TEST(*it == 123); + BOOST_TEST(*valid == 9); + } + + { + Devector i; + i.insert(i.begin(), T(1)); + i.insert(i.end(), T(10)); + for (int j = 2; j < 10; ++j) + { + i.insert(i.begin() + (j-1), T(j)); + } + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(i, expected); + } + + test_insert_rvalue_throwing + (dtl::bool_::value>()); +} + +template void test_insert_n_throwing(dtl::true_) +{ + typedef typename Devector::value_type T; + // insert at begin + { + Devector j; get_range(4, j); + + const T x(404); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), 4, x), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + + const T x(404); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), 4, x), test_exception); + test_elem_throw::do_not_throw(); + } +} + +template void test_insert_n_throwing(dtl::false_) +{} + +template void test_insert_n() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; + const T x(123); + iterator ret = a.insert(a.end(), 5, x); + const int expected[] = {123, 123, 123, 123, 123}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + const T x(9); + iterator ret = b.insert(b.begin(), 3, x); + const int expected[] = {9, 9, 9, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + const T x(9); + iterator ret = c.insert(c.end(), 3, x); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + const T x(9); + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), 3, x); + + const int expected[] = {9, 9, 9, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + const T x(9); + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), 3, x); + + const int expected[] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(e, expected); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + const T x(9); + iterator ret = f.insert(f.begin() + 2, 4, x); + + const int expected[] = {3, 4, 9, 9, 9, 9, 5, 6}; + test_equal_range(f, expected); + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + const T x(9); + iterator ret = g.insert(g.begin() + 2, 5, x); + + const int expected[] = {3, 4, 9, 9, 9, 9, 9, 5}; + test_equal_range(g, expected); + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + const T x(9); + iterator ret = g.insert(g.begin() + 2, 5, x); + + const int expected[] = {1, 2, 9, 9, 9, 9, 9, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + const T x(9); + + iterator ret = h.insert(h.begin(), 0, x); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, 0, x); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), 0, x); + BOOST_TEST(ret == h.end()); + + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + BOOST_TEST(h.get_alloc_count() == 0u); + } + + { // test insert already inserted + Devector i; get_range(8, i); + i.reset_alloc_stats(); + + i.pop_front(); + i.pop_front(); + + iterator ret = i.insert(i.end() - 1, 2, *i.begin()); + + const int expected[] = {3, 4, 5, 6, 7, 3, 3, 8}; + test_equal_range(i, expected); + BOOST_TEST(i.get_alloc_count() == 0u); + BOOST_TEST(ret == i.begin() + 5); + } + + test_insert_n_throwing + (dtl::bool_::value>()); +} + +template void test_insert_input_range() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + devector x; + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + x.emplace_back(9); + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector a; + iterator ret = a.insert(a.end(), input_begin, input_end); + const int expected[] = {9, 9, 9, 9, 9}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), input_begin, input_end); + const int expected[] = {9, 9, 9, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator ret = d.insert(d.begin(), input_begin, input_end); + const int expected[] = {9, 9, 9, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.begin()); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 3); + + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), input_begin, input_end); + const int expected[] = {1, 2, 3, 4, 5, 9, 9, 9}; + test_equal_range(e, expected); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, input_begin, input_end); + + const int expected[] = {3, 4, 9, 9, 9, 9, 5, 6}; + test_equal_range(f, expected); + BOOST_TEST(ret == f.begin() + 2); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, input_begin, input_end); + + const int expected [] = {3, 4, 9, 9, 9, 9, 9, 5}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 5); + + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, input_begin, input_end); + + const int expected [] = {1, 2, 9, 9, 9, 9, 9, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + iterator ret = h.insert(h.begin(), input_begin, input_begin); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, input_begin, input_begin); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), input_begin, input_begin); + BOOST_TEST(ret == h.end()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + devector input = x; + + input_iterator input_begin = make_input_iterator(input, input.begin()); + input_iterator input_end = make_input_iterator(input, input.begin() + 4); + + Devector k; get_range(4, k); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), input_begin, input_end), test_exception); + test_elem_throw::do_not_throw(); + } + } +} + +template void test_insert_range() +{ + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + typedef boost::container::vector Vector; + + Vector x; + x.emplace_back(9); + x.emplace_back(10); + x.emplace_back(11); + x.emplace_back(12); + x.emplace_back(13); + + typename Vector::iterator xb = x.begin(); + + { + Devector a; + iterator ret = a.insert(a.end(), xb, xb+5); + const int expected [] = {9, 10, 11, 12, 13}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), xb, xb+3); + const int expected [] = {9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), xb, xb+3); + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), xb, xb+3); + + const int expected [] = {9, 10, 11, 4, 5, 6, 7, 8}; + test_equal_range(d, expected); + + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), xb, xb+3); + + const int expected [] = {1, 2, 3, 4, 5, 9, 10, 11}; + test_equal_range(e, expected); + + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, xb, xb+4); + + const int expected [] = {3, 4, 9, 10, 11, 12, 5, 6}; + test_equal_range(f, expected); + + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, xb, xb+5); + + const int expected [] = {3, 4, 9, 10, 11, 12, 13, 5}; + test_equal_range(g, expected); + + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, xb, xb+5); + + const int expected [] = {1, 2, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8}; + test_equal_range(g, expected); + + BOOST_TEST(ret == g.begin() + 2); + } + + { // n == 0 + Devector h; get_range(8, h); + h.reset_alloc_stats(); + + iterator ret = h.insert(h.begin(), xb, xb); + BOOST_TEST(ret == h.begin()); + + ret = h.insert(h.begin() + 4, xb, xb); + BOOST_TEST(ret == h.begin() + 4); + + ret = h.insert(h.end(), xb, xb); + BOOST_TEST(ret == h.end()); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8}; + test_equal_range(h, expected); + + BOOST_TEST(h.get_alloc_count() == 0u); + } + + if (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), xb, xb+4), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), xb, xb+4), test_exception); + test_elem_throw::do_not_throw(); + } + } +} + +template void test_insert_init_list() +{ + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef typename Devector::value_type T; + typedef typename Devector::iterator iterator; + + { + Devector a; + iterator ret = a.insert(a.end(), {T(123), T(124), T(125), T(126), T(127)}); + test_equal_range(a, {123, 124, 125, 126, 127}); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.insert(b.begin(), {T(9), T(10), T(11)}); + test_equal_range(b, {9, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(ret == b.begin()); + } + + { + Devector c; get_range(8, c); + iterator ret = c.insert(c.end(), {T(9), T(10), T(11)}); + test_equal_range(c, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + BOOST_TEST(ret == c.begin() + 8); + } + + { + Devector d; get_range(8, d); + + d.pop_front(); + d.pop_front(); + d.pop_front(); + + iterator origi_end = d.end(); + iterator ret = d.insert(d.begin(), {T(9), T(10), T(11)}); + + test_equal_range(d, {9, 10, 11, 4, 5, 6, 7, 8}); + BOOST_TEST(origi_end == d.end()); + BOOST_TEST(ret == d.begin()); + } + + { + Devector e; get_range(8, e); + + e.pop_back(); + e.pop_back(); + e.pop_back(); + + iterator origi_begin = e.begin(); + iterator ret = e.insert(e.end(), {T(9), T(10), T(11)}); + + test_equal_range(e, {1, 2, 3, 4, 5, 9, 10, 11}); + BOOST_TEST(origi_begin == e.begin()); + BOOST_TEST(ret == e.begin() + 5); + } + + { + Devector f; get_range(8, f); + f.reset_alloc_stats(); + + f.pop_front(); + f.pop_front(); + f.pop_back(); + f.pop_back(); + + iterator ret = f.insert(f.begin() + 2, {T(9), T(10), T(11), T(12)}); + + test_equal_range(f, {3, 4, 9, 10, 11, 12, 5, 6}); + BOOST_TEST(f.get_alloc_count() == 0u); + BOOST_TEST(ret == f.begin() + 2); + } + + { + Devector g; get_range(8, g); + g.reset_alloc_stats(); + + g.pop_front(); + g.pop_front(); + g.pop_back(); + g.pop_back(); + g.pop_back(); + + iterator ret = g.insert(g.begin() + 2, {T(9), T(10), T(11), T(12), T(13)}); + + test_equal_range(g, {3, 4, 9, 10, 11, 12, 13, 5}); + BOOST_TEST(g.get_alloc_count() == 0u); + BOOST_TEST(ret == g.begin() + 2); + } + + { + Devector g; get_range(8, g); + + iterator ret = g.insert(g.begin() + 2, {T(9), T(10), T(11), T(12), T(13)}); + + test_equal_range(g, {1, 2, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8}); + BOOST_TEST(ret == g.begin() + 2); + } + + BOOST_IF_CONSTEXPR (! boost::move_detail::is_nothrow_copy_constructible::value) + { + // insert at begin + { + Devector j; get_range(4, j); + + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(j.insert(j.begin(), {T(9), T(9), T(9), T(9), T(9)}), test_exception); + test_elem_throw::do_not_throw(); + } + + // insert at end + { + Devector k; get_range(4, k); + test_elem_throw::on_copy_after(3); + BOOST_TEST_THROWS(k.insert(k.end(), {T(9), T(9), T(9), T(9), T(9)}), test_exception); + test_elem_throw::do_not_throw(); + } + } + #endif // #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +} + +template void test_erase() +{ + typedef typename Devector::iterator iterator; + { + Devector a; get_range(4, a); + iterator ret = a.erase(a.begin()); + const int expected[] = {2, 3, 4}; + test_equal_range(a, expected); + BOOST_TEST(ret == a.begin()); + } + + { + Devector b; get_range(4, b); + iterator ret = b.erase(b.end() - 1); + const int expected[] = {1, 2, 3}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.end()); + } + + { + Devector c; get_range(6, c); + iterator ret = c.erase(c.begin() + 2); + const int expected [] = {1, 2, 4, 5, 6}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 2); + BOOST_TEST(c.front_free_capacity() > 0u); + } + + { + Devector d; get_range(6, d); + iterator ret = d.erase(d.begin() + 4); + const int expected [] = {1, 2, 3, 4, 6}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.begin() + 4); + BOOST_TEST(d.back_free_capacity() > 0u); + } +} + +template void test_erase_range() +{ + typedef typename Devector::iterator iterator; + { + Devector a; get_range(4, a); + a.erase(a.end(), a.end()); + a.erase(a.begin(), a.begin()); + } + + { + Devector b; get_range(8, b); + iterator ret = b.erase(b.begin(), b.begin() + 2); + const int expected [] = {3, 4, 5, 6, 7, 8}; + test_equal_range(b, expected); + BOOST_TEST(ret == b.begin()); + BOOST_TEST(b.front_free_capacity() > 0u); + } + + { + Devector c; get_range(8, c); + iterator ret = c.erase(c.begin() + 1, c.begin() + 3); + const int expected [] = {1, 4, 5, 6, 7, 8}; + test_equal_range(c, expected); + BOOST_TEST(ret == c.begin() + 1); + BOOST_TEST(c.front_free_capacity() > 0u); + } + + { + Devector d; get_range(8, d); + iterator ret = d.erase(d.end() - 2, d.end()); + const int expected [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(d, expected); + BOOST_TEST(ret == d.end()); + BOOST_TEST(d.back_free_capacity() > 0u); + } + + { + Devector e; get_range(8, e); + iterator ret = e.erase(e.end() - 3, e.end() - 1); + const int expected [] = {1, 2, 3, 4, 5, 8}; + test_equal_range(e, expected); + BOOST_TEST(ret == e.end() - 1); + BOOST_TEST(e.back_free_capacity() > 0u); + } + + { + Devector f; get_range(8, f); + iterator ret = f.erase(f.begin(), f.end()); + test_equal_range(f); + BOOST_TEST(ret == f.end()); + } +} + +template void test_swap() +{ + using std::swap; // test if ADL works + + // empty-empty + { + Devector a; + Devector b; + + swap(a, b); + + BOOST_TEST(a.empty()); + BOOST_TEST(b.empty()); + } + + // empty-not empty + { + Devector a; + Devector b; get_range(4, b); + + swap(a, b); + + const int expected [] = {1, 2, 3, 4}; + { + BOOST_TEST(b.empty()); + test_equal_range(a, expected); + } + + swap(a, b); + { + BOOST_TEST(a.empty()); + test_equal_range(b, expected); + } + } + + // small-small / big-big + { + Devector a; get_range(1, 5, 5, 7, a); + Devector b; get_range(13, 15, 15, 19, b); + + swap(a, b); + + const int expected [] = {13, 14, 15, 16, 17, 18}; + test_equal_range(a, expected); + const int expected2 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(b, expected2); + + swap(a, b); + + const int expected3 [] = {13, 14, 15, 16, 17, 18}; + test_equal_range(b, expected3); + const int expected4 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(a, expected4); + } + + // big-small + small-big + { + Devector a; get_range(10, a); + Devector b; get_range(9, 11, 11, 17, b); + + swap(a, b); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(b, expected); + const int expected2 [] = {9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(a, expected2); + + swap(a, b); + + const int expected3 [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(a, expected3); + const int expected4 [] = {9, 10, 11, 12, 13, 14, 15, 16}; + test_equal_range(b, expected4); + } + + // self swap + { + Devector a; get_range(10, a); + + swap(a, a); + + const int expected [] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + test_equal_range(a, expected); + } + + // no overlap + { + Devector a; get_range(1, 9, 0, 0, a); + Devector b; get_range(0, 0, 11, 17, b); + + a.pop_back(); + a.pop_back(); + + b.pop_front(); + b.pop_front(); + + swap(a, b); + + const int expected [] = {13, 14, 15, 16}; + test_equal_range(a, expected); + const int expected2 [] = {1, 2, 3, 4, 5, 6}; + test_equal_range(b, expected2); + } + + // big-big does not copy or move + { + Devector a; get_range(32, a); + Devector b; get_range(32, b); + boost::container::vector c; get_range >(32, c); + + test_elem_throw::on_copy_after(1); + test_elem_throw::on_move_after(1); + + swap(a, b); + + test_elem_throw::do_not_throw(); + + test_equal_range(a, c); + test_equal_range(b, c); + } +} + +template void test_clear() +{ + { + Devector a; + a.clear(); + BOOST_TEST(a.empty()); + } + + { + Devector a; get_range(8, a); + typename Devector::size_type cp = a.capacity(); + a.clear(); + BOOST_TEST(a.empty()); + BOOST_TEST(cp == a.capacity()); + } +} + +template void test_op_eq() +{ + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(a == b); + } + + { // diff size + Devector a; get_range(8, a); + Devector b; get_range(9, b); + + BOOST_TEST(!(a == b)); + } + + { // diff content + Devector a; get_range(8, a); + Devector b; get_range(2,6,6,10, b); + + BOOST_TEST(!(a == b)); + } +} + +template void test_op_lt() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST((a < b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a < b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST(!(a < b)); + } +} + +template void test_op_ne() +{ + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a != b)); + } + + { // diff size + Devector a; get_range(8, a); + Devector b; get_range(9, b); + + BOOST_TEST((a != b)); + } + + { // diff content + Devector a; get_range(8, a); + Devector b; get_range(2,6,6,10, b); + + BOOST_TEST((a != b)); + } +} + + +template void test_op_gt() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a > b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a > b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST((a > b)); + } +} + +template void test_op_ge() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST(!(a >= b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST((a >= b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST((a >= b)); + } +} + +template void test_op_le() +{ + { // little than + Devector a; get_range(7, a); + Devector b; get_range(8, b); + + BOOST_TEST((a <= b)); + } + + { // equal + Devector a; get_range(8, a); + Devector b; get_range(8, b); + + BOOST_TEST((a <= b)); + } + + { // greater than + Devector a; get_range(8, a); + Devector b; get_range(7, b); + + BOOST_TEST(!(a <= b)); + } +} + + +template +void test_devector_default_constructible(dtl::true_) +{ + test_constructor_n(); + test_resize_front(); + test_resize_back(); +} + +template +void test_devector_default_constructible(dtl::false_) +{} + +template +void test_devector_copy_constructible(dtl::false_) +{} + + +template +void test_devector_copy_constructible(dtl::true_) +{ + test_constructor_n_copy(); + test_constructor_input_range(); + test_constructor_forward_range(); + test_constructor_pointer_range(); + test_copy_constructor(); + test_assignment(); + test_assign_input_range(); + test_assign_pointer_range(); + test_assign_n(); + test_resize_front_copy(); + test_push_back(); + //test_unsafe_push_back(); + test_push_front(); + //test_unsafe_push_front(); + test_resize_back_copy(); + test_insert(); + test_insert_n(); + test_insert_input_range(); + test_insert_range(); + test_insert_init_list(); +} + +template +void test_devector() +{ + test_devector_default_constructible(dtl::bool_::value>()); + test_devector_copy_constructible(dtl::bool_::value>()); + + test_constructor_default(); + test_constructor_allocator(); + + test_constructor_reserve_only(); + test_constructor_reserve_only_front_back(); + //test_constructor_unsafe_uninitialized(); + + test_move_constructor(); + test_destructor(); + + test_move_assignment(); + test_get_allocator(); + test_begin_end(); + test_empty(); + test_size(); + test_capacity(); + + //test_unsafe_uninitialized_resize_front(); + //test_unsafe_uninitialized_resize_back(); + test_reserve_front(); + test_reserve_back(); + test_index_operator(); + test_at(); + test_front(); + test_back(); + test_emplace_front(); + test_push_front_rvalue(); + + //test_unsafe_push_front_rvalue(); + test_pop_front(); + test_emplace_back(); + test_push_back_rvalue(); + + //test_unsafe_push_back_rvalue(); + test_pop_back(); + test_emplace(); + test_insert_rvalue(); + + test_erase(); + test_erase_range(); + test_swap(); + test_clear(); + test_op_eq(); + test_op_lt(); + test_op_ne(); + test_op_gt(); + test_op_ge(); + test_op_le(); +} + +class recursive_devector +{ + public: + recursive_devector(const recursive_devector &x) + : devector_(x.devector_) + {} + + recursive_devector & operator=(const recursive_devector &x) + { this->devector_ = x.devector_; return *this; } + + int id_; + devector devector_; + devector::iterator it_; + devector::const_iterator cit_; + devector::reverse_iterator rit_; + devector::const_reverse_iterator crit_; +}; + +void test_recursive_devector()//Test for recursive types +{ + devector rdv; + BOOST_TEST(rdv.empty()); + BOOST_TEST(rdv.get_alloc_count() == 0u); + BOOST_TEST(rdv.capacity() == 0u); +} + +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef vector< ValueType + , typename allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +#ifdef _MSC_VER + #pragma warning (pop) +#endif + + +void test_all() +{/* + test_recursive_devector(); + test_max_size(); + test_exceeding_max_size(); + shrink_to_fit(); + test_data(); + test_il_assignment< devector >(); + test_assign_forward_range< devector >(); + test_assign_il >(); +*/ + //test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + test_devector< devector >(); + + //////////////////////////////////// + // Allocator propagation testing + //////////////////////////////////// + (void)boost::container::test::test_propagate_allocator(); +} + + +boost::container::vector getom() +{ + typedef boost::container::vector V; + V v; + return BOOST_MOVE_RET(V, v); +} + + +boost::container::vector get() +{ + typedef boost::container::vector V; + V v; + return BOOST_MOVE_RET(V, v); +} + +int main() +{ +// boost::container::vectora(get()); + //boost::container::vector b(getom()); + //boost::container::vector c(get_range< boost::container::vector >(1, 5, 5, 9)); + test_all(); + return boost::report_errors(); +} diff --git a/test/explicit_inst_devector_test.cpp b/test/explicit_inst_devector_test.cpp new file mode 100644 index 0000000..ded7e24 --- /dev/null +++ b/test/explicit_inst_devector_test.cpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. 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 "movable_int.hpp" + +struct empty +{ + friend bool operator == (const empty &, const empty &){ return true; } + friend bool operator < (const empty &, const empty &){ return true; } +}; + +template class ::boost::container::devector; + +namespace boost { +namespace container { + +//Test stored_size option +template class devector< test::movable_and_copyable_int + , new_allocator + , devector_options< stored_size >::type + >; + + +} //namespace container { +} //namespace boost { + +int main() +{ + ::boost::container::devector dummy; + (void)dummy; + return 0; +} diff --git a/test/flat_map_adaptor_test.cpp b/test/flat_map_adaptor_test.cpp index bc75949..2ffa02d 100644 --- a/test/flat_map_adaptor_test.cpp +++ b/test/flat_map_adaptor_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,15 @@ int main() std::cout << "Error in map_test > >" << std::endl; return 1; } + + if (0 != test::map_test + < GetMapContainer > >::apply::map_type + , MyStdMap + , GetMapContainer > >::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test > >" << std::endl; + return 1; + } } { using namespace boost::container; diff --git a/test/flat_set_adaptor_test.cpp b/test/flat_set_adaptor_test.cpp index 6225bbf..cd5ef19 100644 --- a/test/flat_set_adaptor_test.cpp +++ b/test/flat_set_adaptor_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,14 @@ int main() std::cout << "Error in set_test >" << std::endl; return 1; } + if (0 != test::set_test + < GetSetContainer >::apply::set_type + , MyStdSet + , GetSetContainer >::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >" << std::endl; + return 1; + } } { using namespace boost::container; diff --git a/test/hash_table_test.cppx b/test/hash_table_test.cppx deleted file mode 100644 index e69de29..0000000 diff --git a/test/input_iterator.hpp b/test/input_iterator.hpp new file mode 100644 index 0000000..1d576cf --- /dev/null +++ b/test/input_iterator.hpp @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. 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://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +/** + * Emulates input iterator, validates algorithm + * does a single pass only, removes visited elements. + * + * Container::erase(front_iterator) must not invalidate other iterators. + * + * The hack around `_erase_on_destroy` is required to make `*it++` work. + */ +template +class input_iterator +{ + typedef typename Container::iterator iterator; + + public: + + typedef std::input_iterator_tag iterator_category; + typedef typename Container::value_type value_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::difference_type difference_type; + + struct erase_on_destroy {}; + +public: + + input_iterator() + : _container() + , _it() + , _erase_on_destroy() + {} + + input_iterator(Container& c, iterator it) + :_container(&c) + , _it(it) + , _erase_on_destroy() + {} + + input_iterator(const input_iterator& rhs) + :_container(rhs._container), + _it(rhs._it), + _erase_on_destroy(rhs._erase_on_destroy) + { + rhs._erase_on_destroy = false; + } + + input_iterator & operator=(const input_iterator& rhs) + { + _container = rhs._container; + _it = rhs._it; + _erase_on_destroy = rhs._erase_on_destroy; + rhs._erase_on_destroy = false; + return *this; + } + + input_iterator(const input_iterator& rhs, erase_on_destroy) + :_container(rhs._container), + _it(rhs._it), + _erase_on_destroy(true) + {} + + ~input_iterator() + { + if (_erase_on_destroy) + { + _container->erase(_it); // must not invalidate other iterators + } + } + + const value_type& operator*() + { + return *_it; + } + + input_iterator operator++() + { + _container->erase(_it); + ++_it; + return *this; + } + + input_iterator operator++(int) + { + input_iterator old(*this, erase_on_destroy()); + ++_it; + return old; + } + + friend bool operator==(const input_iterator a, const input_iterator b) + { + return a._it == b._it; + } + + friend bool operator!=(const input_iterator a, const input_iterator b) + { + return !(a == b); + } + +private: + Container* _container; + iterator _it; + mutable bool _erase_on_destroy; +}; + +template +input_iterator make_input_iterator(Container& c, typename Container::iterator it) +{ + return input_iterator(c, it); +} diff --git a/test/pmr_devector_test.cpp b/test/pmr_devector_test.cpp new file mode 100644 index 0000000..b7001d0 --- /dev/null +++ b/test/pmr_devector_test.cpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. 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 + +int main() +{ + using namespace boost::container; + using boost::container::dtl::is_same; + + typedef devector > intcontainer_t; + BOOST_STATIC_ASSERT(( is_same::type >::value )); + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + BOOST_STATIC_ASSERT(( is_same >::value )); + #endif + return 0; +} diff --git a/test/test_elem.hpp b/test/test_elem.hpp new file mode 100644 index 0000000..b57a8dd --- /dev/null +++ b/test/test_elem.hpp @@ -0,0 +1,319 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. 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://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_TEST_ELEM_HPP +#define BOOST_CONTAINER_TEST_TEST_ELEM_HPP + +#include + +namespace boost { +namespace container { + +struct test_exception {}; + +struct test_elem_throw +{ + private: + static int throw_on_ctor_after /*= -1*/; + static int throw_on_copy_after /*= -1*/; + static int throw_on_move_after /*= -1*/; + + public: + static void on_ctor_after(int x) { throw_on_ctor_after = x; } + static void on_copy_after(int x) { throw_on_copy_after = x; } + static void on_move_after(int x) { throw_on_move_after = x; } + + static void do_not_throw() + { + throw_on_ctor_after = -1; + throw_on_copy_after = -1; + throw_on_move_after = -1; + } + + static void in_constructor() { maybe_throw(throw_on_ctor_after); } + static void in_copy() { maybe_throw(throw_on_copy_after); } + static void in_move() { maybe_throw(throw_on_move_after); } + + private: + static void maybe_throw(int& counter) + { + if (counter > 0) + { + --counter; + if (counter == 0) + { + --counter; + throw test_exception(); + } + } + } +}; + +int test_elem_throw::throw_on_ctor_after = -1; +int test_elem_throw::throw_on_copy_after = -1; +int test_elem_throw::throw_on_move_after = -1; + +struct test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(test_elem_base) + + public: + test_elem_base() + { + test_elem_throw::in_constructor(); + _index = new int(0); + ++_live_count; + } + + test_elem_base(int index) + { + test_elem_throw::in_constructor(); + _index = new int(index); + ++_live_count; + } + + explicit test_elem_base(const test_elem_base& rhs) + { + test_elem_throw::in_copy(); + _index = new int(*rhs._index); + ++_live_count; + } + + test_elem_base(BOOST_RV_REF(test_elem_base) rhs) + { + test_elem_throw::in_move(); + _index = rhs._index; + rhs._index = 0; + ++_live_count; + } + + test_elem_base &operator=(BOOST_COPY_ASSIGN_REF(test_elem_base) rhs) + { + test_elem_throw::in_copy(); + if (_index) { delete _index; } + _index = new int(*rhs._index); + return *this; + } + + test_elem_base &operator=(BOOST_RV_REF(test_elem_base) rhs) + { + test_elem_throw::in_move(); + if (_index) { delete _index; } + _index = rhs._index; + rhs._index = 0; + return *this; + } + + ~test_elem_base() + { + if (_index) { delete _index; } + --_live_count; + } + + friend bool operator==(const test_elem_base& a, const test_elem_base& b) + { + return a._index && b._index && *(a._index) == *(b._index); + } + + friend bool operator==(int a, const test_elem_base& b) + { + return b._index != 0 && a == *(b._index); + } + + friend bool operator==(const test_elem_base& a, int b) + { + return a._index != 0 && *(a._index) == b; + } + + friend bool operator<(const test_elem_base& a, const test_elem_base& b) + { + return boost::less_pointees(a._index, b._index); + } + + friend std::ostream& operator<<(std::ostream& out, const test_elem_base& elem) + { + if (elem._index) { out << *elem._index; } + else { out << "null"; } + return out; + } + + template + void serialize(Archive& ar, unsigned /* version */) + { + ar & *_index; + } + + static bool no_living_elem() + { + return _live_count == 0; + } + + private: + int* _index; + + static int _live_count; +}; + +int test_elem_base::_live_count = 0; + +struct regular_elem : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(regular_elem) + + public: + regular_elem() + {} + + regular_elem(int index) : test_elem_base(index) {} + + regular_elem(const regular_elem& rhs) + :test_elem_base(rhs) + {} + + regular_elem(BOOST_RV_REF(regular_elem) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + regular_elem &operator=(BOOST_COPY_ASSIGN_REF(regular_elem) rhs) + { + static_cast(*this) = rhs; + return *this; + } + + regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs) + { + regular_elem &r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct noex_move : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(noex_move) + + public: + noex_move() + {} + + noex_move(int index) : test_elem_base(index) {} + + noex_move(const noex_move& rhs) + :test_elem_base(rhs) + {} + + noex_move(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + noex_move &operator=(BOOST_COPY_ASSIGN_REF(noex_move) rhs) + { + static_cast(*this) = rhs; + return *this; + } + + noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT + { + noex_move & r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct noex_copy : test_elem_base +{ + private: + BOOST_COPYABLE_AND_MOVABLE(noex_copy) + + public: + noex_copy(){} + + noex_copy(int index) : test_elem_base(index) {} + + noex_copy(const noex_copy& rhs) BOOST_NOEXCEPT + :test_elem_base(rhs) + {} + + noex_copy(BOOST_RV_REF(noex_copy) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + noex_copy &operator=(BOOST_COPY_ASSIGN_REF(noex_copy) rhs) BOOST_NOEXCEPT + { + static_cast(*this) = rhs; + return *this; + } + + noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs) + { + noex_copy &r = rhs; + static_cast(*this) = boost::move(r); + return *this; + } +}; + +struct only_movable : test_elem_base +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable) + + public: + only_movable(){}; + + only_movable(int index) : test_elem_base(index) {} + + only_movable(BOOST_RV_REF(only_movable) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + only_movable &operator=(BOOST_RV_REF(only_movable) rhs) + { + static_cast(*this) = boost::move(rhs); + return *this; + } +}; + +struct no_default_ctor : test_elem_base +{ + + private: + BOOST_COPYABLE_AND_MOVABLE(no_default_ctor) + + public: + no_default_ctor(int index) : test_elem_base(index) {} + + no_default_ctor(const no_default_ctor& rhs) + :test_elem_base(rhs) + {} + + no_default_ctor(BOOST_RV_REF(no_default_ctor) rhs) + :test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs)) + {} + + no_default_ctor &operator=(BOOST_RV_REF(no_default_ctor) rhs) + { + static_cast(*this) = boost::move(rhs); + return *this; + } + + no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs) + { + static_cast(*this) = rhs; + return *this; + } +}; + +}} + +#endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP diff --git a/test/test_util.hpp b/test/test_util.hpp new file mode 100644 index 0000000..f2db77b --- /dev/null +++ b/test/test_util.hpp @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +// +// \(C\) Copyright Benedek Thaler 2015-2016 +// \(C\) Copyright Ion Gaztanaga 2019-2020. 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://erenon.hu/double_ended for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_TEST_TEST_UTIL_HPP +#define BOOST_CONTAINER_TEST_TEST_UTIL_HPP + +#include "test_elem.hpp" + +// get_range + +template +void get_range(int fbeg, int fend, int bbeg, int bend, DeVector &c) +{ + c.clear(); + + for (int i = fend; i > fbeg ;) + { + c.emplace_front(--i); + } + + for (int i = bbeg; i < bend; ++i) + { + c.emplace_back(i); + } +} + +template +void get_range(int count, Container &c) +{ + c.clear(); + + for (int i = 1; i <= count; ++i) + { + c.emplace_back(i); + } +} + +template +void get_range(Container &c) +{ + get_range(1, 13, 13, 25, c); +} + +template +void test_equal_range(const C1& a) +{ + BOOST_TEST(a.empty()); +} + +template +void print_range(std::ostream& out, Iterator b, Iterator e) +{ + out << '['; + bool first = true; + + for (; b != e; ++b) + { + if (first) { first = false; } + else { out << ','; } + out << *b; + } + out << ']'; +} + +template +void print_range(std::ostream& out, const Range& range) +{ + print_range(out, range.cbegin(), range.cend()); +} + +template +void print_range(std::ostream& out, Array (&range)[N]) +{ + print_range(out, range, range + N); +} + +template +void test_equal_range(const C1& a, const C2 (&b)[N]) +{ + bool equals = boost::algorithm::equal + (a.begin(), a.end(), b, b+N); + + BOOST_TEST(equals); + + if (!equals) + { + print_range(std::cerr, a); + std::cerr << "\n"; + print_range(std::cerr, b); + std::cerr << "\n"; + } +} + + +template +void test_equal_range(const C1& a, const C2&b) +{ + bool equals = boost::algorithm::equal + (a.begin(), a.end(), b.begin(), b.end()); + + BOOST_TEST(equals); + + if (!equals) + { + print_range(std::cerr, a); + std::cerr << "\n"; + print_range(std::cerr, b); + std::cerr << "\n"; + } +} + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +// support initializer_list +template +void test_equal_range(const C& a, std::initializer_list il) +{ + typedef typename C::value_type T; + boost::container::vector b; + + for (auto&& elem : il) + { + b.emplace_back(elem); + } + + test_equal_range(a, b); +} + +#endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + +#endif //BOOST_CONTAINER_TEST_TEST_UTIL_HPP