forked from boostorg/unordered
Compare commits
24 Commits
esp-idf-co
...
before-fla
Author | SHA1 | Date | |
---|---|---|---|
668abe4b0a | |||
5dcccfda3b | |||
56b271850a | |||
d338e94267 | |||
42abfe3c7d | |||
6ef6540378 | |||
9a9b8e0a7b | |||
5ad86f559f | |||
a8b0e19a33 | |||
2b61fbb8df | |||
dea6ce164c | |||
9ebb705e75 | |||
010dfa52e3 | |||
db9d9d1f77 | |||
6f342bf119 | |||
48765e82e0 | |||
f141cd1dea | |||
6258856d2b | |||
c93ea188f7 | |||
329eb419f5 | |||
e83c42ca26 | |||
f9eae4153f | |||
7b41f4783f | |||
7227cfc68a |
@ -85,7 +85,14 @@ environment:
|
||||
- FLAVOR: mingw-w64, 64 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
B2_CXXSTD: 03,11,14,17,2a
|
||||
B2_CXXSTD: 03,11,14
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 64
|
||||
|
||||
- FLAVOR: mingw-w64, 64 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
B2_CXXSTD: 17,2a
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 64
|
||||
|
||||
|
@ -32,6 +32,7 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
|
||||
commands:
|
||||
[
|
||||
'set -e',
|
||||
'uname -a',
|
||||
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
|
||||
] +
|
||||
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
||||
@ -63,6 +64,7 @@ local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "c
|
||||
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
|
||||
commands:
|
||||
[
|
||||
'uname -a',
|
||||
'export LIBRARY=' + library,
|
||||
'./.drone/drone.sh',
|
||||
]
|
||||
@ -89,6 +91,7 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
environment: environment,
|
||||
commands:
|
||||
[
|
||||
'echo $env:DRONE_STAGE_MACHINE',
|
||||
'cmd /C .drone\\\\drone.bat ' + library,
|
||||
]
|
||||
}
|
||||
@ -168,8 +171,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 ASAN",
|
||||
"MacOS 12.4 Xcode 13.4.1 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
|
@ -5,6 +5,7 @@
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
set -ex
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
DRONE_BUILD_DIR=$(pwd)
|
||||
|
||||
|
@ -1566,7 +1566,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
|
||||
void rehash(size_type n);
|
||||
```
|
||||
|
||||
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
||||
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
@ -1580,6 +1582,10 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
void reserve(size_type n);
|
||||
```
|
||||
|
||||
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
|
||||
|
||||
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
[horizontal]
|
||||
|
@ -1345,7 +1345,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
|
||||
void rehash(size_type n);
|
||||
```
|
||||
|
||||
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
||||
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
@ -1359,6 +1361,10 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
void reserve(size_type n);
|
||||
```
|
||||
|
||||
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
|
||||
|
||||
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
[horizontal]
|
||||
|
@ -1306,7 +1306,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
|
||||
void rehash(size_type n);
|
||||
```
|
||||
|
||||
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
||||
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
@ -1320,11 +1322,16 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
void reserve(size_type n);
|
||||
```
|
||||
|
||||
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
|
||||
|
||||
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
[horizontal]
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
|
||||
---
|
||||
|
||||
=== Equality Comparisons
|
||||
|
@ -1329,7 +1329,9 @@ Effects:;; Changes the container's maximum load factor, using `z` as a hint.
|
||||
void rehash(size_type n);
|
||||
```
|
||||
|
||||
Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
||||
Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
@ -1343,11 +1345,16 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
void reserve(size_type n);
|
||||
```
|
||||
|
||||
Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits<float>::infinity()`.
|
||||
|
||||
Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container.
|
||||
|
||||
Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated.
|
||||
|
||||
[horizontal]
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
@ -494,11 +494,33 @@ namespace boost {
|
||||
group_pointer groups;
|
||||
|
||||
public:
|
||||
static std::size_t bucket_count_for(std::size_t num_buckets)
|
||||
{
|
||||
if (num_buckets == 0) {
|
||||
return 0;
|
||||
}
|
||||
return size_policy::size(size_policy::size_index(num_buckets));
|
||||
}
|
||||
|
||||
grouped_bucket_array()
|
||||
: empty_value<node_allocator_type>(
|
||||
empty_init_t(), node_allocator_type()),
|
||||
size_index_(0), size_(0), buckets(), groups()
|
||||
{
|
||||
}
|
||||
|
||||
grouped_bucket_array(size_type n, const Allocator& al)
|
||||
: empty_value<node_allocator_type>(empty_init_t(), al),
|
||||
size_index_(size_policy::size_index(n)),
|
||||
size_(size_policy::size(size_index_)), buckets(), groups()
|
||||
size_index_(0),
|
||||
size_(0), buckets(), groups()
|
||||
{
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_index_ = size_policy::size_index(n);
|
||||
size_ = size_policy::size(size_index_);
|
||||
|
||||
bucket_allocator_type bucket_alloc = this->get_bucket_allocator();
|
||||
group_allocator_type group_alloc = this->get_group_allocator();
|
||||
|
||||
@ -646,7 +668,7 @@ namespace boost {
|
||||
|
||||
size_type bucket_count() const { return size_; }
|
||||
|
||||
iterator begin() const { return ++at(size_); }
|
||||
iterator begin() const { return size_ == 0 ? end() : ++at(size_); }
|
||||
|
||||
iterator end() const
|
||||
{
|
||||
@ -660,6 +682,10 @@ namespace boost {
|
||||
|
||||
local_iterator begin(size_type n) const
|
||||
{
|
||||
if (size_ == 0) {
|
||||
return this->end(n);
|
||||
}
|
||||
|
||||
return local_iterator(
|
||||
(buckets + static_cast<difference_type>(n))->next);
|
||||
}
|
||||
@ -670,12 +696,16 @@ namespace boost {
|
||||
|
||||
iterator at(size_type n) const
|
||||
{
|
||||
std::size_t const N = group::N;
|
||||
if (size_ > 0) {
|
||||
std::size_t const N = group::N;
|
||||
|
||||
iterator pbg(buckets + static_cast<difference_type>(n),
|
||||
groups + static_cast<difference_type>(n / N));
|
||||
iterator pbg(buckets + static_cast<difference_type>(n),
|
||||
groups + static_cast<difference_type>(n / N));
|
||||
|
||||
return pbg;
|
||||
return pbg;
|
||||
} else {
|
||||
return this->end();
|
||||
}
|
||||
}
|
||||
|
||||
span<Bucket> raw()
|
||||
|
@ -200,7 +200,7 @@ namespace boost {
|
||||
template <typename Types> struct table;
|
||||
|
||||
static const float minimum_max_load_factor = 1e-3f;
|
||||
static const std::size_t default_bucket_count = 11;
|
||||
static const std::size_t default_bucket_count = 0;
|
||||
|
||||
struct move_tag
|
||||
{
|
||||
@ -2054,12 +2054,14 @@ namespace boost {
|
||||
|
||||
std::size_t bucket_size(std::size_t index) const
|
||||
{
|
||||
bucket_iterator itb = buckets_.at(index);
|
||||
node_pointer n = itb->next;
|
||||
std::size_t count = 0;
|
||||
while (n) {
|
||||
++count;
|
||||
n = n->next;
|
||||
if (size_ > 0) {
|
||||
bucket_iterator itb = buckets_.at(index);
|
||||
node_pointer n = itb->next;
|
||||
while (n) {
|
||||
++count;
|
||||
n = n->next;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@ -2069,13 +2071,18 @@ namespace boost {
|
||||
|
||||
void recalculate_max_load()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// Only resize when size >= mlf_ * count
|
||||
max_load_ = boost::unordered::detail::double_to_size(
|
||||
floor(static_cast<double>(mlf_) *
|
||||
static_cast<double>(buckets_.bucket_count())));
|
||||
std::size_t const bc = buckets_.bucket_count();
|
||||
|
||||
// it's important we do the `bc == 0` check here because the `mlf_`
|
||||
// can be specified to be infinity. The operation `n * INF` is `INF`
|
||||
// for all `n > 0` but NaN for `n == 0`.
|
||||
//
|
||||
max_load_ =
|
||||
bc == 0 ? 0
|
||||
: boost::unordered::detail::double_to_size(
|
||||
static_cast<double>(mlf_) * static_cast<double>(bc));
|
||||
}
|
||||
|
||||
void max_load_factor(float z)
|
||||
@ -2088,6 +2095,12 @@ namespace boost {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
table()
|
||||
: functions(hasher(), key_equal()), size_(0), mlf_(1.0f),
|
||||
max_load_(0)
|
||||
{
|
||||
}
|
||||
|
||||
table(std::size_t num_buckets, hasher const& hf, key_equal const& eq,
|
||||
node_allocator_type const& a)
|
||||
: functions(hf, eq), size_(0), mlf_(1.0f), max_load_(0),
|
||||
@ -2359,7 +2372,6 @@ namespace boost {
|
||||
template <typename UniqueType>
|
||||
void move_assign(table& x, UniqueType is_unique, false_type)
|
||||
{
|
||||
reserve(x.size_);
|
||||
if (node_alloc() == x.node_alloc()) {
|
||||
move_assign_equal_alloc(x);
|
||||
} else {
|
||||
@ -2388,7 +2400,9 @@ namespace boost {
|
||||
{
|
||||
mlf_ = x.mlf_;
|
||||
recalculate_max_load();
|
||||
this->reserve_for_insert(x.size_);
|
||||
if (x.size_ > 0) {
|
||||
this->reserve_for_insert(x.size_);
|
||||
}
|
||||
this->clear_impl();
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
@ -2420,11 +2434,14 @@ namespace boost {
|
||||
node_pointer find_node_impl(
|
||||
Key const& x, bucket_iterator itb) const
|
||||
{
|
||||
key_equal const& pred = this->key_eq();
|
||||
node_pointer p = itb->next;
|
||||
for (; p; p = p->next) {
|
||||
if (pred(x, extractor::extract(p->value()))) {
|
||||
break;
|
||||
node_pointer p = node_pointer();
|
||||
if (itb != buckets_.end()) {
|
||||
key_equal const& pred = this->key_eq();
|
||||
p = itb->next;
|
||||
for (; p; p = p->next) {
|
||||
if (pred(x, extractor::extract(p->value()))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
@ -2453,11 +2470,13 @@ namespace boost {
|
||||
inline iterator transparent_find(
|
||||
Key const& k, Hash const& h, Pred const& pred) const
|
||||
{
|
||||
std::size_t const key_hash = h(k);
|
||||
bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
|
||||
for (node_pointer p = itb->next; p; p = p->next) {
|
||||
if (BOOST_LIKELY(pred(k, extractor::extract(p->value())))) {
|
||||
return iterator(p, itb);
|
||||
if (size_ > 0) {
|
||||
std::size_t const key_hash = h(k);
|
||||
bucket_iterator itb = buckets_.at(buckets_.position(key_hash));
|
||||
for (node_pointer p = itb->next; p; p = p->next) {
|
||||
if (BOOST_LIKELY(pred(k, extractor::extract(p->value())))) {
|
||||
return iterator(p, itb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2467,11 +2486,13 @@ namespace boost {
|
||||
template <class Key>
|
||||
node_pointer* find_prev(Key const& key, bucket_iterator itb)
|
||||
{
|
||||
key_equal pred = this->key_eq();
|
||||
for (node_pointer* pp = boost::addressof(itb->next); *pp;
|
||||
pp = boost::addressof((*pp)->next)) {
|
||||
if (pred(key, extractor::extract((*pp)->value()))) {
|
||||
return pp;
|
||||
if (size_ > 0) {
|
||||
key_equal pred = this->key_eq();
|
||||
for (node_pointer* pp = boost::addressof(itb->next); *pp;
|
||||
pp = boost::addressof((*pp)->next)) {
|
||||
if (pred(key, extractor::extract((*pp)->value()))) {
|
||||
return pp;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef node_pointer* node_pointer_pointer;
|
||||
@ -2503,6 +2524,17 @@ namespace boost {
|
||||
new_buckets.insert_node(itnewb, p);
|
||||
}
|
||||
|
||||
static std::size_t min_buckets(std::size_t num_elements, float mlf)
|
||||
{
|
||||
std::size_t num_buckets = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<float>(num_elements) / mlf));
|
||||
|
||||
if (num_buckets == 0 && num_elements > 0) { // mlf == inf
|
||||
num_buckets = 1;
|
||||
}
|
||||
return num_buckets;
|
||||
}
|
||||
|
||||
void rehash(std::size_t);
|
||||
void reserve(std::size_t);
|
||||
void reserve_for_insert(std::size_t);
|
||||
@ -3411,22 +3443,18 @@ namespace boost {
|
||||
template <typename Types>
|
||||
inline void table<Types>::rehash(std::size_t num_buckets)
|
||||
{
|
||||
std::size_t bc = (std::max)(num_buckets,
|
||||
static_cast<std::size_t>(1.0f + static_cast<float>(size_) / mlf_));
|
||||
num_buckets = (std::max)(
|
||||
min_buckets(size_, mlf_), buckets_.bucket_count_for(num_buckets));
|
||||
|
||||
if (bc <= buckets_.bucket_count()) {
|
||||
return;
|
||||
if (num_buckets != this->bucket_count()) {
|
||||
this->rehash_impl(num_buckets);
|
||||
}
|
||||
|
||||
this->rehash_impl(bc);
|
||||
}
|
||||
|
||||
template <class Types>
|
||||
inline void table<Types>::reserve(std::size_t num_elements)
|
||||
{
|
||||
std::size_t const num_buckets = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<float>(num_elements) / mlf_));
|
||||
|
||||
std::size_t num_buckets = min_buckets(num_elements, mlf_);
|
||||
this->rehash(num_buckets);
|
||||
}
|
||||
|
||||
|
@ -1664,8 +1664,6 @@ namespace boost {
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_map<K, T, H, P, A>::unordered_map()
|
||||
: table_(boost::unordered::detail::default_bucket_count, hasher(),
|
||||
key_equal(), allocator_type())
|
||||
{
|
||||
}
|
||||
|
||||
@ -2069,6 +2067,10 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
float unordered_map<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
if (table_.size_ == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count());
|
||||
@ -2143,8 +2145,6 @@ namespace boost {
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_multimap<K, T, H, P, A>::unordered_multimap()
|
||||
: table_(boost::unordered::detail::default_bucket_count, hasher(),
|
||||
key_equal(), allocator_type())
|
||||
{
|
||||
}
|
||||
|
||||
@ -2506,6 +2506,10 @@ namespace boost {
|
||||
template <class K, class T, class H, class P, class A>
|
||||
float unordered_multimap<K, T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
if (table_.size_ == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count());
|
||||
|
@ -1266,8 +1266,6 @@ namespace boost {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_set<T, H, P, A>::unordered_set()
|
||||
: table_(boost::unordered::detail::default_bucket_count, hasher(),
|
||||
key_equal(), allocator_type())
|
||||
{
|
||||
}
|
||||
|
||||
@ -1586,6 +1584,10 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
float unordered_set<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
if (table_.size_ == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count());
|
||||
@ -1660,8 +1662,6 @@ namespace boost {
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_multiset<T, H, P, A>::unordered_multiset()
|
||||
: table_(boost::unordered::detail::default_bucket_count, hasher(),
|
||||
key_equal(), allocator_type())
|
||||
{
|
||||
}
|
||||
|
||||
@ -1986,6 +1986,10 @@ namespace boost {
|
||||
template <class T, class H, class P, class A>
|
||||
float unordered_multiset<T, H, P, A>::load_factor() const BOOST_NOEXCEPT
|
||||
{
|
||||
if (table_.size_ == 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(table_.bucket_count() != 0);
|
||||
return static_cast<float>(table_.size_) /
|
||||
static_cast<float>(table_.bucket_count());
|
||||
|
@ -95,7 +95,7 @@ void insert_rehash_exception_test(
|
||||
T*, Inserter insert, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
T x(1);
|
||||
rehash_prep(x);
|
||||
|
||||
test::random_values<T> v2(5, gen);
|
||||
@ -393,7 +393,7 @@ template <typename T>
|
||||
void insert_range_rehash_exception_test(T*, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
T x(1);
|
||||
rehash_prep(x);
|
||||
|
||||
test::random_values<T> v2(5, gen);
|
||||
|
@ -45,6 +45,7 @@ namespace assign_tests {
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
|
||||
@ -94,6 +95,7 @@ namespace assign_tests {
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_container(x1, x2);
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace constructor_tests {
|
||||
|
||||
T x(0, hf, eq);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
@ -73,6 +74,7 @@ namespace constructor_tests {
|
||||
|
||||
T x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
@ -140,6 +142,7 @@ namespace constructor_tests {
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
@ -166,6 +169,7 @@ namespace constructor_tests {
|
||||
|
||||
T x(al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
@ -325,6 +329,7 @@ namespace constructor_tests {
|
||||
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
@ -380,6 +385,104 @@ namespace constructor_tests {
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void no_alloc_default_construct_test(T*, test::random_generator)
|
||||
{
|
||||
UNORDERED_SUB_TEST("Construct 1")
|
||||
{
|
||||
T x;
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 2")
|
||||
{
|
||||
{
|
||||
T x(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
T x(1);
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 3")
|
||||
{
|
||||
test::random_values<T> v;
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 4")
|
||||
{
|
||||
{
|
||||
test::random_values<T> v;
|
||||
T x(v.begin(), v.end(), 0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v;
|
||||
T x(v.begin(), v.end(), 1);
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 5")
|
||||
{
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
T x(al);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 6")
|
||||
{
|
||||
typename T::allocator_type al;
|
||||
|
||||
T x(0, al);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
UNORDERED_SUB_TEST("Initializer list 1")
|
||||
{
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
T x(list);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list 2")
|
||||
{
|
||||
{
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
T x(list, 0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
T x(list, 1);
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T*, test::random_generator const& generator)
|
||||
{
|
||||
@ -422,6 +525,10 @@ namespace constructor_tests {
|
||||
((test_map_std_alloc)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(no_alloc_default_construct_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST (test_default_initializer_list) {
|
||||
|
@ -43,6 +43,23 @@ namespace copy_tests {
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
@ -91,6 +108,22 @@ namespace copy_tests {
|
||||
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -106,6 +139,21 @@ namespace copy_tests {
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -120,6 +168,22 @@ namespace copy_tests {
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -135,6 +199,21 @@ namespace copy_tests {
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <iterator>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
@ -70,6 +73,10 @@ namespace move_tests {
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(y.max_load_factor() == 1.0);
|
||||
test::check_equivalent_keys(y);
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
@ -87,7 +94,7 @@ namespace move_tests {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_assign_tests1(T*, test::random_generator const& generator)
|
||||
void move_assign_tests1(T* p, test::random_generator const& generator)
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
@ -98,6 +105,19 @@ namespace move_tests {
|
||||
y = create(v, count);
|
||||
#if BOOST_UNORDERED_TEST_MOVING && defined(BOOST_HAS_NRVO)
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v;
|
||||
|
||||
T y;
|
||||
y = empty(p);
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
@ -233,6 +253,32 @@ namespace move_tests {
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<T> v;
|
||||
T y(0, hf, eq, al1);
|
||||
T x(0, hf, eq, al2);
|
||||
x.max_load_factor(0.25);
|
||||
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
y = boost::move(x);
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(y.max_load_factor() == 0.25);
|
||||
|
||||
if (BOOST_UNORDERED_TEST_MOVING
|
||||
? (bool)allocator_type::is_propagate_on_move
|
||||
: (bool)allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -298,17 +344,533 @@ namespace move_tests {
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> T const& get_key(T const& t) { return t; }
|
||||
|
||||
template <class K, class V> K const& get_key(std::pair<K const, V> const& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
template <class T> T const& get_value(T const& t) { return t; }
|
||||
|
||||
template <class K, class V> K const& get_value(std::pair<K const, V> const& kv)
|
||||
{
|
||||
return kv.second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void insert_range(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
y.insert(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void insert_single(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
y.insert(*v.begin());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void insert_single_hint(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
y.insert(y.end(), *v.begin());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> struct insert_or_assign_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct insert_or_assign_invoker<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
|
||||
Allocator>::size_type size_type;
|
||||
|
||||
y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin()));
|
||||
BOOST_TEST_EQ(
|
||||
y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void insert_or_assign(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
insert_or_assign_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> struct insert_or_assign_hint_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct insert_or_assign_hint_invoker<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
|
||||
Allocator>::size_type size_type;
|
||||
y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin()));
|
||||
BOOST_TEST_EQ(
|
||||
y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void insert_or_assign_hint(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
insert_or_assign_hint_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> struct try_emplace_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct try_emplace_invoker<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
|
||||
Allocator>::size_type size_type;
|
||||
y.try_emplace(get_key(*v.begin()), get_value(*v.begin()));
|
||||
BOOST_TEST_EQ(
|
||||
y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void try_emplace(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
try_emplace_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> struct try_emplace_hint_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct try_emplace_hint_invoker<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
|
||||
Allocator>::size_type size_type;
|
||||
y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin()));
|
||||
BOOST_TEST_EQ(
|
||||
y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void try_emplace_hint(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
try_emplace_hint_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> struct at_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct at_invoker<boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
BOOST_TRY { y.at(get_key(*v.begin())); }
|
||||
BOOST_CATCH(...) {}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> static void at(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
at_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> struct index_operator_invoker
|
||||
{
|
||||
void operator()(T&, test::random_values<T> const&) {}
|
||||
};
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct index_operator_invoker<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
|
||||
{
|
||||
void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
|
||||
test::random_values<
|
||||
boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
|
||||
{
|
||||
typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
|
||||
Allocator>::size_type size_type;
|
||||
y[get_key(*v.begin())] = get_value(*v.begin());
|
||||
BOOST_TEST_EQ(
|
||||
y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void index_operator(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
index_operator_invoker<T>()(y, v);
|
||||
}
|
||||
|
||||
template <class T> static void clear(T& y, test::random_values<T> const&)
|
||||
{
|
||||
y.clear();
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void capacity(T& y, test::random_values<T> const&)
|
||||
{
|
||||
(void)y.empty();
|
||||
(void)y.size();
|
||||
(void)y.max_size();
|
||||
(void)y.load_factor();
|
||||
(void)y.max_load_factor();
|
||||
(void)y.hash_function();
|
||||
(void)y.key_eq();
|
||||
(void)y.get_allocator();
|
||||
}
|
||||
|
||||
template <class T> static void iterators(T& y, test::random_values<T> const&)
|
||||
{
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void erase_range(T& y, test::random_values<T> const&)
|
||||
{
|
||||
y.erase(y.begin(), y.end());
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void erase_key(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
y.erase(get_key(*v.begin()));
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void lookup(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
(void)y.count(get_key(*v.begin()));
|
||||
(void)y.find(get_key(*v.begin()));
|
||||
(void)y.contains(get_key(*v.begin()));
|
||||
(void)y.equal_range(get_key(*v.begin()));
|
||||
}
|
||||
|
||||
template <class T> static void reserve(T& y, test::random_values<T> const&)
|
||||
{
|
||||
y.reserve(1337);
|
||||
BOOST_TEST_GT(y.bucket_count(), 1337u);
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void copy_assignment(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
T x(v.begin(), v.end());
|
||||
y = x;
|
||||
BOOST_TEST_EQ(y.size(), x.size());
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void move_assignment(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
T x(v.begin(), v.end());
|
||||
std::size_t const size = x.size();
|
||||
y = boost::move(x);
|
||||
BOOST_TEST_GE(y.size(), size);
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void equal(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
T x(v.begin(), v.end());
|
||||
(void)(y == x);
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void extract(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
(void)y.extract(get_key(*v.begin()));
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void merge(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
T x(v.begin(), v.end());
|
||||
if (y.get_allocator() == x.get_allocator()) {
|
||||
y.merge(x);
|
||||
}
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class X> bool pred(X const&) { return true; }
|
||||
|
||||
template <class T>
|
||||
static void erase_with_pred(T& y, test::random_values<T> const&)
|
||||
{
|
||||
erase_if(y, pred<typename T::value_type>);
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void container_swap(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
T x(v.begin(), v.end());
|
||||
if (boost::allocator_propagate_on_container_swap<
|
||||
typename T::allocator_type>::type::value ||
|
||||
x.get_allocator() == y.get_allocator()) {
|
||||
y.swap(x);
|
||||
}
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
template <class T> static void buckets(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
(void)y.begin(0);
|
||||
(void)y.end(0);
|
||||
(void)y.bucket_count();
|
||||
(void)y.max_bucket_count();
|
||||
(void)y.bucket_size(0);
|
||||
(void)y.bucket(get_key(*v.begin()));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void double_move_construct(T& y, test::random_values<T> const&)
|
||||
{
|
||||
T x = boost::move(y);
|
||||
x.clear();
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
BOOST_TEST_EQ(x.size(),
|
||||
static_cast<typename T::size_type>(std::distance(x.begin(), x.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void double_move_assign(T& y, test::random_values<T> const&)
|
||||
{
|
||||
T x;
|
||||
x = boost::move(y);
|
||||
x.clear();
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
BOOST_TEST_EQ(x.size(),
|
||||
static_cast<typename T::size_type>(std::distance(x.begin(), x.end())));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void post_move_tests(T* ptr, test::random_generator const& generator)
|
||||
{
|
||||
// clang-format off
|
||||
void (*fps[])(T&, test::random_values<T> const&) = {
|
||||
insert_range<T>,
|
||||
insert_single<T>,
|
||||
insert_single_hint<T>,
|
||||
insert_or_assign<T>,
|
||||
insert_or_assign_hint<T>,
|
||||
try_emplace<T>,
|
||||
try_emplace_hint<T>,
|
||||
at<T>,
|
||||
index_operator<T>,
|
||||
clear<T>,
|
||||
capacity<T>,
|
||||
iterators<T>,
|
||||
erase_range<T>,
|
||||
erase_key<T>,
|
||||
lookup<T>,
|
||||
reserve<T>,
|
||||
copy_assignment<T>,
|
||||
move_assignment<T>,
|
||||
equal<T>,
|
||||
extract<T>,
|
||||
merge<T>,
|
||||
erase_with_pred<T>,
|
||||
container_swap<T>,
|
||||
buckets<T>,
|
||||
double_move_construct<T>,
|
||||
double_move_assign<T>
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
std::size_t const len = (sizeof(fps) / sizeof(*(fps)));
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> const v(1000, generator);
|
||||
test::object_count count;
|
||||
T y(create(v, count));
|
||||
|
||||
unsigned num_allocs = test::detail::tracker.count_allocations;
|
||||
(void)num_allocs;
|
||||
|
||||
T x(boost::move(y));
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(y.begin() == y.end());
|
||||
BOOST_TEST_EQ(y.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
|
||||
#endif
|
||||
|
||||
fps[i](y, v);
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
typename T::hasher hf(1);
|
||||
typename T::key_equal eq(1);
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::object_count count;
|
||||
T y(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T x(boost::move(y), al2);
|
||||
|
||||
BOOST_TEST_NOT(y.empty());
|
||||
BOOST_TEST(y.begin() != y.end());
|
||||
|
||||
fps[i](y, v);
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::object_count count;
|
||||
T y(create(v, count));
|
||||
|
||||
unsigned num_allocs = test::detail::tracker.count_allocations;
|
||||
(void)num_allocs;
|
||||
|
||||
T x(empty(ptr));
|
||||
x = boost::move(y);
|
||||
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(y.begin() == y.end());
|
||||
BOOST_TEST_EQ(y.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
|
||||
#endif
|
||||
|
||||
fps[i](y, v);
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
typename T::hasher hf(1);
|
||||
typename T::key_equal eq(1);
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::object_count count;
|
||||
T y(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
|
||||
unsigned num_allocs = test::detail::tracker.count_allocations;
|
||||
(void)num_allocs;
|
||||
|
||||
T x(al2);
|
||||
x = boost::move(y);
|
||||
|
||||
bool b = boost::allocator_propagate_on_container_move_assignment<
|
||||
typename T::allocator_type>::type::value;
|
||||
if (b) {
|
||||
#if defined(BOOST_UNORDERED_USE_MOVE) || \
|
||||
!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(y.begin() == y.end());
|
||||
BOOST_TEST_EQ(y.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
|
||||
#else
|
||||
BOOST_TEST_NOT(y.empty());
|
||||
BOOST_TEST(y.begin() != y.end());
|
||||
|
||||
#endif
|
||||
} else {
|
||||
BOOST_TEST_NOT(y.empty());
|
||||
BOOST_TEST(y.begin() != y.end());
|
||||
}
|
||||
|
||||
fps[i](y, v);
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
std::allocator<std::pair<test::object const, test::object> > >*
|
||||
test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator1<std::pair<test::object const, test::object> > >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
test::equal_to,
|
||||
test::allocator2<std::pair<test::object const, test::object> > >*
|
||||
test_multimap;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
@ -317,11 +879,12 @@ namespace move_tests {
|
||||
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
test_multiset_prop_move;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
test_map_prop_move;
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::propagate_move> >* test_map_prop_move;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
test_multimap_prop_move;
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::propagate_move> >* test_multimap_prop_move;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
@ -330,12 +893,12 @@ namespace move_tests {
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
test_multiset_no_prop_move;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
test_map_no_prop_move;
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_map_no_prop_move;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
test_multimap_no_prop_move;
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_multimap_no_prop_move;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
@ -367,6 +930,12 @@ namespace move_tests {
|
||||
test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(
|
||||
test_multimap_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(post_move_tests,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)(
|
||||
test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)(
|
||||
test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(
|
||||
test_multimap_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -11,6 +11,7 @@
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/fwd.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
@ -247,37 +248,65 @@ namespace noexcept_tests {
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_nothrow_move_assign_when_noexcept) {
|
||||
typedef boost::unordered_set<int, hash_nothrow_move_assign,
|
||||
equal_to_nothrow_move_assign>
|
||||
throwing_set;
|
||||
template <class T>
|
||||
void test_nothrow_move_assign_when_noexcept(T*, test::random_generator const&)
|
||||
{
|
||||
{
|
||||
if (have_is_nothrow_move_assign) {
|
||||
BOOST_TEST(boost::is_nothrow_move_assignable<T>::value);
|
||||
}
|
||||
|
||||
if (have_is_nothrow_move_assign) {
|
||||
BOOST_TEST(boost::is_nothrow_move_assignable<throwing_set>::value);
|
||||
throwing_test_exception = false;
|
||||
|
||||
T x1;
|
||||
T x2;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
x2.insert(i);
|
||||
}
|
||||
|
||||
try {
|
||||
throwing_test_exception = true;
|
||||
|
||||
x2 = boost::move(x1);
|
||||
BOOST_TEST(x2.size() == 2);
|
||||
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
|
||||
BOOST_TEST(have_is_nothrow_move_assign);
|
||||
} catch (test_exception) {
|
||||
BOOST_TEST(!have_is_nothrow_move_assign);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
{
|
||||
if (have_is_nothrow_move_assign) {
|
||||
BOOST_TEST(boost::is_nothrow_move_assignable<T>::value);
|
||||
}
|
||||
|
||||
throwing_set x1;
|
||||
throwing_set x2;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
x2.insert(i);
|
||||
throwing_test_exception = false;
|
||||
|
||||
T x1;
|
||||
T x2;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
x2.insert(i);
|
||||
}
|
||||
|
||||
try {
|
||||
throwing_test_exception = true;
|
||||
|
||||
x1 = boost::move(x2);
|
||||
BOOST_TEST(x1.size() == 100);
|
||||
BOOST_TEST(have_is_nothrow_move_assign);
|
||||
} catch (test_exception) {
|
||||
BOOST_TEST(!have_is_nothrow_move_assign);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
|
||||
try {
|
||||
throwing_test_exception = true;
|
||||
|
||||
x2 = boost::move(x1);
|
||||
BOOST_TEST(x2.size() == 2);
|
||||
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
|
||||
BOOST_TEST(have_is_nothrow_move_assign);
|
||||
} catch (test_exception) {
|
||||
BOOST_TEST(!have_is_nothrow_move_assign);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) {
|
||||
@ -318,4 +347,80 @@ namespace noexcept_tests {
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class T> class allocator1
|
||||
{
|
||||
BOOST_COPYABLE_AND_MOVABLE(allocator1)
|
||||
allocator1 operator=(BOOST_COPY_ASSIGN_REF(allocator1));
|
||||
allocator1 operator=(BOOST_RV_REF(allocator1));
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
allocator1() {}
|
||||
allocator1(allocator1 const&) {}
|
||||
|
||||
template <class U> allocator1(allocator1<U> const&) {}
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
noexcept_tests::test_throw("Allocate");
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||
|
||||
friend bool operator==(allocator1 const&, allocator1 const&) { return true; }
|
||||
friend bool operator!=(allocator1 const&, allocator1 const&) { return false; }
|
||||
};
|
||||
|
||||
template <class T> class allocator2
|
||||
{
|
||||
BOOST_COPYABLE_AND_MOVABLE(allocator2)
|
||||
allocator2 operator=(BOOST_COPY_ASSIGN_REF(allocator2));
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef boost::true_type propagate_on_container_move_assignment;
|
||||
|
||||
allocator2() {}
|
||||
allocator2(allocator2 const&) {}
|
||||
|
||||
template <class U> allocator2(allocator2<U> const&) {}
|
||||
|
||||
allocator2& operator=(BOOST_RV_REF(allocator2)) { return *this; }
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
noexcept_tests::test_throw("Allocate");
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||
|
||||
friend bool operator==(allocator2 const&, allocator2 const&) { return true; }
|
||||
friend bool operator!=(allocator2 const&, allocator2 const&) { return false; }
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (prelim_allocator_checks) {
|
||||
BOOST_TEST(boost::allocator_is_always_equal<allocator1<int> >::type::value);
|
||||
BOOST_TEST(!boost::allocator_propagate_on_container_move_assignment<
|
||||
allocator1<int> >::type::value);
|
||||
|
||||
BOOST_TEST(boost::allocator_is_always_equal<allocator2<int> >::type::value);
|
||||
BOOST_TEST(boost::allocator_propagate_on_container_move_assignment<
|
||||
allocator2<int> >::type::value);
|
||||
}
|
||||
|
||||
boost::unordered_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator1<int> >*
|
||||
throwing_set_alloc1;
|
||||
|
||||
boost::unordered_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator2<int> >*
|
||||
throwing_set_alloc2;
|
||||
|
||||
using test::default_generator;
|
||||
|
||||
UNORDERED_TEST(test_nothrow_move_assign_when_noexcept,
|
||||
((throwing_set_alloc1)(throwing_set_alloc2))((default_generator)))
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -81,6 +81,300 @@ namespace rehash_tests {
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
}
|
||||
|
||||
template <class X> void rehash_empty_tracking(X*, test::random_generator)
|
||||
{
|
||||
// valid for all load factors
|
||||
float const max_load_factors[] = {
|
||||
0.5f, 1.0f, 1e6f, std::numeric_limits<float>::infinity()};
|
||||
|
||||
std::size_t const max_load_factors_len =
|
||||
sizeof(max_load_factors) / sizeof(*max_load_factors);
|
||||
|
||||
for (std::size_t i = 0; i < max_load_factors_len; ++i) {
|
||||
X x;
|
||||
BOOST_TEST_EQ(x.size(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.max_load_factor(max_load_factors[i]);
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.rehash(1000);
|
||||
BOOST_TEST_GE(x.bucket_count(), 1000u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.rehash(1000);
|
||||
BOOST_TEST_GE(x.bucket_count(), 1000u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.rehash(10);
|
||||
BOOST_TEST_GE(x.bucket_count(), 10u);
|
||||
BOOST_TEST_LT(x.bucket_count(), 1000u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST_LT(x.bucket_count(), 1000u);
|
||||
|
||||
x.rehash(1000);
|
||||
BOOST_TEST_GE(x.bucket_count(), 1000u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < max_load_factors_len; ++i) {
|
||||
typedef typename X::size_type size_type;
|
||||
|
||||
X x;
|
||||
BOOST_TEST_EQ(x.size(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
float const mlf = max_load_factors[i];
|
||||
x.max_load_factor(mlf);
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(1000);
|
||||
BOOST_TEST_GE(
|
||||
x.bucket_count(), static_cast<size_type>(std::ceil(1000 / mlf)));
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.reserve(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(1000);
|
||||
BOOST_TEST_GE(
|
||||
x.bucket_count(), static_cast<size_type>(std::ceil(1000 / mlf)));
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.reserve(10);
|
||||
BOOST_TEST_GE(
|
||||
x.bucket_count(), static_cast<size_type>(std::ceil(10 / mlf)));
|
||||
BOOST_TEST_LT(x.bucket_count(), 1000u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST_LT(x.bucket_count(), 1000u);
|
||||
|
||||
x.reserve(1000);
|
||||
BOOST_TEST_GE(
|
||||
x.bucket_count(), static_cast<size_type>(std::ceil(1000 / mlf)));
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.reserve(0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST_EQ(test::detail::tracker.count_allocations, 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_nonempty_tracking(X*, test::random_generator generator)
|
||||
{
|
||||
test::random_values<X> const v(1000, generator);
|
||||
|
||||
typedef typename X::size_type size_type;
|
||||
|
||||
float const max_load_factors[] = {0.5f, 1.0f, 1e2f};
|
||||
|
||||
size_type const max_load_factors_len =
|
||||
sizeof(max_load_factors) / sizeof(*max_load_factors);
|
||||
|
||||
for (size_type i = 0; i < max_load_factors_len; ++i) {
|
||||
float const mlf = max_load_factors[i];
|
||||
|
||||
X x(v.begin(), v.end());
|
||||
BOOST_TEST_GT(x.size(), 0u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
x.max_load_factor(mlf);
|
||||
|
||||
size_type bucket_count = x.bucket_count();
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST_GE(x.bucket_count(),
|
||||
static_cast<size_type>(
|
||||
std::floor(static_cast<float>(x.size()) / x.max_load_factor())));
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(bucket_count, 0u);
|
||||
|
||||
x.rehash(2 * x.bucket_count());
|
||||
BOOST_TEST_GT(x.bucket_count(), bucket_count);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
}
|
||||
|
||||
{
|
||||
float const old_mlf = x.max_load_factor();
|
||||
|
||||
BOOST_TEST_GT(bucket_count, 0u);
|
||||
|
||||
x.rehash(bucket_count / 4);
|
||||
BOOST_TEST_LT(x.bucket_count(), bucket_count);
|
||||
|
||||
x.max_load_factor(std::numeric_limits<float>::infinity());
|
||||
x.rehash(0);
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.max_load_factor(old_mlf);
|
||||
}
|
||||
|
||||
{
|
||||
std::size_t const max_load =
|
||||
static_cast<std::size_t>(static_cast<double>(x.max_load_factor()) *
|
||||
static_cast<double>(x.bucket_count()));
|
||||
|
||||
while (x.size() < max_load) {
|
||||
test::random_values<X> const t(max_load, generator);
|
||||
typename test::random_values<X>::const_iterator pos = t.begin();
|
||||
typename test::random_values<X>::const_iterator end = t.end();
|
||||
for (; pos != end; ++pos) {
|
||||
x.insert(*pos);
|
||||
if (x.size() == max_load) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (x.size() > max_load) {
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(x.size(), max_load);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
x.rehash(x.bucket_count());
|
||||
BOOST_TEST_EQ(x.bucket_count(), bucket_count);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_type i = 0; i < max_load_factors_len; ++i) {
|
||||
X x(v.begin(), v.end());
|
||||
BOOST_TEST_GT(x.size(), 0u);
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
float const mlf = max_load_factors[i];
|
||||
x.max_load_factor(mlf);
|
||||
|
||||
size_type bucket_count = x.bucket_count();
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(0);
|
||||
BOOST_TEST_GE(x.bucket_count(),
|
||||
static_cast<size_type>(
|
||||
std::floor(static_cast<float>(x.size()) / x.max_load_factor())));
|
||||
BOOST_TEST_GT(test::detail::tracker.count_allocations, 0u);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
}
|
||||
|
||||
{
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(
|
||||
2 * (static_cast<size_type>(
|
||||
std::floor(static_cast<float>(x.size()) / x.max_load_factor()) +
|
||||
std::floor(static_cast<float>(x.size()) * x.max_load_factor()))));
|
||||
|
||||
BOOST_TEST_GT(x.bucket_count(), bucket_count);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
BOOST_TEST_GT(bucket_count, 1u);
|
||||
}
|
||||
|
||||
{
|
||||
float const old_mlf = x.max_load_factor();
|
||||
|
||||
BOOST_TEST_GT(bucket_count, 4u);
|
||||
|
||||
x.reserve(bucket_count / 4);
|
||||
BOOST_TEST_LT(x.bucket_count(), bucket_count);
|
||||
|
||||
x.max_load_factor(std::numeric_limits<float>::infinity());
|
||||
x.reserve(0);
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.max_load_factor(old_mlf);
|
||||
}
|
||||
|
||||
{
|
||||
std::size_t const max_load =
|
||||
static_cast<std::size_t>(static_cast<double>(x.max_load_factor()) *
|
||||
static_cast<double>(x.bucket_count()));
|
||||
|
||||
while (x.size() < max_load) {
|
||||
test::random_values<X> const t(max_load, generator);
|
||||
typename test::random_values<X>::const_iterator pos = t.begin();
|
||||
typename test::random_values<X>::const_iterator end = t.end();
|
||||
for (; pos != end; ++pos) {
|
||||
x.insert(*pos);
|
||||
if (x.size() == max_load) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (x.size() > max_load) {
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(x.size(), max_load);
|
||||
|
||||
bucket_count = x.bucket_count();
|
||||
x.reserve(x.size());
|
||||
BOOST_TEST_EQ(x.bucket_count(), bucket_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class X> void rehash_test1(X*, test::random_generator generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
@ -199,6 +493,18 @@ namespace rehash_tests {
|
||||
test::allocator2<test::movable> >* test_map_ptr;
|
||||
boost::unordered_multimap<int, int>* int_multimap_ptr;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set_tracking;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset_tracking;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_map_tracking;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_multimap_tracking;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
@ -224,6 +530,12 @@ namespace rehash_tests {
|
||||
UNORDERED_TEST(reserve_test2,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_empty_tracking,
|
||||
((test_set_tracking)(test_multiset_tracking)(test_map_tracking)(test_multimap_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_nonempty_tracking,
|
||||
((test_set_tracking)(test_multiset_tracking)(test_map_tracking)(test_multimap_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -224,7 +224,7 @@ template <class C1, class C2> void scary_test()
|
||||
typename C2::const_iterator cbegin(x.cbegin());
|
||||
BOOST_TEST(cbegin == x.cend());
|
||||
|
||||
BOOST_ASSERT(x.bucket_count() > 0);
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
|
||||
typename C2::local_iterator lbegin(x.begin(0));
|
||||
BOOST_TEST(lbegin == x.end(0));
|
||||
|
Reference in New Issue
Block a user