diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index b1b2528a..77431650 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -216,12 +216,14 @@ namespace boost { void clear() noexcept { table_.clear(); } - std::pair insert(value_type const& value) + template + auto insert(Ty&& value) + -> decltype(table_.insert(std::forward(value))) { - return table_.insert(value); + return table_.insert(std::forward(value)); } - std::pair insert(value_type&& value) + std::pair insert(init_type&& value) { return table_.insert(std::move(value)); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4d9b4a8e..2c27334b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -133,6 +133,7 @@ build_foa reserve_tests ; build_foa contains_tests ; build_foa erase_if ; build_foa scary_tests ; +build_foa init_type_insert_tests ; run exception/constructor_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ; run exception/copy_exception_tests.cpp : : : 98:no 03:no 0x:no BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ; diff --git a/test/unordered/init_type_insert_tests.cpp b/test/unordered/init_type_insert_tests.cpp new file mode 100644 index 00000000..3bdeb78e --- /dev/null +++ b/test/unordered/init_type_insert_tests.cpp @@ -0,0 +1,165 @@ +#if !defined(BOOST_UNORDERED_FOA_TESTS) +#error "This test is only for the FOA-style conatiners" +#endif + +#include +#include + +#include "../helpers/test.hpp" + +struct move_only +{ + int x_ = -1; + + move_only() = default; + move_only(int x) : x_{x} {} + move_only(move_only const&) = delete; + move_only(move_only&&) = default; + + friend bool operator==(move_only const& lhs, move_only const& rhs) + { + return lhs.x_ == rhs.x_; + } +}; + +template <> struct std::hash +{ + std::size_t operator()(move_only const& mo) const noexcept + { + return std::hash()(mo.x_); + } +}; + +struct raii_tracker +{ + static int move_constructs; + static int copy_constructs; + + int x_ = -1; + + static void reset_counts() + { + move_constructs = 0; + copy_constructs = 0; + } + + raii_tracker() {} + raii_tracker(int x) : x_{x} {} + raii_tracker(raii_tracker const& rhs) : x_{rhs.x_} { ++copy_constructs; } + + raii_tracker(raii_tracker&& rhs) noexcept : x_{rhs.x_} + { + rhs.x_ = -1; + + ++move_constructs; + } + + friend bool operator==(raii_tracker const& lhs, raii_tracker const& rhs) + { + return lhs.x_ == rhs.x_; + } +}; + +template <> struct std::hash +{ + std::size_t operator()(raii_tracker const& rt) const noexcept + { + return std::hash()(rt.x_); + } +}; + +int raii_tracker::move_constructs = 0; +int raii_tracker::copy_constructs = 0; + +static void test_move_only() +{ + int const v = 128; + + boost::unordered_flat_map > map; + + using init_type = decltype(map)::init_type; + static_assert( + std::is_same::value, + ""); + + map.insert(std::make_pair(move_only(1), v)); + map.insert({move_only(2), v}); + + BOOST_TEST_EQ(map.size(), 2); + + map.rehash(1024); + BOOST_TEST_GE(map.bucket_count(), 1024); +} + +static void test_insert_tracking() +{ + raii_tracker::reset_counts(); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 0); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + + boost::unordered_flat_map > + map; + + { + std::pair value{1, 2}; + + map.insert(value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); + BOOST_TEST_EQ(raii_tracker::move_constructs, 0); + } + + { + std::pair value{2, 3}; + + map.insert(std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 2); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + } + + { + std::pair value{3, 4}; + + map.insert(value); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 4); + BOOST_TEST_EQ(raii_tracker::move_constructs, 2); + } + + { + std::pair value{4, 5}; + + map.insert(std::move(value)); + + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 3); + } + + { + map.insert(std::make_pair(5, 6)); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 5); + } + + { + map.insert({6, 7}); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7); + } + + BOOST_TEST_EQ(map.size(), 6); + + map.rehash(1024); + BOOST_TEST_EQ(raii_tracker::copy_constructs, 5); + BOOST_TEST_EQ(raii_tracker::move_constructs, 7 + 2 * map.size()); +} + +int main() +{ + test_move_only(); + test_insert_tracking(); + return boost::report_errors(); +}