The rest of N4279 and LWG#2464 - for unordered_map

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@241555 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Marshall Clow 2015-07-07 05:45:35 +00:00
parent f3a1a187a1
commit 0ce05a9f86
4 changed files with 526 additions and 2 deletions

View File

@ -122,6 +122,23 @@ public:
void insert(InputIterator first, InputIterator last);
void insert(initializer_list<value_type>);
template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); // C++17
template <class... Args>
pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); // C++17
template <class... Args>
iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17
template <class... Args>
iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); // C++17
template <class M>
pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); // C++17
template <class M>
pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); // C++17
template <class M>
iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); // C++17
template <class M>
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);
@ -939,6 +956,120 @@ public:
{insert(__il.begin(), __il.end());}
#endif // _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
#if _LIBCPP_STD_VER > 14
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
pair<iterator, bool> try_emplace(const key_type& __k, _Args&&... __args)
{
iterator __p = __table_.find(__k);
if ( __p != end())
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 <class... _Args>
_LIBCPP_INLINE_VISIBILITY
pair<iterator, bool> try_emplace(key_type&& __k, _Args&&... __args)
{
iterator __p = __table_.find(__k);
if ( __p != end())
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 <class... _Args>
_LIBCPP_INLINE_VISIBILITY
iterator try_emplace(const_iterator __h, const key_type& __k, _Args&&... __args)
{
iterator __p = __table_.find(__k);
if ( __p != end())
return __p;
else
return emplace_hint(__h,
_VSTD::piecewise_construct, _VSTD::forward_as_tuple(__k),
_VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...));
}
template <class... _Args>
_LIBCPP_INLINE_VISIBILITY
iterator try_emplace(const_iterator __h, key_type&& __k, _Args&&... __args)
{
iterator __p = __table_.find(__k);
if ( __p != end())
return __p;
else
return emplace_hint(__h,
_VSTD::piecewise_construct, _VSTD::forward_as_tuple(_VSTD::move(__k)),
_VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...));
}
template <class _Vp>
_LIBCPP_INLINE_VISIBILITY
pair<iterator, bool> insert_or_assign(const key_type& __k, _Vp&& __v)
{
iterator __p = __table_.find(__k);
if ( __p != end())
{
__p->second = _VSTD::move(__v);
return _VSTD::make_pair(__p, false);
}
return _VSTD::make_pair(emplace_hint(__p, __k, _VSTD::forward<_Vp>(__v)), true);
}
template <class _Vp>
_LIBCPP_INLINE_VISIBILITY
pair<iterator, bool> insert_or_assign(key_type&& __k, _Vp&& __v)
{
iterator __p = __table_.find(__k);
if ( __p != end())
{
__p->second = _VSTD::move(__v);
return _VSTD::make_pair(__p, false);
}
return _VSTD::make_pair(emplace_hint(__p, _VSTD::forward<key_type>(__k), _VSTD::forward<_Vp>(__v)), true);
}
template <class _Vp>
_LIBCPP_INLINE_VISIBILITY
iterator insert_or_assign(const_iterator __h, const key_type& __k, _Vp&& __v)
{
iterator __p = __table_.find(__k);
if ( __p != end())
{
__p->second = _VSTD::move(__v);
return __p;
}
return emplace_hint(__h, __k, _VSTD::forward<_Vp>(__v));
}
template <class _Vp>
_LIBCPP_INLINE_VISIBILITY
iterator insert_or_assign(const_iterator __h, key_type&& __k, _Vp&& __v)
{
iterator __p = __table_.find(__k);
if ( __p != end())
{
__p->second = _VSTD::move(__v);
return __p;
}
return emplace_hint(__h, _VSTD::forward<key_type>(__k), _VSTD::forward<_Vp>(__v));
}
#endif
#endif
#endif
_LIBCPP_INLINE_VISIBILITY
iterator erase(const_iterator __p) {return __table_.erase(__p.__i_);}
_LIBCPP_INLINE_VISIBILITY

View File

