diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fc452148..f487247a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -119,6 +119,7 @@ local FCA_TESTS = transparent_tests unnecessary_copy_tests fancy_pointer_noleak + pmr_allocator_tests ; for local test in $(FCA_TESTS) @@ -226,6 +227,7 @@ local FOA_TESTS = uses_allocator hash_is_avalanching_test fancy_pointer_noleak + pmr_allocator_tests ; for local test in $(FOA_TESTS) @@ -330,6 +332,7 @@ local CFOA_TESTS = rw_spinlock_test8 reentrancy_check_test explicit_alloc_ctor_tests + pmr_allocator_tests ; for local test in $(CFOA_TESTS) diff --git a/test/cfoa/helpers.hpp b/test/cfoa/helpers.hpp index 4514b0a7..ef58f3fe 100644 --- a/test/cfoa/helpers.hpp +++ b/test/cfoa/helpers.hpp @@ -8,6 +8,8 @@ #define BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP #include "../helpers/generators.hpp" +#include "../helpers/helpers.hpp" +#include "../helpers/pmr.hpp" #include "../helpers/test.hpp" #include "common_helpers.hpp" diff --git a/test/cfoa/pmr_allocator_tests.cpp b/test/cfoa/pmr_allocator_tests.cpp new file mode 100644 index 00000000..0c0df338 --- /dev/null +++ b/test/cfoa/pmr_allocator_tests.cpp @@ -0,0 +1,8 @@ +// Copyright (C) 2024 Braden Ganetsky +// 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) + +#define BOOST_UNORDERED_CFOA_TESTS +#include +#include +#include "../unordered/pmr_allocator_tests.cpp" diff --git a/test/helpers/helpers.hpp b/test/helpers/helpers.hpp index 146dea4d..d421efab 100644 --- a/test/helpers/helpers.hpp +++ b/test/helpers/helpers.hpp @@ -51,6 +51,11 @@ namespace test { static_cast::difference_type>(x)); return it; } + + template + using is_map = + std::integral_constant::value>; } #endif diff --git a/test/unordered/pmr_allocator_tests.cpp b/test/unordered/pmr_allocator_tests.cpp new file mode 100644 index 00000000..6dbbbf22 --- /dev/null +++ b/test/unordered/pmr_allocator_tests.cpp @@ -0,0 +1,183 @@ +// +// Copyright 2024 Braden Ganetsky. +// 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/helpers.hpp" +#include "../helpers/pmr.hpp" +#include "../helpers/test.hpp" +#include "../helpers/unordered.hpp" +#include +#include + +#ifdef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE + +BOOST_PRAGMA_MESSAGE( + "Test skipped because C++17 header is not available.") + +#else + +namespace pmr_allocator_tests { + + using pmr_string = std::basic_string, + std::pmr::polymorphic_allocator >; + +#if defined(BOOST_UNORDERED_CFOA_TESTS) + static boost::unordered::pmr::concurrent_flat_map* + test_string_flat_map; + static boost::unordered::pmr::concurrent_flat_map* + test_pmr_string_flat_map; + static boost::unordered::pmr::concurrent_flat_set* + test_string_flat_set; + static boost::unordered::pmr::concurrent_flat_set* + test_pmr_string_flat_set; +#define PMR_ALLOCATOR_TESTS_ARGS \ + ((test_string_flat_map)(test_pmr_string_flat_map)(test_string_flat_set)(test_pmr_string_flat_set)) +#elif defined(BOOST_UNORDERED_FOA_TESTS) + static boost::unordered::pmr::unordered_flat_map* + test_string_flat_map; + static boost::unordered::pmr::unordered_flat_map* + test_pmr_string_flat_map; + static boost::unordered::pmr::unordered_node_map* + test_string_node_map; + static boost::unordered::pmr::unordered_node_map* + test_pmr_string_node_map; + static boost::unordered::pmr::unordered_flat_set* + test_string_flat_set; + static boost::unordered::pmr::unordered_flat_set* + test_pmr_string_flat_set; + static boost::unordered::pmr::unordered_node_set* + test_string_node_set; + static boost::unordered::pmr::unordered_node_set* + test_pmr_string_node_set; +#define PMR_ALLOCATOR_TESTS_ARGS \ + ((test_string_flat_map)(test_pmr_string_flat_map)(test_string_node_map)(test_pmr_string_node_map)(test_string_flat_set)(test_pmr_string_flat_set)(test_string_node_set)(test_pmr_string_node_set)) +#else + static boost::unordered::pmr::unordered_map* + test_string_map; + static boost::unordered::pmr::unordered_map* + test_pmr_string_map; + static boost::unordered::pmr::unordered_multimap* + test_string_multimap; + static boost::unordered::pmr::unordered_multimap* + test_pmr_string_multimap; + static boost::unordered::pmr::unordered_set* test_string_set; + static boost::unordered::pmr::unordered_set* test_pmr_string_set; + static boost::unordered::pmr::unordered_multiset* + test_string_multiset; + static boost::unordered::pmr::unordered_multiset* + test_pmr_string_multiset; +#define PMR_ALLOCATOR_TESTS_ARGS \ + ((test_string_map)(test_pmr_string_map)(test_string_multimap)(test_pmr_string_multimap)(test_string_set)(test_pmr_string_set)(test_string_multiset)(test_pmr_string_multiset)) +#endif + + template + typename std::enable_if::value, std::size_t>::type + emplace_strings(X& x) + { + std::string_view sv = + "this is a string that's longer than the SBO threshold"; + x.emplace(sv); + // Return how many chars were allocated using a pmr allocator + return std::is_same::value ? sv.size() + 1 + : 0; + } + + template + typename std::enable_if::value, std::size_t>::type + emplace_strings(X& x) + { + std::string_view key = + "this is a string that's longer than the SBO threshold"; + std::string_view value = + "this is another long string that's longer than the SBO threshold"; + x.emplace(key, value); + // Return how many chars were allocated using a pmr allocator + return std::is_same::value + ? key.size() + value.size() + 2 + : 0; + } + + void validate_resource( + pmr_string const& str, test::counted_new_delete_resource const& resource) + { + BOOST_TEST_EQ(str.get_allocator().resource(), &resource); + } + + void validate_resource( + std::string const&, test::counted_new_delete_resource const&) + { + // Pass through + } + + template + typename std::enable_if::value>::type validate_resource( + X& x, test::counted_new_delete_resource const& resource) + { +#if defined(BOOST_UNORDERED_CFOA_TESTS) + x.cvisit_all( + [&resource](auto& element) { validate_resource(element, resource); }); +#else + for (auto& element : x) { + validate_resource(element, resource); + } +#endif + } + + template + typename std::enable_if::value>::type validate_resource( + X& x, test::counted_new_delete_resource const& resource) + { +#if defined(BOOST_UNORDERED_CFOA_TESTS) + x.cvisit_all([&resource](auto& element) { + validate_resource(element.first, resource); + validate_resource(element.second, resource); + }); +#else + for (auto& element : x) { + validate_resource(element.first, resource); + validate_resource(element.second, resource); + } +#endif + } + + template static void pmr_emplace_erase(X*) + { + using container = X; + using allocator_type = typename container::allocator_type; + + test::counted_new_delete_resource resource; + + { + allocator_type alloc(&resource); + container x(alloc); + + std::size_t num_chars = emplace_strings(x); + BOOST_TEST_EQ(x.size(), 1); + std::size_t count_after_emplace = resource.count(); + BOOST_TEST_GT(count_after_emplace, + num_chars + sizeof(typename container::value_type)); + + validate_resource(x, resource); + + x.clear(); + BOOST_TEST_LE(resource.count(), count_after_emplace); + } + + BOOST_TEST_EQ(resource.count(), 0); + } + + // clang-format off + + UNORDERED_TEST( + pmr_emplace_erase, + PMR_ALLOCATOR_TESTS_ARGS + ) + + // clang-format on + +} // namespace pmr_allocator_tests + +#endif + +RUN_TESTS()