From a004e71dd0896f7ec4d9a29a86eadca349fa2ee6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 5 Apr 2023 13:21:18 -0700 Subject: [PATCH] Implement emplace, emplace_or_[c]visit --- .../boost/unordered/concurrent_flat_map.hpp | 17 ++ test/Jamfile.v2 | 2 + test/cfoa/emplace_tests.cpp | 167 ++++++++++++++++++ test/cfoa/insert_tests.cpp | 1 + 4 files changed, 187 insertions(+) create mode 100644 test/cfoa/emplace_tests.cpp diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index bbab9d5c..bca9f61f 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -270,6 +270,23 @@ namespace boost { this->insert_or_visit(ilist.begin(), ilist.end(), f); } + template bool emplace(Args&&... args) + { + return table_.emplace(std::forward(args)...); + } + + template + bool emplace_or_visit(F f, Args&&... args) + { + return table_.emplace_or_visit(f, std::forward(args)...); + } + + template + bool emplace_or_cvisit(F f, Args&&... args) + { + return table_.emplace_or_cvisit(f, std::forward(args)...); + } + template bool try_emplace(key_type const& k, Args&&... args) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 83e60710..bd7891fc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -215,9 +215,11 @@ rule build_cfoa ( name ) build_cfoa insert_tests ; build_cfoa erase_tests ; build_cfoa try_emplace_tests ; +build_cfoa emplace_tests ; alias cfoa_tests : cfoa_insert_tests cfoa_erase_tests cfoa_try_emplace_tests + cfoa_emplace_tests ; diff --git a/test/cfoa/emplace_tests.cpp b/test/cfoa/emplace_tests.cpp new file mode 100644 index 00000000..9e62122a --- /dev/null +++ b/test/cfoa/emplace_tests.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2023 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "helpers.hpp" + +#include + +#include + +namespace { + test::seed_t initialize_seed(335740237); + + struct lvalue_emplacer_type + { + template void operator()(std::vector& values, X& x) + { + std::atomic num_inserts{0}; + thread_runner(values, [&x, &num_inserts](boost::span s) { + for (auto const& r : s) { + bool b = x.emplace(r.first.x_, r.second.x_); + if (b) { + ++num_inserts; + } + } + }); + BOOST_TEST_EQ(num_inserts, x.size()); + BOOST_TEST_EQ(raii::default_constructor, 2 * values.size()); + + BOOST_TEST_EQ(raii::copy_constructor, 0u); + BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); + + BOOST_TEST_EQ(raii::copy_constructor, 0u); + BOOST_TEST_EQ(raii::copy_assignment, 0u); + BOOST_TEST_EQ(raii::move_assignment, 0u); + } + } lvalue_emplacer; + + struct norehash_lvalue_emplacer_type : public lvalue_emplacer_type + { + template void operator()(std::vector& values, X& x) + { + x.reserve(values.size()); + lvalue_emplacer_type::operator()(values, x); + BOOST_TEST_EQ(raii::move_constructor, 2 * x.size()); + } + } norehash_lvalue_emplacer; + + struct lvalue_emplace_or_cvisit_type + { + template void operator()(std::vector& values, X& x) + { + std::atomic num_inserts{0}; + std::atomic num_invokes{0}; + thread_runner(values, [&x, &num_inserts, &num_invokes](boost::span s) { + for (auto& r : s) { + bool b = x.emplace_or_cvisit( + [&num_invokes](typename X::value_type const& v) { + (void)v; + ++num_invokes; + }, + r.first.x_, r.second.x_); + + if (b) { + ++num_inserts; + } + } + }); + + BOOST_TEST_EQ(num_inserts, x.size()); + BOOST_TEST_EQ(num_invokes, values.size() - x.size()); + + BOOST_TEST_EQ(raii::default_constructor, 2 * values.size()); + BOOST_TEST_EQ(raii::copy_constructor, 0u); + BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); + BOOST_TEST_EQ(raii::move_assignment, 0u); + BOOST_TEST_EQ(raii::copy_assignment, 0u); + } + } lvalue_emplace_or_cvisit; + + struct lvalue_emplace_or_visit_type + { + template void operator()(std::vector& values, X& x) + { + std::atomic num_inserts{0}; + std::atomic num_invokes{0}; + thread_runner(values, [&x, &num_inserts, &num_invokes](boost::span s) { + for (auto& r : s) { + bool b = x.emplace_or_visit( + [&num_invokes](typename X::value_type& v) { + (void)v; + ++num_invokes; + }, + r.first.x_, r.second.x_); + + if (b) { + ++num_inserts; + } + } + }); + + BOOST_TEST_EQ(num_inserts, x.size()); + BOOST_TEST_EQ(num_invokes, values.size() - x.size()); + + BOOST_TEST_EQ(raii::default_constructor, 2 * values.size()); + BOOST_TEST_EQ(raii::copy_constructor, 0u); + BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); + BOOST_TEST_EQ(raii::move_assignment, 0u); + BOOST_TEST_EQ(raii::copy_assignment, 0u); + } + } lvalue_emplace_or_visit; + + template + void emplace(X*, G gen, F emplacer, test::random_generator rg) + { + auto values = make_random_values(1024 * 16, [&] { return gen(rg); }); + auto reference_map = + boost::unordered_flat_map(values.begin(), values.end()); + raii::reset_counts(); + + { + X x; + + emplacer(values, x); + + BOOST_TEST_EQ(x.size(), reference_map.size()); + + using value_type = typename X::value_type; + BOOST_TEST_EQ(x.size(), x.visit_all([&](value_type const& kv) { + BOOST_TEST(reference_map.contains(kv.first)); + if (rg == test::sequential) { + BOOST_TEST_EQ(kv.second, reference_map[kv.first]); + } + })); + } + + BOOST_TEST_GE(raii::default_constructor, 0u); + BOOST_TEST_GE(raii::copy_constructor, 0u); + BOOST_TEST_GE(raii::move_constructor, 0u); + BOOST_TEST_GT(raii::destructor, 0u); + + BOOST_TEST_EQ(raii::default_constructor + raii::copy_constructor + + raii::move_constructor, + raii::destructor); + } + + boost::unordered::concurrent_flat_map* map; + +} // namespace + +using test::default_generator; +using test::limited_range; +using test::sequential; + +// clang-format off + +UNORDERED_TEST( + emplace, + ((map)) + ((value_type_generator)(init_type_generator)) + ((lvalue_emplacer)(norehash_lvalue_emplacer) + (lvalue_emplace_or_cvisit)(lvalue_emplace_or_visit)) + ((default_generator)(sequential)(limited_range))) + +// clang-format on + +RUN_TESTS() diff --git a/test/cfoa/insert_tests.cpp b/test/cfoa/insert_tests.cpp index d4dacc11..01b628ef 100644 --- a/test/cfoa/insert_tests.cpp +++ b/test/cfoa/insert_tests.cpp @@ -25,6 +25,7 @@ namespace { } }); BOOST_TEST_EQ(num_inserts, x.size()); + BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size()); BOOST_TEST_EQ(raii::copy_assignment, 0u); BOOST_TEST_EQ(raii::move_assignment, 0u); }