From 2297f6af72eae193fe02f56531c42580a2396292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 27 Aug 2017 12:40:15 +0200 Subject: [PATCH] Modify flat associative containers to be adaptors if the allocator argument is a container. This allows using stable_vector, small_vector, static_vector as underlying containers. --- doc/container.qbk | 18 +- .../container/detail/advanced_insert_int.hpp | 2 +- include/boost/container/detail/destroyers.hpp | 4 +- include/boost/container/detail/flat_tree.hpp | 433 +++++++++++++----- .../boost/container/detail/is_container.hpp | 55 +++ .../detail/is_contiguous_container.hpp | 47 ++ include/boost/container/flat_map.hpp | 340 ++++++++------ include/boost/container/flat_set.hpp | 361 ++++++++------- include/boost/container/static_vector.hpp | 15 + proj/vc7ide/container.sln | 8 + proj/vc7ide/container.vcproj | 6 + test/flat_map_test.cpp | 45 +- test/flat_set_test.cpp | 19 - test/flat_tree_test.cpp | 124 +++++ test/map_test.hpp | 4 +- test/tree_test.cpp | 1 - 16 files changed, 1008 insertions(+), 474 deletions(-) create mode 100644 include/boost/container/detail/is_container.hpp create mode 100644 include/boost/container/detail/is_contiguous_container.hpp create mode 100644 test/flat_tree_test.cpp diff --git a/doc/container.qbk b/doc/container.qbk index e6c2f55..561fdcb 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -426,11 +426,10 @@ functions), implemented on top of std::vector. AssocVector differs from a map in its erase functions (AssocVector::erase invalidates all iterators into the object) and in the complexity guarantees of insert and erase (linear as opposed to constant). ]] -[*Boost.Container] `flat_[multi]map/set` containers are ordered-vector based associative containers -based on Austern's and Alexandrescu's guidelines. These ordered vector containers have also -benefited recently with the addition of `move semantics` to C++, speeding up insertion -and erasure times considerably. Flat associative containers have the following -attributes: +[*Boost.Container] `flat_[multi]map/set` containers are ordered, vector-like container based, associative +containers following Austern's and Alexandrescu's guidelines. These ordered vector containers have also +benefited with the addition of `move semantics` to C++11, speeding up insertion and +erasure times considerably. Flat associative containers have the following attributes: * Faster lookup than standard associative containers * Much faster iteration than standard associative containers. @@ -1213,6 +1212,14 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_66_00 Boost 1.66 Release] + +* ['flat_[multi]map/set] can now work as container adaptors, as proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0429r1.pdf P0429R1]. + The allocator argument is checked for ['size()] and ['empty()] members. If so, the argument is interpreted as the required underlying container. + This means that ['static_vector], ['stable_vector] and ['small_vector] can be used now with flat associative containers. + +[endsect] + [section:release_notes_boost_1_65_00 Boost 1.65 Release] * Implemented `extract_sequence`, `adopt_sequence` functions for flat_[multi]map/set associative containers. @@ -1246,7 +1253,6 @@ use [*Boost.Container]? There are several reasons for that: [endsect] -https://svn.boost.org/trac/boost/ticket/12577#comment:1 [section:release_notes_boost_1_62_00 Boost 1.62 Release] * Fixed bugs: diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 20adb52..db5e8df 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -163,7 +163,7 @@ struct insert_copy_proxy void copy_n_and_update(Allocator &, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; - *p =v_; + *p = v_; } const value_type &v_; diff --git a/include/boost/container/detail/destroyers.hpp b/include/boost/container/detail/destroyers.hpp index b110561..c3a5d90 100644 --- a/include/boost/container/detail/destroyers.hpp +++ b/include/boost/container/detail/destroyers.hpp @@ -270,12 +270,12 @@ class scoped_destructor }; -template +template class value_destructor { typedef boost::container::allocator_traits AllocTraits; public: - typedef typename Allocator::value_type value_type; + typedef Value value_type; value_destructor(Allocator &a, value_type &rv) : rv_(rv), a_(a) {} diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 9aab873..b6e4187 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -37,10 +37,10 @@ #include #include #include +#include +#include +#include -#ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER -#include -#endif #include //pair #include @@ -52,11 +52,152 @@ #include #endif +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//merge_unique +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge_unique +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3 +#include + +//merge_equal +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME merge +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 3 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 3 +#include + +//index_of +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME index_of +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include + +//nth +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME nth +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED namespace boost { namespace container { namespace container_detail { + +template +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal + (SequenceContainer& dest, Iterator begin, Iterator end, Compare comp, container_detail::false_) +{ + typedef typename SequenceContainer::iterator iterator; + typedef typename SequenceContainer::value_type value_type; + + iterator it = dest.insert( dest.end(), boost::make_move_iterator(begin), boost::make_move_iterator(end) ); + + if (is_contiguous_container::value){ + 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()); + value_type *const sraw = boost::movelib::iterator_to_raw_pointer(dest.begin()+dest.size()); + boost::movelib::adaptive_sort(iraw, eraw, comp, sraw, dest.capacity()); + boost::movelib::adaptive_merge(braw, iraw, eraw, comp, sraw, dest.capacity()- dest.size()); + } + else{ + boost::movelib::adaptive_sort(it, dest.end(), comp); + boost::movelib::adaptive_merge(dest.begin(), it, dest.end(), comp); + } +} + +template +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique + (SequenceContainer& dest, Iterator begin, Iterator end, Compare comp, container_detail::false_) +{ + (flat_tree_merge_equal)(dest, begin, end, comp, container_detail::false_()); + dest.erase(boost::movelib::unique + (dest.begin(), dest.end(), boost::movelib::negate(comp)), dest.cend()); +} + +template +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_equal + (SequenceContainer& dest, Iterator begin, Iterator end, Compare comp, container_detail::true_) +{ + dest.merge(begin, end, comp); +} + +template +BOOST_CONTAINER_FORCEINLINE void flat_tree_merge_unique + (SequenceContainer& dest, Iterator begin, Iterator end, Compare comp, container_detail::true_) +{ + dest.merge_unique(begin, end, comp); +} + +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(stored_allocator_type) + +template +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_index_of + (SequenceContainer& cont, Iterator p, container_detail::true_) +{ + return cont.index_of(p); +} + +template +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::size_type + flat_tree_index_of + (SequenceContainer& cont, Iterator p, container_detail::false_) +{ + typedef typename SequenceContainer::size_type size_type; + return static_cast(p - cont.begin()); +} + +template +BOOST_CONTAINER_FORCEINLINE Iterator + flat_tree_nth + (SequenceContainer& cont, typename SequenceContainer::size_type n, container_detail::true_) +{ + return cont.nth(n); +} + +template +BOOST_CONTAINER_FORCEINLINE Iterator + flat_tree_nth + (SequenceContainer& cont, typename SequenceContainer::size_type n, container_detail::false_) +{ + return cont.begin()+ n; +} + +template +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::stored_allocator_type & + flat_tree_get_stored_allocator + (SequenceContainer& cont, container_detail::true_) +{ + return cont.get_stored_allocator(); +} + +template +BOOST_CONTAINER_FORCEINLINE const typename SequenceContainer::stored_allocator_type & + flat_tree_get_stored_allocator + (const SequenceContainer& cont, container_detail::true_) +{ + return cont.get_stored_allocator(); +} + +template +BOOST_CONTAINER_FORCEINLINE typename SequenceContainer::allocator_type +flat_tree_get_stored_allocator + (SequenceContainer& cont, container_detail::false_) +{ + return cont.get_allocator(); +} + template class flat_tree_value_compare : private Compare @@ -85,37 +226,43 @@ class flat_tree_value_compare Compare &get_comp() { return *this; } }; - +/* template struct get_flat_tree_iterators { - #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER - typedef Pointer iterator; - typedef typename boost::intrusive:: - pointer_traits::element_type iterator_element_type; - typedef typename boost::intrusive:: - pointer_traits:: template - rebind_pointer::type const_iterator; - #else //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER typedef typename boost::container::container_detail:: vec_iterator iterator; typedef typename boost::container::container_detail:: vec_iterator const_iterator; - #endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER typedef boost::container::reverse_iterator reverse_iterator; typedef boost::container::reverse_iterator const_reverse_iterator; }; +*/ + +template < class Value, class AllocatorOrContainer + , bool = boost::container::container_detail::is_container::value > +struct select_container_type +{ + typedef AllocatorOrContainer type; +}; + +template +struct select_container_type +{ + typedef boost::container::vector type; +}; template + class Compare, class AllocatorOrContainer> class flat_tree { public: - typedef boost::container::vector sequence_type; + typedef typename select_container_type::type container_type; + typedef container_type sequence_type; //For backwards compatibility private: - typedef Allocator allocator_t; - typedef allocator_traits allocator_traits_type; + typedef typename container_type::allocator_type allocator_t; + typedef allocator_traits allocator_traits_type; public: typedef flat_tree_value_compare value_compare; @@ -152,11 +299,11 @@ class flat_tree : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq)) {} - Data(const Data &d, const Allocator &a) + Data(const Data &d, const allocator_t &a) : value_compare(static_cast(d)), m_seq(d.m_seq, a) {} - Data(BOOST_RV_REF(Data) d, const Allocator &a) + Data(BOOST_RV_REF(Data) d, const allocator_t &a) : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq), a) {} @@ -181,7 +328,7 @@ class flat_tree this->m_seq.swap(d.m_seq); } - sequence_type m_seq; + container_type m_seq; }; Data m_data; @@ -189,26 +336,36 @@ class flat_tree public: - typedef typename sequence_type::value_type value_type; - typedef typename sequence_type::pointer pointer; - typedef typename sequence_type::const_pointer const_pointer; - typedef typename sequence_type::reference reference; - typedef typename sequence_type::const_reference const_reference; + typedef typename container_type::value_type value_type; + typedef typename container_type::pointer pointer; + typedef typename container_type::const_pointer const_pointer; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; typedef typename KeyOfValue::type key_type; typedef Compare key_compare; - typedef typename sequence_type::allocator_type allocator_type; - typedef typename sequence_type::size_type size_type; - typedef typename sequence_type::difference_type difference_type; - typedef typename sequence_type::iterator iterator; - typedef typename sequence_type::const_iterator const_iterator; - typedef typename sequence_type::reverse_iterator reverse_iterator; - typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; + typedef typename container_type::allocator_type allocator_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::reverse_iterator reverse_iterator; + typedef typename container_type::const_reverse_iterator const_reverse_iterator; //!Standard extension - typedef allocator_type stored_allocator_type; + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT + (boost::container::container_detail::, container_type + ,stored_allocator_type, allocator_type) stored_allocator_type; + + static const bool has_stored_allocator_type = + BOOST_INTRUSIVE_HAS_TYPE(boost::container::container_detail::, container_type, stored_allocator_type); private: typedef allocator_traits stored_allocator_traits; + typedef typename container_detail::if_c + ::type get_stored_allocator_const_return_t; + + typedef typename container_detail::if_c + ::type get_stored_allocator_noconst_return_t; public: BOOST_CONTAINER_FORCEINLINE flat_tree() @@ -357,6 +514,11 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp() { return this->priv_value_comp().get_comp(); } + struct insert_commit_data + { + const_iterator position; + }; + public: // accessors: BOOST_CONTAINER_FORCEINLINE Compare key_comp() const @@ -368,11 +530,15 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const { return this->m_data.m_seq.get_allocator(); } - BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const - { return this->m_data.m_seq.get_stored_allocator(); } + BOOST_CONTAINER_FORCEINLINE get_stored_allocator_const_return_t get_stored_allocator() const + { + return flat_tree_get_stored_allocator(this->m_data.m_seq, container_detail::bool_()); + } - BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() - { return this->m_data.m_seq.get_stored_allocator(); } + BOOST_CONTAINER_FORCEINLINE get_stored_allocator_noconst_return_t get_stored_allocator() + { + return flat_tree_get_stored_allocator(this->m_data.m_seq, container_detail::bool_()); + } BOOST_CONTAINER_FORCEINLINE iterator begin() { return this->m_data.m_seq.begin(); } @@ -432,7 +598,8 @@ class flat_tree insert_commit_data data; ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data); ret.first = ret.second ? this->priv_insert_commit(data, val) - : iterator(vector_iterator_get_ptr(data.position)); + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); return ret; } @@ -442,7 +609,8 @@ class flat_tree insert_commit_data data; ret.second = this->priv_insert_unique_prepare(KeyOfValue()(val), data); ret.first = ret.second ? this->priv_insert_commit(data, boost::move(val)) - : iterator(vector_iterator_get_ptr(data.position)); + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); return ret; } @@ -466,7 +634,8 @@ class flat_tree insert_commit_data data; return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data) ? this->priv_insert_commit(data, val) - : iterator(vector_iterator_get_ptr(data.position)); + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); } iterator insert_unique(const_iterator hint, BOOST_RV_REF(value_type) val) @@ -475,7 +644,8 @@ class flat_tree insert_commit_data data; return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data) ? this->priv_insert_commit(data, boost::move(val)) - : iterator(vector_iterator_get_ptr(data.position)); + : this->begin() + (data.position - this->cbegin()); + //: iterator(vector_iterator_get_ptr(data.position)); } iterator insert_equal(const_iterator hint, const value_type& val) @@ -563,7 +733,11 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_seq.merge(first, last, static_cast(this->m_data)); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_merge_unique::value; + (flat_tree_merge_equal)(this->m_data.m_seq, first, last, this->priv_value_comp(), container_detail::bool_()); + } template void insert_unique(ordered_unique_range_t, InIt first, InIt last @@ -592,7 +766,11 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_seq.merge_unique(first, last, static_cast(this->m_data)); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_merge_unique::value; + (flat_tree_merge_unique)(this->m_data.m_seq, first, last, this->priv_value_comp(), container_detail::bool_()); + } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -601,9 +779,9 @@ class flat_tree { typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); - stored_allocator_type &a = this->get_stored_allocator(); + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); - value_destructor d(a, val); + value_destructor d(a, val); return this->insert_unique(::boost::move(val)); } @@ -613,9 +791,9 @@ class flat_tree //hint checked in insert_unique typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); - stored_allocator_type &a = this->get_stored_allocator(); + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); - value_destructor d(a, val); + value_destructor d(a, val); return this->insert_unique(hint, ::boost::move(val)); } @@ -624,9 +802,9 @@ class flat_tree { typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); - stored_allocator_type &a = this->get_stored_allocator(); + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); - value_destructor d(a, val); + value_destructor d(a, val); return this->insert_equal(::boost::move(val)); } @@ -636,9 +814,9 @@ class flat_tree //hint checked in insert_equal typename aligned_storage::value>::type v; value_type &val = *static_cast(static_cast(&v)); - stored_allocator_type &a = this->get_stored_allocator(); + get_stored_allocator_noconst_return_t a = this->get_stored_allocator(); stored_allocator_traits::construct(a, &val, ::boost::forward(args)... ); - value_destructor d(a, val); + value_destructor d(a, val); return this->insert_equal(hint, ::boost::move(val)); } @@ -673,9 +851,9 @@ class flat_tree {\ typename aligned_storage::value>::type v;\ value_type &val = *static_cast(static_cast(&v));\ - stored_allocator_type &a = this->get_stored_allocator();\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ stored_allocator_traits::construct(a, &val BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - value_destructor d(a, val);\ + value_destructor d(a, val);\ return this->insert_unique(::boost::move(val));\ }\ \ @@ -684,9 +862,9 @@ class flat_tree {\ typename aligned_storage::value>::type v;\ value_type &val = *static_cast(static_cast(&v));\ - stored_allocator_type &a = this->get_stored_allocator();\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ stored_allocator_traits::construct(a, &val BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - value_destructor d(a, val);\ + value_destructor d(a, val);\ return this->insert_unique(hint, ::boost::move(val));\ }\ \ @@ -695,9 +873,9 @@ class flat_tree {\ typename aligned_storage::value>::type v;\ value_type &val = *static_cast(static_cast(&v));\ - stored_allocator_type &a = this->get_stored_allocator();\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ stored_allocator_traits::construct(a, &val BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - value_destructor d(a, val);\ + value_destructor d(a, val);\ return this->insert_equal(::boost::move(val));\ }\ \ @@ -706,9 +884,9 @@ class flat_tree {\ typename aligned_storage ::value>::type v;\ value_type &val = *static_cast(static_cast(&v));\ - stored_allocator_type &a = this->get_stored_allocator();\ + get_stored_allocator_noconst_return_t a = this->get_stored_allocator();\ stored_allocator_traits::construct(a, &val BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - value_destructor d(a, val);\ + value_destructor d(a, val);\ return this->insert_equal(hint, ::boost::move(val));\ }\ template \ @@ -790,16 +968,32 @@ class flat_tree { this->m_data.m_seq.shrink_to_fit(); } BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_seq.nth(n); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_nth::value; + return flat_tree_nth(this->m_data.m_seq, n, container_detail::bool_()); + } BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_seq.nth(n); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_nth::value; + return flat_tree_nth(this->m_data.m_seq, n, container_detail::bool_()); + } BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_seq.index_of(p); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_index_of::value; + return flat_tree_index_of(this->m_data.m_seq, p, container_detail::bool_()); + } BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_seq.index_of(p); } + { + const bool value = boost::container::container_detail:: + has_member_function_callable_with_index_of::value; + return flat_tree_index_of(this->m_data.m_seq, p, container_detail::bool_()); + } // set operations: iterator find(const key_type& k) @@ -832,33 +1026,41 @@ class flat_tree } template - void merge_unique(flat_tree& source) + BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& source) { this->insert( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end())); } template - void merge_equal(flat_tree& source) + BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree& source) { this->insert( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end())); } - void merge_unique(flat_tree& source) + BOOST_CONTAINER_FORCEINLINE void merge_unique(flat_tree& source) { - this->m_data.m_seq.merge_unique - ( boost::make_move_iterator(source.begin()) - , boost::make_move_iterator(source.end()) - , static_cast(this->m_data)); + const bool value = boost::container::container_detail:: + has_member_function_callable_with_merge_unique::value; + (flat_tree_merge_unique) + ( this->m_data.m_seq + , boost::make_move_iterator(source.m_data.m_seq.begin()) + , boost::make_move_iterator(source.m_data.m_seq.end()) + , this->priv_value_comp() + , container_detail::bool_()); } - void merge_equal(flat_tree& source) + BOOST_CONTAINER_FORCEINLINE void merge_equal(flat_tree& source) { - this->m_data.m_seq.merge - ( boost::make_move_iterator(source.begin()) - , boost::make_move_iterator(source.end()) - , static_cast(this->m_data)); + const bool value = boost::container::container_detail:: + has_member_function_callable_with_merge::value; + (flat_tree_merge_equal) + ( this->m_data.m_seq + , boost::make_move_iterator(source.m_data.m_seq.begin()) + , boost::make_move_iterator(source.m_data.m_seq.end()) + , this->priv_value_comp() + , container_detail::bool_()); } BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k) @@ -891,54 +1093,66 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt) { this->m_data.m_seq.reserve(cnt); } - BOOST_CONTAINER_FORCEINLINE sequence_type extract_sequence() + BOOST_CONTAINER_FORCEINLINE container_type extract_sequence() { return boost::move(m_data.m_seq); } - BOOST_CONTAINER_FORCEINLINE sequence_type &get_sequence_ref() + BOOST_CONTAINER_FORCEINLINE container_type &get_sequence_ref() { return m_data.m_seq; } - void adopt_sequence_equal(BOOST_RV_REF(sequence_type) seq) + void adopt_sequence_equal(BOOST_RV_REF(container_type) seq) { - sequence_type &tseq = m_data.m_seq; - boost::movelib::adaptive_sort - ( boost::movelib::iterator_to_raw_pointer(seq.begin()) - , boost::movelib::iterator_to_raw_pointer(seq.end()) - , this->priv_value_comp() - , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) - , tseq.capacity() - tseq.size()); + container_type &tseq = m_data.m_seq; + if (is_contiguous_container::value){ + boost::movelib::adaptive_sort + ( boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + } + else{ + boost::movelib::adaptive_sort + (seq.begin(), seq.end(), this->priv_value_comp()); + } tseq = boost::move(seq); } - void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + void adopt_sequence_unique(BOOST_RV_REF(container_type) seq) { - BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp())); - sequence_type &tseq = m_data.m_seq; - tseq = boost::move(seq); - } - - void adopt_sequence_unique(BOOST_RV_REF(sequence_type) seq) - { - sequence_type &tseq = m_data.m_seq; - boost::movelib::adaptive_sort - ( boost::movelib::iterator_to_raw_pointer(seq.begin()) - , boost::movelib::iterator_to_raw_pointer(seq.end()) - , this->priv_value_comp() - , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) - , tseq.capacity() - tseq.size()); + container_type &tseq = m_data.m_seq; + if (is_contiguous_container::value){ + boost::movelib::adaptive_sort + ( boost::movelib::iterator_to_raw_pointer(seq.begin()) + , boost::movelib::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , boost::movelib::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + } + else{ + boost::movelib::adaptive_sort + ( seq.begin(), seq.end(), this->priv_value_comp()); + } seq.erase( boost::movelib::unique (seq.begin(), seq.end(), boost::movelib::negate(this->m_data.get_comp())) , seq.cend()); tseq = boost::move(seq); } - void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(container_type) seq) + { + BOOST_ASSERT((is_sorted)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + container_type &tseq = m_data.m_seq; + tseq = boost::move(seq); + } + + void adopt_sequence_unique(ordered_unique_range_t, BOOST_RV_REF(container_type) seq) { BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp())); - sequence_type &tseq = m_data.m_seq; + container_type &tseq = m_data.m_seq; tseq = boost::move(seq); } @@ -993,11 +1207,6 @@ class flat_tree return (this->begin() <= pos) && (pos <= this->end()); } - struct insert_commit_data - { - const_iterator position; - }; - // insert/erase void priv_insert_equal_prepare (const_iterator pos, const value_type& val, insert_commit_data &data) @@ -1216,11 +1425,13 @@ class flat_tree //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations template -struct has_trivial_destructor_after_move > +class Compare, class AllocatorOrContainer> +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename boost::container::container_detail::select_container_type::type container_type; + typedef typename container_type::allocator_type allocator_t; + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/detail/is_container.hpp b/include/boost/container/detail/is_container.hpp new file mode 100644 index 0000000..6052f04 --- /dev/null +++ b/include/boost/container/detail/is_container.hpp @@ -0,0 +1,55 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. 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_DETAIL_IS_CONTAINER_HPP +#define BOOST_CONTAINER_DETAIL_IS_CONTAINER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//empty +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME empty +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_container_detail { +#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 + +//size +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME size +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_container_detail { +#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 + +namespace boost { +namespace container { +namespace container_detail { + +template +struct is_container +{ + static const bool value = + boost::container::is_container_detail:: + has_member_function_callable_with_size ::value && + boost::container::is_container_detail:: + has_member_function_callable_with_empty::value; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_CONTAINER_HPP diff --git a/include/boost/container/detail/is_contiguous_container.hpp b/include/boost/container/detail/is_contiguous_container.hpp new file mode 100644 index 0000000..af98c7f --- /dev/null +++ b/include/boost/container/detail/is_contiguous_container.hpp @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. 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_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP +#define BOOST_CONTAINER_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//data +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME data +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace is_contiguous_container_detail { +#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 + +namespace boost { +namespace container { +namespace container_detail { + +template +struct is_contiguous_container +{ + static const bool value = + boost::container::is_contiguous_container_detail:: + has_member_function_callable_with_data::value && + boost::container::is_contiguous_container_detail:: + has_member_function_callable_with_data::value; +}; + +} //namespace container_detail { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_IS_CONTIGUOUS_CONTAINER_HPP diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 4ef95e6..7945cd9 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -53,7 +53,7 @@ namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -template +template class flat_multimap; namespace container_detail{ @@ -76,37 +76,37 @@ BOOST_CONTAINER_FORCEINLINE static D force_copy(const S &s) //! A flat_map is a kind of associative container that supports unique keys (contains at //! most one of each key value) and provides for fast retrieval of values of another -//! type T based on the keys. The flat_map class supports random-access iterators. +//! type T based on the keys. //! -//! A flat_map satisfies all of the requirements of a container and of a reversible -//! container and of an associative container. A flat_map also provides +//! A flat_map satisfies all of the requirements of a container, a reversible +//! container and an associative container. A flat_map also provides //! most operations described for unique keys. For a //! flat_map the key_type is Key and the value_type is std::pair //! (unlike std::map which value_type is std::pair<const Key, T>). //! -//! Compare is the ordering function for Keys (e.g. std::less). +//! flat_map is similar to std::map but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default vector but it can also work +//! user-provided vector-like SequenceContainers (like static_vector or small_vector). //! -//! Allocator is the allocator to allocate the value_types -//! (e.g. allocator< std::pair >). -//! -//! flat_map is similar to std::map but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_map invalidates -//! previous iterators and references -//! -//! Erasing an element invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. +//! Using vector-like sequence containers means that inserting a new element into a flat_map might invalidate +//! previous iterators and references (unless that sequence container is stable_vector or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. //! //! This container provides random-access iterators. //! //! \tparam Key is the key_type of the map //! \tparam Value is the mapped_type //! \tparam Compare is the ordering function for Keys (e.g. std::less). -//! \tparam Allocator is the allocator to allocate the value_types -//! (e.g. allocator< std::pair > ). +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate value_types (e.g. allocator< std::pair > ). +//! (in this case sequence_type will be vector) +//! - The SequenceContainer to be used as the underlying sequence_type. It must be a vector-like +//! sequence container with random-access iterators.. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = new_allocator< std::pair< Key, T> > > +template , class AllocatorOrContainer = new_allocator< std::pair< Key, T> > > #else -template +template #endif class flat_map { @@ -118,14 +118,14 @@ class flat_map std::pair, container_detail::select1st, Compare, - Allocator> tree_t; + AllocatorOrContainer> tree_t; //This is the real tree stored here. It's based on a movable pair typedef container_detail::flat_tree< container_detail::pair, container_detail::select1st, Compare, - typename allocator_traits::template portable_rebind_alloc + typename allocator_traits::template portable_rebind_alloc >::type> impl_tree_t; impl_tree_t m_flat_tree; // flat tree representing flat_map @@ -133,18 +133,18 @@ class flat_map typedef typename impl_tree_t::const_iterator impl_const_iterator; typedef typename impl_tree_t::iterator impl_iterator; typedef typename impl_tree_t::allocator_type impl_allocator_type; + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef std::initializer_list impl_initializer_list; + #endif + typedef container_detail::flat_tree_value_compare < Compare , container_detail::select1st - , std::pair > value_compare_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::iterator iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::const_iterator const_iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::reverse_iterator reverse_iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::const_reverse_iterator const_reverse_iterator_impl; + , std::pair > value_compare_t; + typedef typename tree_t::iterator iterator_t; + typedef typename tree_t::const_iterator const_iterator_t; + typedef typename tree_t::reverse_iterator reverse_iterator_t; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator_t; public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; @@ -168,27 +168,28 @@ class flat_map ////////////////////////////////////////////// typedef Key key_type; typedef T mapped_type; - typedef std::pair value_type; - typedef ::boost::container::allocator_traits allocator_traits_type; - typedef typename boost::container::allocator_traits::pointer pointer; - typedef typename boost::container::allocator_traits::const_pointer const_pointer; - typedef typename boost::container::allocator_traits::reference reference; - typedef typename boost::container::allocator_traits::const_reference const_reference; - typedef typename boost::container::allocator_traits::size_type size_type; - typedef typename boost::container::allocator_traits::difference_type difference_type; - typedef Allocator allocator_type; - typedef BOOST_CONTAINER_IMPDEF(Allocator) stored_allocator_type; - typedef BOOST_CONTAINER_IMPDEF(value_compare_impl) value_compare; typedef Compare key_compare; - typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; - typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; - typedef BOOST_CONTAINER_IMPDEF(reverse_iterator_impl) reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(const_reverse_iterator_impl) const_reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + typedef std::pair value_type; typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; - //Allocator::value_type must be std::pair - BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + + //AllocatorOrContainer::value_type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename allocator_type::value_type>::value)); ////////////////////////////////////////////// // @@ -199,7 +200,7 @@ class flat_map //! Effects: Default constructs an empty flat_map. //! //! Complexity: Constant. - BOOST_CONTAINER_FORCEINLINE flat_map() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + BOOST_CONTAINER_FORCEINLINE flat_map() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) : m_flat_tree() {} @@ -309,7 +310,7 @@ class flat_map template BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) - : m_flat_tree(ordered_range, first, last, comp, a) + : m_flat_tree(ordered_range, first, last, comp, container_detail::force(a)) {} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -319,7 +320,9 @@ class flat_map //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list il) - : m_flat_tree(true, il.begin(), il.end()) + : m_flat_tree( true + , container_detail::force(il).begin() + , container_detail::force(il).end()) {} //! Effects: Constructs an empty flat_map using the specified @@ -328,7 +331,10 @@ class flat_map //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list il, const allocator_type& a) - : m_flat_tree(true, il.begin(), il.end(), container_detail::force(a)) + : m_flat_tree( true + , container_detail::force(il).begin() + , container_detail::force(il).end() + , container_detail::force(a)) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -337,7 +343,10 @@ class flat_map //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list il, const Compare& comp) - : m_flat_tree(true, il.begin(), il.end(), comp) + : m_flat_tree(true + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -346,7 +355,11 @@ class flat_map //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_map(std::initializer_list il, const Compare& comp, const allocator_type& a) - : m_flat_tree(true, il.begin(), il.end(), comp, container_detail::force(a)) + : m_flat_tree(true + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp + , container_detail::force(a)) {} //! Effects: Constructs an empty flat_map using and @@ -360,7 +373,9 @@ class flat_map //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list il) - : m_flat_tree(ordered_unique_range, il.begin(), il.end()) + : m_flat_tree(ordered_unique_range + , container_detail::force(il).begin() + , container_detail::force(il).end()) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -374,7 +389,10 @@ class flat_map //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list il, const Compare& comp) - : m_flat_tree(ordered_unique_range, il.begin(), il.end(), comp) + : m_flat_tree(ordered_unique_range + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -388,7 +406,11 @@ class flat_map //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_map(ordered_unique_range_t, std::initializer_list il, const Compare& comp, const allocator_type& a) - : m_flat_tree(ordered_unique_range, il.begin(), il.end(), comp, a) + : m_flat_tree( ordered_unique_range + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp + , container_detail::force(a)) {} #endif @@ -414,7 +436,7 @@ class flat_map //! //! Complexity: Linear in x.size(). BOOST_CONTAINER_FORCEINLINE flat_map(const flat_map& x, const allocator_type &a) - : m_flat_tree(x.m_flat_tree, a) + : m_flat_tree(x.m_flat_tree, container_detail::force(a)) {} //! Effects: Move constructs a flat_map using the specified allocator. @@ -422,7 +444,7 @@ class flat_map //! //! Complexity: Constant if x.get_allocator() == a, linear otherwise. BOOST_CONTAINER_FORCEINLINE flat_map(BOOST_RV_REF(flat_map) x, const allocator_type &a) - : m_flat_tree(boost::move(x.m_flat_tree), a) + : m_flat_tree(boost::move(x.m_flat_tree), container_detail::force(a)) {} //! Effects: Makes *this a copy of x. @@ -1114,7 +1136,10 @@ class flat_map //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) - { m_flat_tree.insert_unique(il.begin(), il.end()); } + { + m_flat_tree.insert_unique( container_detail::force(il).begin() + , container_detail::force(il).end()); + } //! Requires: [il.begin(), il.end()) must be ordered according to the predicate and must be //! unique values. @@ -1130,7 +1155,11 @@ class flat_map //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, std::initializer_list il) - { m_flat_tree.insert_unique(ordered_unique_range, il.begin(), il.end()); } + { + m_flat_tree.insert_unique(ordered_unique_range + , container_detail::force(il).begin() + , container_detail::force(il).end()); + } #endif //! Requires: this->get_allocator() == source.get_allocator(). @@ -1148,23 +1177,23 @@ class flat_map //! //! Complexity: N log(a.size() + N) (N has the value source.size()) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) + BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) { m_flat_tree.merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_map::merge(flat_map&) + //! @copydoc ::boost::container::flat_map::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } - //! @copydoc ::boost::container::flat_map::merge(flat_map&) + //! @copydoc ::boost::container::flat_map::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) + BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) { m_flat_tree.merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_map::merge(flat_map&) + //! @copydoc ::boost::container::flat_map::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } //! Effects: Erases the element pointed to by p. //! @@ -1417,11 +1446,11 @@ class flat_map //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; @@ -1432,37 +1461,36 @@ namespace container { //! A flat_multimap is a kind of associative container that supports equivalent keys //! (possibly containing multiple copies of the same key value) and provides for -//! fast retrieval of values of another type T based on the keys. The flat_multimap -//! class supports random-access iterators. +//! fast retrieval of values of another type T based on the keys. //! //! A flat_multimap satisfies all of the requirements of a container and of a reversible //! container and of an associative container. For a //! flat_multimap the key_type is Key and the value_type is std::pair //! (unlike std::multimap which value_type is std::pair<const Key, T>). //! -//! Compare is the ordering function for Keys (e.g. std::less). +//! flat_multimap is similar to std::multimap but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default vector but it can also work +//! user-provided vector-like SequenceContainers (like static_vector or small_vector). //! -//! Allocator is the allocator to allocate the value_types -//! (e.g. allocator< std::pair >). -//! -//! flat_multimap is similar to std::multimap but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_map invalidates -//! previous iterators and references -//! -//! Erasing an element invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. +//! Using vector-like sequence containers means that inserting a new element into a flat_multimap might invalidate +//! previous iterators and references (unless that sequence container is stable_vector or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. //! //! This container provides random-access iterators. //! //! \tparam Key is the key_type of the map //! \tparam Value is the mapped_type //! \tparam Compare is the ordering function for Keys (e.g. std::less). -//! \tparam Allocator is the allocator to allocate the value_types -//! (e.g. allocator< std::pair > ). +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate value_types (e.g. allocator< std::pair > ). +//! (in this case sequence_type will be vector) +//! - The SequenceContainer to be used as the underlying sequence_type. It must be a vector-like +//! sequence container with random-access iterators. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = new_allocator< std::pair< Key, T> > > +template , class AllocatorOrContainer = new_allocator< std::pair< Key, T> > > #else -template +template #endif class flat_multimap { @@ -1473,13 +1501,13 @@ class flat_multimap std::pair, container_detail::select1st, Compare, - Allocator> tree_t; + AllocatorOrContainer> tree_t; //This is the real tree stored here. It's based on a movable pair typedef container_detail::flat_tree< container_detail::pair, container_detail::select1st, Compare, - typename allocator_traits::template portable_rebind_alloc + typename allocator_traits::template portable_rebind_alloc >::type> impl_tree_t; impl_tree_t m_flat_tree; // flat tree representing flat_map @@ -1487,21 +1515,22 @@ class flat_multimap typedef typename impl_tree_t::const_iterator impl_const_iterator; typedef typename impl_tree_t::iterator impl_iterator; typedef typename impl_tree_t::allocator_type impl_allocator_type; + #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + typedef std::initializer_list impl_initializer_list; + #endif + typedef container_detail::flat_tree_value_compare < Compare , container_detail::select1st - , std::pair > value_compare_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::iterator iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::const_iterator const_iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::reverse_iterator reverse_iterator_impl; - typedef typename container_detail::get_flat_tree_iterators - ::pointer>::const_reverse_iterator const_reverse_iterator_impl; + , std::pair > value_compare_t; + typedef typename tree_t::iterator iterator_t; + typedef typename tree_t::const_iterator const_iterator_t; + typedef typename tree_t::reverse_iterator reverse_iterator_t; + typedef typename tree_t::const_reverse_iterator const_reverse_iterator_t; + public: - typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; - typedef typename impl_tree_t::sequence_type impl_sequence_type; + typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; BOOST_CONTAINER_FORCEINLINE impl_tree_t &tree() { return m_flat_tree; } @@ -1521,27 +1550,28 @@ class flat_multimap ////////////////////////////////////////////// typedef Key key_type; typedef T mapped_type; - typedef std::pair value_type; - typedef ::boost::container::allocator_traits allocator_traits_type; - typedef typename boost::container::allocator_traits::pointer pointer; - typedef typename boost::container::allocator_traits::const_pointer const_pointer; - typedef typename boost::container::allocator_traits::reference reference; - typedef typename boost::container::allocator_traits::const_reference const_reference; - typedef typename boost::container::allocator_traits::size_type size_type; - typedef typename boost::container::allocator_traits::difference_type difference_type; - typedef Allocator allocator_type; - typedef BOOST_CONTAINER_IMPDEF(Allocator) stored_allocator_type; - typedef BOOST_CONTAINER_IMPDEF(value_compare_impl) value_compare; typedef Compare key_compare; - typedef BOOST_CONTAINER_IMPDEF(iterator_impl) iterator; - typedef BOOST_CONTAINER_IMPDEF(const_iterator_impl) const_iterator; - typedef BOOST_CONTAINER_IMPDEF(reverse_iterator_impl) reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(const_reverse_iterator_impl) const_reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + typedef std::pair value_type; typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; - //Allocator::value_type must be std::pair - BOOST_STATIC_ASSERT((container_detail::is_same, typename Allocator::value_type>::value)); + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(impl_value_type) movable_value_type; + + //AllocatorOrContainer::value_type must be std::pair + BOOST_STATIC_ASSERT((container_detail::is_same, typename AllocatorOrContainer::value_type>::value)); ////////////////////////////////////////////// // @@ -1553,7 +1583,7 @@ class flat_multimap //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE flat_multimap() - BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) : m_flat_tree() {} @@ -1679,7 +1709,9 @@ class flat_multimap //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_multimap(std::initializer_list il) - : m_flat_tree(false, il.begin(), il.end()) + : m_flat_tree( false + , container_detail::force(il).begin() + , container_detail::force(il).end()) {} //! Effects: Constructs an empty flat_map using the specified @@ -1689,7 +1721,10 @@ class flat_multimap //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_multimap(std::initializer_list il, const allocator_type& a) - : m_flat_tree(false, il.begin(), il.end(), container_detail::force(a)) + : m_flat_tree(false + , container_detail::force(il).begin() + , container_detail::force(il).end() + , container_detail::force(a)) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -1699,7 +1734,9 @@ class flat_multimap //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_multimap(std::initializer_list il, const Compare& comp) - : m_flat_tree(false, il.begin(), il.end(), comp) + : m_flat_tree(false + , container_detail::force(il).begin() + , container_detail::force(il).end(), comp) {} //! Effects: Constructs an empty flat_map using the specified comparison object and @@ -1709,7 +1746,10 @@ class flat_multimap //! the predicate and otherwise N logN, where N is last - first. BOOST_CONTAINER_FORCEINLINE flat_multimap(std::initializer_list il, const Compare& comp, const allocator_type& a) - : m_flat_tree(false, il.begin(), il.end(), comp, container_detail::force(a)) + : m_flat_tree( false + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp, container_detail::force(a)) {} //! Effects: Constructs an empty flat_multimap and @@ -1723,7 +1763,9 @@ class flat_multimap //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multimap(ordered_range_t, std::initializer_list il) - : m_flat_tree(ordered_range, il.begin(), il.end()) + : m_flat_tree( ordered_range + , container_detail::force(il).begin() + , container_detail::force(il).end()) {} //! Effects: Constructs an empty flat_multimap using the specified comparison object and @@ -1737,7 +1779,9 @@ class flat_multimap //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multimap(ordered_range_t, std::initializer_list il, const Compare& comp) - : m_flat_tree(ordered_range, il.begin(), il.end(), comp) + : m_flat_tree( ordered_range + , container_detail::force(il).begin() + , container_detail::force(il).end(), comp) {} //! Effects: Constructs an empty flat_multimap using the specified comparison object and @@ -1751,7 +1795,10 @@ class flat_multimap //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multimap(ordered_range_t, std::initializer_list il, const Compare& comp, const allocator_type& a) - : m_flat_tree(ordered_range, il.begin(), il.end(), comp, a) + : m_flat_tree( ordered_range + , container_detail::force(il).begin() + , container_detail::force(il).end() + , comp, a) {} #endif @@ -2235,7 +2282,10 @@ class flat_multimap //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) - { m_flat_tree.insert_equal(il.begin(), il.end()); } + { + m_flat_tree.insert_equal( container_detail::force(il).begin() + , container_detail::force(il).end()); + } //! Requires: [il.begin(), il.end()) must be ordered according to the predicate. //! @@ -2250,7 +2300,11 @@ class flat_multimap //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, std::initializer_list il) - { m_flat_tree.insert_equal(ordered_range, il.begin(), il.end()); } + { + m_flat_tree.insert_equal( ordered_range + , container_detail::force(il).begin() + , container_detail::force(il).end()); + } #endif //! Requires: this->get_allocator() == source.get_allocator(). @@ -2267,23 +2321,23 @@ class flat_multimap //! //! Complexity: N log(a.size() + N) (N has the value source.size()) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) + BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) { m_flat_tree.merge_equal(source.tree()); } - //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } - //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) + BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) { m_flat_tree.merge_equal(source.tree()); } - //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } //! Effects: Erases the element pointed to by p. //! @@ -2512,11 +2566,11 @@ namespace boost { //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move< boost::container::flat_multimap > +template +struct has_trivial_destructor_after_move< boost::container::flat_multimap > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 064145c..61ceb9e 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -48,45 +48,51 @@ namespace boost { namespace container { #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) -template -class flat_multimap; +template +class flat_multiset; #endif //! flat_set is a Sorted Associative Container that stores objects of type Key. //! It is also a Unique Associative Container, meaning that no two elements are the same. //! -//! flat_set is similar to std::set but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_set invalidates -//! previous iterators and references +//! flat_set is similar to std::set but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default vector but it can also work +//! user-provided vector-like SequenceContainers (like static_vector or small_vector). //! -//! Erasing an element of a flat_set invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. +//! Using vector-like sequence containers means that inserting a new element into a flat_set might invalidate +//! previous iterators and references (unless that sequence container is stable_vector or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. //! //! This container provides random-access iterators. //! //! \tparam Key is the type to be inserted in the set, which is also the key_type //! \tparam Compare is the comparison functor used to order keys -//! \tparam Allocator is the allocator to be used to allocate memory for this container +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate value_types (e.g. allocator< std::pair > ). +//! (in this case sequence_type will be vector) +//! - The SequenceContainer to be used as the underlying sequence_type. It must be a vector-like +//! sequence container with random-access iterators. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = new_allocator > +template , class AllocatorOrContainer = new_allocator > #else -template +template #endif class flat_set ///@cond - : public container_detail::flat_tree, Compare, Allocator> + : public container_detail::flat_tree, Compare, AllocatorOrContainer> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(flat_set) - typedef container_detail::flat_tree, Compare, Allocator> base_t; + typedef container_detail::flat_tree, Compare, AllocatorOrContainer> tree_t; public: - base_t &tree() + tree_t &tree() { return *this; } - const base_t &tree() const + const tree_t &tree() const { return *this; } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -97,24 +103,25 @@ class flat_set // types // ////////////////////////////////////////////// - typedef Key key_type; - typedef Key value_type; - typedef Compare key_compare; - typedef Compare value_compare; - typedef ::boost::container::allocator_traits allocator_traits_type; - typedef typename ::boost::container::allocator_traits::pointer pointer; - typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; - typedef typename ::boost::container::allocator_traits::reference reference; - typedef typename ::boost::container::allocator_traits::const_reference const_reference; - typedef typename ::boost::container::allocator_traits::size_type size_type; - typedef typename ::boost::container::allocator_traits::difference_type difference_type; - typedef Allocator allocator_type; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::stored_allocator_type) stored_allocator_type; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::iterator) iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::sequence_type) sequence_type; + typedef Key key_type; + typedef Compare key_compare; + typedef Key value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; + + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; public: ////////////////////////////////////////////// @@ -127,9 +134,9 @@ class flat_set //! //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE - flat_set() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + flat_set() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) - : base_t() + : tree_t() {} //! Effects: Constructs an empty container using the specified @@ -138,7 +145,7 @@ class flat_set //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE explicit flat_set(const Compare& comp) - : base_t(comp) + : tree_t(comp) {} //! Effects: Constructs an empty container using the specified allocator. @@ -146,7 +153,7 @@ class flat_set //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE explicit flat_set(const allocator_type& a) - : base_t(a) + : tree_t(a) {} //! Effects: Constructs an empty container using the specified @@ -155,7 +162,7 @@ class flat_set //! Complexity: Constant. BOOST_CONTAINER_FORCEINLINE flat_set(const Compare& comp, const allocator_type& a) - : base_t(comp, a) + : tree_t(comp, a) {} //! Effects: Constructs an empty container and @@ -166,7 +173,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(InputIterator first, InputIterator last) - : base_t(true, first, last) + : tree_t(true, first, last) {} //! Effects: Constructs an empty container using the specified @@ -177,7 +184,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(InputIterator first, InputIterator last, const allocator_type& a) - : base_t(true, first, last, a) + : tree_t(true, first, last, a) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -188,7 +195,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(InputIterator first, InputIterator last, const Compare& comp) - : base_t(true, first, last, comp) + : tree_t(true, first, last, comp) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -199,7 +206,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) - : base_t(true, first, last, comp, a) + : tree_t(true, first, last, comp, a) {} //! Effects: Constructs an empty container and @@ -215,7 +222,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, InputIterator first, InputIterator last) - : base_t(ordered_unique_range, first, last) + : tree_t(ordered_unique_range, first, last) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -231,7 +238,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp) - : base_t(ordered_unique_range, first, last, comp) + : tree_t(ordered_unique_range, first, last, comp) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -247,7 +254,7 @@ class flat_set template BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) - : base_t(ordered_unique_range, first, last, comp, a) + : tree_t(ordered_unique_range, first, last, comp, a) {} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -257,7 +264,7 @@ class flat_set //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! comp and otherwise N logN, where N is il.begin() - il.end(). BOOST_CONTAINER_FORCEINLINE flat_set(std::initializer_list il) - : base_t(true, il.begin(), il.end()) + : tree_t(true, il.begin(), il.end()) {} //! Effects: Constructs an empty container using the specified @@ -266,7 +273,7 @@ class flat_set //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! comp and otherwise N logN, where N is il.begin() - il.end(). BOOST_CONTAINER_FORCEINLINE flat_set(std::initializer_list il, const allocator_type& a) - : base_t(true, il.begin(), il.end(), a) + : tree_t(true, il.begin(), il.end(), a) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -275,7 +282,7 @@ class flat_set //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! comp and otherwise N logN, where N is il.begin() - il.end(). BOOST_CONTAINER_FORCEINLINE flat_set(std::initializer_list il, const Compare& comp) - : base_t(true, il.begin(), il.end(), comp) + : tree_t(true, il.begin(), il.end(), comp) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -284,7 +291,7 @@ class flat_set //! Complexity: Linear in N if the range [il.begin(), il.end()) is already sorted using //! comp and otherwise N logN, where N is il.begin() - il.end(). BOOST_CONTAINER_FORCEINLINE flat_set(std::initializer_list il, const Compare& comp, const allocator_type& a) - : base_t(true, il.begin(), il.end(), comp, a) + : tree_t(true, il.begin(), il.end(), comp, a) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -298,7 +305,7 @@ class flat_set //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, std::initializer_list il) - : base_t(ordered_unique_range, il.begin(), il.end()) + : tree_t(ordered_unique_range, il.begin(), il.end()) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -312,7 +319,7 @@ class flat_set //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, std::initializer_list il, const Compare& comp) - : base_t(ordered_unique_range, il.begin(), il.end(), comp) + : tree_t(ordered_unique_range, il.begin(), il.end(), comp) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -326,7 +333,7 @@ class flat_set //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_set(ordered_unique_range_t, std::initializer_list il, const Compare& comp, const allocator_type& a) - : base_t(ordered_unique_range, il.begin(), il.end(), comp, a) + : tree_t(ordered_unique_range, il.begin(), il.end(), comp, a) {} #endif @@ -334,7 +341,7 @@ class flat_set //! //! Complexity: Linear in x.size(). BOOST_CONTAINER_FORCEINLINE flat_set(const flat_set& x) - : base_t(static_cast(x)) + : tree_t(static_cast(x)) {} //! Effects: Move constructs thecontainer. Constructs *this using x's resources. @@ -344,14 +351,14 @@ class flat_set //! Postcondition: x is emptied. BOOST_CONTAINER_FORCEINLINE flat_set(BOOST_RV_REF(flat_set) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) - : base_t(BOOST_MOVE_BASE(base_t, x)) + : tree_t(BOOST_MOVE_BASE(tree_t, x)) {} //! Effects: Copy constructs a container using the specified allocator. //! //! Complexity: Linear in x.size(). BOOST_CONTAINER_FORCEINLINE flat_set(const flat_set& x, const allocator_type &a) - : base_t(static_cast(x), a) + : tree_t(static_cast(x), a) {} //! Effects: Move constructs a container using the specified allocator. @@ -359,14 +366,14 @@ class flat_set //! //! Complexity: Constant if a == x.get_allocator(), linear otherwise BOOST_CONTAINER_FORCEINLINE flat_set(BOOST_RV_REF(flat_set) x, const allocator_type &a) - : base_t(BOOST_MOVE_BASE(base_t, x), a) + : tree_t(BOOST_MOVE_BASE(tree_t, x), a) {} //! Effects: Makes *this a copy of x. //! //! Complexity: Linear in x.size(). BOOST_CONTAINER_FORCEINLINE flat_set& operator=(BOOST_COPY_ASSIGN_REF(flat_set) x) - { return static_cast(this->base_t::operator=(static_cast(x))); } + { return static_cast(this->tree_t::operator=(static_cast(x))); } //! Throws: If allocator_traits_type::propagate_on_container_move_assignment //! is false and (allocation throws or value_type's move constructor throws) @@ -378,7 +385,7 @@ class flat_set BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) && boost::container::container_detail::is_nothrow_move_assignable::value) - { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } + { return static_cast(this->tree_t::operator=(BOOST_MOVE_BASE(tree_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: Copy all elements from il to *this. @@ -579,7 +586,7 @@ class flat_set //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE std::pair emplace(BOOST_FWD_REF(Args)... args) - { return this->base_t::emplace_unique(boost::forward(args)...); } + { return this->tree_t::emplace_unique(boost::forward(args)...); } //! Effects: Inserts an object of type Key constructed with //! std::forward(args)... in the container if and only if there is @@ -595,18 +602,18 @@ class flat_set //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator p, BOOST_FWD_REF(Args)... args) - { return this->base_t::emplace_hint_unique(p, boost::forward(args)...); } + { return this->tree_t::emplace_hint_unique(p, boost::forward(args)...); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_FLAT_SET_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE std::pair emplace(BOOST_MOVE_UREF##N)\ - { return this->base_t::emplace_unique(BOOST_MOVE_FWD##N); }\ + { return this->tree_t::emplace_unique(BOOST_MOVE_FWD##N); }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - { return this->base_t::emplace_hint_unique(hint BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + { return this->tree_t::emplace_hint_unique(hint BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_SET_EMPLACE_CODE) #undef BOOST_CONTAINER_FLAT_SET_EMPLACE_CODE @@ -685,7 +692,7 @@ class flat_set //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) - { this->base_t::insert_unique(first, last); } + { this->tree_t::insert_unique(first, last); } //! Requires: first, last are not iterators into *this and //! must be ordered according to the predicate and must be @@ -700,7 +707,7 @@ class flat_set //! Note: Non-standard extension. If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, InputIterator first, InputIterator last) - { this->base_t::insert_unique(ordered_unique_range, first, last); } + { this->tree_t::insert_unique(ordered_unique_range, first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: inserts each element from the range [il.begin(), il.end()) if and only @@ -711,7 +718,7 @@ class flat_set //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) - { this->base_t::insert_unique(il.begin(), il.end()); } + { this->tree_t::insert_unique(il.begin(), il.end()); } //! Requires: Range [il.begin(), il.end()) must be ordered according to the predicate //! and must be unique values. @@ -724,28 +731,28 @@ class flat_set //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(ordered_unique_range_t, std::initializer_list il) - { this->base_t::insert_unique(ordered_unique_range, il.begin(), il.end()); } + { this->tree_t::insert_unique(ordered_unique_range, il.begin(), il.end()); } #endif - //! @copydoc ::boost::container::flat_map::merge(flat_map&) + //! @copydoc ::boost::container::flat_map::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) - { this->base_t::merge_unique(source.tree()); } + BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) + { this->tree_t::merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_set::merge(flat_set&) + //! @copydoc ::boost::container::flat_set::merge(flat_set&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } - //! @copydoc ::boost::container::flat_map::merge(flat_multimap&) + //! @copydoc ::boost::container::flat_map::merge(flat_multimap&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) - { this->base_t::merge_unique(source.tree()); } + BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) + { this->tree_t::merge_unique(source.tree()); } - //! @copydoc ::boost::container::flat_set::merge(flat_multiset&) + //! @copydoc ::boost::container::flat_set::merge(flat_multiset&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -875,7 +882,7 @@ class flat_set //! //! Complexity: log(size())+count(k) BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const - { return static_cast(this->base_t::find(x) != this->base_t::cend()); } + { return static_cast(this->tree_t::find(x) != this->tree_t::cend()); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Returns: An iterator pointing to the first element with key not less @@ -908,13 +915,13 @@ class flat_set //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& x) const - { return this->base_t::lower_bound_range(x); } + { return this->tree_t::lower_bound_range(x); } //! Effects: Equivalent to std::make_pair(this->lower_bound(k), this->upper_bound(k)). //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& x) - { return this->base_t::lower_bound_range(x); } + { return this->tree_t::lower_bound_range(x); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -971,7 +978,7 @@ class flat_set //! //! Throws: If the comparison or the move constructor throws BOOST_CONTAINER_FORCEINLINE void adopt_sequence(BOOST_RV_REF(sequence_type) seq) - { this->base_t::adopt_sequence_unique(boost::move(seq)); } + { this->tree_t::adopt_sequence_unique(boost::move(seq)); } //! Requires: seq shall be ordered according to this->compare() //! and shall contain unique elements. @@ -983,17 +990,17 @@ class flat_set //! //! Throws: If the move assignment throws BOOST_CONTAINER_FORCEINLINE void adopt_sequence(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) - { this->base_t::adopt_sequence_unique(ordered_unique_range_t(), boost::move(seq)); } + { this->tree_t::adopt_sequence_unique(ordered_unique_range_t(), boost::move(seq)); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template BOOST_CONTAINER_FORCEINLINE std::pair priv_insert(BOOST_FWD_REF(KeyType) x) - { return this->base_t::insert_unique(::boost::forward(x)); } + { return this->tree_t::insert_unique(::boost::forward(x)); } template BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator p, BOOST_FWD_REF(KeyType) x) - { return this->base_t::insert_unique(p, ::boost::forward(x)); } + { return this->tree_t::insert_unique(p, ::boost::forward(x)); } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; @@ -1003,11 +1010,11 @@ class flat_set //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; @@ -1016,42 +1023,47 @@ namespace container { #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -//! flat_multiset is a Sorted Associative Container that stores objects of type Key. +//! flat_multiset is a Sorted Associative Container that stores objects of type Key and +//! can store multiple copies of the same key value. //! -//! flat_multiset can store multiple copies of the same key value. +//! flat_multiset is similar to std::multiset but it's implemented by as an ordered sequence container. +//! The underlying sequence container is by default vector but it can also work +//! user-provided vector-like SequenceContainers (like static_vector or small_vector). //! -//! flat_multiset is similar to std::multiset but it's implemented like an ordered vector. -//! This means that inserting a new element into a flat_multiset invalidates -//! previous iterators and references -//! -//! Erasing an element invalidates iterators and references -//! pointing to elements that come after (their keys are bigger) the erased element. +//! Using vector-like sequence containers means that inserting a new element into a flat_multiset might invalidate +//! previous iterators and references (unless that sequence container is stable_vector or a similar +//! container that offers stable pointers and references). Similarly, erasing an element might invalidate +//! iterators and references pointing to elements that come after (their keys are bigger) the erased element. //! //! This container provides random-access iterators. //! //! \tparam Key is the type to be inserted in the multiset, which is also the key_type //! \tparam Compare is the comparison functor used to order keys -//! \tparam Allocator is the allocator to be used to allocate memory for this container +//! \tparam AllocatorOrContainer is either: +//! - The allocator to allocate value_types (e.g. allocator< std::pair > ). +//! (in this case sequence_type will be vector) +//! - The SequenceContainer to be used as the underlying sequence_type. It must be a vector-like +//! sequence container with random-access iterators. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = new_allocator > +template , class AllocatorOrContainer = new_allocator > #else -template +template #endif class flat_multiset ///@cond - : public container_detail::flat_tree, Compare, Allocator> + : public container_detail::flat_tree, Compare, AllocatorOrContainer> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(flat_multiset) - typedef container_detail::flat_tree, Compare, Allocator> base_t; + typedef container_detail::flat_tree, Compare, AllocatorOrContainer> tree_t; public: - base_t &tree() + tree_t &tree() { return *this; } - const base_t &tree() const + const tree_t &tree() const { return *this; } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1061,68 +1073,69 @@ class flat_multiset // types // ////////////////////////////////////////////// - typedef Key key_type; - typedef Key value_type; - typedef Compare key_compare; - typedef Compare value_compare; - typedef ::boost::container::allocator_traits allocator_traits_type; - typedef typename ::boost::container::allocator_traits::pointer pointer; - typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; - typedef typename ::boost::container::allocator_traits::reference reference; - typedef typename ::boost::container::allocator_traits::const_reference const_reference; - typedef typename ::boost::container::allocator_traits::size_type size_type; - typedef typename ::boost::container::allocator_traits::difference_type difference_type; - typedef Allocator allocator_type; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::stored_allocator_type) stored_allocator_type; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::iterator) iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; - typedef typename BOOST_CONTAINER_IMPDEF(base_t::sequence_type) sequence_type; + typedef Key key_type; + typedef Compare key_compare; + typedef Key value_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; + typedef typename sequence_type::allocator_type allocator_type; + typedef ::boost::container::allocator_traits allocator_traits_type; + typedef typename sequence_type::pointer pointer; + typedef typename sequence_type::const_pointer const_pointer; + typedef typename sequence_type::reference reference; + typedef typename sequence_type::const_reference const_reference; + typedef typename sequence_type::size_type size_type; + typedef typename sequence_type::difference_type difference_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::stored_allocator_type) stored_allocator_type; + typedef typename BOOST_CONTAINER_IMPDEF(tree_t::value_compare) value_compare; + + typedef typename sequence_type::iterator iterator; + typedef typename sequence_type::const_iterator const_iterator; + typedef typename sequence_type::reverse_iterator reverse_iterator; + typedef typename sequence_type::const_reverse_iterator const_reverse_iterator; //! @copydoc ::boost::container::flat_set::flat_set() - BOOST_CONTAINER_FORCEINLINE flat_multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + BOOST_CONTAINER_FORCEINLINE flat_multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) - : base_t() + : tree_t() {} //! @copydoc ::boost::container::flat_set::flat_set(const Compare&) BOOST_CONTAINER_FORCEINLINE explicit flat_multiset(const Compare& comp) - : base_t(comp) + : tree_t(comp) {} //! @copydoc ::boost::container::flat_set::flat_set(const allocator_type&) BOOST_CONTAINER_FORCEINLINE explicit flat_multiset(const allocator_type& a) - : base_t(a) + : tree_t(a) {} //! @copydoc ::boost::container::flat_set::flat_set(const Compare&, const allocator_type&) BOOST_CONTAINER_FORCEINLINE flat_multiset(const Compare& comp, const allocator_type& a) - : base_t(comp, a) + : tree_t(comp, a) {} //! @copydoc ::boost::container::flat_set::flat_set(InputIterator, InputIterator) template BOOST_CONTAINER_FORCEINLINE flat_multiset(InputIterator first, InputIterator last) - : base_t(false, first, last) + : tree_t(false, first, last) {} //! @copydoc ::boost::container::flat_set::flat_set(InputIterator, InputIterator, const allocator_type&) template BOOST_CONTAINER_FORCEINLINE flat_multiset(InputIterator first, InputIterator last, const allocator_type& a) - : base_t(false, first, last, a) + : tree_t(false, first, last, a) {} //! @copydoc ::boost::container::flat_set::flat_set(InputIterator, InputIterator, const Compare& comp) template BOOST_CONTAINER_FORCEINLINE flat_multiset(InputIterator first, InputIterator last, const Compare& comp) - : base_t(false, first, last, comp) + : tree_t(false, first, last, comp) {} //! @copydoc ::boost::container::flat_set::flat_set(InputIterator, InputIterator, const Compare& comp, const allocator_type&) template BOOST_CONTAINER_FORCEINLINE flat_multiset(InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) - : base_t(false, first, last, comp, a) + : tree_t(false, first, last, comp, a) {} //! Effects: Constructs an empty flat_multiset and @@ -1136,7 +1149,7 @@ class flat_multiset //! Note: Non-standard extension. template BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, InputIterator first, InputIterator last) - : base_t(ordered_range, first, last) + : tree_t(ordered_range, first, last) {} //! Effects: Constructs an empty flat_multiset using the specified comparison object and @@ -1150,7 +1163,7 @@ class flat_multiset //! Note: Non-standard extension. template BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp) - : base_t(ordered_range, first, last, comp) + : tree_t(ordered_range, first, last, comp) {} //! Effects: Constructs an empty flat_multiset using the specified comparison object and @@ -1164,28 +1177,28 @@ class flat_multiset //! Note: Non-standard extension. template BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp, const allocator_type& a) - : base_t(ordered_range, first, last, comp, a) + : tree_t(ordered_range, first, last, comp, a) {} #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! @copydoc ::boost::container::flat_set::flat_set(std::initializer_list il) - : base_t(false, il.begin(), il.end()) + : tree_t(false, il.begin(), il.end()) {} //! @copydoc ::boost::container::flat_set::flat_set(std::initializer_list, const allocator_type&) BOOST_CONTAINER_FORCEINLINE flat_multiset(std::initializer_list il, const allocator_type& a) - : base_t(false, il.begin(), il.end(), a) + : tree_t(false, il.begin(), il.end(), a) {} //! @copydoc ::boost::container::flat_set::flat_set(std::initializer_list, const Compare& comp) BOOST_CONTAINER_FORCEINLINE flat_multiset(std::initializer_list il, const Compare& comp) - : base_t(false, il.begin(), il.end(), comp) + : tree_t(false, il.begin(), il.end(), comp) {} //! @copydoc ::boost::container::flat_set::flat_set(std::initializer_list, const Compare& comp, const allocator_type&) BOOST_CONTAINER_FORCEINLINE flat_multiset(std::initializer_list il, const Compare& comp, const allocator_type& a) - : base_t(false, il.begin(), il.end(), comp, a) + : tree_t(false, il.begin(), il.end(), comp, a) {} //! Effects: Constructs an empty containerand @@ -1198,7 +1211,7 @@ class flat_multiset //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, std::initializer_list il) - : base_t(ordered_range, il.begin(), il.end()) + : tree_t(ordered_range, il.begin(), il.end()) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -1211,7 +1224,7 @@ class flat_multiset //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, std::initializer_list il, const Compare& comp) - : base_t(ordered_range, il.begin(), il.end(), comp) + : tree_t(ordered_range, il.begin(), il.end(), comp) {} //! Effects: Constructs an empty container using the specified comparison object and @@ -1224,41 +1237,41 @@ class flat_multiset //! //! Note: Non-standard extension. BOOST_CONTAINER_FORCEINLINE flat_multiset(ordered_range_t, std::initializer_list il, const Compare& comp, const allocator_type& a) - : base_t(ordered_range, il.begin(), il.end(), comp, a) + : tree_t(ordered_range, il.begin(), il.end(), comp, a) {} #endif //! @copydoc ::boost::container::flat_set::flat_set(const flat_set &) BOOST_CONTAINER_FORCEINLINE flat_multiset(const flat_multiset& x) - : base_t(static_cast(x)) + : tree_t(static_cast(x)) {} //! @copydoc ::boost::container::flat_set::flat_set(flat_set &&) BOOST_CONTAINER_FORCEINLINE flat_multiset(BOOST_RV_REF(flat_multiset) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) - : base_t(boost::move(static_cast(x))) + : tree_t(boost::move(static_cast(x))) {} //! @copydoc ::boost::container::flat_set::flat_set(const flat_set &, const allocator_type &) BOOST_CONTAINER_FORCEINLINE flat_multiset(const flat_multiset& x, const allocator_type &a) - : base_t(static_cast(x), a) + : tree_t(static_cast(x), a) {} //! @copydoc ::boost::container::flat_set::flat_set(flat_set &&, const allocator_type &) BOOST_CONTAINER_FORCEINLINE flat_multiset(BOOST_RV_REF(flat_multiset) x, const allocator_type &a) - : base_t(BOOST_MOVE_BASE(base_t, x), a) + : tree_t(BOOST_MOVE_BASE(tree_t, x), a) {} //! @copydoc ::boost::container::flat_set::operator=(const flat_set &) BOOST_CONTAINER_FORCEINLINE flat_multiset& operator=(BOOST_COPY_ASSIGN_REF(flat_multiset) x) - { return static_cast(this->base_t::operator=(static_cast(x))); } + { return static_cast(this->tree_t::operator=(static_cast(x))); } //! @copydoc ::boost::container::flat_set::operator=(flat_set &&) BOOST_CONTAINER_FORCEINLINE flat_multiset& operator=(BOOST_RV_REF(flat_multiset) x) BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) && boost::container::container_detail::is_nothrow_move_assignable::value) - { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } + { return static_cast(this->tree_t::operator=(BOOST_MOVE_BASE(tree_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! @copydoc ::boost::container::flat_set::operator=(std::initializer_list) @@ -1355,7 +1368,7 @@ class flat_multiset //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_FWD_REF(Args)... args) - { return this->base_t::emplace_equal(boost::forward(args)...); } + { return this->tree_t::emplace_equal(boost::forward(args)...); } //! Effects: Inserts an object of type Key constructed with //! std::forward(args)... in the container. @@ -1370,18 +1383,18 @@ class flat_multiset //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator p, BOOST_FWD_REF(Args)... args) - { return this->base_t::emplace_hint_equal(p, boost::forward(args)...); } + { return this->tree_t::emplace_hint_equal(p, boost::forward(args)...); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_FLAT_MULTISET_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_MOVE_UREF##N)\ - { return this->base_t::emplace_equal(BOOST_MOVE_FWD##N); }\ + { return this->tree_t::emplace_equal(BOOST_MOVE_FWD##N); }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ - { return this->base_t::emplace_hint_equal(hint BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + { return this->tree_t::emplace_hint_equal(hint BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_MULTISET_EMPLACE_CODE) #undef BOOST_CONTAINER_FLAT_MULTISET_EMPLACE_CODE @@ -1448,7 +1461,7 @@ class flat_multiset //! Note: If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) - { this->base_t::insert_equal(first, last); } + { this->tree_t::insert_equal(first, last); } //! Requires: first, last are not iterators into *this and //! must be ordered according to the predicate. @@ -1462,7 +1475,7 @@ class flat_multiset //! Note: Non-standard extension. If an element is inserted it might invalidate elements. template BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, InputIterator first, InputIterator last) - { this->base_t::insert_equal(ordered_range, first, last); } + { this->tree_t::insert_equal(ordered_range, first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: inserts each element from the range [il.begin(), il.end()). @@ -1472,7 +1485,7 @@ class flat_multiset //! //! Note: If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) - { this->base_t::insert_equal(il.begin(), il.end()); } + { this->tree_t::insert_equal(il.begin(), il.end()); } //! Requires: Range [il.begin(), il.end()) must be ordered according to the predicate. //! @@ -1484,28 +1497,28 @@ class flat_multiset //! //! Note: Non-standard extension. If an element is inserted it might invalidate elements. BOOST_CONTAINER_FORCEINLINE void insert(ordered_range_t, std::initializer_list il) - { this->base_t::insert_equal(ordered_range, il.begin(), il.end()); } + { this->tree_t::insert_equal(ordered_range, il.begin(), il.end()); } #endif - //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) - { this->base_t::merge_equal(source.tree()); } + BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) + { this->tree_t::merge_equal(source.tree()); } - //! @copydoc ::boost::container::flat_multiset::merge(flat_multiset&) + //! @copydoc ::boost::container::flat_multiset::merge(flat_multiset&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } - //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) + //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) template - BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) - { this->base_t::merge_equal(source.tree()); } + BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) + { this->tree_t::merge_equal(source.tree()); } - //! @copydoc ::boost::container::flat_multiset::merge(flat_set&) + //! @copydoc ::boost::container::flat_multiset::merge(flat_set&) template - BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) - { return this->merge(static_cast&>(source)); } + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1624,7 +1637,7 @@ class flat_multiset //! //! Throws: If the comparison or the move constructor throws BOOST_CONTAINER_FORCEINLINE void adopt_sequence(BOOST_RV_REF(sequence_type) seq) - { this->base_t::adopt_sequence_equal(boost::move(seq)); } + { this->tree_t::adopt_sequence_equal(boost::move(seq)); } //! Requires: seq shall be ordered according to this->compare() //! @@ -1635,17 +1648,17 @@ class flat_multiset //! //! Throws: If the move assignment throws BOOST_CONTAINER_FORCEINLINE void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) - { this->base_t::adopt_sequence_equal(ordered_range_t(), boost::move(seq)); } + { this->tree_t::adopt_sequence_equal(ordered_range_t(), boost::move(seq)); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template BOOST_CONTAINER_FORCEINLINE iterator priv_insert(BOOST_FWD_REF(KeyType) x) - { return this->base_t::insert_equal(::boost::forward(x)); } + { return this->tree_t::insert_equal(::boost::forward(x)); } template BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator p, BOOST_FWD_REF(KeyType) x) - { return this->base_t::insert_equal(p, ::boost::forward(x)); } + { return this->tree_t::insert_equal(p, ::boost::forward(x)); } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; @@ -1655,11 +1668,11 @@ class flat_multiset //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { - typedef typename ::boost::container::allocator_traits::pointer pointer; - static const bool value = ::boost::has_trivial_destructor_after_move::value && + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value && ::boost::has_trivial_destructor_after_move::value; }; diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 21168cb..4a341c3 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -113,6 +113,8 @@ class static_vector template friend class static_vector; + public: + typedef container_detail::static_storage_allocator allocator_type; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -252,6 +254,19 @@ public: : base_t(other) {} + BOOST_CONTAINER_FORCEINLINE static_vector(static_vector const& other, const allocator_type &) + : base_t(other) + {} + + BOOST_CONTAINER_FORCEINLINE static_vector(BOOST_RV_REF(static_vector) other, const allocator_type &) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) + : base_t(BOOST_MOVE_BASE(base_t, other)) + {} + + BOOST_CONTAINER_FORCEINLINE explicit static_vector(const allocator_type &) + : base_t() + {} + //! @pre other.size() <= capacity(). //! //! @brief Constructs a copy of other static_vector. diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index c7f7a2b..bce3d02 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -315,6 +315,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tree_test", "tree_test.vcpr ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_tree_test", "flat_tree_test.vcproj", "{DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -637,6 +641,10 @@ Global {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Debug.Build.0 = Debug|Win32 {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.ActiveCfg = Release|Win32 {5CE185C3-2609-4FA5-FE38-792BA0D3A606}.Release.Build.0 = Release|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Debug.ActiveCfg = Debug|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Debug.Build.0 = Debug|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Release.ActiveCfg = Release|Win32 + {DE1834C3-2609-FE38-4FA5-0BA0D3CD0796}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 387f4ae..de0ddfb 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -245,6 +245,12 @@ + + + + diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index 314d188..290efde 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "print_container.hpp" #include "dummy_test_allocator.hpp" @@ -336,9 +337,25 @@ bool flat_tree_extract_adopt_test() }}} +template::value> +struct RebindAllocatorOrContainer +{ + typedef typename allocator_traits + ::template portable_rebind_alloc< std::pair >::type type; +}; -template -struct GetAllocatorMap +template class Allocator> +struct RebindAllocatorOrContainer< boost::container::stable_vector >, ValueType, true> +{ + typedef std::pair type_t; + typedef typename allocator_traits< Allocator > + ::template portable_rebind_alloc< type_t >::type allocator_t; + typedef typename boost::container::stable_vector type; +}; + + +template +struct GetMapContainer { template struct apply @@ -346,15 +363,13 @@ struct GetAllocatorMap typedef flat_map< ValueType , ValueType , std::less - , typename allocator_traits - ::template portable_rebind_alloc< std::pair >::type + , typename RebindAllocatorOrContainer::type > map_type; typedef flat_multimap< ValueType , ValueType , std::less - , typename allocator_traits - ::template portable_rebind_alloc< std::pair >::type + , typename RebindAllocatorOrContainer::type > multimap_type; }; }; @@ -402,18 +417,18 @@ struct get_real_stored_allocator > }}} //namespace boost::container::test -template +template int test_map_variants() { - typedef typename GetAllocatorMap::template apply::map_type MyMap; - typedef typename GetAllocatorMap::template apply::map_type MyMoveMap; - typedef typename GetAllocatorMap::template apply::map_type MyCopyMoveMap; - typedef typename GetAllocatorMap::template apply::map_type MyCopyMap; + typedef typename GetMapContainer::template apply::map_type MyMap; + typedef typename GetMapContainer::template apply::map_type MyMoveMap; + typedef typename GetMapContainer::template apply::map_type MyCopyMoveMap; + typedef typename GetMapContainer::template apply::map_type MyCopyMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyMoveMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMoveMultiMap; - typedef typename GetAllocatorMap::template apply::multimap_type MyCopyMultiMap; + typedef typename GetMapContainer::template apply::multimap_type MyMultiMap; + typedef typename GetMapContainer::template apply::multimap_type MyMoveMultiMap; + typedef typename GetMapContainer::template apply::multimap_type MyCopyMoveMultiMap; + typedef typename GetMapContainer::template apply::multimap_type MyCopyMultiMap; typedef std::map MyStdMap; typedef std::multimap MyStdMultiMap; diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 41c2642..a18b7d2 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -57,25 +57,6 @@ template class flat_multiset , allocator >; -namespace container_detail { - -//Instantiate base class as previous instantiations don't instantiate inherited members -template class flat_tree - < test::movable_and_copyable_int - , identity - , std::less - , test::simple_allocator - >; - -template class flat_tree - < test::movable_and_copyable_int - , identity - , std::less - , allocator - >; - -} //container_detail { - //As flat container iterators are typedefs for vector::[const_]iterator, //no need to explicit instantiate them diff --git a/test/flat_tree_test.cpp b/test/flat_tree_test.cpp new file mode 100644 index 0000000..cd42242 --- /dev/null +++ b/test/flat_tree_test.cpp @@ -0,0 +1,124 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +#include "movable_int.hpp" +#include "dummy_test_allocator.hpp" + +using namespace boost::container; + +typedef boost::container::container_detail::pair pair_t; + +namespace boost { +namespace container { + +//Explicit instantiation to detect compilation errors + +namespace container_detail { + +template class flat_tree + < pair_t + , select1st + , std::less + , test::simple_allocator + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , std::allocator + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , small_vector + >; + +template class flat_tree + < pair_t + , select1st + , std::less + , stable_vector + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , test::simple_allocator + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , std::allocator + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , small_vector + >; + +template class flat_tree + < test::movable_and_copyable_int + , identity + , std::less + , stable_vector + >; + +template class flat_tree +< test::movable_and_copyable_int + , identity + , std::less + , static_vector +>; + +} //container_detail { +}} //boost::container + +#if (__cplusplus >= 201402L) +#include + +namespace boost{ +namespace container{ +namespace container_detail{ + +template class flat_tree +< test::movable_and_copyable_int + , identity + , std::less + , std::vector +>; + +template class flat_tree +< pair_t + , select1st + , std::less + , std::vector +>; + +} //container_detail { +}} //boost::container + +#endif + +int main () +{ + return 0; +} diff --git a/test/map_test.hpp b/test/map_test.hpp index 6f2aa7e..01dd4c4 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -886,14 +886,14 @@ int map_test() for(int i = 0; i < MaxElem; ++i){ stdmultimap.insert(StdPairType(MaxElem/2+i, MaxElem-i)); } - boostmultimap.merge(boost::move(boostmultimap2)); + boostmultimap.merge(boostmultimap2); if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; for(int i = 0; i < MaxElem; ++i){ stdmultimap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i)); } - boostmultimap.merge(boost::move(boostmap2)); + boostmultimap.merge(boostmap2); if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } diff --git a/test/tree_test.cpp b/test/tree_test.cpp index 6d84cd1..d1140dd 100644 --- a/test/tree_test.cpp +++ b/test/tree_test.cpp @@ -49,7 +49,6 @@ template class tree , tree_assoc_defaults >; -//Instantiate base class as previous instantiations don't instantiate inherited members template class tree < test::movable_and_copyable_int , identity