+2015-08-09 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Implement N4279, Improved insertion interface for unique-key maps.
+ * include/bits/stl_map.h (try_emplace, insert_or_assign): New.
+ * include/bits/stl_tree.h (_M_get_insert_unique_pos,
+ _M_get_insert_equal_pos, _M_get_insert_hint_unique_pos,
+ _M_get_insert_hint_equal_pos): Make public.
+ * include/bits/unordered_map.h (try_emplace, insert_or_assign): New.
+ * testsuite/23_containers/map/modifiers/insert_or_assign/1.cc:
+ Likewise.
+ * testsuite/23_containers/map/modifiers/try_emplace/1.cc: Likewise.
+ * testsuite/23_containers/unordered_map/modifiers/insert_or_assign.cc:
+ Likewise.
+ * testsuite/23_containers/unordered_map/modifiers/try_emplace.cc:
+ Likewise.
+
2015-08-08 Ville Voutilainen <ville.voutilainen@gmail.com>
Implement N4089 Safe conversions in unique_ptr<T[]> (LWG 2118)
std::forward<_Args>(__args)...);
}
#endif
+#if __cplusplus > 201402L
+ /**
+ * @brief Attempts to build and insert a std::pair into the %map.
+ *
+ * @param __k Key to use for finding a possibly existing pair in
+ * the map.
+ * @param __args Arguments used to generate the .second for a new pair
+ * instance.
+ *
+ * @return A pair, of which the first element is an iterator that points
+ * to the possibly inserted pair, and the second is a bool that
+ * is true if the pair was actually inserted.
+ *
+ * This function attempts to build and insert a (key, value) %pair into
+ * the %map.
+ * A %map relies on unique keys and thus a %pair is only inserted if its
+ * first element (the key) is not already present in the %map.
+ * If a %pair is not inserted, this function has no effect.
+ *
+ * Insertion requires logarithmic time.
+ */
+ template <typename... _Args>
+ pair<iterator, bool>
+ try_emplace(const key_type& __k, _Args&&... __args)
+ {
+ iterator __i = lower_bound(__k);
+ if (__i == end() || key_comp()(__k, (*__i).first))
+ {
+ __i = emplace_hint(__i, std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ return {__i, true};
+ }
+ return {__i, false};
+ }
+
+ // move-capable overload
+ template <typename... _Args>
+ pair<iterator, bool>
+ try_emplace(key_type&& __k, _Args&&... __args)
+ {
+ iterator __i = lower_bound(__k);
+ if (__i == end() || key_comp()(__k, (*__i).first))
+ {
+ __i = emplace_hint(__i, std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ return {__i, true};
+ }
+ return {__i, false};
+ }
+ /**
+ * @brief Attempts to build and insert a std::pair into the %map.
+ *
+ * @param __hint An iterator that serves as a hint as to where the
+ * pair should be inserted.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the map.
+ * @param __args Arguments used to generate the .second for a new pair
+ * instance.
+ * @return An iterator that points to the element with key of the
+ * std::pair built from @a __args (may or may not be that
+ * std::pair).
+ *
+ * This function is not concerned about whether the insertion took place,
+ * and thus does not return a boolean like the single-argument
+ * try_emplace() does. However, if insertion did not take place,
+ * this function has no effect.
+ * Note that the first parameter is only a hint and can potentially
+ * improve the performance of the insertion process. A bad hint would
+ * cause no gains in efficiency.
+ *
+ * See
+ * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
+ * for more on @a hinting.
+ *
+ * Insertion requires logarithmic time (if the hint is not taken).
+ */
+ template <typename... _Args>
+ iterator
+ try_emplace(const_iterator __hint, const key_type& __k,
+ _Args&&... __args)
+ {
+ iterator __i;
+ auto __true_hint = _M_t._M_get_insert_hint_unique_pos(__hint, __k);
+ if (__true_hint.second)
+ __i = emplace_hint(iterator(__true_hint.second),
+ std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ else
+ __i = iterator(__true_hint.first);
+ return __i;
+ }
+
+ // move-capable overload
+ template <typename... _Args>
+ iterator
+ try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
+ {
+ iterator __i;
+ auto __true_hint = _M_t._M_get_insert_hint_unique_pos(__hint, __k);
+ if (__true_hint.second)
+ __i = emplace_hint(iterator(__true_hint.second),
+ std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ else
+ __i = iterator(__true_hint.first);
+ return __i;
+ }
+#endif
/**
* @brief Attempts to insert a std::pair into the %map.
insert(_InputIterator __first, _InputIterator __last)
{ _M_t._M_insert_unique(__first, __last); }
+#if __cplusplus > 201402L
+ /**
+ * @brief Attempts to insert or assign a std::pair into the %map.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the map.
+ * @param __obj Argument used to generate the .second for a pair
+ * instance.
+ *
+ * @return A pair, of which the first element is an iterator that
+ * points to the possibly inserted pair, and the second is
+ * a bool that is true if the pair was actually inserted.
+ *
+ * This function attempts to insert a (key, value) %pair into the %map.
+ * A %map relies on unique keys and thus a %pair is only inserted if its
+ * first element (the key) is not already present in the %map.
+ * If the %pair was already in the %map, the .second of the %pair
+ * is assigned from __obj.
+ *
+ * Insertion requires logarithmic time.
+ */
+ template <typename _Obj>
+ pair<iterator, bool>
+ insert_or_assign(const key_type& __k, _Obj&& __obj)
+ {
+ iterator __i = lower_bound(__k);
+ if (__i == end() || key_comp()(__k, (*__i).first))
+ {
+ __i = emplace_hint(__i, std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ return {__i, true};
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return {__i, false};
+ }
+
+ // move-capable overload
+ template <typename _Obj>
+ pair<iterator, bool>
+ insert_or_assign(key_type&& __k, _Obj&& __obj)
+ {
+ iterator __i = lower_bound(__k);
+ if (__i == end() || key_comp()(__k, (*__i).first))
+ {
+ __i = emplace_hint(__i, std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ return {__i, true};
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return {__i, false};
+ }
+
+ /**
+ * @brief Attempts to insert or assign a std::pair into the %map.
+ * @param __hint An iterator that serves as a hint as to where the
+ * pair should be inserted.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the map.
+ * @param __obj Argument used to generate the .second for a pair
+ * instance.
+ *
+ * @return An iterator that points to the element with key of
+ * @a __x (may or may not be the %pair passed in).
+ *
+ * This function attempts to insert a (key, value) %pair into the %map.
+ * A %map relies on unique keys and thus a %pair is only inserted if its
+ * first element (the key) is not already present in the %map.
+ * If the %pair was already in the %map, the .second of the %pair
+ * is assigned from __obj.
+ *
+ * Insertion requires logarithmic time.
+ */
+ template <typename _Obj>
+ iterator
+ insert_or_assign(const_iterator __hint,
+ const key_type& __k, _Obj&& __obj)
+ {
+ iterator __i;
+ auto __true_hint = _M_t._M_get_insert_hint_unique_pos(__hint, __k);
+ if (__true_hint.second)
+ {
+ return emplace_hint(iterator(__true_hint.second),
+ std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ }
+ __i = iterator(__true_hint.first);
+ (*__i).second = std::forward<_Obj>(__obj);
+ return __i;
+ }
+
+ // move-capable overload
+ template <typename _Obj>
+ iterator
+ insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
+ {
+ iterator __i;
+ auto __true_hint = _M_t._M_get_insert_hint_unique_pos(__hint, __k);
+ if (__true_hint.second)
+ {
+ return emplace_hint(iterator(__true_hint.second),
+ std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ }
+ __i = iterator(__true_hint.first);
+ (*__i).second = std::forward<_Obj>(__obj);
+ return __i;
+ }
+#endif
+
#if __cplusplus >= 201103L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 130. Associative erase should return an iterator.
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- private:
pair<_Base_ptr, _Base_ptr>
_M_get_insert_unique_pos(const key_type& __k);
_M_get_insert_hint_equal_pos(const_iterator __pos,
const key_type& __k);
+ private:
#if __cplusplus >= 201103L
template<typename _Arg, typename _NodeGen>
iterator
emplace_hint(const_iterator __pos, _Args&&... __args)
{ return _M_h.emplace_hint(__pos, std::forward<_Args>(__args)...); }
+
+#if __cplusplus > 201402L
+ /**
+ * @brief Attempts to build and insert a std::pair into the
+ * %unordered_map.
+ *
+ * @param __k Key to use for finding a possibly existing pair in
+ * the unordered_map.
+ * @param __args Arguments used to generate the .second for a
+ * new pair instance.
+ *
+ * @return A pair, of which the first element is an iterator that points
+ * to the possibly inserted pair, and the second is a bool that
+ * is true if the pair was actually inserted.
+ *
+ * This function attempts to build and insert a (key, value) %pair into
+ * the %unordered_map.
+ * An %unordered_map relies on unique keys and thus a %pair is only
+ * inserted if its first element (the key) is not already present in the
+ * %unordered_map.
+ * If a %pair is not inserted, this function has no effect.
+ *
+ * Insertion requires amortized constant time.
+ */
+ template <typename... _Args>
+ pair<iterator, bool>
+ try_emplace(const key_type& __k, _Args&&... __args)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ __i = emplace(std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...))
+ .first;
+ return {__i, true};
+ }
+ return {__i, false};
+ }
+
+ // move-capable overload
+ template <typename... _Args>
+ pair<iterator, bool>
+ try_emplace(key_type&& __k, _Args&&... __args)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ __i = emplace(std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...))
+ .first;
+ return {__i, true};
+ }
+ return {__i, false};
+ }
+
+ /**
+ * @brief Attempts to build and insert a std::pair into the
+ * %unordered_map.
+ *
+ * @param __hint An iterator that serves as a hint as to where the pair
+ * should be inserted.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the unordered_map.
+ * @param __args Arguments used to generate the .second for a
+ * new pair instance.
+ * @return An iterator that points to the element with key of the
+ * std::pair built from @a __args (may or may not be that
+ * std::pair).
+ *
+ * This function is not concerned about whether the insertion took place,
+ * and thus does not return a boolean like the single-argument emplace()
+ * does. However, if insertion did not take place,
+ * this function has no effect.
+ * Note that the first parameter is only a hint and can potentially
+ * improve the performance of the insertion process. A bad hint would
+ * cause no gains in efficiency.
+ *
+ * See
+ * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
+ * for more on @a hinting.
+ *
+ * Insertion requires amortized constant time.
+ */
+ template <typename... _Args>
+ iterator
+ try_emplace(const_iterator __hint, const key_type& __k,
+ _Args&&... __args)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ __i = emplace_hint(__hint, std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ return __i;
+ }
+
+ // move-capable overload
+ template <typename... _Args>
+ iterator
+ try_emplace(const_iterator __hint, key_type&& __k, _Args&&... __args)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ __i = emplace_hint(__hint, std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Args>(__args)...));
+ return __i;
+ }
+#endif
+
//@{
/**
* @brief Attempts to insert a std::pair into the %unordered_map.
insert(initializer_list<value_type> __l)
{ _M_h.insert(__l); }
+
+#if __cplusplus > 201402L
+ /**
+ * @brief Attempts to insert a std::pair into the %unordered_map.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the map.
+ * @param __obj Argument used to generate the .second for a pair
+ * instance.
+ *
+ * @return A pair, of which the first element is an iterator that
+ * points to the possibly inserted pair, and the second is
+ * a bool that is true if the pair was actually inserted.
+ *
+ * This function attempts to insert a (key, value) %pair into the
+ * %unordered_map. An %unordered_map relies on unique keys and thus a
+ * %pair is only inserted if its first element (the key) is not already
+ * present in the %unordered_map.
+ * If the %pair was already in the %unordered_map, the .second of
+ * the %pair is assigned from __obj.
+ *
+ * Insertion requires amortized constant time.
+ */
+ template <typename _Obj>
+ pair<iterator, bool>
+ insert_or_assign(const key_type& __k, _Obj&& __obj)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ __i = emplace(std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(std::forward<_Obj>(__obj)))
+ .first;
+ return {__i, true};
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return {__i, false};
+ }
+
+ // move-capable overload
+ template <typename _Obj>
+ pair<iterator, bool>
+ insert_or_assign(key_type&& __k, _Obj&& __obj)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ __i = emplace(std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(std::forward<_Obj>(__obj)))
+ .first;
+ return {__i, true};
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return {__i, false};
+ }
+
+ /**
+ * @brief Attempts to insert a std::pair into the %unordered_map.
+ * @param __hint An iterator that serves as a hint as to where the
+ * pair should be inserted.
+ * @param __k Key to use for finding a possibly existing pair in
+ * the unordered_map.
+ * @param __obj Argument used to generate the .second for a pair
+ * instance.
+ * @return An iterator that points to the element with key of
+ * @a __x (may or may not be the %pair passed in).
+ *
+ * This function is not concerned about whether the insertion took place,
+ * and thus does not return a boolean like the single-argument insert()
+ * does.
+ * If the %pair was already in the %unordered map, the .second of
+ * the %pair is assigned from __obj.
+ * Note that the first parameter is only a hint and can
+ * potentially improve the performance of the insertion process. A bad
+ * hint would cause no gains in efficiency.
+ *
+ * See
+ * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
+ * for more on @a hinting.
+ *
+ * Insertion requires amortized constant time.
+ */
+ template <typename _Obj>
+ iterator
+ insert_or_assign(const_iterator __hint, const key_type& __k,
+ _Obj&& __obj)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ return emplace_hint(__hint, std::piecewise_construct,
+ std::forward_as_tuple(__k),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return __i;
+ }
+
+ // move-capable overload
+ template <typename _Obj>
+ iterator
+ insert_or_assign(const_iterator __hint, key_type&& __k, _Obj&& __obj)
+ {
+ iterator __i = find(__k);
+ if (__i == end())
+ {
+ return emplace_hint(__hint, std::piecewise_construct,
+ std::forward_as_tuple(std::move(__k)),
+ std::forward_as_tuple(
+ std::forward<_Obj>(__obj)));
+ }
+ (*__i).second = std::forward<_Obj>(__obj);
+ return __i;
+ }
+#endif
+
//@{
/**
* @brief Erases an element from an %unordered_map.
--- /dev/null
+// { dg-options "-std=gnu++17" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+#include <map>
+#include <testsuite_hooks.h>
+
+
+bool test __attribute__((unused)) = true;
+
+struct Val
+{
+ bool moved_from_ctor = false;
+ bool moved_from_assign = false;
+ int val;
+ Val(int val = 0) : val(val) {}
+ Val(const Val& other) : val(other.val)
+ {
+ }
+ Val(Val&& other) : val(other.val)
+ {
+ other.moved_from_ctor = true;
+ }
+ Val& operator=(Val&& other)
+ {
+ val = other.val;
+ other.moved_from_assign = true;
+ }
+ Val& operator=(const Val& other)
+ {
+ val = other.val;
+ }
+};
+
+bool operator<(const Val& a, const Val& b)
+{
+ return a.val < b.val;
+}
+
+void test01()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(0, std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(1, std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test02()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), 0, std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(m.begin(), 1, std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test03()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(std::move(k1), std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(std::move(k2), std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test04()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), std::move(k1), std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(m.begin(), std::move(k2), std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test05()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(0, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.insert_or_assign(1, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test06()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), 0, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.insert_or_assign(m.begin(), 1, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test07()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(k1, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.insert_or_assign(k2, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test08()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), k1, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.insert_or_assign(m.begin(), k2, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ return 0;
+}
--- /dev/null
+// { dg-options "-std=gnu++17" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+#include <map>
+#include <testsuite_hooks.h>
+
+
+bool test __attribute__((unused)) = true;
+
+struct Val
+{
+ bool moved_from_ctor = false;
+ bool moved_from_assign = false;
+ int val;
+ Val(int val = 0) : val(val) {}
+ Val(const Val& other) : val(other.val)
+ {
+ }
+ Val(Val&& other) : val(other.val)
+ {
+ other.moved_from_ctor = true;
+ }
+ Val& operator=(Val&& other)
+ {
+ val = other.val;
+ other.moved_from_assign = true;
+ }
+};
+
+bool operator<(const Val& a, const Val& b)
+{
+ return a.val < b.val;
+}
+
+void test01()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(0, std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(1, std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test02()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), 0, std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(m.begin(), 1, std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test03()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(std::move(k1), std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(std::move(k2), std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test04()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), std::move(k1), std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(m.begin(), std::move(k2), std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test05()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(0, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(1, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test06()
+{
+ typedef std::map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), 0, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(m.begin(), 1, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test07()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(k1, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(k2, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test08()
+{
+ typedef std::map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), k1, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(m.begin(), k2, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ return 0;
+}
--- /dev/null
+// { dg-options "-std=gnu++17" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+
+bool test __attribute__((unused)) = true;
+
+struct Val
+{
+ bool moved_from_ctor = false;
+ bool moved_from_assign = false;
+ int val;
+ Val(int val = 0) : val(val) {}
+ Val(const Val& other) : val(other.val)
+ {
+ }
+ Val(Val&& other) : val(other.val)
+ {
+ other.moved_from_ctor = true;
+ }
+ Val& operator=(Val&& other)
+ {
+ val = other.val;
+ other.moved_from_assign = true;
+ }
+ Val& operator=(const Val& other)
+ {
+ val = other.val;
+ }
+};
+
+bool operator==(const Val& a, const Val& b)
+{
+ return a.val == b.val;
+}
+
+namespace std
+{
+ template <> struct hash<Val>
+ {
+ using result_type = size_t;
+ using argument_type = Val;
+
+ size_t
+ operator()(const Val& t) const
+ noexcept
+ {
+ return hash<int>{}(t.val);
+ }
+ };
+}
+
+void test01()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(0, std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(1, std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test02()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), 0, std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(m.begin(), 1, std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test03()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(std::move(k1), std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(std::move(k2), std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test04()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), std::move(k1), std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ v1.moved_from_assign = false;
+ auto res3 = m.insert_or_assign(m.begin(), std::move(k2), std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test05()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(0, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.insert_or_assign(1, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test06()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), 0, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.insert_or_assign(m.begin(), 1, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test07()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(k1, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.insert_or_assign(k2, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test08()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.insert_or_assign(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.insert_or_assign(m.begin(), k1, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 6);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.insert_or_assign(m.begin(), k2, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 6);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ return 0;
+}
--- /dev/null
+// { dg-options "-std=gnu++17" }
+
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <utility>
+#include <unordered_map>
+#include <functional>
+#include <testsuite_hooks.h>
+
+
+bool test __attribute__((unused)) = true;
+
+struct Val
+{
+ bool moved_from_ctor = false;
+ bool moved_from_assign = false;
+ int val;
+ Val(int val = 0) : val(val) {}
+ Val(const Val& other) : val(other.val)
+ {
+ }
+ Val(Val&& other) : val(other.val)
+ {
+ other.moved_from_ctor = true;
+ }
+ Val& operator=(Val&& other)
+ {
+ val = other.val;
+ other.moved_from_assign = true;
+ }
+};
+
+bool operator==(const Val& a, const Val& b)
+{
+ return a.val == b.val;
+}
+
+namespace std
+{
+ template <> struct hash<Val>
+ {
+ using result_type = size_t;
+ using argument_type = Val;
+
+ size_t
+ operator()(const Val& t) const
+ noexcept
+ {
+ return hash<int>{}(t.val);
+ }
+ };
+}
+
+void test01()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(0, std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(1, std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test02()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), 0, std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(m.begin(), 1, std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test03()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(std::move(k1), std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(std::move(k2), std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test04()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), std::move(k1), std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(m.begin(), std::move(k2), std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test05()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(0, std::move(v1));
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(1, std::move(v1));
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test06()
+{
+ typedef std::unordered_map<int, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), 0, std::move(v1));
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ auto res3 = m.try_emplace(m.begin(), 1, std::move(v1));
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test07()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(0, Val(5));
+ VERIFY(res1.second);
+ VERIFY(res1.first != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(k1, v1);
+ VERIFY(!res2.second);
+ VERIFY(res2.first == res1.first);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(k2, v1);
+ VERIFY(res3.first != res1.first && res3.first != m.end());
+ VERIFY(res3.second);
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+void test08()
+{
+ typedef std::unordered_map<Val, Val> Map;
+ Map m;
+ auto res1 = m.try_emplace(m.begin(), 0, Val(5));
+ VERIFY(res1 != m.end());
+ VERIFY(m[0].val == 5);
+ Val k1{0};
+ Val v1{6};
+ VERIFY(m.size() == 1);
+ auto res2 = m.try_emplace(m.begin(), k1, v1);
+ VERIFY(res2 == res1);
+ VERIFY(m[0].val == 5);
+ VERIFY(!k1.moved_from_ctor);
+ VERIFY(!k1.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 1);
+ Val k2{1};
+ auto res3 = m.try_emplace(m.begin(), k2, v1);
+ VERIFY(res3 != res1 && res3 != m.end());
+ VERIFY(m[0].val == 5);
+ VERIFY(m[1].val == 6);
+ VERIFY(!k2.moved_from_ctor);
+ VERIFY(!k2.moved_from_assign);
+ VERIFY(!v1.moved_from_ctor);
+ VERIFY(!v1.moved_from_assign);
+ VERIFY(m.size() == 2);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ return 0;
+}