[libc++] Optimize __hash_table copy constructors and assignment (#151951)
``` ---------------------------------------------------------------------------------------------------------------------- Benchmark old new ---------------------------------------------------------------------------------------------------------------------- std::unordered_set<int>::ctor(const&)/0 15.4 ns 14.6 ns std::unordered_set<int>::ctor(const&)/32 686 ns 322 ns std::unordered_set<int>::ctor(const&)/1024 35839 ns 21490 ns std::unordered_set<int>::ctor(const&)/8192 385790 ns 280270 ns std::unordered_set<int>::operator=(const&) (into cleared Container)/0 15.1 ns 15.9 ns std::unordered_set<int>::operator=(const&) (into cleared Container)/32 1077 ns 333 ns std::unordered_set<int>::operator=(const&) (into cleared Container)/1024 31296 ns 9984 ns std::unordered_set<int>::operator=(const&) (into cleared Container)/8192 266776 ns 109418 ns std::unordered_set<int>::operator=(const&) (into partially populated Container)/0 15.1 ns 16.3 ns std::unordered_set<int>::operator=(const&) (into partially populated Container)/32 962 ns 320 ns std::unordered_set<int>::operator=(const&) (into partially populated Container)/1024 31713 ns 10128 ns std::unordered_set<int>::operator=(const&) (into partially populated Container)/8192 266113 ns 108525 ns std::unordered_set<int>::operator=(const&) (into populated Container)/0 0.990 ns 2.03 ns std::unordered_set<int>::operator=(const&) (into populated Container)/32 963 ns 263 ns std::unordered_set<int>::operator=(const&) (into populated Container)/1024 27600 ns 7793 ns std::unordered_set<int>::operator=(const&) (into populated Container)/8192 235295 ns 66248 ns std::unordered_set<std::string>::ctor(const&)/0 16.0 ns 15.0 ns std::unordered_set<std::string>::ctor(const&)/32 2950 ns 1277 ns std::unordered_set<std::string>::ctor(const&)/1024 246935 ns 73762 ns std::unordered_set<std::string>::ctor(const&)/8192 3310895 ns 2468608 ns std::unordered_set<std::string>::operator=(const&) (into cleared Container)/0 16.1 ns 15.8 ns std::unordered_set<std::string>::operator=(const&) (into cleared Container)/32 5856 ns 1039 ns std::unordered_set<std::string>::operator=(const&) (into cleared Container)/1024 170436 ns 74836 ns std::unordered_set<std::string>::operator=(const&) (into cleared Container)/8192 1574235 ns 1096891 ns std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/0 16.0 ns 16.3 ns std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/32 5571 ns 1064 ns std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/1024 199220 ns 75462 ns std::unordered_set<std::string>::operator=(const&) (into partially populated Container)/8192 1552465 ns 1116094 ns std::unordered_set<std::string>::operator=(const&) (into populated Container)/0 1.70 ns 2.14 ns std::unordered_set<std::string>::operator=(const&) (into populated Container)/32 2562 ns 645 ns std::unordered_set<std::string>::operator=(const&) (into populated Container)/1024 228608 ns 39100 ns std::unordered_set<std::string>::operator=(const&) (into populated Container)/8192 2013723 ns 390401 ns ``` Fixes #77657
This commit is contained in:
parent
b9e33fd493
commit
cbbf303ff5
@ -45,6 +45,8 @@ Improvements and New Features
|
||||
|
||||
- The performance of ``map::map(const map&)`` has been improved up to 2.3x
|
||||
- The performance of ``map::operator=(const map&)`` has been improved by up to 11x
|
||||
- The performance of ``unordered_set::unordered_set(const unordered_set&)`` has been improved by up to 3.3x.
|
||||
- The performance of ``unordered_set::operator=(const unordered_set&)`` has been improved by up to 5x.
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef _LIBCPP___HASH_TABLE
|
||||
#define _LIBCPP___HASH_TABLE
|
||||
|
||||
#include <__algorithm/fill_n.h>
|
||||
#include <__algorithm/max.h>
|
||||
#include <__algorithm/min.h>
|
||||
#include <__assert>
|
||||
@ -700,6 +701,38 @@ private:
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void
|
||||
__copy_construct(__next_pointer __other_iter, __next_pointer __own_iter, size_t __current_chash) {
|
||||
auto __bucket_count = bucket_count();
|
||||
|
||||
for (; __other_iter; __other_iter = __other_iter->__next_) {
|
||||
__node_holder __new_node = __construct_node_hash(__other_iter->__hash(), __other_iter->__upcast()->__get_value());
|
||||
|
||||
size_t __new_chash = std::__constrain_hash(__new_node->__hash(), __bucket_count);
|
||||
if (__new_chash != __current_chash) {
|
||||
__bucket_list_[__new_chash] = __own_iter;
|
||||
__current_chash = __new_chash;
|
||||
}
|
||||
|
||||
__own_iter->__next_ = static_cast<__next_pointer>(__new_node.release());
|
||||
__own_iter = __own_iter->__next_;
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI void __copy_construct(__next_pointer __other_iter) {
|
||||
__next_pointer __own_iter = __first_node_.__ptr();
|
||||
{
|
||||
__node_holder __new_node = __construct_node_hash(__other_iter->__hash(), __other_iter->__upcast()->__get_value());
|
||||
__own_iter->__next_ = static_cast<__next_pointer>(__new_node.release());
|
||||
}
|
||||
|
||||
size_t __current_chash = std::__constrain_hash(__own_iter->__next_->__hash(), bucket_count());
|
||||
__bucket_list_[__current_chash] = __own_iter;
|
||||
__other_iter = __other_iter->__next_;
|
||||
__own_iter = __own_iter->__next_;
|
||||
__copy_construct(__other_iter, __own_iter, __current_chash);
|
||||
}
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
|
||||
|
||||
@ -1048,16 +1081,29 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a
|
||||
__max_load_factor_(1.0f) {}
|
||||
|
||||
template <class _Tp, class _Hash, class _Equal, class _Alloc>
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __other)
|
||||
: __bucket_list_(nullptr,
|
||||
__bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction(
|
||||
__u.__bucket_list_.get_deleter().__alloc()),
|
||||
__bucket_list_deleter(__pointer_alloc_traits::select_on_container_copy_construction(
|
||||
__other.__bucket_list_.get_deleter().__alloc()),
|
||||
0)),
|
||||
__node_alloc_(allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
|
||||
__node_alloc_(__node_traits::select_on_container_copy_construction(__other.__node_alloc())),
|
||||
__size_(0),
|
||||
__hasher_(__u.hash_function()),
|
||||
__max_load_factor_(__u.__max_load_factor_),
|
||||
__key_eq_(__u.__key_eq_) {}
|
||||
__hasher_(__other.hash_function()),
|
||||
__max_load_factor_(__other.__max_load_factor_),
|
||||
__key_eq_(__other.__key_eq_) {
|
||||
if (__other.size() == 0)
|
||||
return;
|
||||
|
||||
auto& __bucket_list_del = __bucket_list_.get_deleter();
|
||||
auto __bucket_count = __other.bucket_count();
|
||||
__bucket_list_.reset(__pointer_alloc_traits::allocate(__bucket_list_del.__alloc(), __bucket_count));
|
||||
__bucket_list_del.size() = __bucket_count;
|
||||
|
||||
std::fill_n(__bucket_list_.get(), __bucket_count, nullptr);
|
||||
|
||||
__copy_construct(__other.__first_node_.__next_);
|
||||
__size_ = __other.size();
|
||||
}
|
||||
|
||||
template <class _Tp, class _Hash, class _Equal, class _Alloc>
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a)
|
||||
@ -1131,14 +1177,75 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(const __hash_
|
||||
}
|
||||
|
||||
template <class _Tp, class _Hash, class _Equal, class _Alloc>
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u) {
|
||||
if (this != std::addressof(__u)) {
|
||||
__copy_assign_alloc(__u);
|
||||
hash_function() = __u.hash_function();
|
||||
key_eq() = __u.key_eq();
|
||||
max_load_factor() = __u.max_load_factor();
|
||||
__assign_multi(__u.begin(), __u.end());
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>&
|
||||
__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __other) {
|
||||
if (this == std::addressof(__other))
|
||||
return *this;
|
||||
|
||||
__copy_assign_alloc(__other);
|
||||
hash_function() = __other.hash_function();
|
||||
key_eq() = __other.key_eq();
|
||||
max_load_factor() = __other.max_load_factor();
|
||||
|
||||
if (__other.size() == 0) {
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto __bucket_count = __other.bucket_count();
|
||||
if (__bucket_count != bucket_count()) {
|
||||
auto& __bucket_list_del = __bucket_list_.get_deleter();
|
||||
__bucket_list_.reset(__pointer_alloc_traits::allocate(__bucket_list_del.__alloc(), __bucket_count));
|
||||
__bucket_list_del.size() = __bucket_count;
|
||||
}
|
||||
std::fill_n(__bucket_list_.get(), __bucket_count, nullptr);
|
||||
|
||||
if (!__first_node_.__next_) {
|
||||
__copy_construct(__other.__first_node_.__next_);
|
||||
__size_ = __other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
__next_pointer __other_iter = __other.__first_node_.__next_;
|
||||
__next_pointer __own_iter = __first_node_.__ptr();
|
||||
{
|
||||
__node_pointer __next = __own_iter->__next_->__upcast();
|
||||
__assign_value(__next->__get_value(), __other_iter->__upcast()->__get_value());
|
||||
__next->__hash_ = __other_iter->__hash();
|
||||
}
|
||||
size_t __current_chash = std::__constrain_hash(__own_iter->__next_->__hash(), __bucket_count);
|
||||
__bucket_list_[__current_chash] = __own_iter;
|
||||
__other_iter = __other_iter->__next_;
|
||||
__own_iter = __own_iter->__next_;
|
||||
|
||||
// Go through the nodes of the incoming hash table and copy then into the destination hash table, reusing as many
|
||||
// existing nodes as posssible in the destination.
|
||||
while (__other_iter && __own_iter->__next_) {
|
||||
__node_pointer __next = __own_iter->__next_->__upcast();
|
||||
__assign_value(__next->__get_value(), __other_iter->__upcast()->__get_value());
|
||||
__next->__hash_ = __other_iter->__hash();
|
||||
|
||||
size_t __new_chash = std::__constrain_hash(__next->__hash_, __bucket_count);
|
||||
if (__new_chash != __current_chash) {
|
||||
__bucket_list_[__new_chash] = __own_iter;
|
||||
__current_chash = __new_chash;
|
||||
}
|
||||
|
||||
__other_iter = __other_iter->__next_;
|
||||
__own_iter = __own_iter->__next_;
|
||||
}
|
||||
|
||||
// At this point we either have consumed the whole incoming hash table, or we don't have any more nodes to reuse in
|
||||
// the destination. Either continue with constructing new nodes, or deallocate the left over nodes.
|
||||
if (__own_iter->__next_) {
|
||||
__deallocate_node(__own_iter->__next_);
|
||||
__own_iter->__next_ = nullptr;
|
||||
} else {
|
||||
__copy_construct(__other_iter, __own_iter, __current_chash);
|
||||
}
|
||||
|
||||
__size_ = __other.size();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1046,10 +1046,11 @@ public:
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit unordered_map(const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u, const allocator_type& __a);
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u) _NOEXCEPT_(is_nothrow_move_constructible<__table>::value);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u, const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map(initializer_list<value_type> __il);
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
@ -1099,24 +1100,10 @@ public:
|
||||
static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), "");
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map& operator=(const unordered_map& __u) {
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
__table_ = __u.__table_;
|
||||
# else
|
||||
if (this != std::addressof(__u)) {
|
||||
__table_.clear();
|
||||
__table_.hash_function() = __u.__table_.hash_function();
|
||||
__table_.key_eq() = __u.__table_.key_eq();
|
||||
__table_.max_load_factor() = __u.__table_.max_load_factor();
|
||||
__table_.__copy_assign_alloc(__u.__table_);
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
# endif
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map& operator=(const unordered_map& __u) = default;
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map& operator=(unordered_map&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value);
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_map& operator=(initializer_list<value_type> __il);
|
||||
# endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
@ -1563,12 +1550,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
|
||||
insert(__first, __last);
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_map& __u) : __table_(__u.__table_) {
|
||||
__table_.__rehash_unique(__u.bucket_count());
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_map& __u, const allocator_type& __a)
|
||||
: __table_(__u.__table_, typename __table::allocator_type(__a)) {
|
||||
@ -1578,11 +1559,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_ma
|
||||
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
|
||||
: __table_(std::move(__u.__table_)) {}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __u, const allocator_type& __a)
|
||||
: __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) {
|
||||
@ -1618,14 +1594,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
|
||||
insert(__il.begin(), __il.end());
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>&
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_map&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
|
||||
__table_ = std::move(__u.__table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>&
|
||||
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) {
|
||||
@ -1852,11 +1820,11 @@ public:
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit unordered_multimap(const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u, const allocator_type& __a);
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(unordered_multimap&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value);
|
||||
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(unordered_multimap&& __u, const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(initializer_list<value_type> __il);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap(
|
||||
@ -1906,24 +1874,10 @@ public:
|
||||
static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), "");
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(const unordered_multimap& __u) {
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
__table_ = __u.__table_;
|
||||
# else
|
||||
if (this != std::addressof(__u)) {
|
||||
__table_.clear();
|
||||
__table_.hash_function() = __u.__table_.hash_function();
|
||||
__table_.key_eq() = __u.__table_.key_eq();
|
||||
__table_.max_load_factor() = __u.__table_.max_load_factor();
|
||||
__table_.__copy_assign_alloc(__u.__table_);
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
# endif
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(const unordered_multimap& __u) = default;
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(unordered_multimap&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value);
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(initializer_list<value_type> __il);
|
||||
# endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
@ -2315,13 +2269,6 @@ template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(const allocator_type& __a)
|
||||
: __table_(typename __table::allocator_type(__a)) {}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(const unordered_multimap& __u)
|
||||
: __table_(__u.__table_) {
|
||||
__table_.__rehash_multi(__u.bucket_count());
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
|
||||
const unordered_multimap& __u, const allocator_type& __a)
|
||||
@ -2332,11 +2279,6 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
|
||||
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(unordered_multimap&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
|
||||
: __table_(std::move(__u.__table_)) {}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
|
||||
unordered_multimap&& __u, const allocator_type& __a)
|
||||
@ -2373,14 +2315,6 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(
|
||||
insert(__il.begin(), __il.end());
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>&
|
||||
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_multimap&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
|
||||
__table_ = std::move(__u.__table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>&
|
||||
unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) {
|
||||
|
@ -703,7 +703,7 @@ public:
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit unordered_set(const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u, const allocator_type& __a);
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set(unordered_set&& __u) _NOEXCEPT_(is_nothrow_move_constructible<__table>::value);
|
||||
@ -733,13 +733,10 @@ public:
|
||||
static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), "");
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(const unordered_set& __u) {
|
||||
__table_ = __u.__table_;
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(const unordered_set& __u) = default;
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(unordered_set&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value);
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_set& operator=(initializer_list<value_type> __il);
|
||||
# endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
@ -1070,12 +1067,6 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const allocator_type& __a) : __table_(__a) {}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const unordered_set& __u) : __table_(__u.__table_) {
|
||||
__table_.__rehash_unique(__u.bucket_count());
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const unordered_set& __u, const allocator_type& __a)
|
||||
: __table_(__u.__table_, __a) {
|
||||
@ -1125,14 +1116,6 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(
|
||||
insert(__il.begin(), __il.end());
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_set<_Value, _Hash, _Pred, _Alloc>&
|
||||
unordered_set<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_set&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
|
||||
__table_ = std::move(__u.__table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_set<_Value, _Hash, _Pred, _Alloc>&
|
||||
unordered_set<_Value, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) {
|
||||
@ -1308,7 +1291,7 @@ public:
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit unordered_multiset(const allocator_type& __a);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u);
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u, const allocator_type& __a);
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset(unordered_multiset&& __u)
|
||||
@ -1339,13 +1322,10 @@ public:
|
||||
static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), "");
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(const unordered_multiset& __u) {
|
||||
__table_ = __u.__table_;
|
||||
return *this;
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(const unordered_multiset& __u) = default;
|
||||
# ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(unordered_multiset&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value);
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) = default;
|
||||
_LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(initializer_list<value_type> __il);
|
||||
# endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
@ -1685,13 +1665,6 @@ template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(const allocator_type& __a)
|
||||
: __table_(__a) {}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(const unordered_multiset& __u)
|
||||
: __table_(__u.__table_) {
|
||||
__table_.__rehash_multi(__u.bucket_count());
|
||||
insert(__u.begin(), __u.end());
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
|
||||
const unordered_multiset& __u, const allocator_type& __a)
|
||||
@ -1743,14 +1716,6 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(
|
||||
insert(__il.begin(), __il.end());
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>&
|
||||
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_multiset&& __u)
|
||||
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value) {
|
||||
__table_ = std::move(__u.__table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Value, class _Hash, class _Pred, class _Alloc>
|
||||
inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>&
|
||||
unordered_multiset<_Value, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) {
|
||||
|
@ -14,13 +14,16 @@
|
||||
|
||||
// unordered_map& operator=(const unordered_map& u);
|
||||
|
||||
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
@ -28,116 +31,437 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <class T>
|
||||
class tracking_allocator {
|
||||
std::vector<void*>* allocs_;
|
||||
|
||||
template <class U>
|
||||
friend class tracking_allocator;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
|
||||
tracking_allocator(std::vector<void*>& allocs) : allocs_(&allocs) {}
|
||||
|
||||
template <class U>
|
||||
tracking_allocator(const tracking_allocator<U>& other) : allocs_(other.allocs_) {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
T* allocation = std::allocator<T>().allocate(n);
|
||||
allocs_->push_back(allocation);
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void deallocate(T* ptr, std::size_t n) TEST_NOEXCEPT {
|
||||
auto res = std::remove(allocs_->begin(), allocs_->end(), ptr);
|
||||
assert(res != allocs_->end() && "Trying to deallocate memory from different allocator?");
|
||||
allocs_->erase(res);
|
||||
std::allocator<T>().deallocate(ptr, n);
|
||||
}
|
||||
|
||||
friend bool operator==(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ == rhs.allocs_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ != rhs.allocs_;
|
||||
}
|
||||
};
|
||||
|
||||
struct NoOp {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
template <class Alloc, class AllocatorInvariant = NoOp>
|
||||
void test_alloc(const Alloc& lhs_alloc = Alloc(),
|
||||
const Alloc& rhs_alloc = Alloc(),
|
||||
AllocatorInvariant check_alloc_invariant = NoOp()) {
|
||||
{ // Test empty/non-empty combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.at(1) == 1);
|
||||
assert(copy.at(2) == 3);
|
||||
assert(copy.at(4) == 4);
|
||||
assert(copy.at(5) == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.at(1) == 1);
|
||||
assert(orig.at(2) == 3);
|
||||
assert(orig.at(4) == 4);
|
||||
assert(orig.at(5) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into a non-empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Test empty/one-element copies. In our implementation that's a special case.
|
||||
{ // assign from a single-element container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.at(1) == 1);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.at(1) == 1);
|
||||
}
|
||||
{ // assign from an empty container into a single-element one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
}
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty map
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.at(1) == 1);
|
||||
assert(orig.at(2) == 3);
|
||||
assert(orig.at(4) == 4);
|
||||
assert(orig.at(5) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // with an empty map
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // check assignment into a non-empty map
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.at(1) == 1);
|
||||
assert(copy.at(2) == 3);
|
||||
assert(copy.at(4) == 4);
|
||||
assert(copy.at(5) == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.at(1) == 1);
|
||||
assert(orig.at(2) == 3);
|
||||
assert(orig.at(4) == 4);
|
||||
assert(orig.at(5) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5), V(12, 324), V(0, 54)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.at(1) == 1);
|
||||
assert(copy.at(2) == 3);
|
||||
assert(copy.at(4) == 4);
|
||||
assert(copy.at(5) == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.at(1) == 1);
|
||||
assert(orig.at(2) == 3);
|
||||
assert(orig.at(4) == 4);
|
||||
assert(orig.at(5) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5), V(12, 324), V(0, 54), V(50, 5), V(2, 5)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.at(1) == 1);
|
||||
assert(copy.at(2) == 3);
|
||||
assert(copy.at(4) == 4);
|
||||
assert(copy.at(5) == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.at(1) == 1);
|
||||
assert(orig.at(2) == 3);
|
||||
assert(orig.at(4) == 4);
|
||||
assert(orig.at(5) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
test_alloc<min_allocator<std::pair<const int, int> > >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001 (report is for std::map, but the unordered containers have the same optimization)
|
||||
class AssertEmpty {
|
||||
std::vector<void*>* lhs_allocs_;
|
||||
std::vector<void*>* rhs_allocs_;
|
||||
|
||||
public:
|
||||
AssertEmpty(std::vector<void*>& lhs_allocs, std::vector<void*>& rhs_allocs)
|
||||
: lhs_allocs_(&lhs_allocs), rhs_allocs_(&rhs_allocs) {}
|
||||
|
||||
void operator()() {
|
||||
assert(lhs_allocs_->empty());
|
||||
assert(rhs_allocs_->empty());
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<void*> lhs_allocs;
|
||||
std::vector<void*> rhs_allocs;
|
||||
test_alloc<tracking_allocator<std::pair<const int, int> > >(
|
||||
lhs_allocs, rhs_allocs, AssertEmpty(lhs_allocs, rhs_allocs));
|
||||
}
|
||||
|
||||
{ // Ensure that the hasher is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, test_hash<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, test_hash<int>(5));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_map<int, int, test_hash<int> >;
|
||||
|
||||
const Map orig(0, test_hash<int>(5));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.empty());
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.empty());
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the equality comparator is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the max load factor is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
Map orig(begin(arr), end(arr));
|
||||
orig.max_load_factor(33.f);
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.max_load_factor() == 33.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.max_load_factor() == 33.f);
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_map<int, int>;
|
||||
|
||||
Map orig;
|
||||
orig.max_load_factor(17.f);
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.max_load_factor() == 17.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.max_load_factor() == 17.f);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Check that pocca is handled properly
|
||||
{ // pocca == true_type
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Alloc = other_allocator<V>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = other_allocator<std::pair<const int, int> >;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
}
|
||||
{ // pocca == false_type
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Alloc = test_allocator<V>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = test_allocator<std::pair<const int, int> >;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef test_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_map<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(4));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_map<int, std::string> C;
|
||||
typedef std::pair<const int, std::string> P;
|
||||
const P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c(a, a + sizeof(a) / sizeof(a[0]));
|
||||
C* p = &c;
|
||||
c = *p;
|
||||
assert(c.size() == 4);
|
||||
assert(std::is_permutation(c.begin(), c.end(), a));
|
||||
}
|
||||
{
|
||||
typedef other_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_map<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
assert(c.bucket_count() >= 5);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef min_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_map<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A());
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A());
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,136 +14,134 @@
|
||||
|
||||
// unordered_map(const unordered_map& u);
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2), V(2, 4), V(3, 1)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.at(1) == 2);
|
||||
assert(copy.at(2) == 4);
|
||||
assert(copy.at(3) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.at(1) == 2);
|
||||
assert(orig.at(2) == 4);
|
||||
assert(orig.at(3) == 1);
|
||||
}
|
||||
{ // single element copy
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.at(1) == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.at(1) == 2);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Map = std::unordered_map<int, int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Map orig(0, test_hash<int>(23));
|
||||
Map copy = orig;
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Map copy = orig;
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
test_alloc<min_allocator<std::pair<const int, int> > >();
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, test_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), test_allocator<V>(10));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == test_allocator<V>(10));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == test_allocator<V>(10));
|
||||
assert(orig.get_allocator().get_id() != test_alloc_base::moved_value);
|
||||
}
|
||||
|
||||
{ // Ensure that soccc is handled properly
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, other_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), other_allocator<V>(10));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == other_allocator<V>(-2));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == other_allocator<V>(10));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_map<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
test_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
test_allocator<std::pair<const int, std::string> >(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (test_allocator<std::pair<const int, std::string> >(10)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_map<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
other_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
other_allocator<std::pair<const int, std::string> >(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (other_allocator<std::pair<const int, std::string> >(-2)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_map<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
min_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
min_allocator<std::pair<const int, std::string> >());
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (min_allocator<std::pair<const int, std::string> >()));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,127 +14,109 @@
|
||||
|
||||
// unordered_map(const unordered_map& u, const allocator_type& a);
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2), V(2, 4), V(3, 1)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.at(1) == 2);
|
||||
assert(copy.at(2) == 4);
|
||||
assert(copy.at(3) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.at(1) == 2);
|
||||
assert(orig.at(2) == 4);
|
||||
assert(orig.at(3) == 1);
|
||||
}
|
||||
{ // single element check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.at(1) == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.at(1) == 2);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Map = std::unordered_map<int, int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Map orig(0, test_hash<int>(23));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Map = std::unordered_map<int, int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<std::pair<const int, int> >());
|
||||
test_alloc(min_allocator<std::pair<const int, int> >());
|
||||
test_alloc(test_allocator<std::pair<const int, int> >(25));
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_map<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
test_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
test_allocator<std::pair<const int, std::string> >(10));
|
||||
C c(c0, test_allocator<std::pair<const int, std::string> >(5));
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (test_allocator<std::pair<const int, std::string> >(5)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_map<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
min_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
min_allocator<std::pair<const int, std::string> >());
|
||||
C c(c0, min_allocator<std::pair<const int, std::string> >());
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (min_allocator<std::pair<const int, std::string> >()));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef explicit_allocator<std::pair<const int, std::string>> A;
|
||||
typedef std::unordered_map<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A{});
|
||||
C c(c0, A{});
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.at(1) == "one");
|
||||
assert(c.at(2) == "two");
|
||||
assert(c.at(3) == "three");
|
||||
assert(c.at(4) == "four");
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A{});
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,153 +14,473 @@
|
||||
|
||||
// unordered_multimap& operator=(const unordered_multimap& u);
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <set>
|
||||
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../check_consecutive.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T>
|
||||
class tracking_allocator {
|
||||
std::vector<void*>* allocs_;
|
||||
|
||||
template <class U>
|
||||
friend class tracking_allocator;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
|
||||
tracking_allocator(std::vector<void*>& allocs) : allocs_(&allocs) {}
|
||||
|
||||
template <class U>
|
||||
tracking_allocator(const tracking_allocator<U>& other) : allocs_(other.allocs_) {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
T* allocation = std::allocator<T>().allocate(n);
|
||||
allocs_->push_back(allocation);
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void deallocate(T* ptr, std::size_t n) TEST_NOEXCEPT {
|
||||
auto res = std::remove(allocs_->begin(), allocs_->end(), ptr);
|
||||
assert(res != allocs_->end() && "Trying to deallocate memory from different allocator?");
|
||||
allocs_->erase(res);
|
||||
std::allocator<T>().deallocate(ptr, n);
|
||||
}
|
||||
|
||||
friend bool operator==(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ == rhs.allocs_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ != rhs.allocs_;
|
||||
}
|
||||
};
|
||||
|
||||
struct NoOp {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
template <class Alloc, class AllocatorInvariant = NoOp>
|
||||
void test_alloc(const Alloc& lhs_alloc = Alloc(),
|
||||
const Alloc& rhs_alloc = Alloc(),
|
||||
AllocatorInvariant check_alloc_invariant = NoOp()) {
|
||||
{ // Test empty/non-empty combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(4, 2)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 1);
|
||||
assert(copy.find(2)->second == 3);
|
||||
{
|
||||
auto range = copy.equal_range(4);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 2 || first_element->second == 4);
|
||||
assert(second_element->second == 2 || second_element->second == 4);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 1);
|
||||
assert(orig.find(2)->second == 3);
|
||||
{
|
||||
auto range = orig.equal_range(4);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 2 || first_element->second == 4);
|
||||
assert(second_element->second == 2 || second_element->second == 4);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into a non-empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Test empty/one-element copies. In our implementation that's a special case.
|
||||
{ // assign from a single-element container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.find(1)->second == 1);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.find(1)->second == 1);
|
||||
}
|
||||
{ // assign from an empty container into a single-element one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
}
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty map
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 1);
|
||||
assert(orig.find(2)->second == 3);
|
||||
assert(orig.find(4)->second == 4);
|
||||
assert(orig.find(5)->second == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // with an empty map
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // check assignment into a non-empty map
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 1);
|
||||
assert(copy.find(2)->second == 3);
|
||||
assert(copy.find(4)->second == 4);
|
||||
assert(copy.find(5)->second == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 1);
|
||||
assert(orig.find(2)->second == 3);
|
||||
assert(orig.find(4)->second == 4);
|
||||
assert(orig.find(5)->second == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5), V(12, 324), V(0, 54)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 1);
|
||||
assert(copy.find(2)->second == 3);
|
||||
assert(copy.find(4)->second == 4);
|
||||
assert(copy.find(5)->second == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 1);
|
||||
assert(orig.find(2)->second == 3);
|
||||
assert(orig.find(4)->second == 4);
|
||||
assert(orig.find(5)->second == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(4, 4), V(5, 2)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(10, 4), V(13, 5), V(12, 324), V(0, 54), V(50, 5), V(2, 5)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 1);
|
||||
assert(copy.find(2)->second == 3);
|
||||
assert(copy.find(4)->second == 4);
|
||||
assert(copy.find(5)->second == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 1);
|
||||
assert(orig.find(2)->second == 3);
|
||||
assert(orig.find(4)->second == 4);
|
||||
assert(orig.find(5)->second == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
test_alloc<min_allocator<std::pair<const int, int> > >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001 (report is for std::map, but the unordered containers have the same optimization)
|
||||
class AssertEmpty {
|
||||
std::vector<void*>* lhs_allocs_;
|
||||
std::vector<void*>* rhs_allocs_;
|
||||
|
||||
public:
|
||||
AssertEmpty(std::vector<void*>& lhs_allocs, std::vector<void*>& rhs_allocs)
|
||||
: lhs_allocs_(&lhs_allocs), rhs_allocs_(&rhs_allocs) {}
|
||||
|
||||
void operator()() {
|
||||
assert(lhs_allocs_->empty());
|
||||
assert(rhs_allocs_->empty());
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<void*> lhs_allocs;
|
||||
std::vector<void*> rhs_allocs;
|
||||
test_alloc<tracking_allocator<std::pair<const int, int> > >(
|
||||
lhs_allocs, rhs_allocs, AssertEmpty(lhs_allocs, rhs_allocs));
|
||||
}
|
||||
|
||||
{ // Ensure that the hasher is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, test_hash<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, test_hash<int>(5));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_multimap<int, int, test_hash<int> >;
|
||||
|
||||
const Map orig(0, test_hash<int>(5));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.empty());
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.empty());
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the equality comparator is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the max load factor is copied
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
Map orig(begin(arr), end(arr));
|
||||
orig.max_load_factor(33.f);
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.max_load_factor() == 33.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.max_load_factor() == 33.f);
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Map = std::unordered_multimap<int, int>;
|
||||
|
||||
Map orig;
|
||||
orig.max_load_factor(17.f);
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.max_load_factor() == 17.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.max_load_factor() == 17.f);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Check that pocca is handled properly
|
||||
{ // pocca == true_type
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Alloc = other_allocator<V>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = other_allocator<std::pair<const int, int> >;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
}
|
||||
{ // pocca == false_type
|
||||
{ // when the container is non-empty
|
||||
using V = std::pair<const int, int>;
|
||||
using Alloc = test_allocator<V>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 2), V(3, 3)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = test_allocator<std::pair<const int, int> >;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig(Alloc(3));
|
||||
Map copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef test_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_multimap<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(4));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_multimap<int, std::string> C;
|
||||
typedef std::pair<const int, std::string> P;
|
||||
const P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c(a, a + sizeof(a) / sizeof(a[0]));
|
||||
C* p = &c;
|
||||
c = *p;
|
||||
assert(c.size() == 6);
|
||||
assert(std::is_permutation(c.begin(), c.end(), a));
|
||||
}
|
||||
{
|
||||
typedef other_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_multimap<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
assert(c.bucket_count() >= 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef min_allocator<std::pair<const int, std::string> > A;
|
||||
typedef std::unordered_multimap<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A());
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A());
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,144 +29,144 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2), V(2, 4), V(3, 1), V(3, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 2);
|
||||
assert(copy.find(2)->second == 4);
|
||||
{
|
||||
auto range = copy.equal_range(3);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 1 || first_element->second == 2);
|
||||
assert(second_element->second == 1 || second_element->second == 2);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 2);
|
||||
assert(orig.find(2)->second == 4);
|
||||
{
|
||||
auto range = orig.equal_range(3);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 1 || first_element->second == 2);
|
||||
assert(second_element->second == 1 || second_element->second == 2);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
}
|
||||
{ // single element copy
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.find(1)->second == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.find(1)->second == 2);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Map = std::unordered_multimap<int, int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Map orig(0, test_hash<int>(23));
|
||||
Map copy = orig;
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Map copy = orig;
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
test_alloc<min_allocator<std::pair<const int, int> > >();
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, test_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), test_allocator<V>(10));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == test_allocator<V>(10));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == test_allocator<V>(10));
|
||||
assert(orig.get_allocator().get_id() != test_alloc_base::moved_value);
|
||||
}
|
||||
|
||||
{ // Ensure that soccc is handled properly
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, other_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), 0, std::hash<int>(), std::equal_to<int>(), other_allocator<V>(10));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == other_allocator<V>(-2));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == other_allocator<V>(10));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_multimap<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
test_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
test_allocator<std::pair<const int, std::string> >(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (test_allocator<std::pair<const int, std::string> >(10)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_multimap<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
other_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
other_allocator<std::pair<const int, std::string> >(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (other_allocator<std::pair<const int, std::string> >(-2)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_multimap<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
min_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
min_allocator<std::pair<const int, std::string> >());
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (min_allocator<std::pair<const int, std::string> >()));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,135 +29,120 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2), V(2, 4), V(3, 1), V(3, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.find(1)->second == 2);
|
||||
assert(copy.find(2)->second == 4);
|
||||
{
|
||||
auto range = copy.equal_range(3);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 1 || first_element->second == 2);
|
||||
assert(second_element->second == 1 || second_element->second == 2);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.find(1)->second == 2);
|
||||
assert(orig.find(2)->second == 4);
|
||||
{
|
||||
auto range = orig.equal_range(3);
|
||||
auto first_element = std::next(range.first, 0);
|
||||
auto second_element = std::next(range.first, 1);
|
||||
auto end = std::next(range.first, 2);
|
||||
|
||||
assert(range.second == end);
|
||||
|
||||
assert(first_element->second == 1 || first_element->second == 2);
|
||||
assert(second_element->second == 1 || second_element->second == 2);
|
||||
assert(second_element->second != range.first->second);
|
||||
}
|
||||
}
|
||||
{ // single element check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 2)};
|
||||
const Map orig(std::begin(arr), std::end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.find(1)->second == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.find(1)->second == 2);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Map = std::unordered_multimap<int, int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Map orig(0, test_hash<int>(23));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Map = std::unordered_multimap<int, int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Map orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<std::pair<const int, int> >());
|
||||
test_alloc(min_allocator<std::pair<const int, int> >());
|
||||
test_alloc(test_allocator<std::pair<const int, int> >(25));
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_multimap<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
test_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
test_allocator<std::pair<const int, std::string> >(10));
|
||||
C c(c0, test_allocator<std::pair<const int, std::string> >(5));
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (test_allocator<std::pair<const int, std::string> >(5)));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_multimap<int,
|
||||
std::string,
|
||||
test_hash<int>,
|
||||
test_equal_to<int>,
|
||||
min_allocator<std::pair<const int, std::string> > >
|
||||
C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a,
|
||||
a + sizeof(a) / sizeof(a[0]),
|
||||
7,
|
||||
test_hash<int>(8),
|
||||
test_equal_to<int>(9),
|
||||
min_allocator<std::pair<const int, std::string> >());
|
||||
C c(c0, min_allocator<std::pair<const int, std::string> >());
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == (min_allocator<std::pair<const int, std::string> >()));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef explicit_allocator<std::pair<const int, std::string>> A;
|
||||
typedef std::unordered_multimap<int, std::string, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef std::pair<int, std::string> P;
|
||||
P a[] = {
|
||||
P(1, "one"),
|
||||
P(2, "two"),
|
||||
P(3, "three"),
|
||||
P(4, "four"),
|
||||
P(1, "four"),
|
||||
P(2, "four"),
|
||||
};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A{});
|
||||
C c(c0, A{});
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
std::multiset<std::string> s;
|
||||
s.insert("one");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(1), c.end(), 1, s);
|
||||
s.insert("two");
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(2), c.end(), 2, s);
|
||||
s.insert("three");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(3), c.end(), 3, s);
|
||||
s.insert("four");
|
||||
CheckConsecutiveKeys<C::const_iterator>(c.find(4), c.end(), 4, s);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A{});
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,103 +14,437 @@
|
||||
|
||||
// unordered_multiset& operator=(const unordered_multiset& u);
|
||||
|
||||
#include <unordered_set>
|
||||
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../check_consecutive.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T>
|
||||
class tracking_allocator {
|
||||
std::vector<void*>* allocs_;
|
||||
|
||||
template <class U>
|
||||
friend class tracking_allocator;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
|
||||
tracking_allocator(std::vector<void*>& allocs) : allocs_(&allocs) {}
|
||||
|
||||
template <class U>
|
||||
tracking_allocator(const tracking_allocator<U>& other) : allocs_(other.allocs_) {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
T* allocation = std::allocator<T>().allocate(n);
|
||||
allocs_->push_back(allocation);
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void deallocate(T* ptr, std::size_t n) TEST_NOEXCEPT {
|
||||
auto res = std::remove(allocs_->begin(), allocs_->end(), ptr);
|
||||
assert(res != allocs_->end() && "Trying to deallocate memory from different allocator?");
|
||||
allocs_->erase(res);
|
||||
std::allocator<T>().deallocate(ptr, n);
|
||||
}
|
||||
|
||||
friend bool operator==(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ == rhs.allocs_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ != rhs.allocs_;
|
||||
}
|
||||
};
|
||||
|
||||
struct NoOp {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
template <class Alloc, class AllocatorInvariant = NoOp>
|
||||
void test_alloc(const Alloc& lhs_alloc = Alloc(),
|
||||
const Alloc& rhs_alloc = Alloc(),
|
||||
AllocatorInvariant check_alloc_invariant = NoOp()) {
|
||||
{ // Test empty/non-empty combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 4};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 2);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 2);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into a non-empty one
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 4};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Test empty/one-element copies. In our implementation that's a special case.
|
||||
{ // assign from a single-element container into an empty one
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // assign from an empty container into a single-element one
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
}
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty map
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 5};
|
||||
Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // with an empty map
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // check assignment into a non-empty map
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13, 12, 0};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13, 12, 0, 50, 2};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001 (report is for std::map, but the unordered containers have the same optimization)
|
||||
class AssertEmpty {
|
||||
std::vector<void*>* lhs_allocs_;
|
||||
std::vector<void*>* rhs_allocs_;
|
||||
|
||||
public:
|
||||
AssertEmpty(std::vector<void*>& lhs_allocs, std::vector<void*>& rhs_allocs)
|
||||
: lhs_allocs_(&lhs_allocs), rhs_allocs_(&rhs_allocs) {}
|
||||
|
||||
void operator()() {
|
||||
assert(lhs_allocs_->empty());
|
||||
assert(rhs_allocs_->empty());
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<void*> lhs_allocs;
|
||||
std::vector<void*> rhs_allocs;
|
||||
test_alloc<tracking_allocator<int> >(lhs_allocs, rhs_allocs, AssertEmpty(lhs_allocs, rhs_allocs));
|
||||
}
|
||||
|
||||
{ // Ensure that the hasher is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_multiset<int, test_hash<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, test_hash<int>(5));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_multiset<int, test_hash<int> >;
|
||||
|
||||
const Set orig(0, test_hash<int>(5));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.empty());
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.empty());
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the equality comparator is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the max load factor is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_multiset<int>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
Set orig(std::begin(arr), std::end(arr));
|
||||
orig.max_load_factor(33.f);
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.max_load_factor() == 33.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.max_load_factor() == 33.f);
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_multiset<int>;
|
||||
|
||||
Set orig;
|
||||
orig.max_load_factor(17.f);
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.max_load_factor() == 17.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.max_load_factor() == 17.f);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Check that pocca is handled properly
|
||||
{ // pocca == true_type
|
||||
{ // when the container is non-empty
|
||||
using Alloc = other_allocator<int>;
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = other_allocator<int>;
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
}
|
||||
{ // pocca == false_type
|
||||
{ // when the container is non-empty
|
||||
using Alloc = test_allocator<int>;
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = test_allocator<int>;
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef test_allocator<int> A;
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(4));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_multiset<int> C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c(a, a + sizeof(a) / sizeof(a[0]));
|
||||
C* p = &c;
|
||||
c = *p;
|
||||
|
||||
assert(c.size() == 6);
|
||||
assert(std::is_permutation(c.begin(), c.end(), a));
|
||||
}
|
||||
{
|
||||
typedef other_allocator<int> A;
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
assert(c.bucket_count() >= 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef min_allocator<int> A;
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A());
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A());
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,72 +27,118 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(3) == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(3) == 2);
|
||||
}
|
||||
{ // single element copy
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Set = std::unordered_multiset<int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Set orig(0, test_hash<int>(23));
|
||||
Set copy = orig;
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Set copy = orig;
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, test_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), test_allocator<int>(10));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == test_allocator<int>(10));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == test_allocator<int>(10));
|
||||
assert(orig.get_allocator().get_id() != test_alloc_base::moved_value);
|
||||
}
|
||||
|
||||
{ // Ensure that soccc is handled properly
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, other_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), other_allocator<int>(10));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == other_allocator<int>(-2));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == other_allocator<int>(10));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, test_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), test_allocator<int>(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == test_allocator<int>(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, other_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), other_allocator<int>(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == other_allocator<int>(-2));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, min_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), min_allocator<int>());
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == min_allocator<int>());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,64 +14,107 @@
|
||||
|
||||
// unordered_multiset(const unordered_multiset& u, const allocator_type& a);
|
||||
|
||||
#include <unordered_set>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../check_consecutive.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(3) == 2);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(3) == 2);
|
||||
}
|
||||
{ // single element check
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Set = std::unordered_multiset<int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Set orig(0, test_hash<int>(23));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Set = std::unordered_multiset<int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<int>());
|
||||
test_alloc(min_allocator<int>());
|
||||
test_alloc(test_allocator<int>(25));
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, test_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), test_allocator<int>(10));
|
||||
C c(c0, test_allocator<int>(5));
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == test_allocator<int>(5));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_multiset<int, test_hash<int>, test_equal_to<int>, min_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), min_allocator<int>());
|
||||
C c(c0, min_allocator<int>());
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 6);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(1), c.end(), 1, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(2), c.end(), 2, 2);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(3), c.end(), 3, 1);
|
||||
CheckConsecutiveValues<C::const_iterator>(c.find(4), c.end(), 4, 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == min_allocator<int>());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,115 +14,440 @@
|
||||
|
||||
// unordered_set& operator=(const unordered_set& u);
|
||||
|
||||
#include <unordered_set>
|
||||
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef test_allocator<int> A;
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(4));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
template <class T>
|
||||
class tracking_allocator {
|
||||
std::vector<void*>* allocs_;
|
||||
|
||||
template <class U>
|
||||
friend class tracking_allocator;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
|
||||
tracking_allocator(std::vector<void*>& allocs) : allocs_(&allocs) {}
|
||||
|
||||
template <class U>
|
||||
tracking_allocator(const tracking_allocator<U>& other) : allocs_(other.allocs_) {}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
T* allocation = std::allocator<T>().allocate(n);
|
||||
allocs_->push_back(allocation);
|
||||
return allocation;
|
||||
}
|
||||
{
|
||||
typedef std::unordered_set<int> C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c(a, a + sizeof(a) / sizeof(a[0]));
|
||||
C* p = &c;
|
||||
c = *p;
|
||||
assert(c.size() == 4);
|
||||
assert(std::is_permutation(c.begin(), c.end(), a));
|
||||
|
||||
void deallocate(T* ptr, std::size_t n) TEST_NOEXCEPT {
|
||||
auto res = std::remove(allocs_->begin(), allocs_->end(), ptr);
|
||||
assert(res != allocs_->end() && "Trying to deallocate memory from different allocator?");
|
||||
allocs_->erase(res);
|
||||
std::allocator<T>().deallocate(ptr, n);
|
||||
}
|
||||
{
|
||||
typedef other_allocator<int> A;
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A(10));
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A(4));
|
||||
c = c0;
|
||||
assert(c.bucket_count() >= 5);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
|
||||
friend bool operator==(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ == rhs.allocs_;
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef min_allocator<int> A;
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, A > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), A());
|
||||
C c(a, a + 2, 7, test_hash<int>(2), test_equal_to<int>(3), A());
|
||||
c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == A());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
|
||||
friend bool operator!=(const tracking_allocator& lhs, const tracking_allocator& rhs) {
|
||||
return lhs.allocs_ != rhs.allocs_;
|
||||
}
|
||||
#endif
|
||||
{ // Test with std::pair, since we have some special handling for pairs inside __hash_table
|
||||
struct pair_hash {
|
||||
size_t operator()(std::pair<int, int> val) const TEST_NOEXCEPT { return val.first | val.second; }
|
||||
};
|
||||
|
||||
std::pair<int, int> arr[] = {
|
||||
std::make_pair(1, 2), std::make_pair(2, 3), std::make_pair(3, 4), std::make_pair(4, 5)};
|
||||
std::unordered_set<std::pair<int, int>, pair_hash> a(arr, arr + 4);
|
||||
std::unordered_set<std::pair<int, int>, pair_hash> b;
|
||||
struct NoOp {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
b = a;
|
||||
assert(a == b);
|
||||
template <class Alloc, class AllocatorInvariant = NoOp>
|
||||
void test_alloc(const Alloc& lhs_alloc = Alloc(),
|
||||
const Alloc& rhs_alloc = Alloc(),
|
||||
AllocatorInvariant check_alloc_invariant = NoOp()) {
|
||||
{ // Test empty/non-empty combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into a non-empty one
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 5};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Test empty/one-element copies. In our implementation that's a special case.
|
||||
{ // assign from a single-element container into an empty one
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // assign from an empty container into a single-element one
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
// Depending on whether the allocator is propagated the bucked count can change
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2 || copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
}
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty map
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 4, 5};
|
||||
Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // with an empty map
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // check assignment into a non-empty map
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13, 12, 0};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 4, 5};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {10, 13, 12, 0, 50, 2};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), 0, std::hash<int>(), std::equal_to<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 4);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(4) == 1);
|
||||
assert(copy.count(5) == 1);
|
||||
assert(std::next(copy.begin(), 4) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 4);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(4) == 1);
|
||||
assert(orig.count(5) == 1);
|
||||
assert(std::next(orig.begin(), 4) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001 (report is for std::map, but the unordered containers have the same optimization)
|
||||
class AssertEmpty {
|
||||
std::vector<void*>* lhs_allocs_;
|
||||
std::vector<void*>* rhs_allocs_;
|
||||
|
||||
public:
|
||||
AssertEmpty(std::vector<void*>& lhs_allocs, std::vector<void*>& rhs_allocs)
|
||||
: lhs_allocs_(&lhs_allocs), rhs_allocs_(&rhs_allocs) {}
|
||||
|
||||
void operator()() {
|
||||
assert(lhs_allocs_->empty());
|
||||
assert(rhs_allocs_->empty());
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<void*> lhs_allocs;
|
||||
std::vector<void*> rhs_allocs;
|
||||
test_alloc<tracking_allocator<int> >(lhs_allocs, rhs_allocs, AssertEmpty(lhs_allocs, rhs_allocs));
|
||||
}
|
||||
|
||||
{ // Ensure that the hasher is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_set<int, test_hash<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, test_hash<int>(5));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_set<int, test_hash<int> >;
|
||||
|
||||
const Set orig(0, test_hash<int>(5));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.empty());
|
||||
assert(copy.hash_function() == test_hash<int>(5));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.empty());
|
||||
assert(orig.hash_function() == test_hash<int>(5));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the equality comparator is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_set<int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_set<int, std::hash<int>, test_equal_to<int> >;
|
||||
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(23));
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(copy.key_eq() == test_equal_to<int>(23));
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that the max load factor is copied
|
||||
{ // when the container is non-empty
|
||||
using Set = std::unordered_set<int>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
Set orig(std::begin(arr), std::end(arr));
|
||||
orig.max_load_factor(33.f);
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.max_load_factor() == 33.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.max_load_factor() == 33.f);
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Set = std::unordered_set<int>;
|
||||
|
||||
Set orig;
|
||||
orig.max_load_factor(17.f);
|
||||
Set copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.max_load_factor() == 17.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.max_load_factor() == 17.f);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Check that pocca is handled properly
|
||||
{ // pocca == true_type
|
||||
{ // when the container is non-empty
|
||||
using Alloc = other_allocator<int>;
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = other_allocator<int>;
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(3));
|
||||
}
|
||||
}
|
||||
{ // pocca == false_type
|
||||
{ // when the container is non-empty
|
||||
using Alloc = test_allocator<int>;
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
{ // when the container is empty
|
||||
using Alloc = test_allocator<int>;
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig(Alloc(3));
|
||||
Set copy(Alloc(1));
|
||||
copy = orig;
|
||||
assert(copy.get_allocator() == Alloc(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,84 +14,130 @@
|
||||
|
||||
// unordered_set(const unordered_set& u);
|
||||
|
||||
#include <unordered_set>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(3) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(3) == 1);
|
||||
}
|
||||
{ // single element copy
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Set = std::unordered_set<int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Set orig(0, test_hash<int>(23));
|
||||
Set copy = orig;
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Set = std::unordered_set<int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Set copy = orig;
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, test_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), test_allocator<int>(10));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == test_allocator<int>(10));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == test_allocator<int>(10));
|
||||
assert(orig.get_allocator().get_id() != test_alloc_base::moved_value);
|
||||
}
|
||||
|
||||
{ // Ensure that soccc is handled properly
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, other_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), 0, std::hash<int>(), std::equal_to<int>(), other_allocator<int>(10));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.get_allocator() == other_allocator<int>(-2));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.get_allocator() == other_allocator<int>(10));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, test_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), test_allocator<int>(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == test_allocator<int>(10));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, other_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), other_allocator<int>(10));
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == other_allocator<int>(-2));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
{
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, min_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), min_allocator<int>());
|
||||
C c = c0;
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == min_allocator<int>());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,63 +14,107 @@
|
||||
|
||||
// unordered_set(const unordered_set& u, const allocator_type& a);
|
||||
|
||||
#include <unordered_set>
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "../../../test_hash.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_allocator.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 5);
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(copy.count(2) == 1);
|
||||
assert(copy.count(3) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 5);
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.count(1) == 1);
|
||||
assert(orig.count(2) == 1);
|
||||
assert(orig.count(3) == 1);
|
||||
}
|
||||
{ // single element check
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
int arr[] = {1};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 2);
|
||||
assert(copy.size() == 1);
|
||||
assert(copy.count(1) == 1);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(std::fabs(copy.load_factor() - static_cast<float>(copy.size()) / copy.bucket_count()) < FLT_EPSILON);
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 2);
|
||||
assert(orig.size() == 1);
|
||||
assert(orig.count(1) == 1);
|
||||
}
|
||||
{ // Copy empty map
|
||||
using Set = std::unordered_set<int, std::hash<int>, std::equal_to<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy(orig, new_alloc);
|
||||
LIBCPP_ASSERT(copy.bucket_count() == 0);
|
||||
assert(copy.size() == 0);
|
||||
assert(static_cast<std::size_t>(std::distance(copy.begin(), copy.end())) == copy.size());
|
||||
assert(copy.max_load_factor() == 1.f);
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
LIBCPP_ASSERT(orig.bucket_count() == 0);
|
||||
assert(orig.size() == 0);
|
||||
}
|
||||
{ // Ensure that the hash function is copied
|
||||
using Set = std::unordered_set<int, test_hash<int>, std::equal_to<int>, Alloc>;
|
||||
const Set orig(0, test_hash<int>(23));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.hash_function() == test_hash<int>(23));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.hash_function() == test_hash<int>(23));
|
||||
}
|
||||
{ // Ensure that the quality comparator is copied
|
||||
using Set = std::unordered_set<int, std::hash<int>, test_equal_to<int>, Alloc>;
|
||||
const Set orig(0, std::hash<int>(), test_equal_to<int>(56));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.key_eq() == test_equal_to<int>(56));
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.key_eq() == test_equal_to<int>(56));
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<int>());
|
||||
test_alloc(min_allocator<int>());
|
||||
test_alloc(test_allocator<int>(25));
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, test_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), test_allocator<int>(10));
|
||||
C c(c0, test_allocator<int>(5));
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == test_allocator<int>(5));
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::unordered_set<int, test_hash<int>, test_equal_to<int>, min_allocator<int> > C;
|
||||
typedef int P;
|
||||
P a[] = {P(1), P(2), P(3), P(4), P(1), P(2)};
|
||||
C c0(a, a + sizeof(a) / sizeof(a[0]), 7, test_hash<int>(8), test_equal_to<int>(9), min_allocator<int>());
|
||||
C c(c0, min_allocator<int>());
|
||||
LIBCPP_ASSERT(c.bucket_count() == 7);
|
||||
assert(c.size() == 4);
|
||||
assert(c.count(1) == 1);
|
||||
assert(c.count(2) == 1);
|
||||
assert(c.count(3) == 1);
|
||||
assert(c.count(4) == 1);
|
||||
assert(c.hash_function() == test_hash<int>(8));
|
||||
assert(c.key_eq() == test_equal_to<int>(9));
|
||||
assert(c.get_allocator() == min_allocator<int>());
|
||||
assert(!c.empty());
|
||||
assert(static_cast<std::size_t>(std::distance(c.begin(), c.end())) == c.size());
|
||||
assert(static_cast<std::size_t>(std::distance(c.cbegin(), c.cend())) == c.size());
|
||||
assert(std::fabs(c.load_factor() - (float)c.size() / c.bucket_count()) < FLT_EPSILON);
|
||||
assert(c.max_load_factor() == 1);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user