diff --git a/test/cfoa/emplace_tests.cpp b/test/cfoa/emplace_tests.cpp index f7105e6c..23105cb7 100644 --- a/test/cfoa/emplace_tests.cpp +++ b/test/cfoa/emplace_tests.cpp @@ -4,6 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include "helpers.hpp" +#include "../helpers/count.hpp" #include #include @@ -293,4 +294,174 @@ UNORDERED_TEST( // clang-format on +namespace { + using converting_key_type = basic_raii; + using converting_value_type = basic_raii; + + class counted_key_type : public basic_raii + { + public: + using basic_raii::basic_raii; + counted_key_type() = default; + counted_key_type(const converting_key_type& k) : counted_key_type(k.x_) {} + }; + class counted_value_type : public basic_raii + { + public: + using basic_raii::basic_raii; + counted_value_type() = default; + counted_value_type(const converting_value_type& v) + : counted_value_type(v.x_) + { + } + }; + + void reset_counts() + { + counted_key_type::reset_counts(); + counted_value_type::reset_counts(); + converting_key_type::reset_counts(); + converting_value_type::reset_counts(); + } + + using test::smf_count; + + template smf_count count_for() + { + return test::smf_count{ + (int)T::default_constructor.load(std::memory_order_relaxed), + (int)T::copy_constructor.load(std::memory_order_relaxed), + (int)T::move_constructor.load(std::memory_order_relaxed), + (int)T::copy_assignment.load(std::memory_order_relaxed), + (int)T::move_assignment.load(std::memory_order_relaxed), + (int)T::destructor.load(std::memory_order_relaxed)}; + } + + enum emplace_kind + { + copy, + move + }; + + enum emplace_status + { + fail, + success + }; + + struct counted_key_checker_type + { + using key_type = counted_key_type; + void operator()(emplace_kind kind, emplace_status status) + { + int copies = (kind == copy && status == success) ? 1 : 0; + int moves = (kind == move && status == success) ? 1 : 0; + BOOST_TEST_EQ( + count_for(), (smf_count{0, copies, moves, 0, 0, 0})); + } + } counted_key_checker; + + struct converting_key_checker_type + { + using key_type = converting_key_type; + void operator()(emplace_kind, emplace_status status) + { + int moves = (status == success) ? 1 : 0; + BOOST_TEST_EQ( + count_for(), (smf_count{1, 0, moves, 0, 0, 1})); + } + } converting_key_checker; + + struct counted_value_checker_type + { + using mapped_type = counted_value_type; + void operator()(emplace_kind kind, emplace_status status) + { + int copies = (kind == copy && status == success) ? 1 : 0; + int moves = (kind == move && status == success) ? 1 : 0; + BOOST_TEST_EQ(count_for(), + (smf_count{0, copies, moves, 0, 0, 0})); + } + } counted_value_checker; + + struct converting_value_checker_type + { + using mapped_type = converting_value_type; + void operator()(emplace_kind, emplace_status status) + { + int ctors = (status == success) ? 1 : 0; + BOOST_TEST_EQ( + count_for(), (smf_count{ctors, 0, 0, 0, 0, 0})); + } + } converting_value_checker; + + template + void emplace_map_key_value( + X*, emplace_kind kind, KC key_checker, VC value_checker) + { + using container = X; + using key_type = typename KC::key_type; + using mapped_type = typename VC::mapped_type; + + container x; + key_type key{}; + key_type key2 = key; + mapped_type value{}; + mapped_type value2 = value; + + { + reset_counts(); + auto ret = (kind == copy) ? x.emplace(key, value) + : x.emplace(std::move(key), std::move(value)); + BOOST_TEST_EQ(ret, true); + key_checker(kind, success); + value_checker(kind, success); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + } + + { + reset_counts(); + bool ret = x.emplace(key2, value2); + BOOST_TEST_EQ(ret, false); + key_checker(kind, fail); + value_checker(kind, fail); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + } + + { + reset_counts(); + bool ret = x.emplace(std::move(key2), std::move(value2)); + BOOST_TEST_EQ(ret, false); + key_checker(kind, fail); + value_checker(kind, fail); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + BOOST_TEST_EQ( + count_for(), (smf_count{0, 0, 0, 0, 0, 0})); + } + } + + boost::unordered::concurrent_flat_map* + test_counted_flat_map = {}; + +} // namespace + +// clang-format off + +UNORDERED_TEST( + emplace_map_key_value, + ((test_counted_flat_map)) + ((copy)(move)) + ((counted_key_checker)(converting_key_checker)) + ((counted_value_checker)(converting_value_checker)) +) + +// clang-format on + RUN_TESTS() diff --git a/test/cfoa/helpers.hpp b/test/cfoa/helpers.hpp index fcdc64ce..c983c916 100644 --- a/test/cfoa/helpers.hpp +++ b/test/cfoa/helpers.hpp @@ -207,7 +207,8 @@ template struct stateful_allocator2 bool operator!=(stateful_allocator2 const& rhs) const { return x_ != rhs.x_; } }; -struct raii +template +struct basic_raii { static std::atomic default_constructor; static std::atomic copy_constructor; @@ -219,17 +220,17 @@ struct raii int x_ = -1; - raii() { ++default_constructor; } - raii(int const x) : x_{x} { ++default_constructor; } - raii(raii const& rhs) : x_{rhs.x_} { ++copy_constructor; } - raii(raii&& rhs) noexcept : x_{rhs.x_} + basic_raii() { ++default_constructor; } + basic_raii(int const x) : x_{x} { ++default_constructor; } + basic_raii(basic_raii const& rhs) : x_{rhs.x_} { ++copy_constructor; } + basic_raii(basic_raii&& rhs) noexcept : x_{rhs.x_} { rhs.x_ = -1; ++move_constructor; } - ~raii() { ++destructor; } + ~basic_raii() { ++destructor; } - raii& operator=(raii const& rhs) + basic_raii& operator=(basic_raii const& rhs) { ++copy_assignment; if (this != &rhs) { @@ -238,7 +239,7 @@ struct raii return *this; } - raii& operator=(raii&& rhs) noexcept + basic_raii& operator=(basic_raii&& rhs) noexcept { ++move_assignment; if (this != &rhs) { @@ -248,37 +249,37 @@ struct raii return *this; } - friend bool operator==(raii const& lhs, raii const& rhs) + friend bool operator==(basic_raii const& lhs, basic_raii const& rhs) { return lhs.x_ == rhs.x_; } - friend bool operator!=(raii const& lhs, raii const& rhs) + friend bool operator!=(basic_raii const& lhs, basic_raii const& rhs) { return !(lhs == rhs); } - friend bool operator==(raii const& lhs, int const x) { return lhs.x_ == x; } - friend bool operator!=(raii const& lhs, int const x) + friend bool operator==(basic_raii const& lhs, int const x) { return lhs.x_ == x; } + friend bool operator!=(basic_raii const& lhs, int const x) { return !(lhs.x_ == x); } - friend bool operator==(int const x, raii const& rhs) { return rhs.x_ == x; } + friend bool operator==(int const x, basic_raii const& rhs) { return rhs.x_ == x; } - friend bool operator!=(int const x, raii const& rhs) + friend bool operator!=(int const x, basic_raii const& rhs) { return !(rhs.x_ == x); } - friend std::ostream& operator<<(std::ostream& os, raii const& rhs) + friend std::ostream& operator<<(std::ostream& os, basic_raii const& rhs) { os << "{ x_: " << rhs.x_ << " }"; return os; } friend std::ostream& operator<<( - std::ostream& os, std::pair const& rhs) + std::ostream& os, std::pair const& rhs) { os << "pair<" << rhs.first << ", " << rhs.second << ">"; return os; @@ -294,16 +295,30 @@ struct raii move_assignment = 0; } - friend void swap(raii& lhs, raii& rhs) { std::swap(lhs.x_, rhs.x_); } + friend void swap(basic_raii& lhs, basic_raii& rhs) { std::swap(lhs.x_, rhs.x_); } }; -std::atomic raii::default_constructor{0}; -std::atomic raii::copy_constructor{0}; -std::atomic raii::move_constructor{0}; -std::atomic raii::destructor{0}; -std::atomic raii::copy_assignment{0}; -std::atomic raii::move_assignment{0}; +template std::atomic basic_raii::default_constructor(0); +template std::atomic basic_raii::copy_constructor(0); +template std::atomic basic_raii::move_constructor(0); +template std::atomic basic_raii::destructor(0); +template std::atomic basic_raii::copy_assignment(0); +template std::atomic basic_raii::move_assignment(0); +struct raii_tag_ +{ +}; +class raii : public basic_raii +{ + using basic_raii::basic_raii; +}; + +template +std::size_t hash_value(basic_raii const& r) noexcept +{ + boost::hash hasher; + return hasher(r.x_); +} std::size_t hash_value(raii const& r) noexcept { boost::hash hasher; @@ -311,6 +326,13 @@ std::size_t hash_value(raii const& r) noexcept } namespace std { + template struct hash> + { + std::size_t operator()(basic_raii const& r) const noexcept + { + return hash_value(r); + } + }; template <> struct hash { std::size_t operator()(raii const& r) const noexcept