From e416cafd491f00778abfbf4518b9c70bdde52723 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 1 Jan 2017 18:35:50 +0000 Subject: [PATCH 1/2] Count instances constructed/destructed in exception tests --- test/helpers/exception_test.hpp | 2 ++ test/objects/exception.hpp | 42 +++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index d1bc1317..ad7ae7ea 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -7,6 +7,7 @@ #define BOOST_UNORDERED_EXCEPTION_TEST_HEADER #include "./test.hpp" +#include "./count.hpp" #include #include @@ -187,6 +188,7 @@ namespace test { test_runner(Test const& t) : test_(t), exception_in_check_(false) {} void run() { DISABLE_EXCEPTIONS; + test::check_instances check; test::scope = ""; BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init()); BOOST_DEDUCED_TYPENAME Test::strong_type strong; diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 0e0aa869..2cd2ce11 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -13,6 +13,7 @@ #include #include #include "../helpers/fwd.hpp" +#include "../helpers/count.hpp" #include "../helpers/memory.hpp" namespace test @@ -24,6 +25,7 @@ namespace exception class equal_to; template class allocator; object generate(object const*, random_generator); + std::pair generate(std::pair const*, random_generator); struct true_type { @@ -35,7 +37,7 @@ namespace exception enum { value = false }; }; - class object + class object : private counted_object { public: int tag1_, tag2_; @@ -55,7 +57,7 @@ namespace exception } object(object const& x) - : tag1_(x.tag1_), tag2_(x.tag2_) + : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_) { UNORDERED_SCOPE(object::object(object)) { UNORDERED_EPOINT("Mock object copy constructor."); @@ -106,6 +108,13 @@ namespace exception return object(::test::generate(x, g), ::test::generate(x, g)); } + friend std::pair generate(std::pair const*, random_generator g) { + int* x = 0; + return std::make_pair( + object(::test::generate(x, g), ::test::generate(x, g)), + object(::test::generate(x, g), ::test::generate(x, g))); + } + friend std::ostream& operator<<(std::ostream& out, object const& o) { return out<<"("< const& x) const { + UNORDERED_SCOPE(hash::operator()(std::pair)) { + UNORDERED_EPOINT("Mock hash pair function."); + } + + return hash_impl(x.first) * 193ul + hash_impl(x.second) * 97ul + 29ul; + } + + std::size_t hash_impl(object const& x) const { int result; switch(tag_) { case 1: @@ -209,6 +230,18 @@ namespace exception UNORDERED_EPOINT("Mock equal_to function."); } + return equal_impl(x1, x2); + } + + bool operator()(std::pair const& x1, std::pair const& x2) const { + UNORDERED_SCOPE(equal_to::operator()(std::pair, std::pair)) { + UNORDERED_EPOINT("Mock equal_to function."); + } + + return equal_impl(x1.first, x2.first) && equal_impl(x1.second, x2.second); + } + + bool equal_impl(object const& x1, object const& x2) const { switch(tag_) { case 1: return x1.tag1_ == x2.tag1_; @@ -596,6 +629,11 @@ namespace test random_generator g) { return test::exception::generate(x, g); } + + std::pair generate(std::pair const* x, + random_generator g) { + return test::exception::generate(x, g); + } } #endif From 57cc6d4bac1cc93fb8fb05696116b184f3d1fecc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 1 Jan 2017 18:35:50 +0000 Subject: [PATCH 2/2] Fix exception safety when constructing pairs --- include/boost/unordered/detail/allocate.hpp | 62 ++++++++++++++++----- test/exception/containers.hpp | 12 ++++ test/exception/insert_exception_tests.cpp | 58 ++++++++++++++++++- 3 files changed, 118 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 8e4f8694..2da85be8 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -1118,10 +1118,19 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) boost::unordered::detail::func::const_cast_pointer( boost::addressof(address->first)), boost::forward(a1)); - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - boost::forward(a2)); + BOOST_TRY { + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + boost::forward(a2)); + } + BOOST_CATCH(...) { + boost::unordered::detail::func::call_destroy(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END } #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES @@ -1194,10 +1203,19 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) boost::unordered::detail::func::const_cast_pointer( boost::addressof(address->first)), args.a1); - boost::unordered::detail::func::construct_from_tuple(alloc, - boost::unordered::detail::func::const_cast_pointer( - boost::addressof(address->second)), - args.a2); + BOOST_TRY { + boost::unordered::detail::func::construct_from_tuple(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->second)), + args.a2); + } + BOOST_CATCH(...) { + boost::unordered::detail::func::call_destroy(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(address->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END } #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES @@ -1362,9 +1380,18 @@ namespace boost { namespace unordered { namespace detail { namespace func { boost::unordered::detail::func::const_cast_pointer( boost::addressof(a.node_->value_ptr()->first)), boost::forward(k)); - boost::unordered::detail::func::call_construct(alloc, + BOOST_TRY { + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second))); + } + BOOST_CATCH(...) { + boost::unordered::detail::func::call_destroy(alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second))); + boost::addressof(a.node_->value_ptr()->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END return a.release(); } @@ -1378,10 +1405,19 @@ namespace boost { namespace unordered { namespace detail { namespace func { boost::unordered::detail::func::const_cast_pointer( boost::addressof(a.node_->value_ptr()->first)), boost::forward(k)); - boost::unordered::detail::func::call_construct(alloc, + BOOST_TRY { + boost::unordered::detail::func::call_construct(alloc, + boost::unordered::detail::func::const_cast_pointer( + boost::addressof(a.node_->value_ptr()->second)), + boost::forward(m)); + } + BOOST_CATCH(...) { + boost::unordered::detail::func::call_destroy(alloc, boost::unordered::detail::func::const_cast_pointer( - boost::addressof(a.node_->value_ptr()->second)), - boost::forward(m)); + boost::addressof(a.node_->value_ptr()->first))); + BOOST_RETHROW; + } + BOOST_CATCH_END return a.release(); } }}}} diff --git a/test/exception/containers.hpp b/test/exception/containers.hpp index 1e379645..ee938330 100644 --- a/test/exception/containers.hpp +++ b/test/exception/containers.hpp @@ -31,5 +31,17 @@ typedef boost::unordered_multimap< test::exception::hash, test::exception::equal_to, test::exception::allocator > test_multimap; +typedef boost::unordered_set< + std::pair, + test::exception::hash, + test::exception::equal_to, + test::exception::allocator > test_pair_set; +typedef boost::unordered_multiset< + std::pair, + test::exception::hash, + test::exception::equal_to, + test::exception::allocator2 > test_pair_multiset; + #define CONTAINER_SEQ (test_set)(test_multiset)(test_map)(test_multimap) +#define CONTAINER_PAIR_SEQ (test_pair_set)(test_pair_multiset)(test_map)(test_multimap) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 588a6713..d4c1e243 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -243,6 +243,62 @@ struct insert_test_rehash3 : public insert_test_base #define ALL_TESTS BASIC_TESTS #endif - EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ) + +template +struct pair_emplace_test1 : public insert_test_base +{ + typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; + + void run(T& x, strong_type& strong) const { + for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + it = this->values.begin(), end = this->values.end(); + it != end; ++it) + { + strong.store(x, test::detail::tracker.count_allocations); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(it->first), + boost::make_tuple(it->second)); + } + } +}; + +template +struct pair_emplace_test2 : public insert_test_base +{ + typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; + + void run(T& x, strong_type& strong) const { + for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + it = this->values.begin(), end = this->values.end(); + it != end; ++it) + { + strong.store(x, test::detail::tracker.count_allocations); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(it->first), + boost::make_tuple(it->second.tag1_, it->second.tag2_)); + } + } +}; + +EXCEPTION_TESTS((pair_emplace_test1)(pair_emplace_test2), CONTAINER_PAIR_SEQ) + +template +struct index_insert_test1 : public insert_test_base +{ + typedef BOOST_DEDUCED_TYPENAME insert_test_base::strong_type strong_type; + + void run(T& x, strong_type& strong) const { + for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + it = this->values.begin(), end = this->values.end(); + it != end; ++it) + { + strong.store(x, test::detail::tracker.count_allocations); + x[it->first]; + } + } +}; + +EXCEPTION_TESTS((index_insert_test1), (test_map)) + RUN_TESTS()