mirror of
https://github.com/boostorg/unordered.git
synced 2025-09-27 00:00:59 +02:00
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_ADD_STATS(stats,args) stats.add args
|
||||||
#define BOOST_UNORDERED_SWAP_STATS(stats1,stats2) std::swap(stats1,stats2)
|
#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_RESET_STATS_OF(x) x.reset_stats()
|
||||||
#define BOOST_UNORDERED_STATS_COUNTER(name) std::size_t name=0
|
#define BOOST_UNORDERED_STATS_COUNTER(name) std::size_t name=0
|
||||||
#define BOOST_UNORDERED_INCREMENT_STATS_COUNTER(name) ++name
|
#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_ADD_STATS(stats,args) ((void)0)
|
||||||
#define BOOST_UNORDERED_SWAP_STATS(stats1,stats2) ((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_RESET_STATS_OF(x) ((void)0)
|
||||||
#define BOOST_UNORDERED_STATS_COUNTER(name) ((void)0)
|
#define BOOST_UNORDERED_STATS_COUNTER(name) ((void)0)
|
||||||
#define BOOST_UNORDERED_INCREMENT_STATS_COUNTER(name) ((void)0)
|
#define BOOST_UNORDERED_INCREMENT_STATS_COUNTER(name) ((void)0)
|
||||||
@@ -1633,9 +1635,11 @@ public:
|
|||||||
arrays=x.arrays;
|
arrays=x.arrays;
|
||||||
size_ctrl.ml=std::size_t(x.size_ctrl.ml);
|
size_ctrl.ml=std::size_t(x.size_ctrl.ml);
|
||||||
size_ctrl.size=std::size_t(x.size_ctrl.size);
|
size_ctrl.size=std::size_t(x.size_ctrl.size);
|
||||||
|
BOOST_UNORDERED_COPY_STATS(cstats,x.cstats);
|
||||||
x.arrays=ah.release();
|
x.arrays=ah.release();
|
||||||
x.size_ctrl.ml=x.initial_max_load();
|
x.size_ctrl.ml=x.initial_max_load();
|
||||||
x.size_ctrl.size=0;
|
x.size_ctrl.size=0;
|
||||||
|
BOOST_UNORDERED_RESET_STATS_OF(x);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
swap(h(),x.h());
|
swap(h(),x.h());
|
||||||
@@ -1645,6 +1649,7 @@ public:
|
|||||||
noshrink_reserve(x.size());
|
noshrink_reserve(x.size());
|
||||||
clear_on_exit c{x};
|
clear_on_exit c{x};
|
||||||
(void)c; /* unused var warning */
|
(void)c; /* unused var warning */
|
||||||
|
BOOST_UNORDERED_RESET_STATS_OF(x);
|
||||||
|
|
||||||
/* This works because subsequent x.clear() does not depend on the
|
/* This works because subsequent x.clear() does not depend on the
|
||||||
* elements' values.
|
* 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);
|
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()
|
template <class Container> void test_stats()
|
||||||
{
|
{
|
||||||
using allocator_type = typename Container::allocator_type;
|
using allocator_type = typename Container::allocator_type;
|
||||||
@@ -138,49 +158,36 @@ template <class Container> void test_stats()
|
|||||||
Container c;
|
Container c;
|
||||||
const Container& cc = 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);
|
check_container_stats(s, empty);
|
||||||
|
|
||||||
test::reset_sequence();
|
// Stats after insertion
|
||||||
|
insert_n(c, 10000);
|
||||||
#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
|
|
||||||
|
|
||||||
s = cc.get_stats();
|
s = cc.get_stats();
|
||||||
check_insertion_stats(s.insertion, full);
|
check_insertion_stats(s.insertion, full); // insertions happened
|
||||||
check_lookup_stats(s.successful_lookup, empty);
|
check_lookup_stats(s.successful_lookup, empty); // no duplicate values
|
||||||
check_lookup_stats(s.unsuccessful_lookup, full);
|
check_lookup_stats(s.unsuccessful_lookup, full); // from insertion
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_CFOA_TESTS)
|
#if !defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||||
// Inequality due to rehashing.
|
// Inequality due to rehashing
|
||||||
// May not hold in concurrent containers because of insertion retries.
|
// May not hold in concurrent containers because of insertion retries
|
||||||
BOOST_TEST_GT(
|
BOOST_TEST_GT(
|
||||||
s.insertion.count, s.unsuccessful_lookup.count);
|
s.insertion.count, s.unsuccessful_lookup.count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// resets_stats() actually clears stats
|
||||||
c.reset_stats();
|
c.reset_stats();
|
||||||
s = cc.get_stats();
|
check_container_stats(cc.get_stats(), empty);
|
||||||
check_container_stats(s, empty);
|
|
||||||
|
// Stats after lookup
|
||||||
|
|
||||||
test::reset_sequence();
|
test::reset_sequence();
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_CFOA_TESTS)
|
#if defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||||
|
|
||||||
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
test::random_values<Container> l2(15000, test::sequential);
|
test::random_values<Container> l2(15000, test::sequential);
|
||||||
std::vector<value_type> v2(l2.begin(), l2.end());
|
std::vector<value_type> v2(l2.begin(), l2.end());
|
||||||
std::atomic<int> found{0}, not_found{0};
|
std::atomic<int> found{0}, not_found{0};
|
||||||
@@ -202,6 +209,7 @@ template <class Container> void test_stats()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// As many [un]successful lookups as recorded externally
|
||||||
s=cc.get_stats();
|
s=cc.get_stats();
|
||||||
check_lookup_stats(s.successful_lookup, full);
|
check_lookup_stats(s.successful_lookup, full);
|
||||||
check_lookup_stats(s.unsuccessful_lookup, full);
|
check_lookup_stats(s.unsuccessful_lookup, full);
|
||||||
@@ -212,28 +220,62 @@ template <class Container> void test_stats()
|
|||||||
s = cc.get_stats();
|
s = cc.get_stats();
|
||||||
check_container_stats(s, empty);
|
check_container_stats(s, empty);
|
||||||
|
|
||||||
test::reset_sequence();
|
// Move constructor tests
|
||||||
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
|
|
||||||
|
|
||||||
|
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();
|
s = cc.get_stats();
|
||||||
Container c2 = std::move(c);
|
Container c2 = std::move(c);
|
||||||
check_container_stats(c.get_stats(), empty);
|
check_container_stats(c.get_stats(), empty);
|
||||||
check_container_stats(c2.get_stats(), s);
|
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());
|
Container c3(std::move(c2), allocator_type());
|
||||||
check_container_stats(c2.get_stats(), empty);
|
check_container_stats(c2.get_stats(), empty);
|
||||||
check_container_stats(c3.get_stats(), s);
|
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));
|
Container c4(std::move(c3), allocator_type(1));
|
||||||
check_container_stats(c3.get_stats(), empty);
|
check_container_stats(c3.get_stats(), empty);
|
||||||
check_insertion_stats(c4.get_stats().insertion, full);
|
check_insertion_stats(c4.get_stats().insertion, full);
|
||||||
check_lookup_stats(c4.get_stats().successful_lookup, empty);
|
check_lookup_stats(c4.get_stats().successful_lookup, empty);
|
||||||
check_lookup_stats(c4.get_stats().unsuccessful_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
|
// TODO: concurrent<->unordered interop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user