forked from boostorg/unordered
implemented proper stats handling on move assignment
This commit is contained in:
@ -1162,6 +1162,7 @@ struct table_core_stats
|
||||
|
||||
#define BOOST_UNORDERED_ADD_STATS(stats,args) stats.add args
|
||||
#define BOOST_UNORDERED_SWAP_STATS(stats1,stats2) std::swap(stats1,stats2)
|
||||
#define BOOST_UNORDERED_COPY_STATS(stats1,stats2) stats1=stats2
|
||||
#define BOOST_UNORDERED_RESET_STATS_OF(x) x.reset_stats()
|
||||
#define BOOST_UNORDERED_STATS_COUNTER(name) std::size_t name=0
|
||||
#define BOOST_UNORDERED_INCREMENT_STATS_COUNTER(name) ++name
|
||||
@ -1170,6 +1171,7 @@ struct table_core_stats
|
||||
|
||||
#define BOOST_UNORDERED_ADD_STATS(stats,args) ((void)0)
|
||||
#define BOOST_UNORDERED_SWAP_STATS(stats1,stats2) ((void)0)
|
||||
#define BOOST_UNORDERED_COPY_STATS(stats1,stats2) ((void)0)
|
||||
#define BOOST_UNORDERED_RESET_STATS_OF(x) ((void)0)
|
||||
#define BOOST_UNORDERED_STATS_COUNTER(name) ((void)0)
|
||||
#define BOOST_UNORDERED_INCREMENT_STATS_COUNTER(name) ((void)0)
|
||||
@ -1633,9 +1635,11 @@ public:
|
||||
arrays=x.arrays;
|
||||
size_ctrl.ml=std::size_t(x.size_ctrl.ml);
|
||||
size_ctrl.size=std::size_t(x.size_ctrl.size);
|
||||
BOOST_UNORDERED_COPY_STATS(cstats,x.cstats);
|
||||
x.arrays=ah.release();
|
||||
x.size_ctrl.ml=x.initial_max_load();
|
||||
x.size_ctrl.size=0;
|
||||
BOOST_UNORDERED_RESET_STATS_OF(x);
|
||||
}
|
||||
else{
|
||||
swap(h(),x.h());
|
||||
@ -1645,6 +1649,7 @@ public:
|
||||
noshrink_reserve(x.size());
|
||||
clear_on_exit c{x};
|
||||
(void)c; /* unused var warning */
|
||||
BOOST_UNORDERED_RESET_STATS_OF(x);
|
||||
|
||||
/* This works because subsequent x.clear() does not depend on the
|
||||
* elements' values.
|
||||
|
@ -129,6 +129,26 @@ void check_container_stats(const Stats& s1, const Stats& s2)
|
||||
check_lookup_stats(s1.unsuccessful_lookup, s2.unsuccessful_lookup);
|
||||
}
|
||||
|
||||
template <class Container> void insert_n(Container& c, std::size_t n)
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
test::reset_sequence();
|
||||
test::random_values<Container> l(n, test::sequential);
|
||||
std::vector<value_type> v(l.begin(), l.end());
|
||||
thread_runner(v, [&c](boost::span<value_type> sp) {
|
||||
for (auto const& x : sp) {
|
||||
c.insert(x);
|
||||
}
|
||||
});
|
||||
#else
|
||||
test::reset_sequence();
|
||||
test::random_values<Container> l(n, test::sequential);
|
||||
c.insert(l.begin(), l.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Container> void test_stats()
|
||||
{
|
||||
using allocator_type = typename Container::allocator_type;
|
||||
@ -138,49 +158,36 @@ template <class Container> void test_stats()
|
||||
Container c;
|
||||
const Container& cc = c;
|
||||
|
||||
stats s = cc.get_stats();
|
||||
// Stats initially empty
|
||||
stats s = cc.get_stats(); // using cc -> get_stats() is const
|
||||
check_container_stats(s, empty);
|
||||
|
||||
test::reset_sequence();
|
||||
|
||||
#if defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
test::random_values<Container> l(10000, test::sequential);
|
||||
std::vector<value_type> v(l.begin(), l.end());
|
||||
thread_runner(v, [&c](boost::span<value_type> sp) {
|
||||
for (auto const& x : sp) {
|
||||
c.insert(x);
|
||||
}
|
||||
});
|
||||
|
||||
#else
|
||||
|
||||
test::random_values<Container> v(10000, test::sequential);
|
||||
c.insert(v.begin(),v.end());
|
||||
|
||||
#endif
|
||||
|
||||
// Stats after insertion
|
||||
insert_n(c, 10000);
|
||||
s = cc.get_stats();
|
||||
check_insertion_stats(s.insertion, full);
|
||||
check_lookup_stats(s.successful_lookup, empty);
|
||||
check_lookup_stats(s.unsuccessful_lookup, full);
|
||||
check_insertion_stats(s.insertion, full); // insertions happened
|
||||
check_lookup_stats(s.successful_lookup, empty); // no duplicate values
|
||||
check_lookup_stats(s.unsuccessful_lookup, full); // from insertion
|
||||
|
||||
#if !defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||
// Inequality due to rehashing.
|
||||
// May not hold in concurrent containers because of insertion retries.
|
||||
// Inequality due to rehashing
|
||||
// May not hold in concurrent containers because of insertion retries
|
||||
BOOST_TEST_GT(
|
||||
s.insertion.count, s.unsuccessful_lookup.count);
|
||||
#endif
|
||||
|
||||
// resets_stats() actually clears stats
|
||||
c.reset_stats();
|
||||
s = cc.get_stats();
|
||||
check_container_stats(s, empty);
|
||||
check_container_stats(cc.get_stats(), empty);
|
||||
|
||||
// Stats after lookup
|
||||
|
||||
test::reset_sequence();
|
||||
|
||||
#if defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
test::random_values<Container> l2(15000, test::sequential);
|
||||
std::vector<value_type> v2(l2.begin(), l2.end());
|
||||
std::atomic<int> found{0}, not_found{0};
|
||||
@ -202,6 +209,7 @@ template <class Container> void test_stats()
|
||||
|
||||
#endif
|
||||
|
||||
// As many [un]successful lookups as recorded externally
|
||||
s=cc.get_stats();
|
||||
check_lookup_stats(s.successful_lookup, full);
|
||||
check_lookup_stats(s.unsuccessful_lookup, full);
|
||||
@ -212,28 +220,62 @@ template <class Container> void test_stats()
|
||||
s = cc.get_stats();
|
||||
check_container_stats(s, empty);
|
||||
|
||||
test::reset_sequence();
|
||||
test::random_values<Container> v3(1000, test::sequential);
|
||||
c.clear();
|
||||
c.insert(v.begin(),v.end());
|
||||
c.insert(v.begin(),v.end()); // produces successful lookups
|
||||
// Move constructor tests
|
||||
|
||||
c.clear();
|
||||
insert_n(c, 1000);
|
||||
insert_n(c, 1000); // produces successful lookups
|
||||
|
||||
// Move contructor
|
||||
// Stats transferred to target and reset in source
|
||||
s = cc.get_stats();
|
||||
Container c2 = std::move(c);
|
||||
check_container_stats(c.get_stats(), empty);
|
||||
check_container_stats(c2.get_stats(), s);
|
||||
|
||||
// Move constructor with equal allocator
|
||||
// Stats transferred to target and reset in source
|
||||
Container c3(std::move(c2), allocator_type());
|
||||
check_container_stats(c2.get_stats(), empty);
|
||||
check_container_stats(c3.get_stats(), s);
|
||||
|
||||
// Move constructor with unequal allocator
|
||||
// Target only has insertions, stats reset in source
|
||||
Container c4(std::move(c3), allocator_type(1));
|
||||
check_container_stats(c3.get_stats(), empty);
|
||||
check_insertion_stats(c4.get_stats().insertion, full);
|
||||
check_lookup_stats(c4.get_stats().successful_lookup, empty);
|
||||
check_lookup_stats(c4.get_stats().unsuccessful_lookup, empty);
|
||||
|
||||
// TODO: move assignment
|
||||
// Move assignment tests
|
||||
|
||||
// Move assignment with equal allocator
|
||||
// Stats transferred to target and reset in source
|
||||
Container c5, c6;
|
||||
insert_n(c5,1000);
|
||||
insert_n(c5,1000); // produces successful lookups
|
||||
insert_n(c6,500);
|
||||
insert_n(c6,500); // produces successful lookups
|
||||
s = c5.get_stats();
|
||||
check_container_stats(s, full);
|
||||
check_container_stats(c6.get_stats(), full);
|
||||
c6 = std::move(c5);
|
||||
check_container_stats(c5.get_stats(), empty);
|
||||
check_container_stats(c6.get_stats(), s);
|
||||
|
||||
// Move assignment with unequal allocator
|
||||
// Target only has insertions (if reset previously), stats reset in source
|
||||
Container c7(allocator_type(1));
|
||||
insert_n(c7,250);
|
||||
insert_n(c7,250); // produces successful lookups
|
||||
check_container_stats(c7.get_stats(), full);
|
||||
c7.reset_stats();
|
||||
c7 = std::move(c6);
|
||||
check_container_stats(c6.get_stats(), empty);
|
||||
check_insertion_stats(c7.get_stats().insertion, full);
|
||||
check_lookup_stats(c7.get_stats().successful_lookup, empty);
|
||||
check_lookup_stats(c7.get_stats().unsuccessful_lookup, empty);
|
||||
|
||||
// TODO: concurrent<->unordered interop
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user