libstdc++: [_GLIBCXX_DEBUG] Implement unordered container merge

The _GLIBCXX_DEBUG unordered containers need a dedicated merge implementation
so that any existing iterator on the transfered nodes is properly invalidated.

Add typedef/using declarations for everything used as-is from normal implementation.

libstdc++-v3/ChangeLog:

	* include/bits/hashtable_policy.h (__distance_fw): Replace class keyword with
	typename.
	* include/bits/hashtable.h (_Hashtable<>::_M_merge_unique): Remove noexcept
	qualification. Use const_iterator for node extraction/reinsert.
	(_Hashtable<>::_M_merge_multi): Likewise. Compute new hash code before extract.
	* include/debug/safe_container.h (_Safe_container<>): Make all methods
	protected.
	* include/debug/safe_unordered_container.h
	(_Safe_unordered_container<>::_UContInvalidatePred<_ExtractKey, _Source>): New.
	(_Safe_unordered_container<>::_UMContInvalidatePred<_ExtractKey, _Source>): New.
	(_Safe_unordered_container<>::_UContMergeGuard<_Source, _InvalidatePred>): New.
	(_Safe_unordered_container<>::_S_uc_guard<_ExtractKey, _Source>): New.
	(_Safe_unordered_container<>::_S_umc_guard<_ExtractKey, _Source>): New.
	(_Safe_unordered_container<>::_M_invalide_all): Make public.
	(_Safe_unordered_container<>::_M_invalide_if): Likewise.
	(_Safe_unordered_container<>::_M_invalide_local_if): Likewise.
	* include/debug/unordered_map
	(unordered_map<>::mapped_type, pointer, const_pointer): New typedef.
	(unordered_map<>::reference, const_reference, difference_type): New typedef.
	(unordered_map<>::get_allocator, empty, size, max_size): Add usings.
	(unordered_map<>::bucket_count, max_bucket_count, bucket): Add usings.
	(unordered_map<>::hash_function, key_equal, count, contains): Add usings.
	(unordered_map<>::operator[], at, rehash, reserve): Add usings.
	(unordered_map<>::merge): New.
	(unordered_multimap<>::mapped_type, pointer, const_pointer): New typedef.
	(unordered_multimap<>::reference, const_reference, difference_type): New typedef.
	(unordered_multimap<>::get_allocator, empty, size, max_size): Add usings.
	(unordered_multimap<>::bucket_count, max_bucket_count, bucket): Add usings.
	(unordered_multimap<>::hash_function, key_equal, count, contains): Add usings.
	(unordered_multimap<>::rehash, reserve): Add usings.
	(unordered_multimap<>::merge): New.
	* include/debug/unordered_set
	(unordered_set<>::mapped_type, pointer, const_pointer): New typedef.
	(unordered_set<>::reference, const_reference, difference_type): New typedef.
	(unordered_set<>::get_allocator, empty, size, max_size): Add usings.
	(unordered_set<>::bucket_count, max_bucket_count, bucket): Add usings.
	(unordered_set<>::hash_function, key_equal, count, contains): Add usings.
	(unordered_set<>::rehash, reserve): Add usings.
	(unordered_set<>::merge): New.
	(unordered_multiset<>::mapped_type, pointer, const_pointer): New typedef.
	(unordered_multiset<>::reference, const_reference, difference_type): New typedef.
	(unordered_multiset<>::get_allocator, empty, size, max_size): Add usings.
	(unordered_multiset<>::bucket_count, max_bucket_count, bucket): Add usings.
	(unordered_multiset<>::hash_function, key_equal, count, contains): Add usings.
	(unordered_multiset<>::rehash, reserve): Add usings.
	(unordered_multiset<>::merge): New.
	* testsuite/23_containers/unordered_map/debug/merge1_neg.cc: New test.
	* testsuite/23_containers/unordered_map/debug/merge2_neg.cc: New test.
	* testsuite/23_containers/unordered_map/debug/merge3_neg.cc: New test.
	* testsuite/23_containers/unordered_map/debug/merge4_neg.cc: New test.
	* testsuite/23_containers/unordered_multimap/debug/merge1_neg.cc: New test.
	* testsuite/23_containers/unordered_multimap/debug/merge2_neg.cc: New test.
	* testsuite/23_containers/unordered_multimap/debug/merge3_neg.cc: New test.
	* testsuite/23_containers/unordered_multimap/debug/merge4_neg.cc: New test.
	* testsuite/23_containers/unordered_multiset/debug/merge1_neg.cc: New test.
	* testsuite/23_containers/unordered_multiset/debug/merge2_neg.cc: New test.
	* testsuite/23_containers/unordered_multiset/debug/merge3_neg.cc: New test.
	* testsuite/23_containers/unordered_multiset/debug/merge4_neg.cc: New test.
	* testsuite/23_containers/unordered_set/debug/merge1_neg.cc: New test.
	* testsuite/23_containers/unordered_set/debug/merge2_neg.cc: New test.
	* testsuite/23_containers/unordered_set/debug/merge3_neg.cc: New test.
	* testsuite/23_containers/unordered_set/debug/merge4_neg.cc: New test.
	* testsuite/util/testsuite_abi.h: [_GLIBCXX_DEBUG] Use normal unordered
	container implementation.
