From d6749960fc896c451cb23633f1f6f3144cdf4017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 5 Apr 2017 16:06:31 +0200 Subject: [PATCH] Implement `extract_sequence` and `adopt_sequence` for flat ordered associative containers --- doc/container.qbk | 5 + include/boost/container/detail/flat_tree.hpp | 197 ++++++++++++------- include/boost/container/flat_map.hpp | 70 +++++++ include/boost/container/flat_set.hpp | 61 ++++++ test/flat_map_test.cpp | 117 +++++++++++ test/flat_set_test.cpp | 117 +++++++++++ 6 files changed, 498 insertions(+), 69 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 1bf1598..0749045 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1213,6 +1213,11 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes Release Notes] +[section:release_notes_boost_1_65_00 Boost 1.65 Release] + +* Implemented `extract_sequence`, `adopt_sequence` functions for flat_[multi]map/set associative containers. + +[endsect] [section:release_notes_boost_1_64_00 Boost 1.64 Release] diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 93984d1..16d2991 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -28,25 +28,30 @@ #include #include +#include + #include #include #include //algo_equal(), algo_lexicographical_compare #include #include -#include +#include +#include + #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER #include #endif -#include -#include +#include //pair + #include +#include #include +#include + #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #endif -#include //pair -#include namespace boost { namespace container { @@ -105,14 +110,17 @@ template class flat_tree { - typedef boost::container::vector vector_t; + public: + typedef boost::container::vector sequence_type; + + private: typedef Allocator allocator_t; typedef allocator_traits allocator_traits_type; public: typedef flat_tree_value_compare value_compare; - private: + private: struct Data //Inherit from value_compare to do EBO : public value_compare @@ -121,48 +129,48 @@ class flat_tree public: Data() - : value_compare(), m_vect() + : value_compare(), m_seq() {} explicit Data(const Data &d) - : value_compare(static_cast(d)), m_vect(d.m_vect) + : value_compare(static_cast(d)), m_seq(d.m_seq) {} Data(BOOST_RV_REF(Data) d) - : value_compare(boost::move(static_cast(d))), m_vect(boost::move(d.m_vect)) + : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq)) {} Data(const Data &d, const Allocator &a) - : value_compare(static_cast(d)), m_vect(d.m_vect, a) + : value_compare(static_cast(d)), m_seq(d.m_seq, a) {} Data(BOOST_RV_REF(Data) d, const Allocator &a) - : value_compare(boost::move(static_cast(d))), m_vect(boost::move(d.m_vect), a) + : value_compare(boost::move(static_cast(d))), m_seq(boost::move(d.m_seq), a) {} explicit Data(const Compare &comp) - : value_compare(comp), m_vect() + : value_compare(comp), m_seq() {} Data(const Compare &comp, const allocator_t &alloc) - : value_compare(comp), m_vect(alloc) + : value_compare(comp), m_seq(alloc) {} explicit Data(const allocator_t &alloc) - : value_compare(), m_vect(alloc) + : value_compare(), m_seq(alloc) {} Data& operator=(BOOST_COPY_ASSIGN_REF(Data) d) { this->value_compare::operator=(d); - m_vect = d.m_vect; + m_seq = d.m_seq; return *this; } Data& operator=(BOOST_RV_REF(Data) d) { this->value_compare::operator=(boost::move(static_cast(d))); - m_vect = boost::move(d.m_vect); + m_seq = boost::move(d.m_seq); return *this; } @@ -170,10 +178,10 @@ class flat_tree { value_compare& mycomp = *this, & othercomp = d; boost::adl_move_swap(mycomp, othercomp); - this->m_vect.swap(d.m_vect); + this->m_seq.swap(d.m_seq); } - vector_t m_vect; + sequence_type m_seq; }; Data m_data; @@ -181,23 +189,23 @@ class flat_tree public: - typedef typename vector_t::value_type value_type; - typedef typename vector_t::pointer pointer; - typedef typename vector_t::const_pointer const_pointer; - typedef typename vector_t::reference reference; - typedef typename vector_t::const_reference const_reference; - typedef typename KeyOfValue::type key_type; - typedef Compare key_compare; - typedef typename vector_t::allocator_type allocator_type; - typedef typename vector_t::size_type size_type; - typedef typename vector_t::difference_type difference_type; - typedef typename vector_t::iterator iterator; - typedef typename vector_t::const_iterator const_iterator; - typedef typename vector_t::reverse_iterator reverse_iterator; - typedef typename vector_t::const_reverse_iterator const_reverse_iterator; + 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 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; //!Standard extension - typedef allocator_type stored_allocator_type; + typedef allocator_type stored_allocator_type; private: typedef allocator_traits stored_allocator_traits; @@ -242,8 +250,8 @@ class flat_tree , const allocator_type& a = allocator_type()) : m_data(comp, a) { - this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); - BOOST_ASSERT((is_sorted)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); } template @@ -252,8 +260,8 @@ class flat_tree , const allocator_type& a = allocator_type()) : m_data(comp, a) { - this->m_data.m_vect.insert(this->m_data.m_vect.end(), first, last); - BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_vect.cbegin(), this->m_data.m_vect.cend(), this->priv_value_comp())); + this->m_data.m_seq.insert(this->m_data.m_seq.end(), first, last); + BOOST_ASSERT((is_sorted_and_unique)(this->m_data.m_seq.cbegin(), this->m_data.m_seq.cend(), this->priv_value_comp())); } template @@ -312,31 +320,31 @@ class flat_tree { return this->m_data; } BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const - { return this->m_data.m_vect.get_allocator(); } + { return this->m_data.m_seq.get_allocator(); } BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const - { return this->m_data.m_vect.get_stored_allocator(); } + { return this->m_data.m_seq.get_stored_allocator(); } BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() - { return this->m_data.m_vect.get_stored_allocator(); } + { return this->m_data.m_seq.get_stored_allocator(); } BOOST_CONTAINER_FORCEINLINE iterator begin() - { return this->m_data.m_vect.begin(); } + { return this->m_data.m_seq.begin(); } BOOST_CONTAINER_FORCEINLINE const_iterator begin() const { return this->cbegin(); } BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const - { return this->m_data.m_vect.begin(); } + { return this->m_data.m_seq.begin(); } BOOST_CONTAINER_FORCEINLINE iterator end() - { return this->m_data.m_vect.end(); } + { return this->m_data.m_seq.end(); } BOOST_CONTAINER_FORCEINLINE const_iterator end() const { return this->cend(); } BOOST_CONTAINER_FORCEINLINE const_iterator cend() const - { return this->m_data.m_vect.end(); } + { return this->m_data.m_seq.end(); } BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() { return reverse_iterator(this->end()); } @@ -357,13 +365,13 @@ class flat_tree { return const_reverse_iterator(this->cbegin()); } BOOST_CONTAINER_FORCEINLINE bool empty() const - { return this->m_data.m_vect.empty(); } + { return this->m_data.m_seq.empty(); } BOOST_CONTAINER_FORCEINLINE size_type size() const - { return this->m_data.m_vect.size(); } + { return this->m_data.m_seq.size(); } BOOST_CONTAINER_FORCEINLINE size_type max_size() const - { return this->m_data.m_vect.max_size(); } + { return this->m_data.m_seq.max_size(); } BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value @@ -395,14 +403,14 @@ class flat_tree iterator insert_equal(const value_type& val) { iterator i = this->upper_bound(KeyOfValue()(val)); - i = this->m_data.m_vect.insert(i, val); + i = this->m_data.m_seq.insert(i, val); return i; } iterator insert_equal(BOOST_RV_REF(value_type) mval) { iterator i = this->upper_bound(KeyOfValue()(mval)); - i = this->m_data.m_vect.insert(i, boost::move(mval)); + i = this->m_data.m_seq.insert(i, boost::move(mval)); return i; } @@ -509,7 +517,7 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_vect.merge(first, last, static_cast(this->m_data)); } + { this->m_data.m_seq.merge(first, last, static_cast(this->m_data)); } template void insert_unique(ordered_unique_range_t, InIt first, InIt last @@ -538,7 +546,7 @@ class flat_tree >::type * = 0 #endif ) - { this->m_data.m_vect.merge_unique(first, last, static_cast(this->m_data)); } + { this->m_data.m_seq.merge_unique(first, last, static_cast(this->m_data)); } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -606,7 +614,7 @@ class flat_tree typedef typename emplace_functor_type::type func_t; typedef emplace_iterator it_t; func_t func(try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); } return ret; } @@ -675,7 +683,7 @@ class flat_tree typedef typename emplace_functor_type::type func_t;\ typedef emplace_iterator it_t;\ func_t func(try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t());\ + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\ }\ return ret;\ }\ @@ -702,29 +710,29 @@ class flat_tree typedef typename emplace_functor_type::type func_t; typedef emplace_iterator it_t; func_t func(boost::forward(key), boost::forward(obj)); - ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t()); + ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t()); } return ret; } BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator position) - { return this->m_data.m_vect.erase(position); } + { return this->m_data.m_seq.erase(position); } size_type erase(const key_type& k) { std::pair itp = this->equal_range(k); size_type ret = static_cast(itp.second-itp.first); if (ret){ - this->m_data.m_vect.erase(itp.first, itp.second); + this->m_data.m_seq.erase(itp.first, itp.second); } return ret; } BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) - { return this->m_data.m_vect.erase(first, last); } + { return this->m_data.m_seq.erase(first, last); } BOOST_CONTAINER_FORCEINLINE void clear() - { this->m_data.m_vect.clear(); } + { this->m_data.m_seq.clear(); } //! Effects: Tries to deallocate the excess of memory created // with previous allocations. The size of the vector is unchanged @@ -733,19 +741,19 @@ class flat_tree //! //! Complexity: Linear to size(). BOOST_CONTAINER_FORCEINLINE void shrink_to_fit() - { this->m_data.m_vect.shrink_to_fit(); } + { 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_vect.nth(n); } + { return this->m_data.m_seq.nth(n); } BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.nth(n); } + { return this->m_data.m_seq.nth(n); } BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.index_of(p); } + { return this->m_data.m_seq.index_of(p); } BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW - { return this->m_data.m_vect.index_of(p); } + { return this->m_data.m_seq.index_of(p); } // set operations: iterator find(const key_type& k) @@ -793,7 +801,7 @@ class flat_tree void merge_unique(flat_tree& source) { - this->m_data.m_vect.merge_unique + this->m_data.m_seq.merge_unique ( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end()) , static_cast(this->m_data)); @@ -801,7 +809,7 @@ class flat_tree void merge_equal(flat_tree& source) { - this->m_data.m_vect.merge + this->m_data.m_seq.merge ( boost::make_move_iterator(source.begin()) , boost::make_move_iterator(source.end()) , static_cast(this->m_data)); @@ -832,10 +840,61 @@ class flat_tree { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } BOOST_CONTAINER_FORCEINLINE size_type capacity() const - { return this->m_data.m_vect.capacity(); } + { return this->m_data.m_seq.capacity(); } BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt) - { this->m_data.m_vect.reserve(cnt); } + { this->m_data.m_seq.reserve(cnt); } + + BOOST_CONTAINER_FORCEINLINE sequence_type extract_sequence() + { + return boost::move(m_data.m_seq); + } + + BOOST_CONTAINER_FORCEINLINE sequence_type &get_sequence_ref() + { + return m_data.m_seq; + } + + void adopt_sequence_equal(BOOST_RV_REF(sequence_type) seq) + { + sequence_type &tseq = m_data.m_seq; + boost::movelib::adaptive_sort + ( container_detail::iterator_to_raw_pointer(seq.begin()) + , container_detail::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + tseq = boost::move(seq); + } + + void adopt_sequence_equal(ordered_range_t, BOOST_RV_REF(sequence_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 + ( container_detail::iterator_to_raw_pointer(seq.begin()) + , container_detail::iterator_to_raw_pointer(seq.end()) + , this->priv_value_comp() + , container_detail::iterator_to_raw_pointer(tseq.begin() + tseq.size()) + , tseq.capacity() - tseq.size()); + 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) + { + BOOST_ASSERT((is_sorted_and_unique)(seq.cbegin(), seq.cend(), this->priv_value_comp())); + sequence_type &tseq = m_data.m_seq; + tseq = boost::move(seq); + } BOOST_CONTAINER_FORCEINLINE friend bool operator==(const flat_tree& x, const flat_tree& y) { @@ -963,7 +1022,7 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible) { - return this->m_data.m_vect.insert + return this->m_data.m_seq.insert ( commit_data.position , boost::forward(convertible)); } diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index b842101..c5d6e03 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -144,8 +144,10 @@ class flat_map ::pointer>::reverse_iterator reverse_iterator_impl; typedef typename container_detail::get_flat_tree_iterators ::pointer>::const_reverse_iterator const_reverse_iterator_impl; + public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; impl_tree_t &tree() { return m_flat_tree; } @@ -182,6 +184,7 @@ class flat_map 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 typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; public: ////////////////////////////////////////////// @@ -1243,6 +1246,39 @@ class flat_map std::pair equal_range(const key_type& x) const { return container_detail::force_copy >(m_flat_tree.lower_bound_range(x)); } + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence() + { + return boost::move(container_detail::force(m_flat_tree.get_sequence_ref())); + } + + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. Erases non-unique elements. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(boost::move(container_detail::force(seq))); } + + //! Requires: seq shall be ordered according to this->compare() + //! and shall contain unique elements. + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_unique_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_unique(ordered_unique_range_t(), boost::move(container_detail::force(seq))); } + //! Effects: Returns true if x and y are equal //! //! Complexity: Linear to the number of elements in the container. @@ -1401,6 +1437,7 @@ class flat_multimap ::pointer>::const_reverse_iterator const_reverse_iterator_impl; public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + typedef typename impl_tree_t::sequence_type impl_sequence_type; impl_tree_t &tree() { return m_flat_tree; } @@ -1437,6 +1474,7 @@ class flat_multimap 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 typename BOOST_CONTAINER_IMPDEF(tree_t::sequence_type) sequence_type; ////////////////////////////////////////////// // @@ -2219,6 +2257,38 @@ class flat_multimap std::pair equal_range(const key_type& x) const { return container_detail::force_copy >(m_flat_tree.equal_range(x)); } + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence() + { + return boost::move(container_detail::force(m_flat_tree.get_sequence_ref())); + } + + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(boost::move(container_detail::force(seq))); } + + //! Requires: seq shall be ordered according to this->compare(). + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { this->m_flat_tree.adopt_sequence_equal(ordered_range_t(), boost::move(container_detail::force(seq))); } + //! Effects: Returns true if x and y are equal //! //! Complexity: Linear to the number of elements in the container. diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index fa27006..5dc6be5 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -114,6 +114,7 @@ class flat_set 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; public: ////////////////////////////////////////////// @@ -844,8 +845,38 @@ class flat_set //! Complexity: Constant. friend void swap(flat_set& x, flat_set& y); + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence(); + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. Erases non-unique elements. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_unique(boost::move(seq)); } + + //! Requires: seq shall be ordered according to this->compare() + //! and shall contain unique elements. + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + 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)); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template @@ -939,6 +970,7 @@ class flat_multiset 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; //! @copydoc ::boost::container::flat_set::flat_set() explicit flat_multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && @@ -1392,8 +1424,37 @@ class flat_multiset //! Complexity: Constant. friend void swap(flat_multiset& x, flat_multiset& y); + //! Effects: Extracts the internal sequence container. + //! + //! Complexity: Same as the move constructor of sequence_type, usually constant. + //! + //! Postcondition: this->empty() + //! + //! Throws: If secuence_type's move constructor throws + sequence_type extract_sequence(); + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignmet, O(NlogN) with N = seq.size() + //! + //! Throws: If the comparison or the move constructor throws + void adopt_sequence(BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_equal(boost::move(seq)); } + + //! Requires: seq shall be ordered according to this->compare() + //! + //! Effects: Discards the internally hold sequence container and move adopts the + //! one passed externally using the move assignment. + //! + //! Complexity: Assuming O(1) move assignment, O(1) + //! + //! Throws: If the move constructor throws + void adopt_sequence(ordered_range_t, BOOST_RV_REF(sequence_type) seq) + { this->base_t::adopt_sequence_equal(ordered_range_t(), boost::move(seq)); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index bd2fb23..b2376dc 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -224,6 +224,116 @@ bool flat_tree_ordered_insertion_test() return true; } +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt map + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + seq.insert(seq.end(), fmap_copy.begin(), fmap_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt map, ordered_unique_range + { + //Construction insertion + flat_map fmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_map fmap_copy(fmap); + flat_map::sequence_type seq(fmap.extract_sequence()); + if(!fmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmap_copy)) + return false; + + fmap.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fmap, fmap_copy)) + return false; + } + + //extract/adopt multimap + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmmap.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + //extract/adopt multimap, ordered_range + { + //Construction insertion + flat_multimap fmmap; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmmap.emplace(static_cast(i), -static_cast(i)); + fmmap.emplace(static_cast(i), -static_cast(i)); + } + + flat_multimap fmmap_copy(fmmap); + flat_multimap::sequence_type seq(fmmap.extract_sequence()); + if(!fmmap.empty()) + return false; + if(!CheckEqualContainers(seq, fmmap_copy)) + return false; + + fmmap.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmmap, fmmap_copy)) + return false; + } + + return true; +} + }}} @@ -385,6 +495,13 @@ int main() return 1; } + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index b9e436f..74742ea 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -312,6 +312,116 @@ bool flat_tree_ordered_insertion_test() return true; } +template< class RandomIt > +void random_shuffle( RandomIt first, RandomIt last ) +{ + typedef typename boost::container::iterator_traits::difference_type difference_type; + difference_type n = last - first; + for (difference_type i = n-1; i > 0; --i) { + difference_type j = std::rand() % (i+1); + if(j != i) { + boost::adl_move_swap(first[i], first[j]); + } + } +} + +bool flat_tree_extract_adopt_test() +{ + using namespace boost::container; + const std::size_t NumElements = 100; + + //extract/adopt set + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + seq.insert(seq.end(), fset_copy.begin(), fset_copy.end()); + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt set, ordered_unique_range + { + //Construction insertion + flat_set fset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fset.insert(static_cast(i)); + } + + flat_set fset_copy(fset); + flat_set::sequence_type seq(fset.extract_sequence()); + if(!fset.empty()) + return false; + if(!CheckEqualContainers(seq, fset_copy)) + return false; + + fset.adopt_sequence(ordered_unique_range, boost::move(seq)); + if(!CheckEqualContainers(fset, fset_copy)) + return false; + } + + //extract/adopt multiset + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + boost::container::test::random_shuffle(seq.begin(), seq.end()); + fmset.adopt_sequence(boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + //extract/adopt multiset, ordered_range + { + //Construction insertion + flat_multiset fmset; + + for(std::size_t i = 0; i != NumElements; ++i){ + fmset.insert(static_cast(i)); + fmset.insert(static_cast(i)); + } + + flat_multiset fmset_copy(fmset); + flat_multiset::sequence_type seq(fmset.extract_sequence()); + if(!fmset.empty()) + return false; + if(!CheckEqualContainers(seq, fmset_copy)) + return false; + + fmset.adopt_sequence(ordered_range, boost::move(seq)); + if(!CheckEqualContainers(fmset, fmset_copy)) + return false; + } + + return true; +} + }}} @@ -491,6 +601,13 @@ int main() return 1; } + //////////////////////////////////// + // Extract/Adopt test + //////////////////////////////////// + if(!flat_tree_extract_adopt_test()){ + return 1; + } + //////////////////////////////////// // Testing allocator implementations ////////////////////////////////////