From f3a1a187a1af2188f47a6e8c20cbfac74ca24823 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Tue, 7 Jul 2015 03:37:33 +0000 Subject: [PATCH] Implement N4279 and LWG#2664 for . Reviewed as http://reviews.llvm.org/D10669 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@241539 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/map | 131 ++++++++++++ .../map.modifiers/insert_or_assign.pass.cpp | 192 ++++++++++++++++++ .../map/map.modifiers/try.emplace.pass.cpp | 189 +++++++++++++++++ 3 files changed, 512 insertions(+) create mode 100644 test/std/containers/associative/map/map.modifiers/insert_or_assign.pass.cpp create mode 100644 test/std/containers/associative/map/map.modifiers/try.emplace.pass.cpp diff --git a/include/map b/include/map index cdcf40569..0f689b7e4 100644 --- a/include/map +++ b/include/map @@ -135,6 +135,23 @@ public: void insert(InputIterator first, InputIterator last); void insert(initializer_list il); + template + pair try_emplace(const key_type& k, Args&&... args); // C++17 + template + pair try_emplace(key_type&& k, Args&&... args); // C++17 + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17 + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); // C++17 + template + pair insert_or_assign(const key_type& k, M&& obj); // C++17 + template + pair insert_or_assign(key_type&& k, M&& obj); // C++17 + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); // C++17 + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); // C++17 + iterator erase(const_iterator position); iterator erase(iterator position); // C++14 size_type erase(const key_type& k); @@ -1077,6 +1094,120 @@ public: #endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS +#if _LIBCPP_STD_VER > 14 +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#ifndef _LIBCPP_HAS_NO_VARIADICS + template + _LIBCPP_INLINE_VISIBILITY + pair try_emplace(const key_type& __k, _Args&&... __args) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + return _VSTD::make_pair(__p, false); + else + return _VSTD::make_pair( + emplace_hint(__p, + _VSTD::piecewise_construct, _VSTD::forward_as_tuple(__k), + _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...)), + true); + } + + template + _LIBCPP_INLINE_VISIBILITY + pair try_emplace(key_type&& __k, _Args&&... __args) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + return _VSTD::make_pair(__p, false); + else + return _VSTD::make_pair( + emplace_hint(__p, + _VSTD::piecewise_construct, _VSTD::forward_as_tuple(_VSTD::move(__k)), + _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...)), + true); + } + + template + _LIBCPP_INLINE_VISIBILITY + iterator try_emplace(const_iterator __h, const key_type& __k, _Args&&... __args) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + return __p; + else + return emplace_hint(__p, + _VSTD::piecewise_construct, _VSTD::forward_as_tuple(__k), + _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...)); + } + + template + _LIBCPP_INLINE_VISIBILITY + iterator try_emplace(const_iterator __h, key_type&& __k, _Args&&... __args) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + return __p; + else + return emplace_hint(__p, + _VSTD::piecewise_construct, _VSTD::forward_as_tuple(_VSTD::move(__k)), + _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...)); + } + + template + _LIBCPP_INLINE_VISIBILITY + pair insert_or_assign(const key_type& __k, _Vp&& __v) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + { + __p->second = _VSTD::forward<_Vp>(__v); + return _VSTD::make_pair(__p, false); + } + return _VSTD::make_pair(emplace_hint(__p, __k, _VSTD::forward<_Vp>(__v)), true); + } + + template + _LIBCPP_INLINE_VISIBILITY + pair insert_or_assign(key_type&& __k, _Vp&& __v) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + { + __p->second = _VSTD::forward<_Vp>(__v); + return _VSTD::make_pair(__p, false); + } + return _VSTD::make_pair(emplace_hint(__p, _VSTD::move(__k), _VSTD::forward<_Vp>(__v)), true); + } + + template + _LIBCPP_INLINE_VISIBILITY + iterator insert_or_assign(const_iterator __h, const key_type& __k, _Vp&& __v) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + { + __p->second = _VSTD::forward<_Vp>(__v); + return __p; + } + return emplace_hint(__h, __k, _VSTD::forward<_Vp>(__v)); + } + + template + _LIBCPP_INLINE_VISIBILITY + iterator insert_or_assign(const_iterator __h, key_type&& __k, _Vp&& __v) + { + iterator __p = lower_bound(__k); + if ( __p != end() && !key_comp()(__k, __p->first)) + { + __p->second = _VSTD::forward<_Vp>(__v); + return __p; + } + return emplace_hint(__h, _VSTD::move(__k), _VSTD::forward<_Vp>(__v)); + } +#endif +#endif +#endif + _LIBCPP_INLINE_VISIBILITY iterator erase(const_iterator __p) {return __tree_.erase(__p.__i_);} _LIBCPP_INLINE_VISIBILITY diff --git a/test/std/containers/associative/map/map.modifiers/insert_or_assign.pass.cpp b/test/std/containers/associative/map/map.modifiers/insert_or_assign.pass.cpp new file mode 100644 index 000000000..484ed0624 --- /dev/null +++ b/test/std/containers/associative/map/map.modifiers/insert_or_assign.pass.cpp @@ -0,0 +1,192 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// class map + +// template +// pair insert_or_assign(const key_type& k, M&& obj); // C++17 +// template +// pair insert_or_assign(key_type&& k, M&& obj); // C++17 +// template +// iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); // C++17 +// template +// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); // C++17 + +#include <__config> +#include +#include +#include + +#include + +class Moveable +{ + Moveable(const Moveable&); + Moveable& operator=(const Moveable&); + + int int_; + double double_; +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) + : int_(x.int_), double_(x.double_) + {x.int_ = -1; x.double_ = -1;} + Moveable& operator=(Moveable&& x) + {int_ = x.int_; x.int_ = -1; + double_ = x.double_; x.double_ = -1; + return *this; + } + + bool operator==(const Moveable& x) const + {return int_ == x.int_ && double_ == x.double_;} + bool operator<(const Moveable& x) const + {return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_);} + + int get() const {return int_;} + bool moved() const {return int_ == -1;} +}; + + +int main() +{ +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#ifndef _LIBCPP_HAS_NO_VARIADICS + + { // pair insert_or_assign(const key_type& k, M&& obj); + typedef std::map M; + typedef std::pair R; + M m; + R r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( i, Moveable(i, (double) i)); + assert(m.size() == 10); + + for (int i=0; i < 20; i += 2) + { + Moveable mv(i+1, i+1); + r = m.insert_or_assign(i, std::move(mv)); + assert(m.size() == 10); + assert(!r.second); // was not inserted + assert(mv.moved()); // was moved from + assert(r.first->first == i); // key + assert(r.first->second.get() == i+1); // value + } + + Moveable mv1(5, 5.0); + r = m.insert_or_assign(-1, std::move(mv1)); + assert(m.size() == 11); + assert(r.second); // was inserted + assert(mv1.moved()); // was moved from + assert(r.first->first == -1); // key + assert(r.first->second.get() == 5); // value + + Moveable mv2(9, 9.0); + r = m.insert_or_assign(3, std::move(mv2)); + assert(m.size() == 12); + assert(r.second); // was inserted + assert(mv2.moved()); // was moved from + assert(r.first->first == 3); // key + assert(r.first->second.get() == 9); // value + + Moveable mv3(-1, 5.0); + r = m.insert_or_assign(117, std::move(mv3)); + assert(m.size() == 13); + assert(r.second); // was inserted + assert(mv3.moved()); // was moved from + assert(r.first->first == 117); // key + assert(r.first->second.get() == -1); // value + } + { // pair insert_or_assign(key_type&& k, M&& obj); + typedef std::map M; + typedef std::pair R; + M m; + R r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1)); + assert(m.size() == 10); + + Moveable mvkey1(2, 2.0); + Moveable mv1(4, 4.0); + r = m.insert_or_assign(std::move(mvkey1), std::move(mv1)); + assert(m.size() == 10); + assert(!r.second); // was not inserted + assert(!mvkey1.moved()); // was not moved from + assert(mv1.moved()); // was moved from + assert(r.first->first == mvkey1); // key + assert(r.first->second.get() == 4); // value + + Moveable mvkey2(3, 3.0); + Moveable mv2(5, 5.0); + r = m.try_emplace(std::move(mvkey2), std::move(mv2)); + assert(m.size() == 11); + assert(r.second); // was inserted + assert(mv2.moved()); // was moved from + assert(mvkey2.moved()); // was moved from + assert(r.first->first.get() == 3); // key + assert(r.first->second.get() == 5); // value + } + { // iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + typedef std::map M; + M m; + M::iterator r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( i, Moveable(i, (double) i)); + assert(m.size() == 10); + M::const_iterator it = m.find(2); + + Moveable mv1(3, 3.0); + r = m.insert_or_assign(it, 2, std::move(mv1)); + assert(m.size() == 10); + assert(mv1.moved()); // was moved from + assert(r->first == 2); // key + assert(r->second.get() == 3); // value + + Moveable mv2(5, 5.0); + r = m.insert_or_assign(it, 3, std::move(mv2)); + assert(m.size() == 11); + assert(mv2.moved()); // was moved from + assert(r->first == 3); // key + assert(r->second.get() == 5); // value + } + { // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + typedef std::map M; + M m; + M::iterator r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1)); + assert(m.size() == 10); + M::const_iterator it = std::next(m.cbegin()); + + Moveable mvkey1(2, 2.0); + Moveable mv1(4, 4.0); + r = m.insert_or_assign(it, std::move(mvkey1), std::move(mv1)); + assert(m.size() == 10); + assert(mv1.moved()); // was moved from + assert(!mvkey1.moved()); // was not moved from + assert(r->first == mvkey1); // key + assert(r->second.get() == 4); // value + + Moveable mvkey2(3, 3.0); + Moveable mv2(5, 5.0); + r = m.insert_or_assign(it, std::move(mvkey2), std::move(mv2)); + assert(m.size() == 11); + assert(mv2.moved()); // was moved from + assert(mvkey2.moved()); // was moved from + assert(r->first.get() == 3); // key + assert(r->second.get() == 5); // value + } + +#endif // _LIBCPP_HAS_NO_VARIADICS +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +} \ No newline at end of file diff --git a/test/std/containers/associative/map/map.modifiers/try.emplace.pass.cpp b/test/std/containers/associative/map/map.modifiers/try.emplace.pass.cpp new file mode 100644 index 000000000..8e0dd7577 --- /dev/null +++ b/test/std/containers/associative/map/map.modifiers/try.emplace.pass.cpp @@ -0,0 +1,189 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++03, c++11, c++14 + +// + +// class map + +// template +// pair try_emplace(const key_type& k, Args&&... args); // C++17 +// template +// pair try_emplace(key_type&& k, Args&&... args); // C++17 +// template +// iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17 +// template +// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); // C++17 + +#include <__config> +#include +#include +#include + +class Moveable +{ + Moveable(const Moveable&); + Moveable& operator=(const Moveable&); + + int int_; + double double_; +public: + Moveable() : int_(0), double_(0) {} + Moveable(int i, double d) : int_(i), double_(d) {} + Moveable(Moveable&& x) + : int_(x.int_), double_(x.double_) + {x.int_ = -1; x.double_ = -1;} + Moveable& operator=(Moveable&& x) + {int_ = x.int_; x.int_ = -1; + double_ = x.double_; x.double_ = -1; + return *this; + } + + bool operator==(const Moveable& x) const + {return int_ == x.int_ && double_ == x.double_;} + bool operator<(const Moveable& x) const + {return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_);} + + int get() const {return int_;} + bool moved() const {return int_ == -1;} +}; + + +int main() +{ +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#ifndef _LIBCPP_HAS_NO_VARIADICS + + { // pair try_emplace(const key_type& k, Args&&... args); + typedef std::map M; + typedef std::pair R; + M m; + R r; + for (int i = 0; i < 20; i += 2) + m.emplace (i, Moveable(i, (double) i)); + assert(m.size() == 10); + + Moveable mv1(3, 3.0); + for (int i=0; i < 20; i += 2) + { + r = m.try_emplace(i, std::move(mv1)); + assert(m.size() == 10); + assert(!r.second); // was not inserted + assert(!mv1.moved()); // was not moved from + assert(r.first->first == i); // key + } + + r = m.try_emplace(-1, std::move(mv1)); + assert(m.size() == 11); + assert(r.second); // was inserted + assert(mv1.moved()); // was moved from + assert(r.first->first == -1); // key + assert(r.first->second.get() == 3); // value + + Moveable mv2(5, 3.0); + r = m.try_emplace(5, std::move(mv2)); + assert(m.size() == 12); + assert(r.second); // was inserted + assert(mv2.moved()); // was moved from + assert(r.first->first == 5); // key + assert(r.first->second.get() == 5); // value + + Moveable mv3(-1, 3.0); + r = m.try_emplace(117, std::move(mv2)); + assert(m.size() == 13); + assert(r.second); // was inserted + assert(mv2.moved()); // was moved from + assert(r.first->first == 117); // key + assert(r.first->second.get() == -1); // value + } + + { // pair try_emplace(key_type&& k, Args&&... args); + typedef std::map M; + typedef std::pair R; + M m; + R r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1)); + assert(m.size() == 10); + + Moveable mvkey1(2, 2.0); + Moveable mv1(4, 4.0); + r = m.try_emplace(std::move(mvkey1), std::move(mv1)); + assert(m.size() == 10); + assert(!r.second); // was not inserted + assert(!mv1.moved()); // was not moved from + assert(!mvkey1.moved()); // was not moved from + assert(r.first->first == mvkey1); // key + + Moveable mvkey2(3, 3.0); + r = m.try_emplace(std::move(mvkey2), std::move(mv1)); + assert(m.size() == 11); + assert(r.second); // was inserted + assert(mv1.moved()); // was moved from + assert(mvkey2.moved()); // was moved from + assert(r.first->first.get() == 3); // key + assert(r.first->second.get() == 4); // value + } + + { // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + typedef std::map M; + M m; + M::iterator r; + for ( int i = 0; i < 20; i += 2 ) + m.try_emplace ( i, Moveable(i, (double) i)); + assert(m.size() == 10); + M::const_iterator it = m.find(2); + + Moveable mv1(3, 3.0); + for (int i=0; i < 20; i += 2) + { + r = m.try_emplace(it, i, std::move(mv1)); + assert(m.size() == 10); + assert(!mv1.moved()); // was not moved from + assert(r->first == i); // key + assert(r->second.get() == i); // value + } + + r = m.try_emplace(it, 3, std::move(mv1)); + assert(m.size() == 11); + assert(mv1.moved()); // was moved from + assert(r->first == 3); // key + assert(r->second.get() == 3); // value + } + + { // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + typedef std::map M; + M m; + M::iterator r; + for ( int i = 0; i < 20; i += 2 ) + m.emplace ( Moveable(i, (double) i), Moveable(i+1, (double) i+1)); + assert(m.size() == 10); + M::const_iterator it = std::next(m.cbegin()); + + Moveable mvkey1(2, 2.0); + Moveable mv1(4, 4.0); + r = m.try_emplace(it, std::move(mvkey1), std::move(mv1)); + assert(m.size() == 10); + assert(!mv1.moved()); // was not moved from + assert(!mvkey1.moved()); // was not moved from + assert(r->first == mvkey1); // key + + Moveable mvkey2(3, 3.0); + r = m.try_emplace(it, std::move(mvkey2), std::move(mv1)); + assert(m.size() == 11); + assert(mv1.moved()); // was moved from + assert(mvkey2.moved()); // was moved from + assert(r->first.get() == 3); // key + assert(r->second.get() == 4); // value + } + +#endif // _LIBCPP_HAS_NO_VARIADICS +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +}