mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
[libc++] Optimize copy construction and assignment of __tree (#151304)
``` ---------------------------------------------------------------------------------------------------------- Benchmark old new ---------------------------------------------------------------------------------------------------------- std::map<int, int>::ctor(const&)/0 15.5 ns 14.9 ns std::map<int, int>::ctor(const&)/32 474 ns 321 ns std::map<int, int>::ctor(const&)/1024 24591 ns 11101 ns std::map<int, int>::ctor(const&)/8192 236153 ns 98868 ns std::map<std::string, int>::ctor(const&)/0 15.2 ns 14.9 ns std::map<std::string, int>::ctor(const&)/32 2673 ns 2340 ns std::map<std::string, int>::ctor(const&)/1024 115354 ns 86088 ns std::map<std::string, int>::ctor(const&)/8192 1298510 ns 626876 ns std::map<int, int>::operator=(const&) (into cleared Container)/0 16.5 ns 16.1 ns std::map<int, int>::operator=(const&) (into cleared Container)/32 548 ns 323 ns std::map<int, int>::operator=(const&) (into cleared Container)/1024 28418 ns 11026 ns std::map<int, int>::operator=(const&) (into cleared Container)/8192 281827 ns 97113 ns std::map<int, int>::operator=(const&) (into populated Container)/0 2.42 ns 1.85 ns std::map<int, int>::operator=(const&) (into populated Container)/32 369 ns 73.0 ns std::map<int, int>::operator=(const&) (into populated Container)/1024 24078 ns 2322 ns std::map<int, int>::operator=(const&) (into populated Container)/8192 266537 ns 22963 ns std::map<std::string, int>::operator=(const&) (into cleared Container)/0 16.6 ns 16.2 ns std::map<std::string, int>::operator=(const&) (into cleared Container)/32 2614 ns 1622 ns std::map<std::string, int>::operator=(const&) (into cleared Container)/1024 116826 ns 63281 ns std::map<std::string, int>::operator=(const&) (into cleared Container)/8192 1316655 ns 649177 ns std::map<std::string, int>::operator=(const&) (into populated Container)/0 2.42 ns 1.89 ns std::map<std::string, int>::operator=(const&) (into populated Container)/32 1264 ns 581 ns std::map<std::string, int>::operator=(const&) (into populated Container)/1024 238826 ns 39943 ns std::map<std::string, int>::operator=(const&) (into populated Container)/8192 2412327 ns 379456 ns ``` Fixes #77658 Fixes #62571
This commit is contained in:
@@ -43,6 +43,9 @@ Implemented Papers
|
||||
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
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
|
||||
@@ -1213,6 +1213,104 @@ private:
|
||||
__node_pointer __cache_root_;
|
||||
__node_pointer __cache_elem_;
|
||||
};
|
||||
|
||||
class __tree_deleter {
|
||||
__node_allocator& __alloc_;
|
||||
|
||||
public:
|
||||
using pointer = __node_pointer;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI __tree_deleter(__node_allocator& __alloc) : __alloc_(__alloc) {}
|
||||
|
||||
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
#endif
|
||||
void
|
||||
operator()(__node_pointer __ptr) {
|
||||
if (!__ptr)
|
||||
return;
|
||||
|
||||
(*this)(static_cast<__node_pointer>(__ptr->__left_));
|
||||
|
||||
auto __right = __ptr->__right_;
|
||||
|
||||
__node_traits::destroy(__alloc_, std::addressof(__ptr->__value_));
|
||||
__node_traits::deallocate(__alloc_, __ptr, 1);
|
||||
|
||||
(*this)(static_cast<__node_pointer>(__right));
|
||||
}
|
||||
};
|
||||
|
||||
// This copy construction will always produce a correct red-black-tree assuming the incoming tree is correct, since we
|
||||
// copy the exact structure 1:1. Since this is for copy construction _only_ we know that we get a correct tree. If we
|
||||
// didn't get a correct tree, the invariants of __tree are broken and we have a much bigger problem than an improperly
|
||||
// balanced tree.
|
||||
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
#endif
|
||||
__node_pointer
|
||||
__copy_construct_tree(__node_pointer __src) {
|
||||
if (!__src)
|
||||
return nullptr;
|
||||
|
||||
__node_holder __new_node = __construct_node(__src->__value_);
|
||||
|
||||
unique_ptr<__node, __tree_deleter> __left(
|
||||
__copy_construct_tree(static_cast<__node_pointer>(__src->__left_)), __node_alloc_);
|
||||
__node_pointer __right = __copy_construct_tree(static_cast<__node_pointer>(__src->__right_));
|
||||
|
||||
__node_pointer __new_node_ptr = __new_node.release();
|
||||
|
||||
__new_node_ptr->__is_black_ = __src->__is_black_;
|
||||
__new_node_ptr->__left_ = static_cast<__node_base_pointer>(__left.release());
|
||||
__new_node_ptr->__right_ = static_cast<__node_base_pointer>(__right);
|
||||
if (__new_node_ptr->__left_)
|
||||
__new_node_ptr->__left_->__parent_ = static_cast<__end_node_pointer>(__new_node_ptr);
|
||||
if (__new_node_ptr->__right_)
|
||||
__new_node_ptr->__right_->__parent_ = static_cast<__end_node_pointer>(__new_node_ptr);
|
||||
return __new_node_ptr;
|
||||
}
|
||||
|
||||
// This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our
|
||||
// own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are
|
||||
// temporarily not met until all of the incoming red-black tree is copied.
|
||||
#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
#endif
|
||||
__node_pointer
|
||||
__copy_assign_tree(__node_pointer __dest, __node_pointer __src) {
|
||||
if (!__src) {
|
||||
destroy(__dest);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
__assign_value(__dest->__value_, __src->__value_);
|
||||
__dest->__is_black_ = __src->__is_black_;
|
||||
|
||||
// If we already have a left node in the destination tree, reuse it and copy-assign recursively
|
||||
if (__dest->__left_) {
|
||||
__dest->__left_ = static_cast<__node_base_pointer>(__copy_assign_tree(
|
||||
static_cast<__node_pointer>(__dest->__left_), static_cast<__node_pointer>(__src->__left_)));
|
||||
|
||||
// Otherwise, we must create new nodes; copy-construct from here on
|
||||
} else if (__src->__left_) {
|
||||
auto __new_left = __copy_construct_tree(static_cast<__node_pointer>(__src->__left_));
|
||||
__dest->__left_ = static_cast<__node_base_pointer>(__new_left);
|
||||
__new_left->__parent_ = static_cast<__end_node_pointer>(__dest);
|
||||
}
|
||||
|
||||
// Identical to the left case above, just for the right nodes
|
||||
if (__dest->__right_) {
|
||||
__dest->__right_ = static_cast<__node_base_pointer>(__copy_assign_tree(
|
||||
static_cast<__node_pointer>(__dest->__right_), static_cast<__node_pointer>(__src->__right_)));
|
||||
} else if (__src->__right_) {
|
||||
auto __new_right = __copy_construct_tree(static_cast<__node_pointer>(__src->__right_));
|
||||
__dest->__right_ = static_cast<__node_base_pointer>(__new_right);
|
||||
__new_right->__parent_ = static_cast<__end_node_pointer>(__dest);
|
||||
}
|
||||
|
||||
return __dest;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
@@ -1277,11 +1375,22 @@ __tree<_Tp, _Compare, _Allocator>::_DetachedTreeCache::__detach_next(__node_poin
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(const __tree& __t) {
|
||||
if (this != std::addressof(__t)) {
|
||||
value_comp() = __t.value_comp();
|
||||
__copy_assign_alloc(__t);
|
||||
__assign_multi(__t.begin(), __t.end());
|
||||
if (this == std::addressof(__t))
|
||||
return *this;
|
||||
|
||||
value_comp() = __t.value_comp();
|
||||
__copy_assign_alloc(__t);
|
||||
|
||||
if (__size_ != 0) {
|
||||
*__root_ptr() = static_cast<__node_base_pointer>(__copy_assign_tree(__root(), __t.__root()));
|
||||
} else {
|
||||
*__root_ptr() = static_cast<__node_base_pointer>(__copy_construct_tree(__t.__root()));
|
||||
if (__root())
|
||||
__root()->__parent_ = __end_node();
|
||||
}
|
||||
__begin_node_ = static_cast<__end_node_pointer>(std::__tree_min(static_cast<__node_base_pointer>(__end_node())));
|
||||
__size_ = __t.size();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1327,11 +1436,17 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
__tree<_Tp, _Compare, _Allocator>::__tree(const __tree& __t)
|
||||
: __begin_node_(),
|
||||
: __begin_node_(__end_node()),
|
||||
__node_alloc_(__node_traits::select_on_container_copy_construction(__t.__node_alloc())),
|
||||
__size_(0),
|
||||
__value_comp_(__t.value_comp()) {
|
||||
__begin_node_ = __end_node();
|
||||
if (__t.size() == 0)
|
||||
return;
|
||||
|
||||
*__root_ptr() = static_cast<__node_base_pointer>(__copy_construct_tree(__t.__root()));
|
||||
__root()->__parent_ = __end_node();
|
||||
__begin_node_ = static_cast<__end_node_pointer>(std::__tree_min(static_cast<__node_base_pointer>(__end_node())));
|
||||
__size_ = __t.size();
|
||||
}
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
@@ -1430,13 +1545,7 @@ __tree<_Tp, _Compare, _Allocator>::~__tree() {
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
void __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT {
|
||||
if (__nd != nullptr) {
|
||||
destroy(static_cast<__node_pointer>(__nd->__left_));
|
||||
destroy(static_cast<__node_pointer>(__nd->__right_));
|
||||
__node_allocator& __na = __node_alloc();
|
||||
__node_traits::destroy(__na, std::addressof(__nd->__value_));
|
||||
__node_traits::deallocate(__na, __nd, 1);
|
||||
}
|
||||
(__tree_deleter(__node_alloc_))(__nd);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Compare, class _Allocator>
|
||||
|
||||
@@ -970,7 +970,7 @@ public:
|
||||
: map(from_range, std::forward<_Range>(__range), key_compare(), __a) {}
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI map(const map& __m) : __tree_(__m.__tree_) { insert(__m.begin(), __m.end()); }
|
||||
_LIBCPP_HIDE_FROM_ABI map(const map& __m) = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI map& operator=(const map& __m) = default;
|
||||
|
||||
@@ -1637,11 +1637,7 @@ public:
|
||||
: multimap(from_range, std::forward<_Range>(__range), key_compare(), __a) {}
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m)
|
||||
: __tree_(__m.__tree_.value_comp(),
|
||||
__alloc_traits::select_on_container_copy_construction(__m.__tree_.__alloc())) {
|
||||
insert(__m.begin(), __m.end());
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m) = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI multimap& operator=(const multimap& __m) = default;
|
||||
|
||||
|
||||
@@ -660,7 +660,7 @@ public:
|
||||
: set(from_range, std::forward<_Range>(__range), key_compare(), __a) {}
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI set(const set& __s) : __tree_(__s.__tree_) { insert(__s.begin(), __s.end()); }
|
||||
_LIBCPP_HIDE_FROM_ABI set(const set& __s) = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI set& operator=(const set& __s) = default;
|
||||
|
||||
@@ -1119,11 +1119,7 @@ public:
|
||||
: multiset(from_range, std::forward<_Range>(__range), key_compare(), __a) {}
|
||||
# endif
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s)
|
||||
: __tree_(__s.__tree_.value_comp(),
|
||||
__alloc_traits::select_on_container_copy_construction(__s.__tree_.__alloc())) {
|
||||
insert(__s.begin(), __s.end());
|
||||
}
|
||||
_LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s) = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI multiset& operator=(const multiset& __s) = default;
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ void associative_container_benchmarks(std::string container) {
|
||||
/////////////////////////
|
||||
// Assignment
|
||||
/////////////////////////
|
||||
bench("operator=(const&)", [=](auto& st) {
|
||||
bench("operator=(const&) (into cleared Container)", [=](auto& st) {
|
||||
const std::size_t size = st.range(0);
|
||||
std::vector<Value> in = make_value_types(generate_unique_keys(size));
|
||||
Container src(in.begin(), in.end());
|
||||
@@ -172,6 +172,42 @@ void associative_container_benchmarks(std::string container) {
|
||||
}
|
||||
});
|
||||
|
||||
bench("operator=(const&) (into partially populated Container)", [=](auto& st) {
|
||||
const std::size_t size = st.range(0);
|
||||
std::vector<Value> in = make_value_types(generate_unique_keys(size));
|
||||
Container src(in.begin(), in.end());
|
||||
Container c[BatchSize];
|
||||
|
||||
while (st.KeepRunningBatch(BatchSize)) {
|
||||
for (std::size_t i = 0; i != BatchSize; ++i) {
|
||||
c[i] = src;
|
||||
benchmark::DoNotOptimize(c[i]);
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
|
||||
st.PauseTiming();
|
||||
for (std::size_t i = 0; i != BatchSize; ++i) {
|
||||
c[i].clear();
|
||||
}
|
||||
st.ResumeTiming();
|
||||
}
|
||||
});
|
||||
|
||||
bench("operator=(const&) (into populated Container)", [=](auto& st) {
|
||||
const std::size_t size = st.range(0);
|
||||
std::vector<Value> in = make_value_types(generate_unique_keys(size));
|
||||
Container src(in.begin(), in.end());
|
||||
Container c[BatchSize];
|
||||
|
||||
while (st.KeepRunningBatch(BatchSize)) {
|
||||
for (std::size_t i = 0; i != BatchSize; ++i) {
|
||||
c[i] = src;
|
||||
benchmark::DoNotOptimize(c[i]);
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/////////////////////////
|
||||
// Insertion
|
||||
/////////////////////////
|
||||
|
||||
@@ -29,6 +29,7 @@ struct support::adapt_operations<std::map<K, V>> {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
support::associative_container_benchmarks<std::map<int, int>>("std::map<int, int>");
|
||||
support::associative_container_benchmarks<std::map<std::string, int>>("std::map<std::string, int>");
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
@@ -28,6 +28,7 @@ struct support::adapt_operations<std::multimap<K, V>> {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
support::associative_container_benchmarks<std::multimap<int, int>>("std::multimap<int, int>");
|
||||
support::associative_container_benchmarks<std::multimap<std::string, int>>("std::multimap<std::string, int>");
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
@@ -26,6 +26,7 @@ struct support::adapt_operations<std::multiset<K>> {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
support::associative_container_benchmarks<std::multiset<int>>("std::multiset<int>");
|
||||
support::associative_container_benchmarks<std::multiset<std::string>>("std::multiset<std::string>");
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
@@ -27,6 +27,7 @@ struct support::adapt_operations<std::set<K>> {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
support::associative_container_benchmarks<std::set<int>>("std::set<int>");
|
||||
support::associative_container_benchmarks<std::set<std::string>>("std::set<std::string>");
|
||||
|
||||
benchmark::Initialize(&argc, argv);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
@@ -324,6 +324,11 @@ void deque_test() {
|
||||
|
||||
void map_test() {
|
||||
std::map<int, int> i_am_empty{};
|
||||
|
||||
// Make __tree_itertor available in the debug info
|
||||
// FIXME: Is there any way to avoid this requirement?
|
||||
(void)i_am_empty.begin();
|
||||
|
||||
ComparePrettyPrintToChars(i_am_empty, "std::map is empty");
|
||||
|
||||
std::map<int, std::string> one_two_three;
|
||||
|
||||
@@ -12,116 +12,129 @@
|
||||
|
||||
// map(const map& m);
|
||||
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "min_allocator.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <template <class> class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty map
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6), V(4, 7), V(5, 0)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(*std::next(copy.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(copy.begin(), 4) == V(5, 0));
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(*std::next(orig.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(orig.begin(), 4) == V(5, 0));
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator>();
|
||||
test_alloc<min_allocator>(); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, test_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<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::map<int, int, std::less<int>, other_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<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::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::map<int, double, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::map<int, double, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(-2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::map<int, double, C, A> m = mo;
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,116 +12,100 @@
|
||||
|
||||
// map(const map& m, const allocator_type& a);
|
||||
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#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::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty map
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6), V(4, 7), V(5, 0)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(*std::next(copy.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(copy.begin(), 4) == V(5, 0));
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(*std::next(orig.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(orig.begin(), 4) == V(5, 0));
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<std::pair<const int, int> >());
|
||||
test_alloc(test_allocator<std::pair<const int, int> >(25)); // Make sure that the new allocator is actually used
|
||||
test_alloc(min_allocator<std::pair<const int, int> >()); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy(orig, std::allocator<V>());
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::map<int, double, C, A> m(mo, A(3));
|
||||
assert(m.get_allocator() == A(3));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::map<int, double, C, A> m(mo, A());
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef explicit_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A{});
|
||||
std::map<int, double, C, A> m(mo, A{});
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
// map& operator=(const map& m);
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
@@ -24,274 +24,286 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
std::vector<int> ca_allocs;
|
||||
std::vector<int> ca_deallocs;
|
||||
|
||||
template <class T>
|
||||
class counting_allocatorT {
|
||||
public:
|
||||
typedef T value_type;
|
||||
int foo{0};
|
||||
counting_allocatorT(int f) noexcept : foo(f) {}
|
||||
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>
|
||||
counting_allocatorT(const counting_allocatorT<U>& other) noexcept {
|
||||
foo = other.foo;
|
||||
}
|
||||
template <class U>
|
||||
bool operator==(const counting_allocatorT<U>& other) const noexcept {
|
||||
return foo == other.foo;
|
||||
}
|
||||
template <class U>
|
||||
bool operator!=(const counting_allocatorT<U>& other) const noexcept {
|
||||
return foo != other.foo;
|
||||
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;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n) const {
|
||||
ca_allocs.push_back(foo);
|
||||
void* const pv = ::malloc(n * sizeof(T));
|
||||
return static_cast<T*>(pv);
|
||||
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);
|
||||
}
|
||||
void deallocate(T* p, std::size_t) const noexcept {
|
||||
ca_deallocs.push_back(foo);
|
||||
free(p);
|
||||
|
||||
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_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class counting_allocatorF {
|
||||
public:
|
||||
typedef T value_type;
|
||||
int foo{0};
|
||||
counting_allocatorF(int f) noexcept : foo(f) {}
|
||||
|
||||
using propagate_on_container_copy_assignment = std::false_type;
|
||||
template <class U>
|
||||
counting_allocatorF(const counting_allocatorF<U>& other) noexcept {
|
||||
foo = other.foo;
|
||||
}
|
||||
template <class U>
|
||||
bool operator==(const counting_allocatorF<U>& other) const noexcept {
|
||||
return foo == other.foo;
|
||||
}
|
||||
template <class U>
|
||||
bool operator!=(const counting_allocatorF<U>& other) const noexcept {
|
||||
return foo != other.foo;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n) const {
|
||||
ca_allocs.push_back(foo);
|
||||
void* const pv = ::malloc(n * sizeof(T));
|
||||
return static_cast<T*>(pv);
|
||||
}
|
||||
void deallocate(T* p, std::size_t) const noexcept {
|
||||
ca_deallocs.push_back(foo);
|
||||
free(p);
|
||||
}
|
||||
struct NoOp {
|
||||
void operator()() {}
|
||||
};
|
||||
|
||||
bool balanced_allocs() {
|
||||
std::vector<int> temp1, temp2;
|
||||
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-empy map combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
std::printf("Allocations = %zu, deallocations = %zu\n", ca_allocs.size(), ca_deallocs.size());
|
||||
if (ca_allocs.size() != ca_deallocs.size())
|
||||
return false;
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
temp1 = ca_allocs;
|
||||
std::sort(temp1.begin(), temp1.end());
|
||||
temp2.clear();
|
||||
std::unique_copy(temp1.begin(), temp1.end(), std::back_inserter<std::vector<int>>(temp2));
|
||||
std::printf("There were %zu different allocators\n", temp2.size());
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
for (std::vector<int>::const_iterator it = temp2.begin(); it != temp2.end(); ++it) {
|
||||
std::ptrdiff_t const allocs = std::count(ca_allocs.begin(), ca_allocs.end(), *it);
|
||||
std::ptrdiff_t const deallocs = std::count(ca_deallocs.begin(), ca_deallocs.end(), *it);
|
||||
std::printf("%d: %td vs %td\n", *it, allocs, deallocs);
|
||||
if (allocs != deallocs)
|
||||
return false;
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
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::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
temp1 = ca_allocs;
|
||||
std::sort(temp1.begin(), temp1.end());
|
||||
temp2.clear();
|
||||
std::unique_copy(temp1.begin(), temp1.end(), std::back_inserter<std::vector<int>>(temp2));
|
||||
std::printf("There were %zu different (de)allocators\n", temp2.size());
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty map
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
for (std::vector<int>::const_iterator it = ca_deallocs.begin(); it != ca_deallocs.end(); ++it) {
|
||||
std::ptrdiff_t const allocs = std::count(ca_allocs.begin(), ca_allocs.end(), *it);
|
||||
std::ptrdiff_t const deallocs = std::count(ca_deallocs.begin(), ca_deallocs.end(), *it);
|
||||
std::printf("%d: %td vs %td\n", *it, allocs, deallocs);
|
||||
if (allocs != deallocs)
|
||||
return false;
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
Map orig(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
{ // with an empty map
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
{ // check assignment into a non-empty map
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == 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::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1), V(6, 0)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1), V(6, 0), V(7, 9)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(3, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(3, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Make a somewhat larget set to exercise the algorithm a bit
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, std::less<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
for (int i = 0; i != 50; ++i)
|
||||
orig[i] = i + 3;
|
||||
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
int i = 0;
|
||||
for (auto v : copy) {
|
||||
assert(v == V(i, i + 3));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
#if TEST_STD_VER >= 11
|
||||
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
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::map<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(3, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
|
||||
{ // Make sure the color is copied as well
|
||||
std::map<int, int> in;
|
||||
|
||||
for (int i = 0; i != 32; ++i)
|
||||
in[i] = i;
|
||||
|
||||
std::map<int, int> out = in;
|
||||
|
||||
out.erase(std::next(out.begin(), 10), out.end());
|
||||
out = in;
|
||||
out.erase(std::next(out.begin(), 17), out.end());
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
const V ar[] = {
|
||||
V(1, 1),
|
||||
V(2, 1),
|
||||
V(3, 1),
|
||||
};
|
||||
std::map<int, double> m(ar, ar + sizeof(ar) / sizeof(ar[0]));
|
||||
std::map<int, double>* p = &m;
|
||||
m = *p;
|
||||
|
||||
assert(m.size() == 3);
|
||||
assert(std::equal(m.begin(), m.end(), ar));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A());
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A());
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
|
||||
assert(balanced_allocs());
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef counting_allocatorT<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(1));
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(2));
|
||||
m = mo;
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
assert(balanced_allocs());
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {V(1, 1), V(1, 1.5), V(1, 2), V(2, 1), V(2, 1.5), V(2, 2), V(3, 1), V(3, 1.5), V(3, 2)};
|
||||
typedef test_less<int> C;
|
||||
typedef counting_allocatorF<V> A;
|
||||
std::map<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(100));
|
||||
std::map<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(200));
|
||||
m = mo;
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == V(1, 1));
|
||||
assert(*std::next(m.begin()) == V(2, 1));
|
||||
assert(*std::next(m.begin(), 2) == V(3, 1));
|
||||
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == V(1, 1));
|
||||
assert(*std::next(mo.begin()) == V(2, 1));
|
||||
assert(*std::next(mo.begin(), 2) == V(3, 1));
|
||||
}
|
||||
assert(balanced_allocs());
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,81 +20,122 @@
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
template <template <class> class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty map
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6), V(4, 7), V(5, 0)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(*std::next(copy.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(copy.begin(), 4) == V(5, 0));
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(*std::next(orig.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(orig.begin(), 4) == V(5, 0));
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator>();
|
||||
test_alloc<min_allocator>(); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, test_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<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::multimap<int, int, std::less<int>, other_allocator<V> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<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::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multimap<int, double, C, A> m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multimap<int, double, C, A> m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A(-2));
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::multimap<int, double, C, A> m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,81 +20,92 @@
|
||||
#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::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy(orig, new_alloc);
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty map
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
const Map orig;
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6), V(4, 7), V(5, 0)};
|
||||
const Map orig(begin(arr), end(arr));
|
||||
Map copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(*std::next(copy.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(copy.begin(), 4) == V(5, 0));
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(*std::next(orig.begin(), 3) == V(4, 7));
|
||||
assert(*std::next(orig.begin(), 4) == V(5, 0));
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<std::pair<const int, int> >());
|
||||
test_alloc(test_allocator<std::pair<const int, int> >(25)); // Make sure that the new allocator is actually used
|
||||
test_alloc(min_allocator<std::pair<const int, int> >()); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy(orig, std::allocator<V>());
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multimap<int, double, C, A> m(mo, A(3));
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A(3));
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::multimap<int, double, C, A> m(mo, A());
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef explicit_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A{});
|
||||
std::multimap<int, double, C, A> m(mo, A{});
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A{});
|
||||
assert(m.key_comp() == C(5));
|
||||
|
||||
assert(mo.get_allocator() == A{});
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,111 +12,286 @@
|
||||
|
||||
// multimap& operator=(const multimap& m);
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::multimap<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
template <class T>
|
||||
class tracking_allocator {
|
||||
std::vector<void*>* allocs_;
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
const V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
std::multimap<int, double> m(ar, ar + sizeof(ar) / sizeof(ar[0]));
|
||||
std::multimap<int, double>* p = &m;
|
||||
m = *p;
|
||||
assert(m.size() == sizeof(ar) / sizeof(ar[0]));
|
||||
assert(std::equal(m.begin(), m.end(), ar));
|
||||
}
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::multimap<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A(2));
|
||||
assert(m.key_comp() == C(5));
|
||||
template <class U>
|
||||
friend class tracking_allocator;
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
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-empy multimap combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
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::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(rhs_alloc);
|
||||
Map copy(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty multimap
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
Map orig(begin(arr), end(arr), std::less<int>(), rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
{ // with an empty multimap
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
orig = static_cast<const Map&>(orig);
|
||||
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // check assignment into a non-empty multimap
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == 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::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1), V(6, 0)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
V lhs_arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(lhs_arr), end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
V rhs_arr[] = {V(4, 2), V(5, 1), V(6, 0), V(7, 9)};
|
||||
Map copy(begin(rhs_arr), end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(copy.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(copy.begin(), 2) == V(2, 6));
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == V(1, 1));
|
||||
assert(*std::next(orig.begin(), 1) == V(2, 3));
|
||||
assert(*std::next(orig.begin(), 2) == V(2, 6));
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
{ // Make a somewhat larget set to exercise the algorithm a bit
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, std::less<int>, Alloc>;
|
||||
|
||||
Map orig(rhs_alloc);
|
||||
for (int i = 0; i != 50; ++i) {
|
||||
orig.insert(V(i, i + 3));
|
||||
orig.insert(V(i, i + 5));
|
||||
}
|
||||
|
||||
Map copy(lhs_alloc);
|
||||
copy = orig;
|
||||
int i = 0;
|
||||
for (auto iter = copy.begin(); iter != copy.end();) {
|
||||
assert(*iter++ == V(i, i + 3));
|
||||
assert(*iter++ == V(i, i + 5));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<std::pair<const int, int> > >();
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef std::pair<const int, double> V;
|
||||
V ar[] = {
|
||||
V(1, 1),
|
||||
V(1, 1.5),
|
||||
V(1, 2),
|
||||
V(2, 1),
|
||||
V(2, 1.5),
|
||||
V(2, 2),
|
||||
V(3, 1),
|
||||
V(3, 1.5),
|
||||
V(3, 2),
|
||||
};
|
||||
typedef test_less<int> C;
|
||||
typedef min_allocator<V> A;
|
||||
std::multimap<int, double, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A());
|
||||
std::multimap<int, double, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A());
|
||||
m = mo;
|
||||
assert(m == mo);
|
||||
assert(m.get_allocator() == A());
|
||||
assert(m.key_comp() == C(5));
|
||||
test_alloc<min_allocator<std::pair<const int, int> > >();
|
||||
|
||||
assert(mo.get_allocator() == A());
|
||||
assert(mo.key_comp() == C(5));
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using V = std::pair<const int, int>;
|
||||
using Map = std::multimap<int, int, test_less<int> >;
|
||||
|
||||
V arr[] = {V(1, 1), V(2, 3), V(2, 6)};
|
||||
const Map orig(begin(arr), end(arr), test_less<int>(3));
|
||||
Map copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,83 +16,121 @@
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
#include "min_allocator.h"
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
|
||||
template <template <class> class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using Set = std::multiset<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty set
|
||||
using Set = std::multiset<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using Set = std::multiset<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3, 3, 5};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(*std::next(copy.begin(), 3) == 3);
|
||||
assert(*std::next(copy.begin(), 4) == 5);
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(*std::next(orig.begin(), 3) == 3);
|
||||
assert(*std::next(orig.begin(), 4) == 5);
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator>();
|
||||
test_alloc<min_allocator>(); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using Set = std::multiset<int, test_less<int> >;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using Set = std::multiset<int, std::less<int>, test_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<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::multiset<int, std::less<int>, other_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<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 int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multiset<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multiset<int, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 9);
|
||||
assert(std::distance(m.begin(), m.end()) == 9);
|
||||
assert(*std::next(m.begin(), 0) == 1);
|
||||
assert(*std::next(m.begin(), 1) == 1);
|
||||
assert(*std::next(m.begin(), 2) == 1);
|
||||
assert(*std::next(m.begin(), 3) == 2);
|
||||
assert(*std::next(m.begin(), 4) == 2);
|
||||
assert(*std::next(m.begin(), 5) == 2);
|
||||
assert(*std::next(m.begin(), 6) == 3);
|
||||
assert(*std::next(m.begin(), 7) == 3);
|
||||
assert(*std::next(m.begin(), 8) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 9);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 9);
|
||||
assert(*std::next(mo.begin(), 0) == 1);
|
||||
assert(*std::next(mo.begin(), 1) == 1);
|
||||
assert(*std::next(mo.begin(), 2) == 1);
|
||||
assert(*std::next(mo.begin(), 3) == 2);
|
||||
assert(*std::next(mo.begin(), 4) == 2);
|
||||
assert(*std::next(mo.begin(), 5) == 2);
|
||||
assert(*std::next(mo.begin(), 6) == 3);
|
||||
assert(*std::next(mo.begin(), 7) == 3);
|
||||
assert(*std::next(mo.begin(), 8) == 3);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::multiset<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multiset<int, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(-2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 9);
|
||||
assert(std::distance(m.begin(), m.end()) == 9);
|
||||
assert(*std::next(m.begin(), 0) == 1);
|
||||
assert(*std::next(m.begin(), 1) == 1);
|
||||
assert(*std::next(m.begin(), 2) == 1);
|
||||
assert(*std::next(m.begin(), 3) == 2);
|
||||
assert(*std::next(m.begin(), 4) == 2);
|
||||
assert(*std::next(m.begin(), 5) == 2);
|
||||
assert(*std::next(m.begin(), 6) == 3);
|
||||
assert(*std::next(m.begin(), 7) == 3);
|
||||
assert(*std::next(m.begin(), 8) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 9);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 9);
|
||||
assert(*std::next(mo.begin(), 0) == 1);
|
||||
assert(*std::next(mo.begin(), 1) == 1);
|
||||
assert(*std::next(mo.begin(), 2) == 1);
|
||||
assert(*std::next(mo.begin(), 3) == 2);
|
||||
assert(*std::next(mo.begin(), 4) == 2);
|
||||
assert(*std::next(mo.begin(), 5) == 2);
|
||||
assert(*std::next(mo.begin(), 6) == 3);
|
||||
assert(*std::next(mo.begin(), 7) == 3);
|
||||
assert(*std::next(mo.begin(), 8) == 3);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,44 +16,92 @@
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
#include "min_allocator.h"
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
|
||||
int main(int, char**) {
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multiset<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::multiset<int, C, A> m(mo, A(3));
|
||||
assert(m.get_allocator() == A(3));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 9);
|
||||
assert(std::distance(m.begin(), m.end()) == 9);
|
||||
assert(*std::next(m.begin(), 0) == 1);
|
||||
assert(*std::next(m.begin(), 1) == 1);
|
||||
assert(*std::next(m.begin(), 2) == 1);
|
||||
assert(*std::next(m.begin(), 3) == 2);
|
||||
assert(*std::next(m.begin(), 4) == 2);
|
||||
assert(*std::next(m.begin(), 5) == 2);
|
||||
assert(*std::next(m.begin(), 6) == 3);
|
||||
assert(*std::next(m.begin(), 7) == 3);
|
||||
assert(*std::next(m.begin(), 8) == 3);
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 9);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 9);
|
||||
assert(*std::next(mo.begin(), 0) == 1);
|
||||
assert(*std::next(mo.begin(), 1) == 1);
|
||||
assert(*std::next(mo.begin(), 2) == 1);
|
||||
assert(*std::next(mo.begin(), 3) == 2);
|
||||
assert(*std::next(mo.begin(), 4) == 2);
|
||||
assert(*std::next(mo.begin(), 5) == 2);
|
||||
assert(*std::next(mo.begin(), 6) == 3);
|
||||
assert(*std::next(mo.begin(), 7) == 3);
|
||||
assert(*std::next(mo.begin(), 8) == 3);
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty set
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3, 3, 5};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(*std::next(copy.begin(), 3) == 3);
|
||||
assert(*std::next(copy.begin(), 4) == 5);
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(*std::next(orig.begin(), 3) == 3);
|
||||
assert(*std::next(orig.begin(), 4) == 5);
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<int>());
|
||||
test_alloc(test_allocator<int>(25)); // Make sure that the new allocator is actually used
|
||||
test_alloc(min_allocator<int>()); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
int arr[] = {1, 2, 2};
|
||||
const std::multiset<int, test_less<int> > orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
std::multiset<int, test_less<int> > copy(orig, std::allocator<int>());
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,96 +12,271 @@
|
||||
|
||||
// multiset& operator=(const multiset& s);
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_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-empy multiset combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
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::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty multiset
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 2};
|
||||
Set orig(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
{ // with an empty multiset
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // check assignment into a non-empty multiset
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5, 6};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 2};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5, 6};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 2);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 2);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // Make a somewhat larget multiset to exercise the algorithm a bit
|
||||
using Set = std::multiset<int, std::less<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
for (int i = 0; i != 50; ++i)
|
||||
orig.insert(i);
|
||||
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
int i = 0;
|
||||
for (auto v : copy) {
|
||||
assert(v == i++);
|
||||
}
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
#if TEST_STD_VER >= 11
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
int arr[] = {1, 2, 2};
|
||||
const std::multiset<int, test_less<int> > orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
std::multiset<int, test_less<int> > copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::multiset<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::multiset<int, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 9);
|
||||
assert(std::distance(m.begin(), m.end()) == 9);
|
||||
assert(*std::next(m.begin(), 0) == 1);
|
||||
assert(*std::next(m.begin(), 1) == 1);
|
||||
assert(*std::next(m.begin(), 2) == 1);
|
||||
assert(*std::next(m.begin(), 3) == 2);
|
||||
assert(*std::next(m.begin(), 4) == 2);
|
||||
assert(*std::next(m.begin(), 5) == 2);
|
||||
assert(*std::next(m.begin(), 6) == 3);
|
||||
assert(*std::next(m.begin(), 7) == 3);
|
||||
assert(*std::next(m.begin(), 8) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 9);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 9);
|
||||
assert(*std::next(mo.begin(), 0) == 1);
|
||||
assert(*std::next(mo.begin(), 1) == 1);
|
||||
assert(*std::next(mo.begin(), 2) == 1);
|
||||
assert(*std::next(mo.begin(), 3) == 2);
|
||||
assert(*std::next(mo.begin(), 4) == 2);
|
||||
assert(*std::next(mo.begin(), 5) == 2);
|
||||
assert(*std::next(mo.begin(), 6) == 3);
|
||||
assert(*std::next(mo.begin(), 7) == 3);
|
||||
assert(*std::next(mo.begin(), 8) == 3);
|
||||
}
|
||||
{
|
||||
typedef int V;
|
||||
const V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
std::multiset<int> m(ar, ar + sizeof(ar) / sizeof(ar[0]));
|
||||
std::multiset<int>* p = &m;
|
||||
m = *p;
|
||||
assert(m.size() == 9);
|
||||
assert(std::equal(m.begin(), m.end(), ar));
|
||||
}
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::multiset<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::multiset<int, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 9);
|
||||
assert(std::distance(m.begin(), m.end()) == 9);
|
||||
assert(*std::next(m.begin(), 0) == 1);
|
||||
assert(*std::next(m.begin(), 1) == 1);
|
||||
assert(*std::next(m.begin(), 2) == 1);
|
||||
assert(*std::next(m.begin(), 3) == 2);
|
||||
assert(*std::next(m.begin(), 4) == 2);
|
||||
assert(*std::next(m.begin(), 5) == 2);
|
||||
assert(*std::next(m.begin(), 6) == 3);
|
||||
assert(*std::next(m.begin(), 7) == 3);
|
||||
assert(*std::next(m.begin(), 8) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 9);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 9);
|
||||
assert(*std::next(mo.begin(), 0) == 1);
|
||||
assert(*std::next(mo.begin(), 1) == 1);
|
||||
assert(*std::next(mo.begin(), 2) == 1);
|
||||
assert(*std::next(mo.begin(), 3) == 2);
|
||||
assert(*std::next(mo.begin(), 4) == 2);
|
||||
assert(*std::next(mo.begin(), 5) == 2);
|
||||
assert(*std::next(mo.begin(), 6) == 3);
|
||||
assert(*std::next(mo.begin(), 7) == 3);
|
||||
assert(*std::next(mo.begin(), 8) == 3);
|
||||
}
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,63 +12,123 @@
|
||||
|
||||
// set(const set& m);
|
||||
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "min_allocator.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "test_allocator.h"
|
||||
|
||||
template <template <class> class Alloc>
|
||||
void test_alloc() {
|
||||
{ // Simple check
|
||||
using Set = std::set<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty set
|
||||
using Set = std::set<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using Set = std::set<int, std::less<int>, Alloc<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3, 4, 5};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(*std::next(copy.begin(), 3) == 4);
|
||||
assert(*std::next(copy.begin(), 4) == 5);
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(*std::next(orig.begin(), 3) == 4);
|
||||
assert(*std::next(orig.begin(), 4) == 5);
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator>();
|
||||
test_alloc<min_allocator>(); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
using Set = std::set<int, test_less<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
|
||||
{ // Ensure that the allocator is copied
|
||||
using Set = std::set<int, std::less<int>, test_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<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::set<int, std::less<int>, other_allocator<int> >;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<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 int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::set<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::set<int, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == 1);
|
||||
assert(*std::next(m.begin()) == 2);
|
||||
assert(*std::next(m.begin(), 2) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == 1);
|
||||
assert(*std::next(mo.begin()) == 2);
|
||||
assert(*std::next(mo.begin(), 2) == 3);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::set<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::set<int, C, A> m = mo;
|
||||
assert(m.get_allocator() == A(-2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == 1);
|
||||
assert(*std::next(m.begin()) == 2);
|
||||
assert(*std::next(m.begin(), 2) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == 1);
|
||||
assert(*std::next(mo.begin()) == 2);
|
||||
assert(*std::next(mo.begin(), 2) == 3);
|
||||
}
|
||||
#endif
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,36 +12,95 @@
|
||||
|
||||
// set(const set& m, const allocator_type& a);
|
||||
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#include "min_allocator.h"
|
||||
#include "test_macros.h"
|
||||
#include "test_allocator.h"
|
||||
|
||||
int main(int, char**) {
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::set<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(7));
|
||||
std::set<int, C, A> m(mo, A(3));
|
||||
assert(m.get_allocator() == A(3));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == 1);
|
||||
assert(*std::next(m.begin()) == 2);
|
||||
assert(*std::next(m.begin(), 2) == 3);
|
||||
template <class Alloc>
|
||||
void test_alloc(const Alloc& new_alloc) {
|
||||
{ // Simple check
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
assert(mo.get_allocator() == A(7));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == 1);
|
||||
assert(*std::next(mo.begin()) == 2);
|
||||
assert(*std::next(mo.begin(), 2) == 3);
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy(orig, new_alloc);
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
assert(copy.get_allocator() == new_alloc);
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
|
||||
{ // copy empty set
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
const Set orig;
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
|
||||
{ // only some leaf nodes exist
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3, 4, 5};
|
||||
const Set orig(std::begin(arr), std::end(arr));
|
||||
Set copy = orig;
|
||||
assert(copy.size() == 5);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(*std::next(copy.begin(), 3) == 4);
|
||||
assert(*std::next(copy.begin(), 4) == 5);
|
||||
assert(std::next(copy.begin(), 5) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 5);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(*std::next(orig.begin(), 3) == 4);
|
||||
assert(*std::next(orig.begin(), 4) == 5);
|
||||
assert(std::next(orig.begin(), 5) == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc(std::allocator<int>());
|
||||
test_alloc(test_allocator<int>(25)); // Make sure that the new allocator is actually used
|
||||
test_alloc(min_allocator<int>()); // Make sure that fancy pointers work
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
int arr[] = {1, 2, 3};
|
||||
const std::set<int, test_less<int> > orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
std::set<int, test_less<int> > copy(orig, std::allocator<int>());
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,83 +12,273 @@
|
||||
|
||||
// set& operator=(const set& s);
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "../../../test_compare.h"
|
||||
#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-empy set combinations
|
||||
{ // assign from a non-empty container into an empty one
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // assign from an empty container into an empty one
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
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::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
const Set orig(rhs_alloc);
|
||||
Set copy(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 0);
|
||||
assert(copy.begin() == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // Ensure that self-assignment works correctly
|
||||
{ // with a non-empty set
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int arr[] = {1, 2, 3};
|
||||
Set orig(std::begin(arr), std::end(arr), std::less<int>(), rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
{ // with an empty set
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
orig = static_cast<const Set&>(orig);
|
||||
|
||||
assert(orig.size() == 0);
|
||||
assert(orig.begin() == orig.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // check assignment into a non-empty set
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains elements, but fewer than the RHS
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS contains the same number of elements as the RHS
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5, 6};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // LHS already contains more elements than the RHS
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
int lhs_arr[] = {1, 2, 3};
|
||||
const Set orig(std::begin(lhs_arr), std::end(lhs_arr), std::less<int>(), rhs_alloc);
|
||||
|
||||
int rhs_arr[] = {4, 5, 6};
|
||||
Set copy(std::begin(rhs_arr), std::end(rhs_arr), std::less<int>(), lhs_alloc);
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(*std::next(copy.begin(), 0) == 1);
|
||||
assert(*std::next(copy.begin(), 1) == 2);
|
||||
assert(*std::next(copy.begin(), 2) == 3);
|
||||
assert(std::next(copy.begin(), 3) == copy.end());
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(*std::next(orig.begin(), 0) == 1);
|
||||
assert(*std::next(orig.begin(), 1) == 2);
|
||||
assert(*std::next(orig.begin(), 2) == 3);
|
||||
assert(std::next(orig.begin(), 3) == orig.end());
|
||||
}
|
||||
check_alloc_invariant();
|
||||
{ // Make a somewhat larget set to exercise the algorithm a bit
|
||||
using Set = std::set<int, std::less<int>, Alloc>;
|
||||
|
||||
Set orig(rhs_alloc);
|
||||
for (int i = 0; i != 50; ++i)
|
||||
orig.insert(i);
|
||||
|
||||
Set copy(lhs_alloc);
|
||||
copy = orig;
|
||||
int i = 0;
|
||||
for (auto v : copy) {
|
||||
assert(v == i++);
|
||||
}
|
||||
}
|
||||
check_alloc_invariant();
|
||||
}
|
||||
}
|
||||
|
||||
void test() {
|
||||
test_alloc<std::allocator<int> >();
|
||||
#if TEST_STD_VER >= 11
|
||||
test_alloc<min_allocator<int> >();
|
||||
|
||||
{ // Make sure we're allocating/deallocating nodes with the correct allocator
|
||||
// See https://llvm.org/PR29001
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
{ // Ensure that the comparator is copied
|
||||
int arr[] = {1, 2, 3};
|
||||
const std::set<int, test_less<int> > orig(std::begin(arr), std::end(arr), test_less<int>(3));
|
||||
std::set<int, test_less<int> > copy;
|
||||
copy = orig;
|
||||
assert(copy.size() == 3);
|
||||
assert(copy.key_comp() == test_less<int>(3));
|
||||
|
||||
// Check that orig is still what is expected
|
||||
assert(orig.size() == 3);
|
||||
assert(orig.key_comp() == test_less<int>(3));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef test_allocator<V> A;
|
||||
std::set<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::set<int, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(7));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == 1);
|
||||
assert(*std::next(m.begin()) == 2);
|
||||
assert(*std::next(m.begin(), 2) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == 1);
|
||||
assert(*std::next(mo.begin()) == 2);
|
||||
assert(*std::next(mo.begin(), 2) == 3);
|
||||
}
|
||||
{
|
||||
typedef int V;
|
||||
const V ar[] = {1, 2, 3};
|
||||
std::set<int> m(ar, ar + sizeof(ar) / sizeof(ar[0]));
|
||||
std::set<int>* p = &m;
|
||||
m = *p;
|
||||
|
||||
assert(m.size() == 3);
|
||||
assert(std::equal(m.begin(), m.end(), ar));
|
||||
}
|
||||
{
|
||||
typedef int V;
|
||||
V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
typedef test_less<int> C;
|
||||
typedef other_allocator<V> A;
|
||||
std::set<int, C, A> mo(ar, ar + sizeof(ar) / sizeof(ar[0]), C(5), A(2));
|
||||
std::set<int, C, A> m(ar, ar + sizeof(ar) / sizeof(ar[0]) / 2, C(3), A(7));
|
||||
m = mo;
|
||||
assert(m.get_allocator() == A(2));
|
||||
assert(m.key_comp() == C(5));
|
||||
assert(m.size() == 3);
|
||||
assert(std::distance(m.begin(), m.end()) == 3);
|
||||
assert(*m.begin() == 1);
|
||||
assert(*std::next(m.begin()) == 2);
|
||||
assert(*std::next(m.begin(), 2) == 3);
|
||||
|
||||
assert(mo.get_allocator() == A(2));
|
||||
assert(mo.key_comp() == C(5));
|
||||
assert(mo.size() == 3);
|
||||
assert(std::distance(mo.begin(), mo.end()) == 3);
|
||||
assert(*mo.begin() == 1);
|
||||
assert(*std::next(mo.begin()) == 2);
|
||||
assert(*std::next(mo.begin(), 2) == 3);
|
||||
}
|
||||
|
||||
{ // Test with std::pair, since we have some special handling for pairs inside __tree
|
||||
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::set<std::pair<int, int> > a(arr, arr + 4);
|
||||
std::set<std::pair<int, int> > b;
|
||||
|
||||
b = a;
|
||||
assert(a == b);
|
||||
}
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user