This commit is contained in:
François Dumont 2021-10-13 22:04:32 +02:00
parent f7844b6a77
commit f4b4ce152a
23 changed files with 845 additions and 13 deletions

View File

@ -1065,14 +1065,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Merge from a compatible container into one with unique keys.
template<typename _Compatible_Hashtable>
void
_M_merge_unique(_Compatible_Hashtable& __src) noexcept
_M_merge_unique(_Compatible_Hashtable& __src)
{
static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
node_type>, "Node types are compatible");
__glibcxx_assert(get_allocator() == __src.get_allocator());
auto __n_elt = __src.size();
for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
{
auto __pos = __i++;
const key_type& __k = _ExtractKey{}(*__pos);
@ -1093,15 +1093,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Merge from a compatible container into one with equivalent keys.
template<typename _Compatible_Hashtable>
void
_M_merge_multi(_Compatible_Hashtable& __src) noexcept
_M_merge_multi(_Compatible_Hashtable& __src)
{
static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
node_type>, "Node types are compatible");
__glibcxx_assert(get_allocator() == __src.get_allocator());
this->reserve(size() + __src.size());
for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
_M_reinsert_node_multi(cend(), __src.extract(__i++));
for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
{
auto __pos = __i++;
const key_type& __k = _ExtractKey{}(*__pos);
__hash_code __code = this->_M_hash_code(__k);
auto __nh = __src.extract(__pos);
_M_insert_multi_node(nullptr, __code, __nh._M_ptr);
__nh._M_ptr = nullptr;
}
}
#endif // C++17

View File

