From: Ville Voutilainen Date: Sat, 8 Aug 2015 22:57:13 +0000 (+0300) Subject: Implement N4279, Improved insertion interface for unique-key maps. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b95170d38038bec337dd5f7a09eb0ebc6f8f3a42;p=gcc.git Implement N4279, Improved insertion interface for unique-key maps. 2015-08-09 Ville Voutilainen 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. From-SVN: r226743 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fc8b2b8a153..cc875a46ee5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,19 @@ +2015-08-09 Ville Voutilainen + + 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 Implement N4089 Safe conversions in unique_ptr (LWG 2118) diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index 6e9fdcc2a4a..68ab6da51f5 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -591,7 +591,123 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER 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 + pair + 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 + pair + 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 + 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 + 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. @@ -688,6 +804,122 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER 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 + pair + 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 + pair + 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 + 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 + 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. diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h index 3030e1ed024..6132aaf480a 100644 --- a/libstdc++-v3/include/bits/stl_tree.h +++ b/libstdc++-v3/include/bits/stl_tree.h @@ -731,7 +731,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - private: pair<_Base_ptr, _Base_ptr> _M_get_insert_unique_pos(const key_type& __k); @@ -746,6 +745,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_get_insert_hint_equal_pos(const_iterator __pos, const key_type& __k); + private: #if __cplusplus >= 201103L template iterator diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index d44efb5f1c3..15d4b8bfeee 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -410,6 +410,122 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER 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 + pair + 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 + pair + 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 + 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 + 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. @@ -499,6 +615,124 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER insert(initializer_list __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 + pair + 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 + pair + 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 + 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 + 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. diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert_or_assign/1.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert_or_assign/1.cc new file mode 100644 index 00000000000..56e4ce08106 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert_or_assign/1.cc @@ -0,0 +1,299 @@ +// { 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 +// . + +#include +#include +#include + + +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 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 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 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 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 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 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 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 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; +} diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/try_emplace/1.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/try_emplace/1.cc new file mode 100644 index 00000000000..c8c777bb85f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/try_emplace/1.cc @@ -0,0 +1,291 @@ +// { 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 +// . + +#include +#include +#include + + +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 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 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 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 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 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 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 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 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; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/insert_or_assign.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/insert_or_assign.cc new file mode 100644 index 00000000000..efb9fba52e2 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/insert_or_assign.cc @@ -0,0 +1,315 @@ +// { 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 +// . + +#include +#include +#include + + +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 + { + using result_type = size_t; + using argument_type = Val; + + size_t + operator()(const Val& t) const + noexcept + { + return hash{}(t.val); + } + }; +} + +void test01() +{ + typedef std::unordered_map 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 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 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 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 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 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 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 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; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/try_emplace.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/try_emplace.cc new file mode 100644 index 00000000000..82b01059a66 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/modifiers/try_emplace.cc @@ -0,0 +1,308 @@ +// { 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 +// . + +#include +#include +#include +#include + + +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 + { + using result_type = size_t; + using argument_type = Val; + + size_t + operator()(const Val& t) const + noexcept + { + return hash{}(t.val); + } + }; +} + +void test01() +{ + typedef std::unordered_map 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 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 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 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 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 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 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 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; +}