From 2d6f781a2f2a3c25a2624c0ea88aba44139595a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 18 Aug 2016 20:29:04 +0200 Subject: [PATCH] Implemented "insert_or_assign" for map-like containers. --- doc/container.qbk | 1 + .../container/detail/construct_in_place.hpp | 44 +++- .../boost/container/detail/copy_move_algo.hpp | 6 +- include/boost/container/detail/flat_tree.hpp | 201 ++++++++++-------- include/boost/container/detail/iterators.hpp | 53 ++++- include/boost/container/detail/tree.hpp | 166 +++++++++------ include/boost/container/detail/value_init.hpp | 2 + include/boost/container/flat_map.hpp | 96 ++++++++- include/boost/container/map.hpp | 168 +++++++++++---- test/map_test.cpp | 1 - test/map_test.hpp | 59 +++++ 11 files changed, 589 insertions(+), 208 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 2368933..3d9fecb 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1230,6 +1230,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://svn.boost.org/trac/boost/ticket/12319 Trac #12319: ['"flat_set` should be nothrow move constructible"]]. * Revised noexcept expressions of default and move constructors in all containers. +* Implemented `insert_or_assign` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. [endsect] diff --git a/include/boost/container/detail/construct_in_place.hpp b/include/boost/container/detail/construct_in_place.hpp index 6cb3395..9fecd24 100644 --- a/include/boost/container/detail/construct_in_place.hpp +++ b/include/boost/container/detail/construct_in_place.hpp @@ -23,16 +23,19 @@ #include #include +#include namespace boost { namespace container { +//In place construction + template -inline void construct_in_place(Allocator &a, T* dest, InpIt source) +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T* dest, InpIt source) { boost::container::allocator_traits::construct(a, dest, *source); } template -inline void construct_in_place(Allocator &a, T *dest, value_init_construct_iterator) +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, value_init_construct_iterator) { boost::container::allocator_traits::construct(a, dest); } @@ -41,7 +44,7 @@ template class default_init_construct_iterator; template -inline void construct_in_place(Allocator &a, T *dest, default_init_construct_iterator) +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, default_init_construct_iterator) { boost::container::allocator_traits::construct(a, dest, default_init); } @@ -50,13 +53,44 @@ template class emplace_iterator; template -inline void construct_in_place(Allocator &a, T *dest, emplace_iterator ei) +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, emplace_iterator ei) { ei.construct_in_place(a, dest); } +//Assignment + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, InpIt source) +{ *dest = *source; } + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, value_init_construct_iterator) +{ + container_detail::value_init val; + *dest = boost::move(val.get()); +} + +template +class default_init_construct_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, default_init_construct_iterator) +{ + U u; + *dest = boost::move(u); +} + +template +class emplace_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, emplace_iterator ei) +{ + ei.assign_in_place(dest); +} + } //namespace container { } //namespace boost { #endif //#ifndef BOOST_CONTAINER_DETAIL_CONSTRUCT_IN_PLACE_HPP - diff --git a/include/boost/container/detail/copy_move_algo.hpp b/include/boost/container/detail/copy_move_algo.hpp index 9dfeb5e..ead93c6 100644 --- a/include/boost/container/detail/copy_move_algo.hpp +++ b/include/boost/container/detail/copy_move_algo.hpp @@ -25,6 +25,8 @@ #include #include #include +#include + // move #include #include @@ -515,7 +517,7 @@ inline typename container_detail::disable_if_memtransfer_copy_constructible::construct(a, container_detail::iterator_to_raw_pointer(r), *f); + boost::container::construct_in_place(a, container_detail::iterator_to_raw_pointer(r), f); ++f; ++r; } } @@ -757,7 +759,7 @@ inline typename container_detail::disable_if_memtransfer_copy_assignable::difference_type n, F r) { while (n--) { - *r = *f; + boost::container::assign_in_place(r, f); ++f; ++r; } return f; diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 23b0af2..b6029e0 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -38,6 +38,7 @@ #include #endif #include +#include #include #include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -201,36 +202,36 @@ class flat_tree typedef allocator_traits stored_allocator_traits; public: - flat_tree() + BOOST_CONTAINER_FORCEINLINE flat_tree() : m_data() { } - explicit flat_tree(const Compare& comp) + BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const Compare& comp) : m_data(comp) { } - flat_tree(const Compare& comp, const allocator_type& a) + BOOST_CONTAINER_FORCEINLINE flat_tree(const Compare& comp, const allocator_type& a) : m_data(comp, a) { } - explicit flat_tree(const allocator_type& a) + BOOST_CONTAINER_FORCEINLINE explicit flat_tree(const allocator_type& a) : m_data(a) { } - flat_tree(const flat_tree& x) + BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x) : m_data(x.m_data) { } - flat_tree(BOOST_RV_REF(flat_tree) x) + BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_data(boost::move(x.m_data)) { } - flat_tree(const flat_tree& x, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE flat_tree(const flat_tree& x, const allocator_type &a) : m_data(x.m_data, a) { } - flat_tree(BOOST_RV_REF(flat_tree) x, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE flat_tree(BOOST_RV_REF(flat_tree) x, const allocator_type &a) : m_data(boost::move(x.m_data), a) { } @@ -277,13 +278,13 @@ class flat_tree } } - ~flat_tree() + BOOST_CONTAINER_FORCEINLINE ~flat_tree() {} - flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x) + BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_COPY_ASSIGN_REF(flat_tree) x) { m_data = x.m_data; return *this; } - flat_tree& operator=(BOOST_RV_REF(flat_tree) x) + BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_RV_REF(flat_tree) 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) @@ -295,69 +296,75 @@ class flat_tree BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp() { return static_cast(this->m_data); } + BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const + { return this->priv_value_comp().get_comp(); } + + BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp() + { return this->priv_value_comp().get_comp(); } + public: // accessors: - Compare key_comp() const + BOOST_CONTAINER_FORCEINLINE Compare key_comp() const { return this->m_data.get_comp(); } - value_compare value_comp() const + BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const { return this->m_data; } - allocator_type get_allocator() const + BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const { return this->m_data.m_vect.get_allocator(); } - const stored_allocator_type &get_stored_allocator() const + BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const { return this->m_data.m_vect.get_stored_allocator(); } - stored_allocator_type &get_stored_allocator() + BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() { return this->m_data.m_vect.get_stored_allocator(); } - iterator begin() + BOOST_CONTAINER_FORCEINLINE iterator begin() { return this->m_data.m_vect.begin(); } - const_iterator begin() const + BOOST_CONTAINER_FORCEINLINE const_iterator begin() const { return this->cbegin(); } - const_iterator cbegin() const + BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const { return this->m_data.m_vect.begin(); } - iterator end() + BOOST_CONTAINER_FORCEINLINE iterator end() { return this->m_data.m_vect.end(); } - const_iterator end() const + BOOST_CONTAINER_FORCEINLINE const_iterator end() const { return this->cend(); } - const_iterator cend() const + BOOST_CONTAINER_FORCEINLINE const_iterator cend() const { return this->m_data.m_vect.end(); } - reverse_iterator rbegin() + BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() { return reverse_iterator(this->end()); } - const_reverse_iterator rbegin() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const { return this->crbegin(); } - const_reverse_iterator crbegin() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const { return const_reverse_iterator(this->cend()); } - reverse_iterator rend() + BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() { return reverse_iterator(this->begin()); } - const_reverse_iterator rend() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const { return this->crend(); } - const_reverse_iterator crend() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const { return const_reverse_iterator(this->cbegin()); } - bool empty() const + BOOST_CONTAINER_FORCEINLINE bool empty() const { return this->m_data.m_vect.empty(); } - size_type size() const + BOOST_CONTAINER_FORCEINLINE size_type size() const { return this->m_data.m_vect.size(); } - size_type max_size() const + BOOST_CONTAINER_FORCEINLINE size_type max_size() const { return this->m_data.m_vect.max_size(); } - void swap(flat_tree& other) + BOOST_CONTAINER_FORCEINLINE void swap(flat_tree& other) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::container_detail::is_nothrow_swappable::value ) { this->m_data.swap(other.m_data); } @@ -368,7 +375,7 @@ class flat_tree { std::pair ret; insert_commit_data data; - ret.second = this->priv_insert_unique_prepare(val, 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)); return ret; @@ -378,7 +385,7 @@ class flat_tree { std::pair ret; insert_commit_data data; - ret.second = this->priv_insert_unique_prepare(val, 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)); return ret; @@ -403,7 +410,7 @@ class flat_tree BOOST_ASSERT(this->priv_in_range_or_end(hint)); std::pair ret; insert_commit_data data; - return this->priv_insert_unique_prepare(hint, val, data) + return this->priv_insert_unique_prepare(hint, KeyOfValue()(val), data) ? this->priv_insert_commit(data, val) : iterator(vector_iterator_get_ptr(data.position)); } @@ -413,7 +420,7 @@ class flat_tree BOOST_ASSERT(this->priv_in_range_or_end(hint)); std::pair ret; insert_commit_data data; - return this->priv_insert_unique_prepare(hint, val, 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)); } @@ -634,7 +641,29 @@ class flat_tree #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - iterator erase(const_iterator position) + template + std::pair insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj) + { + const key_type& k = key; + std::pair ret; + insert_commit_data data; + ret.second = hint == const_iterator() + ? this->priv_insert_unique_prepare(k, data) + : this->priv_insert_unique_prepare(hint, k, data); + if(!ret.second){ + ret.first = this->nth(data.position - this->cbegin()); + ret.first->second = boost::forward(obj); + } + else{ + typedef typename emplace_functor_type::type func_t; + typedef emplace_iterator it_t; + func_t func(boost::forward(key), boost::forward(obj)); + ret.first = this->m_data.m_vect.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); } size_type erase(const key_type& k) @@ -647,10 +676,10 @@ class flat_tree return ret; } - iterator erase(const_iterator first, const_iterator last) + BOOST_CONTAINER_FORCEINLINE iterator erase(const_iterator first, const_iterator last) { return this->m_data.m_vect.erase(first, last); } - void clear() + BOOST_CONTAINER_FORCEINLINE void clear() { this->m_data.m_vect.clear(); } //! Effects: Tries to deallocate the excess of memory created @@ -659,19 +688,19 @@ class flat_tree //! Throws: If memory allocation throws, or T's copy constructor throws. //! //! Complexity: Linear to size(). - void shrink_to_fit() + BOOST_CONTAINER_FORCEINLINE void shrink_to_fit() { this->m_data.m_vect.shrink_to_fit(); } - iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW { return this->m_data.m_vect.nth(n); } - const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_data.m_vect.nth(n); } - size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW { return this->m_data.m_vect.index_of(p); } - size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW { return this->m_data.m_vect.index_of(p); } // set operations: @@ -704,64 +733,64 @@ class flat_tree return n; } - iterator lower_bound(const key_type& k) + BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k) { return this->priv_lower_bound(this->begin(), this->end(), k); } - const_iterator lower_bound(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const { return this->priv_lower_bound(this->cbegin(), this->cend(), k); } - iterator upper_bound(const key_type& k) + BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k) { return this->priv_upper_bound(this->begin(), this->end(), k); } - const_iterator upper_bound(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const { return this->priv_upper_bound(this->cbegin(), this->cend(), k); } - std::pair equal_range(const key_type& k) + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& k) { return this->priv_equal_range(this->begin(), this->end(), k); } - std::pair equal_range(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE std::pair equal_range(const key_type& k) const { return this->priv_equal_range(this->cbegin(), this->cend(), k); } - std::pair lower_bound_range(const key_type& k) + BOOST_CONTAINER_FORCEINLINE std::pair lower_bound_range(const key_type& k) { return this->priv_lower_bound_range(this->begin(), this->end(), k); } - std::pair lower_bound_range(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE std::pair lower_bound_range(const key_type& k) const { return this->priv_lower_bound_range(this->cbegin(), this->cend(), k); } - size_type capacity() const + BOOST_CONTAINER_FORCEINLINE size_type capacity() const { return this->m_data.m_vect.capacity(); } - void reserve(size_type cnt) + BOOST_CONTAINER_FORCEINLINE void reserve(size_type cnt) { this->m_data.m_vect.reserve(cnt); } - friend bool operator==(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const flat_tree& x, const flat_tree& y) { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } - friend bool operator<(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator<(const flat_tree& x, const flat_tree& y) { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - friend bool operator!=(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const flat_tree& x, const flat_tree& y) { return !(x == y); } - friend bool operator>(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const flat_tree& x, const flat_tree& y) { return y < x; } - friend bool operator<=(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const flat_tree& x, const flat_tree& y) { return !(y < x); } - friend bool operator>=(const flat_tree& x, const flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const flat_tree& x, const flat_tree& y) { return !(x < y); } - friend void swap(flat_tree& x, flat_tree& y) + BOOST_CONTAINER_FORCEINLINE friend void swap(flat_tree& x, flat_tree& y) { x.swap(y); } private: - bool priv_in_range_or_end(const_iterator pos) const + BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const { return (this->begin() <= pos) && (pos <= this->end()); } @@ -802,34 +831,34 @@ class flat_tree } bool priv_insert_unique_prepare - (const_iterator b, const_iterator e, const value_type& val, insert_commit_data &commit_data) + (const_iterator b, const_iterator e, const key_type& k, insert_commit_data &commit_data) { - const value_compare &val_cmp = this->m_data; - commit_data.position = this->priv_lower_bound(b, e, KeyOfValue()(val)); - return commit_data.position == e || val_cmp(val, *commit_data.position); + const key_compare &key_cmp = this->priv_key_comp(); + commit_data.position = this->priv_lower_bound(b, e, k); + return commit_data.position == e || key_cmp(k, KeyOfValue()(*commit_data.position)); } - bool priv_insert_unique_prepare - (const value_type& val, insert_commit_data &commit_data) - { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), val, commit_data); } + BOOST_CONTAINER_FORCEINLINE bool priv_insert_unique_prepare + (const key_type& k, insert_commit_data &commit_data) + { return this->priv_insert_unique_prepare(this->cbegin(), this->cend(), k, commit_data); } bool priv_insert_unique_prepare - (const_iterator pos, const value_type& val, insert_commit_data &commit_data) + (const_iterator pos, const key_type& k, insert_commit_data &commit_data) { //N1780. Props to Howard Hinnant! - //To insert val at pos: - //if pos == end || val <= *pos - // if pos == begin || val >= *(pos-1) - // insert val before pos + //To insert k at pos: + //if pos == end || k <= *pos + // if pos == begin || k >= *(pos-1) + // insert k before pos // else - // insert val before upper_bound(val) - //else if pos+1 == end || val <= *(pos+1) - // insert val after pos + // insert k before upper_bound(k) + //else if pos+1 == end || k <= *(pos+1) + // insert k after pos //else - // insert val before lower_bound(val) - const value_compare &val_cmp = this->m_data; + // insert k before lower_bound(k) + const key_compare &key_cmp = this->priv_key_comp(); const const_iterator cend_it = this->cend(); - if(pos == cend_it || val_cmp(val, *pos)){ //Check if val should go before end + if(pos == cend_it || key_cmp(k, KeyOfValue()(*pos))){ //Check if k should go before end const const_iterator cbeg = this->cbegin(); commit_data.position = pos; if(pos == cbeg){ //If container is empty then insert it in the beginning @@ -837,27 +866,27 @@ class flat_tree } const_iterator prev(pos); --prev; - if(val_cmp(*prev, val)){ //If previous element was less, then it should go between prev and pos + if(key_cmp(KeyOfValue()(*prev), k)){ //If previous element was less, then it should go between prev and pos return true; } - else if(!val_cmp(val, *prev)){ //If previous was equal then insertion should fail + else if(!key_cmp(k, KeyOfValue()(*prev))){ //If previous was equal then insertion should fail commit_data.position = prev; return false; } else{ //Previous was bigger so insertion hint was pointless, dispatch to hintless insertion - //but reduce the search between beg and prev as prev is bigger than val - return this->priv_insert_unique_prepare(cbeg, prev, val, commit_data); + //but reduce the search between beg and prev as prev is bigger than k + return this->priv_insert_unique_prepare(cbeg, prev, k, commit_data); } } else{ //The hint is before the insertion position, so insert it //in the remaining range [pos, end) - return this->priv_insert_unique_prepare(pos, cend_it, val, commit_data); + return this->priv_insert_unique_prepare(pos, cend_it, k, commit_data); } } template - iterator priv_insert_commit + BOOST_CONTAINER_FORCEINLINE iterator priv_insert_commit (insert_commit_data &commit_data, BOOST_FWD_REF(Convertible) convertible) { return this->m_data.m_vect.insert diff --git a/include/boost/container/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index 32ff32f..172db26 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -560,17 +560,23 @@ class emplace_iterator BOOST_CONTAINER_FORCEINLINE this_type operator-(difference_type off) const { return *this + (-off); } + private: //This pseudo-iterator's dereference operations have no sense since value is not //constructed until ::boost::container::construct_in_place is called. //So comment them to catch bad uses - //const T& operator*() const; - //const T& operator[](difference_type) const; - //const T* operator->() const; + const T& operator*() const; + const T& operator[](difference_type) const; + const T* operator->() const; + public: template void construct_in_place(Allocator &a, T* ptr) { (*m_pe)(a, ptr); } + template + void assign_in_place(DestIt dest) + { (*m_pe)(dest); } + private: difference_type m_num; EmplaceFunctor * m_pe; @@ -612,9 +618,14 @@ struct emplace_functor {} template - void operator()(Allocator &a, T *ptr) + BOOST_CONTAINER_FORCEINLINE void operator()(Allocator &a, T *ptr) { emplace_functor::inplace_impl(a, ptr, index_tuple_t()); } + template + BOOST_CONTAINER_FORCEINLINE void operator()(DestIt dest) + { emplace_functor::inplace_impl(dest, index_tuple_t()); } + + private: template BOOST_CONTAINER_FORCEINLINE void inplace_impl(Allocator &a, T* ptr, const container_detail::index_tuple&) { @@ -622,11 +633,29 @@ struct emplace_functor (a, ptr, ::boost::forward(container_detail::get(args_))...); } + template + BOOST_CONTAINER_FORCEINLINE void inplace_impl(DestIt dest, const container_detail::index_tuple&) + { + typedef typename boost::container::iterator_traits::value_type value_type; + value_type && tmp= value_type(::boost::forward(container_detail::get(args_))...); + *dest = ::boost::move(tmp); + } + container_detail::tuple args_; }; +template +struct emplace_functor_type +{ + typedef emplace_functor type; +}; + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +//Partial specializations cannot match argument list for primary template, so add an extra argument +template +struct emplace_functor_type; + #define BOOST_MOVE_ITERATOR_EMPLACE_FUNCTOR_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ struct emplace_functor##N\ @@ -638,10 +667,26 @@ struct emplace_functor##N\ void operator()(Allocator &a, T *ptr)\ { allocator_traits::construct(a, ptr BOOST_MOVE_I##N BOOST_MOVE_MFWD##N); }\ \ + template\ + void operator()(DestIt dest)\ + {\ + typedef typename boost::container::iterator_traits::value_type value_type;\ + value_type tmp(BOOST_MOVE_MFWD##N);\ + *dest = ::boost::move(const_cast(tmp));\ + }\ + \ BOOST_MOVE_MREF##N\ };\ +\ +template \ +struct emplace_functor_type\ +{\ + typedef emplace_functor##N BOOST_MOVE_LT##N BOOST_MOVE_TARG##N BOOST_MOVE_GT##N type;\ +};\ // + BOOST_MOVE_ITERATE_0TO9(BOOST_MOVE_ITERATOR_EMPLACE_FUNCTOR_CODE) + #undef BOOST_MOVE_ITERATOR_EMPLACE_FUNCTOR_CODE #endif diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 384c1fd..0fa3f6a 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -199,11 +199,11 @@ class insert_equal_end_hint_functor Icont &icont_; public: - insert_equal_end_hint_functor(Icont &icont) + BOOST_CONTAINER_FORCEINLINE insert_equal_end_hint_functor(Icont &icont) : icont_(icont) {} - void operator()(Node &n) + BOOST_CONTAINER_FORCEINLINE void operator()(Node &n) { this->icont_.insert_equal(this->icont_.cend(), n); } }; @@ -213,11 +213,11 @@ class push_back_functor Icont &icont_; public: - push_back_functor(Icont &icont) + BOOST_CONTAINER_FORCEINLINE push_back_functor(Icont &icont) : icont_(icont) {} - void operator()(Node &n) + BOOST_CONTAINER_FORCEINLINE void operator()(Node &n) { this->icont_.push_back(n); } }; @@ -328,14 +328,14 @@ template< boost::container::tree_type_enum tree_type_value struct intrusive_tree_proxy { template - static void rebalance(Icont &) {} + BOOST_CONTAINER_FORCEINLINE static void rebalance(Icont &) {} }; template struct intrusive_tree_proxy { template - static void rebalance(Icont &c) + BOOST_CONTAINER_FORCEINLINE static void rebalance(Icont &c) { c.rebalance(); } }; @@ -359,10 +359,10 @@ class RecyclingCloner : m_holder(holder), m_icont(itree) {} - static void do_assign(node_ptr_type &p, const node_type &other, bool_) + BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_type &other, bool_) { p->do_move_assign(const_cast(other).m_data); } - static void do_assign(node_ptr_type &p, const node_type &other, bool_) + BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_type &other, bool_) { p->do_assign(other.m_data); } node_ptr_type operator()(const node_type &other) const @@ -398,7 +398,7 @@ template struct key_node_compare : private KeyValueCompare { - explicit key_node_compare(const KeyValueCompare &comp) + BOOST_CONTAINER_FORCEINLINE explicit key_node_compare(const KeyValueCompare &comp) : KeyValueCompare(comp) {} @@ -409,20 +409,20 @@ struct key_node_compare }; template - typename enable_if_c::value, const typename KeyValueCompare::value_type &>::type + BOOST_CONTAINER_FORCEINLINE typename enable_if_c::value, const typename KeyValueCompare::value_type &>::type key_forward(const T &node) const { return node.get_data(); } template #if defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) - const T &key_forward(const T &key, typename enable_if_c::value>::type* =0) const + BOOST_CONTAINER_FORCEINLINE const T &key_forward(const T &key, typename enable_if_c::value>::type* =0) const #else - typename enable_if_c::value, const T &>::type key_forward(const T &key) const + BOOST_CONTAINER_FORCEINLINE typename enable_if_c::value, const T &>::type key_forward(const T &key) const #endif { return key; } template - bool operator()(const KeyType &key1, const KeyType2 &key2) const + BOOST_CONTAINER_FORCEINLINE bool operator()(const KeyType &key1, const KeyType2 &key2) const { return KeyValueCompare::operator()(this->key_forward(key1), this->key_forward(key2)); } }; @@ -496,15 +496,15 @@ class tree typedef boost::container::reverse_iterator reverse_iterator; typedef boost::container::reverse_iterator const_reverse_iterator; - tree() + BOOST_CONTAINER_FORCEINLINE tree() : AllocHolder() {} - explicit tree(const key_compare& comp, const allocator_type& a = allocator_type()) + BOOST_CONTAINER_FORCEINLINE explicit tree(const key_compare& comp, const allocator_type& a = allocator_type()) : AllocHolder(ValComp(comp), a) {} - explicit tree(const allocator_type& a) + BOOST_CONTAINER_FORCEINLINE explicit tree(const allocator_type& a) : AllocHolder(a) {} @@ -604,19 +604,19 @@ class tree , container_detail::push_back_functor(this->icont())); } - tree(const tree& x) + BOOST_CONTAINER_FORCEINLINE tree(const tree& x) : AllocHolder(x.value_comp(), x) { this->icont().clone_from (x.icont(), typename AllocHolder::cloner(*this), Destroyer(this->node_alloc())); } - tree(BOOST_RV_REF(tree) x) + BOOST_CONTAINER_FORCEINLINE tree(BOOST_RV_REF(tree) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : AllocHolder(BOOST_MOVE_BASE(AllocHolder, x), x.value_comp()) {} - tree(const tree& x, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE tree(const tree& x, const allocator_type &a) : AllocHolder(x.value_comp(), a) { this->icont().clone_from @@ -635,7 +635,7 @@ class tree } } - ~tree() + BOOST_CONTAINER_FORCEINLINE ~tree() {} //AllocHolder clears the tree tree& operator=(BOOST_COPY_ASSIGN_REF(tree) x) @@ -714,43 +714,43 @@ class tree public: // accessors: - value_compare value_comp() const + BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const { return this->icont().value_comp().predicate(); } - key_compare key_comp() const + BOOST_CONTAINER_FORCEINLINE key_compare key_comp() const { return this->icont().value_comp().predicate().key_comp(); } - allocator_type get_allocator() const + BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const { return allocator_type(this->node_alloc()); } - const stored_allocator_type &get_stored_allocator() const + BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const { return this->node_alloc(); } - stored_allocator_type &get_stored_allocator() + BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() { return this->node_alloc(); } - iterator begin() + BOOST_CONTAINER_FORCEINLINE iterator begin() { return iterator(this->icont().begin()); } - const_iterator begin() const + BOOST_CONTAINER_FORCEINLINE const_iterator begin() const { return this->cbegin(); } - iterator end() + BOOST_CONTAINER_FORCEINLINE iterator end() { return iterator(this->icont().end()); } - const_iterator end() const + BOOST_CONTAINER_FORCEINLINE const_iterator end() const { return this->cend(); } - reverse_iterator rbegin() + BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const { return this->crbegin(); } - reverse_iterator rend() + BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const { return this->crend(); } //! Effects: Returns a const_iterator to the first element contained in the container. @@ -758,7 +758,7 @@ class tree //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cbegin() const + BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const { return const_iterator(this->non_const_icont().begin()); } //! Effects: Returns a const_iterator to the end of the container. @@ -766,7 +766,7 @@ class tree //! Throws: Nothing. //! //! Complexity: Constant. - const_iterator cend() const + BOOST_CONTAINER_FORCEINLINE const_iterator cend() const { return const_iterator(this->non_const_icont().end()); } //! Effects: Returns a const_reverse_iterator pointing to the beginning @@ -775,7 +775,7 @@ class tree //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crbegin() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); } //! Effects: Returns a const_reverse_iterator pointing to the end @@ -784,19 +784,19 @@ class tree //! Throws: Nothing. //! //! Complexity: Constant. - const_reverse_iterator crend() const + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); } - bool empty() const + BOOST_CONTAINER_FORCEINLINE bool empty() const { return !this->size(); } - size_type size() const + BOOST_CONTAINER_FORCEINLINE size_type size() const { return this->icont().size(); } - size_type max_size() const + BOOST_CONTAINER_FORCEINLINE size_type max_size() const { return AllocHolder::max_size(); } - void swap(ThisType& x) + BOOST_CONTAINER_FORCEINLINE void swap(ThisType& x) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::container_detail::is_nothrow_swappable::value ) { AllocHolder::swap(x); } @@ -868,6 +868,28 @@ class tree private: + template + iterator priv_insert_unique_key_commit + (BOOST_FWD_REF(KeyConvertible) key, insert_commit_data &data) + { + NodePtr tmp = AllocHolder::create_node_from_key(boost::forward(key)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; + } + + template + iiterator priv_insert_or_assign_commit + (BOOST_FWD_REF(KeyConvertible) key, BOOST_FWD_REF(M) obj, insert_commit_data &data) + { + NodePtr tmp = AllocHolder::create_node(boost::forward(key), boost::forward(obj)); + scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); + iiterator ret(this->icont().insert_unique_commit(*tmp, data)); + destroy_deallocator.release(); + return ret; + } + bool priv_is_linked(const_iterator const position) const { iiterator const cur(position.get()); @@ -921,11 +943,11 @@ class tree #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template - std::pair emplace_unique(BOOST_FWD_REF(Args)... args) + BOOST_CONTAINER_FORCEINLINE std::pair emplace_unique(BOOST_FWD_REF(Args)... args) { return this->emplace_unique_impl(AllocHolder::create_node(boost::forward(args)...)); } template - iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args) + BOOST_CONTAINER_FORCEINLINE iterator emplace_hint_unique(const_iterator hint, BOOST_FWD_REF(Args)... args) { return this->emplace_unique_hint_impl(hint, AllocHolder::create_node(boost::forward(args)...)); } template @@ -1054,19 +1076,25 @@ class tree std::pair ret = this->icont().insert_unique_check(k, KeyNodeCompare(value_comp()), data); return ret.second - ? this->insert_unique_key_commit(boost::forward(key), data) + ? this->priv_insert_unique_key_commit(boost::forward(key), data) : iterator(ret.first); } - template - iterator insert_unique_key_commit - (BOOST_FWD_REF(KeyConvertible) key, insert_commit_data &data) + template + std::pair insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj) { - NodePtr tmp = AllocHolder::create_node_from_key(boost::forward(key)); - scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); - iterator ret(this->icont().insert_unique_commit(*tmp, data)); - destroy_deallocator.release(); - return ret; + insert_commit_data data; + const key_type & k = key; //Support emulated rvalue references + std::pair ret = + hint == const_iterator() ? this->icont().insert_unique_check(k, KeyNodeCompare(value_comp()), data) + : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(value_comp()), data); + if(ret.second){ + ret.first = this->priv_insert_or_assign_commit(boost::forward(key), boost::forward(obj), data); + } + else{ + ret.first->get_data().second = boost::forward(obj); + } + return std::pair(iterator(ret.first), ret.second); } iterator erase(const_iterator position) @@ -1075,7 +1103,7 @@ class tree return iterator(this->icont().erase_and_dispose(position.get(), Destroyer(this->node_alloc()))); } - size_type erase(const key_type& k) + BOOST_CONTAINER_FORCEINLINE size_type erase(const key_type& k) { return AllocHolder::erase_key(k, KeyNodeCompare(value_comp()), alloc_version()); } iterator erase(const_iterator first, const_iterator last) @@ -1085,30 +1113,30 @@ class tree return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } - void clear() + BOOST_CONTAINER_FORCEINLINE void clear() { AllocHolder::clear(alloc_version()); } // search operations. Const and non-const overloads even if no iterator is returned // so splay implementations can to their rebalancing when searching in non-const versions - iterator find(const key_type& k) + BOOST_CONTAINER_FORCEINLINE iterator find(const key_type& k) { return iterator(this->icont().find(k, KeyNodeCompare(value_comp()))); } - const_iterator find(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE const_iterator find(const key_type& k) const { return const_iterator(this->non_const_icont().find(k, KeyNodeCompare(value_comp()))); } - size_type count(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& k) const { return size_type(this->icont().count(k, KeyNodeCompare(value_comp()))); } - iterator lower_bound(const key_type& k) + BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k) { return iterator(this->icont().lower_bound(k, KeyNodeCompare(value_comp()))); } - const_iterator lower_bound(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& k) const { return const_iterator(this->non_const_icont().lower_bound(k, KeyNodeCompare(value_comp()))); } - iterator upper_bound(const key_type& k) + BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& k) { return iterator(this->icont().upper_bound(k, KeyNodeCompare(value_comp()))); } - const_iterator upper_bound(const key_type& k) const + BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& k) const { return const_iterator(this->non_const_icont().upper_bound(k, KeyNodeCompare(value_comp()))); } std::pair equal_range(const key_type& k) @@ -1141,28 +1169,28 @@ class tree (const_iterator(ret.first), const_iterator(ret.second)); } - void rebalance() + BOOST_CONTAINER_FORCEINLINE void rebalance() { intrusive_tree_proxy_t::rebalance(this->icont()); } - friend bool operator==(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const tree& x, const tree& y) { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } - friend bool operator<(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator<(const tree& x, const tree& y) { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } - friend bool operator!=(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const tree& x, const tree& y) { return !(x == y); } - friend bool operator>(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const tree& x, const tree& y) { return y < x; } - friend bool operator<=(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const tree& x, const tree& y) { return !(y < x); } - friend bool operator>=(const tree& x, const tree& y) + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const tree& x, const tree& y) { return !(x < y); } - friend void swap(tree& x, tree& y) + BOOST_CONTAINER_FORCEINLINE friend void swap(tree& x, tree& y) { x.swap(y); } }; diff --git a/include/boost/container/detail/value_init.hpp b/include/boost/container/detail/value_init.hpp index eb4c976..faba70e 100644 --- a/include/boost/container/detail/value_init.hpp +++ b/include/boost/container/detail/value_init.hpp @@ -37,6 +37,8 @@ struct value_init operator T &() { return m_t; } + T &get() { return m_t; } + T m_t; }; diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index d18fffe..afba9d1 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -56,11 +56,11 @@ namespace container { namespace container_detail{ template -static D &force(const S &s) +BOOST_CONTAINER_FORCEINLINE static D &force(const S &s) { return *const_cast((reinterpret_cast(&s))); } template -static D force_copy(S s) +BOOST_CONTAINER_FORCEINLINE static D force_copy(S s) { D *vp = reinterpret_cast(&s); return D(*vp); @@ -604,6 +604,98 @@ class flat_map BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript) #endif + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template + BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(const key_type& k, BOOST_FWD_REF(M) obj) + { + return container_detail::force_copy< std::pair > + (this->m_flat_tree.insert_or_assign + ( container_detail::force_copy(const_iterator()) + , k, ::boost::forward(obj)) + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template + BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return container_detail::force_copy< std::pair > + (this->m_flat_tree.insert_or_assign + ( container_detail::force_copy(const_iterator()) + , ::boost::move(k), ::boost::forward(obj)) + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, const key_type& k, BOOST_FWD_REF(M) obj) + { + return container_detail::force_copy< std::pair > + (this->m_flat_tree.insert_or_assign + ( container_detail::force_copy(hint) + , k, ::boost::forward(obj)) + ); + } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { + return container_detail::force_copy< std::pair > + (this->m_flat_tree.insert_or_assign + ( container_detail::force_copy(hint) + , ::boost::move(k), ::boost::forward(obj)) + ); + } + //! @copydoc ::boost::container::flat_set::nth(size_type) iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW { return container_detail::force_copy(m_flat_tree.nth(n)); } diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index e71cb2d..d2cf0ca 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -132,6 +132,7 @@ class map //! Effects: Default constructs an empty map. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE map() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) : base_t() @@ -144,6 +145,7 @@ class map //! and allocator. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE explicit map(const Compare& comp, const allocator_type& a = allocator_type()) : base_t(comp, a) { @@ -154,6 +156,7 @@ class map //! Effects: Constructs an empty map using the specified allocator. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE explicit map(const allocator_type& a) : base_t(a) { @@ -167,6 +170,7 @@ class map //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is last - first. template + BOOST_CONTAINER_FORCEINLINE map(InputIterator first, InputIterator last, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(true, first, last, comp, a) @@ -181,6 +185,7 @@ class map //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is last - first. template + BOOST_CONTAINER_FORCEINLINE map(InputIterator first, InputIterator last, const allocator_type& a) : base_t(true, first, last, Compare(), a) { @@ -199,6 +204,7 @@ class map //! //! Note: Non-standard extension. template + BOOST_CONTAINER_FORCEINLINE map( ordered_unique_range_t, InputIterator first, InputIterator last , const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(ordered_range, first, last, comp, a) @@ -213,6 +219,7 @@ class map //! //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE map(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(true, il.begin(), il.end(), comp, a) { @@ -225,6 +232,7 @@ class map //! //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE map(std::initializer_list il, const allocator_type& a) : base_t(true, il.begin(), il.end(), Compare(), a) { @@ -242,6 +250,7 @@ class map //! Complexity: Linear in N. //! //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE map(ordered_unique_range_t, std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(ordered_range, il.begin(), il.end(), comp, a) @@ -254,6 +263,7 @@ class map //! Effects: Copy constructs a map. //! //! Complexity: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE map(const map& x) : base_t(static_cast(x)) { @@ -266,6 +276,7 @@ class map //! Complexity: Constant. //! //! Postcondition: x is emptied. + BOOST_CONTAINER_FORCEINLINE map(BOOST_RV_REF(map) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) @@ -277,6 +288,7 @@ class map //! Effects: Copy constructs a map using the specified allocator. //! //! Complexity: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE map(const map& x, const allocator_type &a) : base_t(static_cast(x), a) { @@ -290,6 +302,7 @@ class map //! Complexity: Constant if x == x.get_allocator(), linear otherwise. //! //! Postcondition: x is emptied. + BOOST_CONTAINER_FORCEINLINE map(BOOST_RV_REF(map) x, const allocator_type &a) : base_t(BOOST_MOVE_BASE(base_t, x), a) { @@ -300,6 +313,7 @@ class map //! Effects: Makes *this a copy of x. //! //! Complexity: Linear in x.size(). + BOOST_CONTAINER_FORCEINLINE map& operator=(BOOST_COPY_ASSIGN_REF(map) x) { return static_cast(this->base_t::operator=(static_cast(x))); } @@ -311,6 +325,7 @@ class map //! Complexity: Constant if allocator_traits_type:: //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. + BOOST_CONTAINER_FORCEINLINE map& operator=(BOOST_RV_REF(map) x) BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) && @@ -320,6 +335,7 @@ class map #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: Assign content of il to *this. //! + BOOST_CONTAINER_FORCEINLINE map& operator=(std::initializer_list il) { this->clear(); @@ -485,12 +501,80 @@ class map mapped_type& operator[](key_type &&k); #elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) //in compilers like GCC 3.4, we can't catch temporaries - mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); } - mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); } + BOOST_CONTAINER_FORCEINLINE mapped_type& operator[](const key_type &k) { return this->priv_subscript(k); } + BOOST_CONTAINER_FORCEINLINE mapped_type& operator[](BOOST_RV_REF(key_type) k) { return this->priv_subscript(::boost::move(k)); } #else BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript) #endif + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template + BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(const key_type& k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(const_iterator(), k, ::boost::forward(obj)); } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template + BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(const_iterator(), ::boost::move(k), ::boost::forward(obj)); } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, forward(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, const key_type& k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(hint, k, ::boost::forward(obj)); } + + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value + //! as if by insert, constructing it from value_type(k, move(obj)) and the new element + //! to the container as close as possible to the position just before hint. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! to the element obtained while it is held in the node handle are invalidated, and pointers and + //! references obtained to that element before it was extracted become valid. + //! + //! Returns: The bool component is true if the insertion took place and false if the assignment + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! the new element is inserted just before hint. + template + BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(hint, ::boost::move(k), ::boost::forward(obj)); } + //! Returns: A reference to the element whose key is equivalent to x. //! Throws: An exception object of type out_of_range if no such element is present. //! Complexity: logarithmic. @@ -529,7 +613,7 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - std::pair insert(const value_type& x) + BOOST_CONTAINER_FORCEINLINE std::pair insert(const value_type& x) { return this->base_t::insert_unique(x); } //! Effects: Inserts a new value_type created from the pair if and only if @@ -540,7 +624,7 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - std::pair insert(const nonconst_value_type& x) + BOOST_CONTAINER_FORCEINLINE std::pair insert(const nonconst_value_type& x) { return this->base_t::insert_unique(x); } //! Effects: Inserts a new value_type move constructed from the pair if and @@ -551,7 +635,7 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - std::pair insert(BOOST_RV_REF(nonconst_value_type) x) + BOOST_CONTAINER_FORCEINLINE std::pair insert(BOOST_RV_REF(nonconst_value_type) x) { return this->base_t::insert_unique(boost::move(x)); } //! Effects: Inserts a new value_type move constructed from the pair if and @@ -562,7 +646,7 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - std::pair insert(BOOST_RV_REF(movable_value_type) x) + BOOST_CONTAINER_FORCEINLINE std::pair insert(BOOST_RV_REF(movable_value_type) x) { return this->base_t::insert_unique(boost::move(x)); } //! Effects: Move constructs a new value from x if and only if there is @@ -573,7 +657,7 @@ class map //! points to the element with key equivalent to the key of x. //! //! Complexity: Logarithmic. - std::pair insert(BOOST_RV_REF(value_type) x) + BOOST_CONTAINER_FORCEINLINE std::pair insert(BOOST_RV_REF(value_type) x) { return this->base_t::insert_unique(boost::move(x)); } //! Effects: Inserts a copy of x in the container if and only if there is @@ -585,7 +669,7 @@ class map //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const value_type& x) { return this->base_t::insert_unique(p, x); } //! Effects: Move constructs a new value from x if and only if there is @@ -637,7 +721,7 @@ class map //! //! Complexity: At most N log(size()+N) (N is the distance from first to last) template - void insert(InputIterator first, InputIterator last) + BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) { this->base_t::insert_unique(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -645,7 +729,7 @@ class map //! if there is no element with key equivalent to the key of that element. //! //! Complexity: At most N log(size()+N) (N is the distance from il.begin() to il.end()) - void insert(std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) { this->base_t::insert_unique(il.begin(), il.end()); } #endif @@ -663,7 +747,7 @@ class map //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. template - std::pair emplace(BOOST_FWD_REF(Args)... args) + BOOST_CONTAINER_FORCEINLINE std::pair emplace(BOOST_FWD_REF(Args)... args) { return this->base_t::emplace_unique(boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with @@ -677,18 +761,18 @@ class map //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. template - iterator emplace_hint(const_iterator p, BOOST_FWD_REF(Args)... args) + 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)...); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_MAP_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - std::pair emplace(BOOST_MOVE_UREF##N)\ + BOOST_CONTAINER_FORCEINLINE std::pair emplace(BOOST_MOVE_UREF##N)\ { return this->base_t::emplace_unique(BOOST_MOVE_FWD##N); }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##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); }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_MAP_EMPLACE_CODE) @@ -766,7 +850,7 @@ class map //! Returns: The number of elements with key equivalent to x. //! //! Complexity: log(size())+count(k) - size_type count(const key_type& x) const + BOOST_CONTAINER_FORCEINLINE size_type count(const key_type& x) const { return static_cast(this->find(x) != this->cend()); } #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -850,11 +934,10 @@ class map #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: template - mapped_type& priv_subscript(BOOST_FWD_REF(KeyConvertible) k) + BOOST_CONTAINER_FORCEINLINE mapped_type& priv_subscript(BOOST_FWD_REF(KeyConvertible) k) { return this->insert_from_key(boost::forward(k))->second; } - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; @@ -959,6 +1042,7 @@ class multimap //! Effects: Default constructs an empty multimap. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE multimap() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && container_detail::is_nothrow_default_constructible::value) : base_t() @@ -970,6 +1054,7 @@ class multimap //! Effects: Constructs an empty multimap using the specified allocator. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE explicit multimap(const Compare& comp, const allocator_type& a = allocator_type()) : base_t(comp, a) { @@ -981,6 +1066,7 @@ class multimap //! object and allocator. //! //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE explicit multimap(const allocator_type& a) : base_t(a) { @@ -994,6 +1080,7 @@ class multimap //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is last - first. template + BOOST_CONTAINER_FORCEINLINE multimap(InputIterator first, InputIterator last, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) @@ -1009,7 +1096,7 @@ class multimap //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is last - first. template - multimap(InputIterator first, InputIterator last, const allocator_type& a) + BOOST_CONTAINER_FORCEINLINE multimap(InputIterator first, InputIterator last, const allocator_type& a) : base_t(false, first, last, Compare(), a) { //A type must be std::pair @@ -1026,7 +1113,7 @@ class multimap //! //! Note: Non-standard extension. template - multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), + BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, InputIterator first, InputIterator last, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(ordered_range, first, last, comp, a) {} @@ -1037,6 +1124,7 @@ class multimap //! //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE multimap(std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(false, il.begin(), il.end(), comp, a) @@ -1050,6 +1138,7 @@ class multimap //! //! Complexity: Linear in N if the range [first ,last ) is already sorted using //! comp and otherwise N logN, where N is il.first() - il.end(). + BOOST_CONTAINER_FORCEINLINE multimap(std::initializer_list il, const allocator_type& a) : base_t(false, il.begin(), il.end(), Compare(), a) { @@ -1066,6 +1155,7 @@ class multimap //! Complexity: Linear in N. //! //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE multimap(ordered_range_t, std::initializer_list il, const Compare& comp = Compare(), const allocator_type& a = allocator_type()) : base_t(ordered_range, il.begin(), il.end(), comp, a) @@ -1078,7 +1168,7 @@ class multimap //! Effects: Copy constructs a multimap. //! //! Complexity: Linear in x.size(). - multimap(const multimap& x) + BOOST_CONTAINER_FORCEINLINE multimap(const multimap& x) : base_t(static_cast(x)) { //A type must be std::pair @@ -1090,7 +1180,7 @@ class multimap //! Complexity: Constant. //! //! Postcondition: x is emptied. - multimap(BOOST_RV_REF(multimap) x) + BOOST_CONTAINER_FORCEINLINE multimap(BOOST_RV_REF(multimap) x) BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) { @@ -1101,7 +1191,7 @@ class multimap //! Effects: Copy constructs a multimap. //! //! Complexity: Linear in x.size(). - multimap(const multimap& x, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE multimap(const multimap& x, const allocator_type &a) : base_t(static_cast(x), a) { //A type must be std::pair @@ -1113,7 +1203,7 @@ class multimap //! Complexity: Constant if a == x.get_allocator(), linear otherwise. //! //! Postcondition: x is emptied. - multimap(BOOST_RV_REF(multimap) x, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE multimap(BOOST_RV_REF(multimap) x, const allocator_type &a) : base_t(BOOST_MOVE_BASE(base_t, x), a) { //A type must be std::pair @@ -1123,13 +1213,13 @@ class multimap //! Effects: Makes *this a copy of x. //! //! Complexity: Linear in x.size(). - multimap& operator=(BOOST_COPY_ASSIGN_REF(multimap) x) + BOOST_CONTAINER_FORCEINLINE multimap& operator=(BOOST_COPY_ASSIGN_REF(multimap) x) { return static_cast(this->base_t::operator=(static_cast(x))); } //! Effects: this->swap(x.get()). //! //! Complexity: Constant. - multimap& operator=(BOOST_RV_REF(multimap) x) + BOOST_CONTAINER_FORCEINLINE multimap& operator=(BOOST_RV_REF(multimap) 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) @@ -1138,7 +1228,7 @@ class multimap #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: Assign content of il to *this. //! - multimap& operator=(std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE multimap& operator=(std::initializer_list il) { this->clear(); insert(il.begin(), il.end()); @@ -1216,7 +1306,7 @@ class multimap //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. template - iterator emplace(BOOST_FWD_REF(Args)... args) + BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_FWD_REF(Args)... args) { return this->base_t::emplace_equal(boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with @@ -1229,18 +1319,18 @@ class multimap //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. template - iterator emplace_hint(const_iterator p, BOOST_FWD_REF(Args)... args) + 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)...); } #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_MULTIMAP_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace(BOOST_MOVE_UREF##N)\ + BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_MOVE_UREF##N)\ { return this->base_t::emplace_equal(BOOST_MOVE_FWD##N); }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##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); }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_MULTIMAP_EMPLACE_CODE) @@ -1252,21 +1342,21 @@ class multimap //! newly inserted element. //! //! Complexity: Logarithmic. - iterator insert(const value_type& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const value_type& x) { return this->base_t::insert_equal(x); } //! Effects: Inserts a new value constructed from x and returns //! the iterator pointing to the newly inserted element. //! //! Complexity: Logarithmic. - iterator insert(const nonconst_value_type& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const nonconst_value_type& x) { return this->base_t::insert_equal(x); } //! Effects: Inserts a new value move-constructed from x and returns //! the iterator pointing to the newly inserted element. //! //! Complexity: Logarithmic. - iterator insert(BOOST_RV_REF(nonconst_value_type) x) + BOOST_CONTAINER_FORCEINLINE iterator insert(BOOST_RV_REF(nonconst_value_type) x) { return this->base_t::insert_equal(boost::move(x)); } //! Effects: Inserts a new value move-constructed from x and returns @@ -1284,7 +1374,7 @@ class multimap //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - iterator insert(const_iterator p, const value_type& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const value_type& x) { return this->base_t::insert_equal(p, x); } //! Effects: Inserts a new value constructed from x in the container. @@ -1295,7 +1385,7 @@ class multimap //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - iterator insert(const_iterator p, const nonconst_value_type& x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const nonconst_value_type& x) { return this->base_t::insert_equal_convertible(p, x); } //! Effects: Inserts a new value move constructed from x in the container. @@ -1306,7 +1396,7 @@ class multimap //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - iterator insert(const_iterator p, BOOST_RV_REF(nonconst_value_type) x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, BOOST_RV_REF(nonconst_value_type) x) { return this->base_t::insert_equal_convertible(p, boost::move(x)); } //! Effects: Inserts a new value move constructed from x in the container. @@ -1317,7 +1407,7 @@ class multimap //! //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. - iterator insert(const_iterator p, BOOST_RV_REF(movable_value_type) x) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, BOOST_RV_REF(movable_value_type) x) { return this->base_t::insert_equal_convertible(p, boost::move(x)); } //! Requires: first, last are not iterators into *this. @@ -1326,14 +1416,14 @@ class multimap //! //! Complexity: At most N log(size()+N) (N is the distance from first to last) template - void insert(InputIterator first, InputIterator last) + BOOST_CONTAINER_FORCEINLINE void insert(InputIterator first, InputIterator last) { this->base_t::insert_equal(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) //! Effects: inserts each element from the range [il.begin(), il.end(). //! //! Complexity: At most N log(size()+N) (N is the distance from il.begin() to il.end()) - void insert(std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE void insert(std::initializer_list il) { this->base_t::insert_equal(il.begin(), il.end()); } #endif diff --git a/test/map_test.cpp b/test/map_test.cpp index df27b5c..26ebd37 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -250,7 +250,6 @@ int main () std::pair p; s.insert(p); s.emplace(p); - return 0; } //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index 1749290..97b6f23 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -667,6 +667,65 @@ int map_test() } } + { //operator[] test + boostmap.clear(); + boostmultimap.clear(); + stdmap.clear(); + stdmultimap.clear(); + + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < max; ++i){ + boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); + stdmap[i] = i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + + { //insert_or_assign test + boostmap.clear(); + boostmultimap.clear(); + stdmap.clear(); + stdmultimap.clear(); + + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[max]; + for(int i = 0; i < max; ++i){ + IntType i1(i); + IntType i2(max-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + for(int i = 0; i < max; ++i){ + boostmap.insert_or_assign(boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); + stdmap[i] = i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < max; ++i){ + boostmap.insert_or_assign(boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); + stdmap[i] = max-i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + if(map_test_copyable (container_detail::bool_::value>())){ return 1;