@ -0,0 +1,198 @@
//===----------------------------------------------------------------------===//
//
// 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
// <unordered_map>
// class unordered_map
// template <class M>
// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); // C++17
// template <class M>
// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); // C++17
// template <class M>
// iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); // C++17
// template <class M>
// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); // C++17
#include <__config>
#include <unordered_map>
#include <cassert>
#include <tuple>
#include <iostream>
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_);}
size_t hash () const { return std::hash<int>()(int_) + std::hash<double>()(double_); }
int get() const {return int_;}
bool moved() const {return int_ == -1;}
};
namespace std {
template <> struct hash<Moveable> {
size_t operator () (const Moveable &m) const { return m.hash(); }
};
}
int main()
{
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#ifndef _LIBCPP_HAS_NO_VARIADICS
{ // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
typedef std::unordered_map<int, Moveable> M;
typedef std::pair<M::iterator, bool> 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<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
typedef std::unordered_map<Moveable, Moveable> M;
typedef std::pair<M::iterator, bool> 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::unordered_map<int, Moveable> 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::unordered_map<Moveable, Moveable> 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
}

View File

@ -0,0 +1,195 @@
//===----------------------------------------------------------------------===//
//
// 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
// <unordered_map>
// class unordered_map
// template <class... Args>
// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); // C++17
// template <class... Args>
// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); // C++17
// template <class... Args>
// iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17
// template <class... Args>
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); // C++17
#include <__config>
#include <unordered_map>
#include <cassert>
#include <tuple>
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_);}
size_t hash () const { return std::hash<int>()(int_) + std::hash<double>()(double_); }
int get() const {return int_;}
bool moved() const {return int_ == -1;}
};
namespace std {
template <> struct hash<Moveable> {
size_t operator () (const Moveable &m) const { return m.hash(); }
};
}
int main()
{
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
#ifndef _LIBCPP_HAS_NO_VARIADICS
{ // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
typedef std::unordered_map<int, Moveable> M;
typedef std::pair<M::iterator, bool> 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<iterator, bool> try_emplace(key_type&& k, Args&&... args);
typedef std::unordered_map<Moveable, Moveable> M;
typedef std::pair<M::iterator, bool> 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::unordered_map<int, Moveable> 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::unordered_map<Moveable, Moveable> 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
}

View File

@ -59,7 +59,7 @@
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4258">N4258</a></td><td>LWG</td></td><td>Cleaning-up noexcept in the Library.</td><td>Urbana</td><td>In progress</td><td>3.7</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4259">N4259</a></td><td>CWG</td></td><td>Wording for std::uncaught_exceptions</td><td>Urbana</td><td>Complete</td><td>3.7</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4277">N4277</a></td><td>LWG</td></td><td>TriviallyCopyable <code>reference_wrapper</code>.</td><td>Urbana</td><td>Complete</td><td>3.2</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4279">N4279</a></td><td>LWG</td></td><td>Improved insertion interface for unique-key maps.</td><td>Urbana</td><td>In Progress</td><td>3.7</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4279">N4279</a></td><td>LWG</td></td><td>Improved insertion interface for unique-key maps.</td><td>Urbana</td><td>Complete</td><td>3.7</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4280">N4280</a></td><td>LWG</td></td><td>Non-member size() and more</td><td>Urbana</td><td>Complete</td><td>3.6</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284">N4284</a></td><td>LWG</td></td><td>Contiguous Iterators.</td><td>Urbana</td><td>Complete</td><td>3.6</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4285">N4285</a></td><td>CWG</td></td><td>Cleanup for exception-specification and throw-expression.</td><td>Urbana</td><td></td><td></td></tr>
@ -133,7 +133,7 @@
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2455">2455</td><td>Allocator default construction should be allowed to throw</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2458">2458</td><td>N3778 and new library deallocation signatures</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2459">2459</td><td>std::polar should require a non-negative rho</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2464">2464</td><td>try_emplace and insert_or_assign misspecified</td><td>Lenexa</td><td></td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2464">2464</td><td>try_emplace and insert_or_assign misspecified</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2467">2467</td><td>is_always_equal has slightly inconsistent default</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2470">2470</td><td>Allocator's destroy function should be allowed to fail to instantiate</td><td>Lenexa</td><td>Complete</td></tr>
<tr><td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2482">2482</td><td>[c.strings] Table 73 mentions nonexistent functions</td><td>Lenexa</td><td>Complete</td></tr>