Fix exception handling in rehash_impl

And improve tests so they will catch the error, and other similar errors.
This commit is contained in:
Daniel James
2017-05-04 19:30:18 +01:00
parent d49d0e90a8
commit 47a8c3fc67
10 changed files with 268 additions and 36 deletions

View File

@ -1516,7 +1516,7 @@ construct_from_args(Alloc& alloc, std::pair<A, B>* address, BOOST_FWD_REF(A0),
{
boost::unordered::detail::func::destroy(
boost::addressof(address->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
}
@ -1551,7 +1551,7 @@ inline typename enable_if<use_piecewise<A0>, void>::type construct_from_args(
{
boost::unordered::detail::func::destroy(
boost::addressof(address->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
}
@ -1630,7 +1630,7 @@ inline void construct_from_args(Alloc& alloc, std::pair<A, B>* address,
{
boost::unordered::detail::func::destroy(
boost::addressof(address->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
}
@ -1841,7 +1841,7 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k)
{
boost::unordered::detail::func::destroy(
boost::addressof(a.node_->value_ptr()->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
@ -1865,7 +1865,7 @@ construct_node_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m)
{
boost::unordered::detail::func::destroy(
boost::addressof(a.node_->value_ptr()->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
@ -1890,7 +1890,7 @@ construct_node_pair_from_args(
{
boost::unordered::detail::func::destroy(
boost::addressof(a.node_->value_ptr()->first));
BOOST_RETHROW;
BOOST_RETHROW
}
BOOST_CATCH_END
return a.release();
@ -4274,7 +4274,10 @@ inline void table<Types>::rehash_impl(std::size_t num_buckets)
}
}
}
BOOST_CATCH(...) { delete_nodes(prev, node_pointer()); }
BOOST_CATCH(...) {
delete_nodes(prev, node_pointer());
BOOST_RETHROW
}
BOOST_CATCH_END
}

View File

@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@ -21,7 +22,13 @@ template <class T> struct self_assign_base : public test::exception_base
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x = x; }
void run(T& x) const {
x = x;
test::check_container(x, values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
test::check_equivalent_keys(x);
@ -57,7 +64,13 @@ template <class T> struct assign_base : public test::exception_base
typedef T data_type;
T init() const { return T(x); }
void run(T& x1) const { x1 = y; }
void run(T& x1) const {
x1 = y;
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);

View File

@ -7,6 +7,8 @@
#include "../helpers/input_iterator.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@ -25,7 +27,8 @@ template <class T> struct construct_test1 : public objects, test::exception_base
void run() const
{
T x;
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -34,7 +37,8 @@ template <class T> struct construct_test2 : public objects, test::exception_base
void run() const
{
T x(300);
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -43,7 +47,8 @@ template <class T> struct construct_test3 : public objects, test::exception_base
void run() const
{
T x(0, hash);
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -52,7 +57,8 @@ template <class T> struct construct_test4 : public objects, test::exception_base
void run() const
{
T x(0, hash, equal_to);
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -61,7 +67,8 @@ template <class T> struct construct_test5 : public objects, test::exception_base
void run() const
{
T x(50, hash, equal_to, allocator);
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -70,7 +77,8 @@ template <class T> struct construct_test6 : public objects, test::exception_base
void run() const
{
T x(allocator);
avoid_unused_warning(x);
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};
@ -87,7 +95,8 @@ template <class T> struct range_construct_test1 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end());
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -96,7 +105,8 @@ template <class T> struct range_construct_test2 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -105,7 +115,8 @@ template <class T> struct range_construct_test3 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 0, hash);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -114,7 +125,8 @@ template <class T> struct range_construct_test4 : public range<T>, objects
void run() const
{
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -128,7 +140,8 @@ template <class T> struct range_construct_test5 : public range<T>, objects
{
T x(this->values.begin(), this->values.end(), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -143,7 +156,8 @@ template <class T> struct input_range_construct_test : public range<T>, objects
end = this->values.end();
T x(test::input_iterator(begin), test::input_iterator(end), 0, hash,
equal_to, allocator);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -156,7 +170,8 @@ template <class T> struct copy_range_construct_test : public range<T>, objects
T x(test::copy_iterator(this->values.begin()),
test::copy_iterator(this->values.end()), 0, hash, equal_to,
allocator);
avoid_unused_warning(x);
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};

View File

@ -6,6 +6,8 @@
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/tracker.hpp"
template <typename T> inline void avoid_unused_warning(T const&) {}
@ -18,7 +20,8 @@ template <class T> struct copy_test1 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
BOOST_TEST(y.empty());
test::check_equivalent_keys(y);
}
};
@ -32,7 +35,8 @@ template <class T> struct copy_test2 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@ -46,7 +50,8 @@ template <class T> struct copy_test3 : public test::exception_base
void run() const
{
T y(x);
avoid_unused_warning(y);
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};
@ -61,7 +66,8 @@ template <class T> struct copy_with_allocator_test : public test::exception_base
void run() const
{
T y(x, allocator);
avoid_unused_warning(y);
test::check_container(y, this->values);
test::check_equivalent_keys(y);
}
};

View File

@ -43,6 +43,9 @@ template <class T> struct erase_by_key_test1 : public erase_test_base<T>
it != end; ++it) {
x.erase(test::get_key<T>(*it));
}
BOOST_TEST(x.empty());
test::check_equivalent_keys(x);
}
};

View File

@ -2,13 +2,14 @@
// Copyright 2006-2009 Daniel James.
// 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 "./containers.hpp"
#include <iostream>
#include "../helpers/helpers.hpp"
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <cmath>
#include <string>
@ -54,6 +55,10 @@ template <class T> struct emplace_test1 : public insert_test_base<T>
strong.store(x, test::detail::tracker.count_allocations);
x.emplace(*it);
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -72,6 +77,10 @@ template <class T> struct insert_test1 : public insert_test_base<T>
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -88,12 +97,23 @@ template <class T> struct insert_test2 : public insert_test_base<T>
strong.store(x, test::detail::tracker.count_allocations);
x.insert(x.begin(), *it);
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct insert_test3 : public insert_test_base<T>
{
void run(T& x) const { x.insert(this->values.begin(), this->values.end()); }
void run(T& x) const
{
x.insert(this->values.begin(), this->values.end());
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
@ -114,6 +134,10 @@ template <class T> struct insert_test4 : public insert_test_base<T>
strong.store(x, test::detail::tracker.count_allocations);
x.insert(it, test::next(it));
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -147,17 +171,30 @@ template <class T> struct insert_test_rehash1 : public insert_test_base<T>
int count = 0;
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
test::list<typename T::value_type> v;
{
DISABLE_EXCEPTIONS;
v.insert(x.begin(), x.end());
}
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
pos = x.insert(pos, *it);
DISABLE_EXCEPTIONS;
v.push_back(*it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
DISABLE_EXCEPTIONS;
test::check_container(x, v);
test::check_equivalent_keys(x);
}
};
@ -170,17 +207,30 @@ template <class T> struct insert_test_rehash2 : public insert_test_rehash1<T>
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
int count = 0;
test::list<typename T::value_type> v;
{
DISABLE_EXCEPTIONS;
v.insert(x.begin(), x.end());
}
for (BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
it = test::next(this->values.begin(), x.size()),
end = this->values.end();
it != end && count < 10; ++it, ++count) {
strong.store(x, test::detail::tracker.count_allocations);
x.insert(*it);
DISABLE_EXCEPTIONS;
v.push_back(*it);
}
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
DISABLE_EXCEPTIONS;
test::check_container(x, v);
test::check_equivalent_keys(x);
}
};
@ -218,6 +268,14 @@ template <class T> struct insert_test_rehash3 : public insert_test_base<T>
void run(T& x) const
{
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
test::list<typename T::value_type> v;
{
DISABLE_EXCEPTIONS;
v.insert(x.begin(), x.end());
v.insert(test::next(this->values.begin(), x.size()),
test::next(this->values.begin(), x.size() + 20));
}
x.insert(test::next(this->values.begin(), x.size()),
test::next(this->values.begin(), x.size() + 20));
@ -225,6 +283,10 @@ template <class T> struct insert_test_rehash3 : public insert_test_base<T>
// This isn't actually a failure, but it means the test isn't doing its
// job.
BOOST_TEST(x.bucket_count() != bucket_count);
DISABLE_EXCEPTIONS;
test::check_container(x, v);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
@ -263,6 +325,10 @@ template <class T> struct pair_emplace_test1 : public insert_test_base<T>
x.emplace(boost::unordered::piecewise_construct,
boost::make_tuple(it->first), boost::make_tuple(it->second));
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
@ -281,6 +347,10 @@ template <class T> struct pair_emplace_test2 : public insert_test_base<T>
boost::make_tuple(it->first),
boost::make_tuple(it->second.tag1_, it->second.tag2_));
}
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};

View File

@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#include <iostream>
#if defined(BOOST_MSVC)
@ -42,7 +43,11 @@ template <class T> struct move_assign_base : public test::exception_base
T y1 = y;
disable_exceptions.release();
x1 = boost::move(y1);
test::check_container(x1, y_values);
test::check_equivalent_keys(x1);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
{
test::check_equivalent_keys(x1);

View File

@ -8,6 +8,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/strong.hpp"
#include "../helpers/tracker.hpp"
#include <string>
#include <iostream>
@ -49,34 +50,76 @@ template <class T> struct rehash_test_base : public test::exception_base
template <class T> struct rehash_test0 : rehash_test_base<T>
{
rehash_test0() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test1 : rehash_test_base<T>
{
rehash_test1() : rehash_test_base<T>(0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test2 : rehash_test_base<T>
{
rehash_test2() : rehash_test_base<T>(0, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test3 : rehash_test_base<T>
{
rehash_test3() : rehash_test_base<T>(10, 0) {}
void run(T& x) const { x.rehash(200); }
void run(T& x) const
{
x.rehash(200);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
template <class T> struct rehash_test4 : rehash_test_base<T>
{
rehash_test4() : rehash_test_base<T>(10, 200) {}
void run(T& x) const { x.rehash(0); }
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS(
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
template <class T> struct rehash_test5 : rehash_test_base<T>
{
rehash_test5() : rehash_test_base<T>(200, 10) {}
void run(T& x) const
{
x.rehash(0);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
};
EXCEPTION_TESTS((rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(
rehash_test4)(rehash_test5),
CONTAINER_SEQ)
RUN_TESTS()

View File

@ -7,6 +7,7 @@
#include "../helpers/invariants.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"
#if defined(BOOST_MSVC)
#pragma warning(disable : 4512) // assignment operator could not be generated
@ -21,7 +22,15 @@ template <class T> struct self_swap_base : public test::exception_base
typedef T data_type;
T init() const { return T(values.begin(), values.end()); }
void run(T& x) const { x.swap(x); }
void run(T& x) const {
x.swap(x);
DISABLE_EXCEPTIONS;
test::check_container(x, this->values);
test::check_equivalent_keys(x);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
{
std::string scope(test::scope);
@ -82,7 +91,14 @@ template <class T> struct swap_base : public test::exception_base
d.x.swap(d.y);
} catch (std::runtime_error) {
}
DISABLE_EXCEPTIONS;
test::check_container(d.x, this->y_values);
test::check_equivalent_keys(d.x);
test::check_container(d.y, this->x_values);
test::check_equivalent_keys(d.y);
}
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
{
std::string scope(test::scope);

View File

@ -11,6 +11,7 @@
#include "../helpers/count.hpp"
#include "../helpers/fwd.hpp"
#include "../helpers/memory.hpp"
#include "../objects/fwd.hpp"
#include <boost/limits.hpp>
#include <cstddef>
#include <iostream>
@ -311,6 +312,55 @@ class equal_to
}
};
class less
{
int tag_;
public:
less(int t = 0) : tag_(t) {}
less(less const& x) : tag_(x.tag_) {}
bool operator()(object const& x1, object const& x2) const
{
return less_impl(x1, x2);
}
bool operator()(std::pair<object, object> const& x1,
std::pair<object, object> const& x2) const
{
if (less_impl(x1.first, x2.first)) {
return true;
}
if (!less_impl(x1.first, x2.first)) {
return false;
}
return less_impl(x1.second, x2.second);
}
bool less_impl(object const& x1, object const& x2) const
{
switch (tag_) {
case 1:
return x1.tag1_ < x2.tag1_;
case 2:
return x1.tag2_ < x2.tag2_;
default:
return x1 < x2;
}
}
friend bool operator==(less const& x1, less const& x2)
{
return x1.tag_ == x2.tag_;
}
friend bool operator!=(less const& x1, less const& x2)
{
return x1.tag_ != x2.tag_;
}
};
template <class T> class allocator
{
public:
@ -672,6 +722,14 @@ inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y)
}
}
namespace test {
template <typename X> struct equals_to_compare;
template <> struct equals_to_compare<test::exception::equal_to>
{
typedef test::exception::less type;
};
}
// Workaround for ADL deficient compilers
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace test {