@ -60,19 +60,19 @@ namespace __detail
// Helper function: return distance(first, last) for forward
// iterators, or 0/1 for input iterators.
template<class _Iterator>
template<typename _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
__distance_fw(_Iterator __first, _Iterator __last,
std::input_iterator_tag)
{ return __first != __last ? 1 : 0; }
template<class _Iterator>
template<typename _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
__distance_fw(_Iterator __first, _Iterator __last,
std::forward_iterator_tag)
{ return std::distance(__first, __last); }
template<class _Iterator>
template<typename _Iterator>
inline typename std::iterator_traits<_Iterator>::difference_type
__distance_fw(_Iterator __first, _Iterator __last)
{ return __distance_fw(__first, __last,

View File

@ -78,7 +78,6 @@ namespace __gnu_debug
{ }
#endif
public:
// Copy assignment invalidate all iterators.
_Safe_container&
operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT

View File

@ -72,6 +72,96 @@ namespace __gnu_debug
{ return __it != __local_end; });
}
#if __cplusplus > 201402L
template<typename _ExtractKey, typename _Source>
struct _UContInvalidatePred
{
template<typename _Iterator>
bool
operator()(_Iterator __it) const
{ return _M_source.count(_ExtractKey{}(*__it)) == 0; }
const _Source& _M_source;
};
template<typename _ExtractKey, typename _Source>
struct _UMContInvalidatePred
{
template<typename _Iterator>
bool
operator()(_Iterator __it) const
{
auto __rng =
_M_source._M_base().equal_range(_ExtractKey{}(*__it));
for (auto __rit = __rng.first;
__rit != __rng.second; ++__rit)
{
if (__it == __rit)
return false;
}
return true;
}
const _Source& _M_source;
};
template<typename _Source, typename _InvalidatePred>
struct _UContMergeGuard
{
_UContMergeGuard(_Source& __src) noexcept
: _M_source(__src), _M_size(__src.size()), _M_pred { __src }
{ }
_UContMergeGuard(const _UContMergeGuard&) = delete;
~_UContMergeGuard()
{
const std::size_t __size = _M_source.size();
if (__size == _M_size)
return;
__try
{
if (__size == 0)
_M_source._M_invalidate_all();
else
{
_M_source._M_invalidate_if(_M_pred);
_M_source._M_invalidate_local_if(_M_pred);
}
}
__catch(...)
{
_M_source._M_invalidate_all();
}
}
_Source& _M_source;
const std::size_t _M_size;
_InvalidatePred _M_pred;
};
template<typename _ExtractKey, typename _Source>
static _UContMergeGuard<_Source,
_UContInvalidatePred<_ExtractKey, _Source>>
_S_uc_guard(_ExtractKey, _Source& __src)
{
typedef _UContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
return _UContMergeGuard<_Source, _InvalidatePred>(__src);
}
template<typename _ExtractKey, typename _Source>
static _UContMergeGuard<_Source,
_UMContInvalidatePred<_ExtractKey, _Source>>
_S_umc_guard(_ExtractKey, _Source& __src)
{
typedef _UMContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
return _UContMergeGuard<_Source, _InvalidatePred>(__src);
}
#endif // C++17
public:
void
_M_invalidate_all()
{

View File

@ -97,7 +97,12 @@ namespace __debug
typedef typename _Base::key_type key_type;
typedef typename _Base::value_type value_type;
typedef typename _Base::mapped_type mapped_type;
typedef typename _Base::pointer pointer;
typedef typename _Base::const_pointer const_pointer;
typedef typename _Base::reference reference;
typedef typename _Base::const_reference const_reference;
typedef __gnu_debug::_Safe_iterator<
_Base_iterator, unordered_map> iterator;
typedef __gnu_debug::_Safe_iterator<
@ -106,6 +111,7 @@ namespace __debug
_Base_local_iterator, unordered_map> local_iterator;
typedef __gnu_debug::_Safe_local_iterator<
_Base_const_local_iterator, unordered_map> const_local_iterator;
typedef typename _Base::difference_type difference_type;
unordered_map() = default;
@ -209,6 +215,11 @@ namespace __debug
return *this;
}
using _Base::get_allocator;
using _Base::empty;
using _Base::size;
using _Base::max_size;
void
swap(unordered_map& __x)
noexcept( noexcept(declval<_Base&>().swap(__x)) )
@ -291,6 +302,10 @@ namespace __debug
return { _Base::cend(__b), this };
}
using _Base::bucket_count;
using _Base::max_bucket_count;
using _Base::bucket;
size_type
bucket_size(size_type __b) const
{
@ -298,6 +313,8 @@ namespace __debug
return _Base::bucket_size(__b);
}
using _Base::load_factor;
float
max_load_factor() const noexcept
{ return _Base::max_load_factor(); }
@ -538,9 +555,38 @@ namespace __debug
return { _Base::insert(__hint.base(), std::move(__nh)), this };
}
using _Base::merge;
template<typename _H2, typename _P2>
void
merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_uc_guard(std::__detail::_Select1st{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
template<typename _H2, typename _P2>
void
merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_umc_guard(std::__detail::_Select1st{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
#endif // C++17
using _Base::hash_function;
using _Base::key_eq;
iterator
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
@ -567,6 +613,11 @@ namespace __debug
{ return { _Base::find(__k), this }; }
#endif
using _Base::count;
#if __cplusplus > 201703L
using _Base::contains;
#endif
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
@ -605,6 +656,9 @@ namespace __debug
}
#endif
using _Base::operator[];
using _Base::at;
size_type
erase(const key_type& __key)
{
@ -651,6 +705,9 @@ namespace __debug
return { __next, this };
}
using _Base::rehash;
using _Base::reserve;
_Base&
_M_base() noexcept { return *this; }
@ -843,7 +900,12 @@ namespace __debug
typedef typename _Base::key_type key_type;
typedef typename _Base::value_type value_type;
typedef typename _Base::mapped_type mapped_type;
typedef typename _Base::pointer pointer;
typedef typename _Base::const_pointer const_pointer;
typedef typename _Base::reference reference;
typedef typename _Base::const_reference const_reference;
typedef __gnu_debug::_Safe_iterator<
_Base_iterator, unordered_multimap> iterator;
typedef __gnu_debug::_Safe_iterator<
@ -852,6 +914,7 @@ namespace __debug
_Base_local_iterator, unordered_multimap> local_iterator;
typedef __gnu_debug::_Safe_local_iterator<
_Base_const_local_iterator, unordered_multimap> const_local_iterator;
typedef typename _Base::difference_type difference_type;
unordered_multimap() = default;
@ -952,6 +1015,11 @@ namespace __debug
return *this;
}
using _Base::get_allocator;
using _Base::empty;
using _Base::size;
using _Base::max_size;
void
swap(unordered_multimap& __x)
noexcept( noexcept(declval<_Base&>().swap(__x)) )
@ -1034,6 +1102,10 @@ namespace __debug
return { _Base::cend(__b), this };
}
using _Base::bucket_count;
using _Base::max_bucket_count;
using _Base::bucket;
size_type
bucket_size(size_type __b) const
{
@ -1192,9 +1264,38 @@ namespace __debug
return { _Base::insert(__hint.base(), std::move(__nh)), this };
}
using _Base::merge;
template<typename _H2, typename _P2>
void
merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_umc_guard(std::__detail::_Select1st{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_multimap<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
template<typename _H2, typename _P2>
void
merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_uc_guard(std::__detail::_Select1st{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_map<_Key, _Tp, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
#endif // C++17
using _Base::hash_function;
using _Base::key_eq;
iterator
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
@ -1221,6 +1322,11 @@ namespace __debug
{ return { _Base::find(__k), this }; }
#endif
using _Base::count;
#if __cplusplus > 201703L
using _Base::contains;
#endif
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
@ -1309,6 +1415,9 @@ namespace __debug
return { __next, this };
}
using _Base::rehash;
using _Base::reserve;
_Base&
_M_base() noexcept { return *this; }

View File

@ -88,6 +88,7 @@ namespace __debug
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::difference_type difference_type;
typedef typename _Base::hasher hasher;
typedef typename _Base::key_equal key_equal;
typedef typename _Base::allocator_type allocator_type;
@ -95,6 +96,10 @@ namespace __debug
typedef typename _Base::key_type key_type;
typedef typename _Base::value_type value_type;
typedef typename _Base::pointer pointer;
typedef typename _Base::const_pointer const_pointer;
typedef typename _Base::reference reference;
typedef typename _Base::const_reference const_reference;
typedef __gnu_debug::_Safe_iterator<
_Base_iterator, unordered_set> iterator;
typedef __gnu_debug::_Safe_iterator<
@ -203,6 +208,11 @@ namespace __debug
return *this;
}
using _Base::get_allocator;
using _Base::empty;
using _Base::size;
using _Base::max_size;
void
swap(unordered_set& __x)
noexcept( noexcept(declval<_Base&>().swap(__x)) )
@ -285,6 +295,9 @@ namespace __debug
return { _Base::cend(__b), this };
}
using _Base::bucket_count;
using _Base::max_bucket_count;
size_type
bucket_size(size_type __b) const
{
@ -292,6 +305,9 @@ namespace __debug
return _Base::bucket_size(__b);
}
using _Base::bucket;
using _Base::load_factor;
float
max_load_factor() const noexcept
{ return _Base::max_load_factor(); }
@ -303,6 +319,9 @@ namespace __debug
_Base::max_load_factor(__f);
}
using _Base::rehash;
using _Base::reserve;
template<typename... _Args>
std::pair<iterator, bool>
emplace(_Args&&... __args)
@ -423,9 +442,38 @@ namespace __debug
return { _Base::insert(__hint.base(), std::move(__nh)), this };
}
using _Base::merge;
template<typename _H2, typename _P2>
void
merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_uc_guard(std::__detail::_Identity{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
template<typename _H2, typename _P2>
void
merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_umc_guard(std::__detail::_Identity{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
#endif // C++17
using _Base::hash_function;
using _Base::key_eq;
iterator
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
@ -452,6 +500,12 @@ namespace __debug
{ return { _Base::find(__k), this }; }
#endif
using _Base::count;
#if __cplusplus > 201703L
using _Base::contains;
#endif
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
@ -707,6 +761,7 @@ namespace __debug
public:
typedef typename _Base::size_type size_type;
typedef typename _Base::difference_type difference_type;
typedef typename _Base::hasher hasher;
typedef typename _Base::key_equal key_equal;
typedef typename _Base::allocator_type allocator_type;
@ -714,6 +769,10 @@ namespace __debug
typedef typename _Base::key_type key_type;
typedef typename _Base::value_type value_type;
typedef typename _Base::pointer pointer;
typedef typename _Base::const_pointer const_pointer;
typedef typename _Base::reference reference;
typedef typename _Base::const_reference const_reference;
typedef __gnu_debug::_Safe_iterator<
_Base_iterator, unordered_multiset> iterator;
typedef __gnu_debug::_Safe_iterator<
@ -822,6 +881,11 @@ namespace __debug
return *this;
}
using _Base::get_allocator;
using _Base::empty;
using _Base::size;
using _Base::max_size;
void
swap(unordered_multiset& __x)
noexcept( noexcept(declval<_Base&>().swap(__x)) )
@ -904,6 +968,9 @@ namespace __debug
return { _Base::cend(__b), this };
}
using _Base::bucket_count;
using _Base::max_bucket_count;
size_type
bucket_size(size_type __b) const
{
@ -911,6 +978,9 @@ namespace __debug
return _Base::bucket_size(__b);
}
using _Base::bucket;
using _Base::load_factor;
float
max_load_factor() const noexcept
{ return _Base::max_load_factor(); }
@ -922,6 +992,9 @@ namespace __debug
_Base::max_load_factor(__f);
}
using _Base::rehash;
using _Base::reserve;
template<typename... _Args>
iterator
emplace(_Args&&... __args)
@ -1037,9 +1110,38 @@ namespace __debug
return { _Base::insert(__hint.base(), std::move(__nh)), this };
}
using _Base::merge;
template<typename _H2, typename _P2>
void
merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_umc_guard(std::__detail::_Identity{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
template<typename _H2, typename _P2>
void
merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source)
{
auto __guard
= _Safe::_S_uc_guard(std::__detail::_Identity{}, __source);
_Base::merge(__source._M_base());
}
template<typename _H2, typename _P2>
void
merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source)
{ merge(__source); }
#endif // C++17
using _Base::hash_function;
using _Base::key_eq;
iterator
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
@ -1066,6 +1168,12 @@ namespace __debug
{ return { _Base::find(__k), this }; }
#endif
using _Base::count;
#if __cplusplus > 201703L
using _Base::contains;
#endif
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{

View File

@ -0,0 +1,31 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_map<int, double>;
void
test01()
{
test_type c0{ { 1, 3.5 }, { 2, 5.5 }, { 3, 7.5 }, { 5, 11.5 }, { 6, 13.5 } };
test_type c1{ { 1, 3.5 }, { 2, 5.5 }, { 3, 7.5 }, { 4, 9.5 } };
auto it2 = c1.find(2);
auto it4 = c1.find(4);
VERIFY( it2->second == 5.5 );
VERIFY( it4->second == 9.5 );
c0.merge(c1);
VERIFY( it2->second == 5.5 );
VERIFY( it4 != it2 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,32 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_map<int, int>;
void
test01()
{
test_type c0{ { 1, 1 }, { 2, 2 }, { 3, 3 }, { 5, 5 }, { 6, 6 } };
test_type c1{ { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 } };
auto it2 = c1.find(2);
auto it4 = c1.find(4);
VERIFY( it2->second == 2 );
VERIFY( it4->second == 4 );
c0.merge(std::move(c1));
VERIFY( it2->second == 2 );
VERIFY( it2 != it4 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,42 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_map<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 2, 2 }, { 3, 3 },
{ 5, 5 }, { 6, 6 }, { 7, 7 }
};
std::unordered_multimap<int, int> c1
{
{ 1, 1 }, { 1, 1 }, { 2, 2 }, { 2, 2 },
{ 3, 3 }, { 3, 3 }, { 4, 4 }, { 4, 4 },
{ 5, 5 }
};
auto it1 = c1.find(1);
auto it41 = c1.find(4);
auto it42 = it41;
++it42;
VERIFY( it42->second == 4 );
c0.merge(c1);
VERIFY( it1->second == 1 );
VERIFY( c1.count(4) == 1 );
VERIFY( it41 != it42 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,42 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_map<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 2, 2 }, { 3, 3 },
{ 5, 5 }, { 6, 6 }, { 7, 7 }
};
std::unordered_multimap<int, int> c1
{
{ 1, 1 }, { 1, 1 }, { 2, 2 }, { 2, 2 },
{ 3, 3 }, { 3, 3 }, { 4, 4 }, { 4, 4 },
{ 5, 5 }
};
auto it1 = c1.find(1);
auto it41 = c1.find(4);
auto it42 = it41;
++it42;
VERIFY( it42->second == 4 );
c0.merge(std::move(c1));
VERIFY( it1->second == 1 );
VERIFY( c1.count(4) == 1 );
VERIFY( it41 != it42 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,32 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multimap<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 1, 1 }, { 2, 2 },
{ 2, 2 }, { 3, 3 }, { 3, 3 }
};
test_type c1 = c0;
auto it = c1.find(2);
VERIFY( it->second == 2 );
c0.merge(c1);
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,32 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multimap<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 1, 1 }, { 2, 2 },
{ 2, 2 }, { 3, 3 }, { 3, 3 }
};
test_type c1 = c0;
auto it = c1.find(2);
VERIFY( it->second == 2 );
c0.merge(std::move(c1));
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,32 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multimap<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 1, 1 }, { 2, 2 },
{ 2, 2 }, { 3, 3 }, { 3, 3 }
};
std::unordered_map<int, int> c1{ { 1, 1 }, { 2, 2 }, { 3, 3 } };
auto it = c1.find(2);
VERIFY( it->second == 2 );
c0.merge(c1);
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,32 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_map>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multimap<int, int>;
void
test01()
{
test_type c0
{
{ 1, 1 }, { 1, 1 }, { 2, 2 },
{ 2, 2 }, { 3, 3 }, { 3, 3 }
};
std::unordered_map<int, int> c1{ { 1, 1 }, { 2, 2 }, { 3, 3 } };
auto it = c1.find(2);
VERIFY( it->second == 2 );
c0.merge(std::move(c1));
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,28 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multiset<int>;
void
test01()
{
test_type c0{ 1, 1, 2, 2, 3, 3 };
test_type c1 = c0;
auto it = c1.find(2);
VERIFY( *it == 2 );
c0.merge(c1);
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,28 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multiset<int>;
void
test01()
{
test_type c0{ 1, 1, 2, 2, 3, 3 };
test_type c1 = c0;
auto it = c1.find(2);
VERIFY( *it == 2 );
c0.merge(std::move(c1));
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,28 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multiset<int>;
void
test01()
{
test_type c0{ 1, 1, 2, 2, 3, 3 };
std::unordered_set<int> c1{ 1, 2, 3 };
auto it = c1.find(2);
VERIFY( *it == 2 );
c0.merge(c1);
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,28 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_multiset<int>;
void
test01()
{
test_type c0{ 1, 1, 2, 2, 3, 3 };
std::unordered_set<int> c1{ 1, 2, 3 };
auto it = c1.find(2);
VERIFY( *it == 2 );
c0.merge(std::move(c1));
VERIFY( it != c1.end() ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,31 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_set<int>;
void
test01()
{
test_type c0{ 1, 2, 3, 5, 6 };
test_type c1{ 1, 2, 3, 4 };
auto it2 = c1.find(2);
auto it4 = c1.find(4);
VERIFY( *it2 == 2 );
VERIFY( *it4 == 4 );
c0.merge(c1);
VERIFY( *it2 == 2 );
VERIFY( it2 != it4 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,31 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_set<int>;
void
test01()
{
test_type c0{ 1, 2, 3, 5, 6 };
test_type c1{ 1, 2, 3, 4 };
auto it2 = c1.find(2);
auto it4 = c1.find(4);
VERIFY( *it2 == 2 );
VERIFY( *it4 == 4 );
c0.merge(std::move(c1));
VERIFY( *it2 == 2 );
VERIFY( it2 != it4 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,33 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_set<int>;
void
test01()
{
test_type c0{ 1, 2, 3, 5, 6, 7 };
std::unordered_multiset<int> c1{ 1, 1, 2, 2, 3, 3, 4, 4, 5 };
auto it1 = c1.find(1);
auto it41 = c1.find(4);
auto it42 = it41;
++it42;
VERIFY( *it42 == 4 );
c0.merge(c1);
VERIFY( *it1 == 1 );
VERIFY( c1.count(4) == 1 );
VERIFY( it41 != it42 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -0,0 +1,33 @@
// { dg-do run { target c++17 xfail *-*-* } }
// { dg-require-debug-mode "" }
#include <unordered_set>
#include <algorithm>
#include <testsuite_hooks.h>
using test_type = std::unordered_set<int>;
void
test01()
{
test_type c0{ 1, 2, 3, 5, 6, 7 };
std::unordered_multiset<int> c1{ 1, 1, 2, 2, 3, 3, 4, 4, 5 };
auto it1 = c1.find(1);
auto it41 = c1.find(4);
auto it42 = it41;
++it42;
VERIFY( *it42 == 4 );
c0.merge(std::move(c1));
VERIFY( *it1 == 1 );
VERIFY( c1.count(4) == 1 );
VERIFY( it41 != it42 ); // Invalid iterator.
}
int
main()
{
test01();
}

View File

@ -24,7 +24,11 @@
#include <locale>
#if __cplusplus >= 201103L
# include <unordered_map>
# ifdef _GLIBCXX_DEBUG
namespace unord = std::_GLIBCXX_STD_C;
# else
namespace unord = std;
# endif
#else
# include <tr1/unordered_map>
namespace unord = std::tr1;