forked from boostorg/unordered
More tests for unordered associative containers.
[SVN r2959]
This commit is contained in:
@@ -5,3 +5,4 @@
|
|||||||
|
|
||||||
build-project container ;
|
build-project container ;
|
||||||
build-project unordered ;
|
build-project unordered ;
|
||||||
|
build-project exception ;
|
||||||
|
111
test/container/simple_tests.cpp
Normal file
111
test/container/simple_tests.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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)
|
||||||
|
|
||||||
|
// This test checks the runtime requirements of containers.
|
||||||
|
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "../helpers/equivalent.hpp"
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void simple_test(X const& a)
|
||||||
|
{
|
||||||
|
test::unordered_equivalence_tester<X> equivalent(a);
|
||||||
|
|
||||||
|
{
|
||||||
|
X u;
|
||||||
|
BOOST_TEST(u.size() == 0);
|
||||||
|
BOOST_TEST(X().size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST(equivalent(X(a)));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X u(a);
|
||||||
|
BOOST_TEST(equivalent(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X u = a;
|
||||||
|
BOOST_TEST(equivalent(u));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X b(a);
|
||||||
|
BOOST_TEST(b.begin() == const_cast<X const&>(b).cbegin());
|
||||||
|
BOOST_TEST(b.end() == const_cast<X const&>(b).cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: Also test with a random container...
|
||||||
|
X b(a);
|
||||||
|
X c;
|
||||||
|
BOOST_TEST(equivalent(b));
|
||||||
|
BOOST_TEST(c.empty());
|
||||||
|
b.swap(c);
|
||||||
|
BOOST_TEST(b.empty());
|
||||||
|
BOOST_TEST(equivalent(c));
|
||||||
|
b.swap(c);
|
||||||
|
BOOST_TEST(b.empty());
|
||||||
|
BOOST_TEST(equivalent(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X u;
|
||||||
|
X& r(u);
|
||||||
|
// TODO: I can't actually see a requirement for that assignment
|
||||||
|
// returns a reference to itself (just that it returns a reference).
|
||||||
|
BOOST_TEST(&(r = r) == &r);
|
||||||
|
BOOST_TEST(r.empty());
|
||||||
|
BOOST_TEST(&(r = a) == &r);
|
||||||
|
BOOST_TEST(equivalent(r));
|
||||||
|
BOOST_TEST(&(r = r) == &r);
|
||||||
|
BOOST_TEST(equivalent(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST(a.size() ==
|
||||||
|
(typename X::size_type) std::distance(a.begin(), a.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test max_size against allocator?
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST(a.empty() == (a.size() == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BOOST_TEST(a.empty() == (a.begin() == a.end()));
|
||||||
|
X u;
|
||||||
|
BOOST_TEST(u.begin() == u.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Test construction with allocator?
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
boost::unordered_set<int> set;
|
||||||
|
simple_test(set);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
boost::unordered_multiset<int> multiset;
|
||||||
|
simple_test(multiset);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_map.\n";
|
||||||
|
boost::unordered_map<int, int> map;
|
||||||
|
simple_test(map);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_multimap.\n";
|
||||||
|
boost::unordered_multimap<int, int> multimap;
|
||||||
|
simple_test(multimap);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
29
test/exception/Jamfile.v2
Normal file
29
test/exception/Jamfile.v2
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
# Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
# subject to 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)
|
||||||
|
|
||||||
|
import testing ;
|
||||||
|
|
||||||
|
alias framework : /boost/test//boost_unit_test_framework/<optimization>speed ;
|
||||||
|
|
||||||
|
project unordered-test/exception-tests
|
||||||
|
: requirements
|
||||||
|
<toolset>intel-linux:"<cxxflags>-strict_ansi -cxxlib-icc"
|
||||||
|
;
|
||||||
|
|
||||||
|
test-suite unordered-tests
|
||||||
|
:
|
||||||
|
[ run constructor_tests.cpp framework ]
|
||||||
|
[ run copy_tests.cpp framework ]
|
||||||
|
[ run assign_tests.cpp framework ]
|
||||||
|
[ run insert_tests.cpp framework ]
|
||||||
|
[ run erase_tests.cpp framework ]
|
||||||
|
[ run rehash_tests.cpp framework ]
|
||||||
|
[ run swap_tests.cpp framework : : :
|
||||||
|
<define>BOOST_UNORDERED_SWAP_METHOD=1 : swap_tests1 ]
|
||||||
|
[ run swap_tests.cpp framework : : :
|
||||||
|
<define>BOOST_UNORDERED_SWAP_METHOD=2 : swap_tests2 ]
|
||||||
|
[ run swap_tests.cpp framework : : :
|
||||||
|
<define>BOOST_UNORDERED_SWAP_METHOD=3 : swap_tests3 ]
|
||||||
|
;
|
79
test/exception/assign_tests.cpp
Normal file
79
test/exception/assign_tests.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_assign_base : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
self_assign_base(int count = 0) : values(count) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
T init() const { return T(values.begin(), values.end()); }
|
||||||
|
void run(T& x) const { x = x; }
|
||||||
|
void check(T const& x) const { test::check_equivalent_keys(x); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_assign_test1 : self_assign_base<T> {};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_assign_test2 : self_assign_base<T>
|
||||||
|
{
|
||||||
|
self_assign_test2() : self_assign_base<T>(100) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct assign_base : public test::exception_base
|
||||||
|
{
|
||||||
|
const test::random_values<T> x_values, y_values;
|
||||||
|
const T x,y;
|
||||||
|
|
||||||
|
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||||
|
: x_values(count1), y_values(count2),
|
||||||
|
x(x_values.begin(), x_values.end(), 0, typename T::hasher(tag1), typename T::key_equal(tag1), typename T::allocator_type(tag1)),
|
||||||
|
y(y_values.begin(), y_values.end(), 0, typename T::hasher(tag2), typename T::key_equal(tag2), typename T::allocator_type(tag2)) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
T init() const { return T(x); }
|
||||||
|
void run(T& x1) const { x1 = y; }
|
||||||
|
void check(T const& x1) const { test::check_equivalent_keys(x1); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct assign_test1 : assign_base<T>
|
||||||
|
{
|
||||||
|
assign_test1() : assign_base<T>(0, 0, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct assign_test2 : assign_base<T>
|
||||||
|
{
|
||||||
|
assign_test2() : assign_base<T>(60, 0, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct assign_test3 : assign_base<T>
|
||||||
|
{
|
||||||
|
assign_test3() : assign_base<T>(0, 60, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct assign_test4 : assign_base<T>
|
||||||
|
{
|
||||||
|
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(self_assign_test1)(self_assign_test2)
|
||||||
|
(assign_test1)(assign_test2)(assign_test3)(assign_test4),
|
||||||
|
CONTAINER_SEQ)
|
119
test/exception/constructor_tests.cpp
Normal file
119
test/exception/constructor_tests.cpp
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
|
||||||
|
struct objects
|
||||||
|
{
|
||||||
|
test::exception::object obj;
|
||||||
|
test::exception::hash hash;
|
||||||
|
test::exception::equal_to equal_to;
|
||||||
|
test::exception::allocator<test::exception::object> allocator;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct construct_test1 : public objects, test::exception_base
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct construct_test2 : public objects, test::exception_base
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(300);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct construct_test3 : public objects, test::exception_base
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(0, hash);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct construct_test4 : public objects, test::exception_base
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(0, hash, equal_to);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct construct_test5 : public objects, test::exception_base
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(50, hash, equal_to, allocator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct range : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
|
||||||
|
range() : values(5) {}
|
||||||
|
range(unsigned int count) : values(count) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct range_construct_test1 : public range<T>, objects
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(this->values.begin(), this->values.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct range_construct_test2 : public range<T>, objects
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(this->values.begin(), this->values.end(), 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct range_construct_test3 : public range<T>, objects
|
||||||
|
{
|
||||||
|
void run() const {
|
||||||
|
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Need to run at least one test with a fairly large number
|
||||||
|
// of objects in case it triggers a rehash.
|
||||||
|
template <class T>
|
||||||
|
struct range_construct_test5 : public range<T>, objects
|
||||||
|
{
|
||||||
|
range_construct_test5() : range<T>(60) {}
|
||||||
|
|
||||||
|
void run() const {
|
||||||
|
T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Write a test using an input iterator.
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5)
|
||||||
|
(range_construct_test1)(range_construct_test2)(range_construct_test3)(range_construct_test4)(range_construct_test5),
|
||||||
|
CONTAINER_SEQ)
|
28
test/exception/containers.hpp
Normal file
28
test/exception/containers.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
#include "../objects/exception.hpp"
|
||||||
|
|
||||||
|
typedef boost::unordered_set<
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::hash,
|
||||||
|
test::exception::equal_to,
|
||||||
|
test::exception::allocator<test::exception::object> > set;
|
||||||
|
typedef boost::unordered_multiset<
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::hash,
|
||||||
|
test::exception::equal_to,
|
||||||
|
test::exception::allocator<test::exception::object> > multiset;
|
||||||
|
typedef boost::unordered_map<
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::hash,
|
||||||
|
test::exception::equal_to,
|
||||||
|
test::exception::allocator<test::exception::object> > map;
|
||||||
|
typedef boost::unordered_multimap<
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::object,
|
||||||
|
test::exception::hash,
|
||||||
|
test::exception::equal_to,
|
||||||
|
test::exception::allocator<test::exception::object> > multimap;
|
||||||
|
|
||||||
|
#define CONTAINER_SEQ (set)(multiset)(map)(multimap)
|
51
test/exception/copy_tests.cpp
Normal file
51
test/exception/copy_tests.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct copy_test1 : public test::exception_base
|
||||||
|
{
|
||||||
|
T x;
|
||||||
|
|
||||||
|
void run() const {
|
||||||
|
T y(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct copy_test2 : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
T x;
|
||||||
|
|
||||||
|
copy_test2() : values(5), x(values.begin(), values.end()) {}
|
||||||
|
|
||||||
|
void run() const {
|
||||||
|
T y(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct copy_test3 : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
T x;
|
||||||
|
|
||||||
|
copy_test3() : values(100), x(values.begin(), values.end()) {}
|
||||||
|
|
||||||
|
void run() const {
|
||||||
|
T y(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(copy_test1)(copy_test2)(copy_test3),
|
||||||
|
CONTAINER_SEQ)
|
55
test/exception/erase_tests.cpp
Normal file
55
test/exception/erase_tests.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
#include "../helpers/helpers.hpp"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct erase_test_base : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
erase_test_base(unsigned int count = 5) : values(count) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
|
||||||
|
data_type init() const {
|
||||||
|
return T(values.begin(), values.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(T const& x) const {
|
||||||
|
// TODO: Check that exception was thrown by hash or predicate object?
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct erase_by_key_test1 : public erase_test_base<T>
|
||||||
|
{
|
||||||
|
void run(T& x) const
|
||||||
|
{
|
||||||
|
typedef typename test::random_values<T>::const_iterator iterator;
|
||||||
|
|
||||||
|
for(iterator it = this->values.begin(), end = this->values.end();
|
||||||
|
it != end; ++it)
|
||||||
|
{
|
||||||
|
x.erase(test::get_key<T>(*it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: More tests...
|
||||||
|
// Better test by key.
|
||||||
|
// Test other erase signatures - generally they won't throw, but the standard
|
||||||
|
// does allow them to. And test clear as well.
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(erase_by_key_test1),
|
||||||
|
CONTAINER_SEQ)
|
168
test/exception/insert_tests.cpp
Normal file
168
test/exception/insert_tests.cpp
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
#include "../helpers/strong.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test_base : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
insert_test_base(unsigned int count = 5) : values(count) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
typedef test::strong<T> strong_type;
|
||||||
|
|
||||||
|
data_type init() const {
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(T const& x, strong_type const& strong) const {
|
||||||
|
std::string scope(test::scope);
|
||||||
|
|
||||||
|
if(scope.find_first_of("hash::operator()") == std::string::npos)
|
||||||
|
strong.test(x);
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test1 : public insert_test_base<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
for(typename test::random_values<T>::const_iterator
|
||||||
|
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
strong.store(x);
|
||||||
|
x.insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test2 : public insert_test_base<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
for(typename test::random_values<T>::const_iterator
|
||||||
|
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
strong.store(x);
|
||||||
|
x.insert(x.begin(), *it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test3 : public insert_test_base<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
// I don't think there's any need for this here.
|
||||||
|
//strong.store(x);
|
||||||
|
x.insert(this->values.begin(), this->values.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(T const& x) const {
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test4 : public insert_test_base<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
for(typename test::random_values<T>::const_iterator
|
||||||
|
it = this->values.begin(), end = this->values.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
strong.store(x);
|
||||||
|
x.insert(it, boost::next(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test_rehash1 : public insert_test_base<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
insert_test_rehash1() : insert_test_base<T>(1000) {}
|
||||||
|
|
||||||
|
T init() const {
|
||||||
|
typedef typename T::size_type size_type;
|
||||||
|
|
||||||
|
T x;
|
||||||
|
x.max_load_factor(0.25);
|
||||||
|
size_type bucket_count = x.bucket_count();
|
||||||
|
size_type initial_elements = static_cast<size_type>(
|
||||||
|
std::ceil(bucket_count * x.max_load_factor()) - 1);
|
||||||
|
BOOST_REQUIRE(initial_elements < this->values.size());
|
||||||
|
x.insert(this->values.begin(),
|
||||||
|
boost::next(this->values.begin(), initial_elements));
|
||||||
|
BOOST_REQUIRE(bucket_count == x.bucket_count());
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
typename T::size_type bucket_count = x.bucket_count();
|
||||||
|
int count = 0;
|
||||||
|
typename T::const_iterator pos = x.cbegin();
|
||||||
|
|
||||||
|
for(typename test::random_values<T>::const_iterator
|
||||||
|
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
|
||||||
|
it != end && count < 10; ++it, ++count)
|
||||||
|
{
|
||||||
|
strong.store(x);
|
||||||
|
pos = x.insert(pos, *it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This isn't actually a failure, but it means the test isn't doing its
|
||||||
|
// job.
|
||||||
|
BOOST_REQUIRE(x.bucket_count() != bucket_count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct insert_test_rehash2 : public insert_test_rehash1<T>
|
||||||
|
{
|
||||||
|
typedef typename insert_test_base<T>::strong_type strong_type;
|
||||||
|
|
||||||
|
void run(T& x, strong_type& strong) const {
|
||||||
|
typename T::size_type bucket_count = x.bucket_count();
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for(typename test::random_values<T>::const_iterator
|
||||||
|
it = boost::next(this->values.begin(), x.size()), end = this->values.end();
|
||||||
|
it != end && count < 10; ++it, ++count)
|
||||||
|
{
|
||||||
|
strong.store(x);
|
||||||
|
x.insert(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This isn't actually a failure, but it means the test isn't doing its
|
||||||
|
// job.
|
||||||
|
BOOST_REQUIRE(x.bucket_count() != bucket_count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(insert_test1)(insert_test2)(insert_test3)(insert_test4)
|
||||||
|
(insert_test_rehash1)(insert_test_rehash2),
|
||||||
|
CONTAINER_SEQ)
|
80
test/exception/rehash_tests.cpp
Normal file
80
test/exception/rehash_tests.cpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
#include "../helpers/strong.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct rehash_test_base : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
unsigned int n;
|
||||||
|
rehash_test_base(unsigned int count = 100, unsigned int n = 0) : values(count), n(n) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
typedef test::strong<T> strong_type;
|
||||||
|
|
||||||
|
data_type init() const {
|
||||||
|
T x(values.begin(), values.end(), n);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(T const& x, strong_type const& strong) const {
|
||||||
|
std::string scope(test::scope);
|
||||||
|
|
||||||
|
if(scope.find_first_of("hash::operator()") == std::string::npos &&
|
||||||
|
scope.find_first_of("equal_to::operator()") == std::string::npos)
|
||||||
|
strong.test(x);
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
|
||||||
|
CONTAINER_SEQ)
|
107
test/exception/swap_tests.cpp
Normal file
107
test/exception/swap_tests.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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"
|
||||||
|
|
||||||
|
#define BOOST_TEST_MAIN
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_swap_base : public test::exception_base
|
||||||
|
{
|
||||||
|
test::random_values<T> values;
|
||||||
|
self_swap_base(int count = 0) : values(count) {}
|
||||||
|
|
||||||
|
typedef T data_type;
|
||||||
|
T init() const { return T(values.begin(), values.end()); }
|
||||||
|
void run(T& x) const { x.swap(x); }
|
||||||
|
void check(T const& x) const {
|
||||||
|
std::string scope(test::scope);
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
||||||
|
BOOST_CHECK(
|
||||||
|
scope == "hash::operator(hash)" ||
|
||||||
|
scope == "hash::operator=(hash)" ||
|
||||||
|
scope == "equal_to::operator(equal_to)" ||
|
||||||
|
scope == "equal_to::operator=(equal_to)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_swap_test1 : self_swap_base<T> {};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct self_swap_test2 : self_swap_base<T>
|
||||||
|
{
|
||||||
|
self_swap_test2() : self_swap_base<T>(100) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct swap_base : public test::exception_base
|
||||||
|
{
|
||||||
|
const test::random_values<T> x_values, y_values;
|
||||||
|
const T initial_x, initial_y;
|
||||||
|
|
||||||
|
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||||
|
: x_values(count1), y_values(count2),
|
||||||
|
initial_x(x_values.begin(), x_values.end(), 0, typename T::hasher(tag1),
|
||||||
|
typename T::key_equal(tag1), typename T::allocator_type(tag1)),
|
||||||
|
initial_y(y_values.begin(), y_values.end(), 0, typename T::hasher(tag2),
|
||||||
|
typename T::key_equal(tag2), typename T::allocator_type(tag2))
|
||||||
|
{}
|
||||||
|
|
||||||
|
struct data_type {
|
||||||
|
data_type(T const& x, T const& y)
|
||||||
|
: x(x), y(y) {}
|
||||||
|
|
||||||
|
T x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
data_type init() const { return data_type(initial_x, initial_y); }
|
||||||
|
void run(data_type& d) const {
|
||||||
|
try {
|
||||||
|
d.x.swap(d.y);
|
||||||
|
} catch (std::runtime_error) {}
|
||||||
|
}
|
||||||
|
void check(data_type const& d) const {
|
||||||
|
test::check_equivalent_keys(d.x);
|
||||||
|
test::check_equivalent_keys(d.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct swap_test1 : swap_base<T>
|
||||||
|
{
|
||||||
|
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct swap_test2 : swap_base<T>
|
||||||
|
{
|
||||||
|
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct swap_test3 : swap_base<T>
|
||||||
|
{
|
||||||
|
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct swap_test4 : swap_base<T>
|
||||||
|
{
|
||||||
|
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
RUN_EXCEPTION_TESTS(
|
||||||
|
(self_swap_test1)(self_swap_test2)
|
||||||
|
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||||
|
CONTAINER_SEQ)
|
@@ -15,20 +15,38 @@
|
|||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
template <class T>
|
template <class T>
|
||||||
bool equivalent(T const& x, T const& y) {
|
bool equivalent_impl(T const& x, T const& y) {
|
||||||
return x == y;
|
return x == y;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool equivalent(boost::hash<T> const&, boost::hash<T> const&) {
|
bool equivalent_impl(boost::hash<T> const&, boost::hash<T> const&) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
bool equivalent(std::equal_to<T> const&, std::equal_to<T> const&) {
|
bool equivalent_impl(std::equal_to<T> const&, std::equal_to<T> const&) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T1, class T2, class T3, class T4>
|
||||||
|
bool equivalent_impl(std::pair<T1, T2> const& x1,
|
||||||
|
std::pair<T3, T4> const& x2) {
|
||||||
|
return equivalent_impl(x1.first, x2.first) &&
|
||||||
|
equivalent_impl(x1.second, x2.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct equivalent_type {
|
||||||
|
template <class T1, class T2>
|
||||||
|
bool operator()(T1 const& x, T2 const& y) {
|
||||||
|
return equivalent_impl(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
equivalent_type equivalent;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Container>
|
template <class Container>
|
||||||
class unordered_equivalence_tester
|
class unordered_equivalence_tester
|
||||||
{
|
{
|
||||||
@@ -56,8 +74,8 @@ namespace test
|
|||||||
bool operator()(Container const& x) const
|
bool operator()(Container const& x) const
|
||||||
{
|
{
|
||||||
if(!((size_ == x.size()) &&
|
if(!((size_ == x.size()) &&
|
||||||
(test::equivalent(hasher_, x.hash_function())) &&
|
(test::equivalent_impl(hasher_, x.hash_function())) &&
|
||||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
(test::equivalent_impl(key_equal_, x.key_eq())) &&
|
||||||
(max_load_factor_ == x.max_load_factor()) &&
|
(max_load_factor_ == x.max_load_factor()) &&
|
||||||
(values_.size() == x.size()))) return false;
|
(values_.size() == x.size()))) return false;
|
||||||
|
|
||||||
|
@@ -51,23 +51,30 @@ namespace test
|
|||||||
if(x1.count(key) != count)
|
if(x1.count(key) != count)
|
||||||
BOOST_ERROR("Incorrect output of count.");
|
BOOST_ERROR("Incorrect output of count.");
|
||||||
|
|
||||||
// Check that the keys are in the correct bucket and are adjacent in
|
// I'm not bothering with the following test for now, as the
|
||||||
// the bucket.
|
// previous test is probably more enough to catch the kind of
|
||||||
typename X::size_type bucket = x1.bucket(key);
|
// errors that this would catch (if an element was in the wrong
|
||||||
typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
|
// bucket it not be found by the call to count, if elements are not
|
||||||
for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
// adjacent then they would be caught when checking against
|
||||||
if(lit == lend)
|
// found_.
|
||||||
BOOST_ERROR("Unable to find element with a local_iterator");
|
|
||||||
unsigned int count2 = 0;
|
// // Check that the keys are in the correct bucket and are
|
||||||
for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
// // adjacent in the bucket.
|
||||||
if(count != count2)
|
// typename X::size_type bucket = x1.bucket(key);
|
||||||
BOOST_ERROR("Element count doesn't match local_iterator.");
|
// typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||||
for(; lit != lend; ++lit) {
|
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||||
if(eq(get_key<X>(*lit), key)) {
|
// if(lit == lend)
|
||||||
BOOST_ERROR("Non-adjacent element with equivalent key in bucket.");
|
// BOOST_ERROR("Unable to find element with a local_iterator");
|
||||||
break;
|
// unsigned int count2 = 0;
|
||||||
}
|
// for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
||||||
}
|
// if(count != count2)
|
||||||
|
// BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||||
|
// for(; lit != lend; ++lit) {
|
||||||
|
// if(eq(get_key<X>(*lit), key)) {
|
||||||
|
// BOOST_ERROR("Non-adjacent element with equivalent key in bucket.");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Finally, check that size matches up.
|
// Finally, check that size matches up.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
// Copyright Daniel James 2005. Use, modification, and distribution are
|
// Copyright Daniel James 2005-2006. Use, modification, and distribution are
|
||||||
// subject to the Boost Software License, Version 1.0. (See accompanying
|
// subject to 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
47
test/helpers/strong.hpp
Normal file
47
test/helpers/strong.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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)
|
||||||
|
|
||||||
|
#if !defined(BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER)
|
||||||
|
#define BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
#include "./metafunctions.hpp"
|
||||||
|
#include "./equivalent.hpp"
|
||||||
|
#include "../objects/exception.hpp"
|
||||||
|
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
template <class X>
|
||||||
|
class strong
|
||||||
|
{
|
||||||
|
typedef std::vector<typename non_const_value_type<X>::type> values_type;
|
||||||
|
values_type values_;
|
||||||
|
public:
|
||||||
|
void store(X const& x) {
|
||||||
|
// TODO: Well, I shouldn't be disabling exceptions here. Instead
|
||||||
|
// the test runner should provide a method to the test which
|
||||||
|
// disables exceptions and calls this.
|
||||||
|
//
|
||||||
|
// Actually, the test runner could also keep track of how many times
|
||||||
|
// store is called in a run. Because it knows that in the next run
|
||||||
|
// the first n-1 stores are unnecessary - since no exceptions will
|
||||||
|
// be thrown for them.
|
||||||
|
DISABLE_EXCEPTIONS;
|
||||||
|
values_.clear();
|
||||||
|
values_.reserve(x.size());
|
||||||
|
std::copy(x.cbegin(), x.cend(), std::back_inserter(values_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test(X const& x) const {
|
||||||
|
if(!(x.size() == values_.size() &&
|
||||||
|
std::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent)))
|
||||||
|
BOOST_ERROR("Strong exception safety failure.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
522
test/objects/exception.hpp
Normal file
522
test/objects/exception.hpp
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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)
|
||||||
|
|
||||||
|
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER)
|
||||||
|
#define BOOST_UNORDERED_TEST_OBJECTS_HEADER
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include <boost/test/test_tools.hpp>
|
||||||
|
#include <boost/test/exception_safety.hpp>
|
||||||
|
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||||
|
#include <boost/preprocessor/seq/elem.hpp>
|
||||||
|
#include <boost/preprocessor/cat.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "../helpers/fwd.hpp"
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// a) This can only be included in compile unit.
|
||||||
|
// b) This stuff should be somewhere else.
|
||||||
|
// but I'm feeling too lazy right now (although sadly not lazy enough to
|
||||||
|
// avoid reinventing yet another wheel).
|
||||||
|
|
||||||
|
#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \
|
||||||
|
BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, (test_seq)(param_seq))
|
||||||
|
|
||||||
|
#define RUN_EXCEPTION_TESTS_OP(r, product) \
|
||||||
|
RUN_EXCEPTION_TESTS_OP2( \
|
||||||
|
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
|
||||||
|
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \
|
||||||
|
), \
|
||||||
|
BOOST_PP_SEQ_ELEM(0, product), \
|
||||||
|
BOOST_PP_SEQ_ELEM(1, product) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define RUN_EXCEPTION_TESTS_OP2(name, test_func, type) \
|
||||||
|
BOOST_AUTO_TEST_CASE(name) \
|
||||||
|
{ \
|
||||||
|
test_func< type > fixture; \
|
||||||
|
::test::exception_safety(fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SCOPE(scope_name) \
|
||||||
|
BOOST_ITEST_SCOPE(scope_name); \
|
||||||
|
for(::test::scope_guard unordered_test_guard( \
|
||||||
|
BOOST_STRINGIZE(scope_name)); \
|
||||||
|
!unordered_test_guard.dismissed(); \
|
||||||
|
unordered_test_guard.dismiss())
|
||||||
|
|
||||||
|
#define EPOINT(name) \
|
||||||
|
if(::test::exceptions_enabled) { \
|
||||||
|
BOOST_ITEST_EPOINT(name); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ENABLE_EXCEPTIONS \
|
||||||
|
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
|
||||||
|
#define DISABLE_EXCEPTIONS \
|
||||||
|
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
static char const* scope = "";
|
||||||
|
bool exceptions_enabled = false;
|
||||||
|
|
||||||
|
class scope_guard {
|
||||||
|
scope_guard& operator=(scope_guard const&);
|
||||||
|
scope_guard(scope_guard const&);
|
||||||
|
|
||||||
|
char const* old_scope_;
|
||||||
|
char const* scope_;
|
||||||
|
bool dismissed_;
|
||||||
|
public:
|
||||||
|
scope_guard(char const* name)
|
||||||
|
: old_scope_(scope),
|
||||||
|
scope_(name),
|
||||||
|
dismissed_(false)
|
||||||
|
{
|
||||||
|
scope = scope_;
|
||||||
|
}
|
||||||
|
|
||||||
|
~scope_guard() {
|
||||||
|
if(dismissed_) scope = old_scope_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dismiss() {
|
||||||
|
dismissed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dismissed() const {
|
||||||
|
return dismissed_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class exceptions_enable
|
||||||
|
{
|
||||||
|
exceptions_enable& operator=(exceptions_enable const&);
|
||||||
|
exceptions_enable(exceptions_enable const&);
|
||||||
|
|
||||||
|
bool old_value_;
|
||||||
|
public:
|
||||||
|
exceptions_enable(bool enable)
|
||||||
|
: old_value_(exceptions_enabled)
|
||||||
|
{
|
||||||
|
exceptions_enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
~exceptions_enable()
|
||||||
|
{
|
||||||
|
exceptions_enabled = old_value_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exception_base {
|
||||||
|
struct data_type {};
|
||||||
|
struct strong_type {
|
||||||
|
template <class T> void store(T const&) {}
|
||||||
|
template <class T> void test(T const&) const {}
|
||||||
|
};
|
||||||
|
data_type init() const { return data_type(); }
|
||||||
|
void check() const {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class P1, class P2, class T2>
|
||||||
|
inline void call_with_increased_arity(void (T::*fn)() const, T2 const& obj,
|
||||||
|
P1&, P2&)
|
||||||
|
{
|
||||||
|
(obj.*fn)();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class P1, class P2, class T2>
|
||||||
|
inline void call_with_increased_arity(void (T::*fn)(P1&) const, T2 const& obj,
|
||||||
|
P1& p1, P2&)
|
||||||
|
{
|
||||||
|
(obj.*fn)(p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class P1, class P2, class T2>
|
||||||
|
inline void call_with_increased_arity(void (T::*fn)(P1&, P2&) const, T2 const& obj,
|
||||||
|
P1& p1, P2& p2)
|
||||||
|
{
|
||||||
|
(obj.*fn)(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T const& constant(T const& x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Test>
|
||||||
|
class test_runner
|
||||||
|
{
|
||||||
|
Test const& test_;
|
||||||
|
public:
|
||||||
|
test_runner(Test const& t) : test_(t) {}
|
||||||
|
void operator()() const {
|
||||||
|
DISABLE_EXCEPTIONS;
|
||||||
|
typename Test::data_type x(test_.init());
|
||||||
|
typename Test::strong_type strong;
|
||||||
|
strong.store(x);
|
||||||
|
try {
|
||||||
|
ENABLE_EXCEPTIONS;
|
||||||
|
call_with_increased_arity(&Test::run, test_, x, strong);
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
call_with_increased_arity(&Test::check, test_,
|
||||||
|
constant(x), constant(strong));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Test>
|
||||||
|
void exception_safety(Test const& f, char const* name) {
|
||||||
|
test_runner<Test> runner(f);
|
||||||
|
::boost::itest::exception_safety(runner, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
namespace exception
|
||||||
|
{
|
||||||
|
class object;
|
||||||
|
class hash;
|
||||||
|
class equal_to;
|
||||||
|
template <class T> class allocator;
|
||||||
|
|
||||||
|
class object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int tag1_, tag2_;
|
||||||
|
|
||||||
|
explicit object() : tag1_(0), tag2_(0)
|
||||||
|
{
|
||||||
|
SCOPE(object::object()) {
|
||||||
|
EPOINT("Mock object default constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit object(int t1, int t2 = 0) : tag1_(t1), tag2_(t2)
|
||||||
|
{
|
||||||
|
SCOPE(object::object(int)) {
|
||||||
|
EPOINT("Mock object constructor by value.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object(object const& x)
|
||||||
|
: tag1_(x.tag1_), tag2_(x.tag2_)
|
||||||
|
{
|
||||||
|
SCOPE(object::object(object)) {
|
||||||
|
EPOINT("Mock object copy constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object& operator=(object const& x)
|
||||||
|
{
|
||||||
|
SCOPE(object::operator=(object)) {
|
||||||
|
tag1_ = x.tag1_;
|
||||||
|
EPOINT("Mock object assign operator 1.");
|
||||||
|
tag2_ = x.tag2_;
|
||||||
|
//EPOINT("Mock object assign operator 2.");
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(object const& x1, object const& x2) {
|
||||||
|
SCOPE(operator==(object, object)) {
|
||||||
|
EPOINT("Mock object equality operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(object const& x1, object const& x2) {
|
||||||
|
SCOPE(operator!=(object, object)) {
|
||||||
|
EPOINT("Mock object inequality operator.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of the last few functions are used by the unordered associative
|
||||||
|
// containers - so there aren't any exception points.
|
||||||
|
friend bool operator<(object const& x1, object const& x2) {
|
||||||
|
return x1.tag1_ < x2.tag1_ ||
|
||||||
|
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend object generate(object const*) {
|
||||||
|
int* x = 0;
|
||||||
|
return object(::test::generate(x), ::test::generate(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, object const& o)
|
||||||
|
{
|
||||||
|
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class hash
|
||||||
|
{
|
||||||
|
int tag_;
|
||||||
|
public:
|
||||||
|
hash(int t = 0) : tag_(t)
|
||||||
|
{
|
||||||
|
SCOPE(hash::object()) {
|
||||||
|
EPOINT("Mock hash default constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hash(hash const& x)
|
||||||
|
: tag_(x.tag_)
|
||||||
|
{
|
||||||
|
SCOPE(hash::hash(hash)) {
|
||||||
|
EPOINT("Mock hash copy constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hash& operator=(hash const& x)
|
||||||
|
{
|
||||||
|
SCOPE(hash::operator=(hash)) {
|
||||||
|
EPOINT("Mock hash assign operator 1.");
|
||||||
|
tag_ = x.tag_;
|
||||||
|
EPOINT("Mock hash assign operator 2.");
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t operator()(object const& x) const {
|
||||||
|
SCOPE(hash::operator()(object)) {
|
||||||
|
EPOINT("Mock hash function.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(tag_) {
|
||||||
|
case 1:
|
||||||
|
return x.tag1_;
|
||||||
|
case 2:
|
||||||
|
return x.tag2_;
|
||||||
|
default:
|
||||||
|
return x.tag1_ + x.tag2_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(hash const& x1, hash const& x2) {
|
||||||
|
SCOPE(operator==(hash, hash)) {
|
||||||
|
EPOINT("Mock hash equality function.");
|
||||||
|
}
|
||||||
|
return x1.tag_ == x2.tag_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(hash const& x1, hash const& x2) {
|
||||||
|
SCOPE(hash::operator!=(hash, hash)) {
|
||||||
|
EPOINT("Mock hash inequality function.");
|
||||||
|
}
|
||||||
|
return x1.tag_ != x2.tag_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class equal_to
|
||||||
|
{
|
||||||
|
int tag_;
|
||||||
|
public:
|
||||||
|
equal_to(int t = 0) : tag_(t)
|
||||||
|
{
|
||||||
|
SCOPE(equal_to::equal_to()) {
|
||||||
|
EPOINT("Mock equal_to default constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
equal_to(equal_to const& x)
|
||||||
|
: tag_(x.tag_)
|
||||||
|
{
|
||||||
|
SCOPE(equal_to::equal_to(equal_to)) {
|
||||||
|
EPOINT("Mock equal_to copy constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
equal_to& operator=(equal_to const& x)
|
||||||
|
{
|
||||||
|
SCOPE(equal_to::operator=(equal_to)) {
|
||||||
|
EPOINT("Mock equal_to assign operator 1.");
|
||||||
|
tag_ = x.tag_;
|
||||||
|
EPOINT("Mock equal_to assign operator 2.");
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t operator()(object const& x1, object const& x2) const {
|
||||||
|
SCOPE(equal_to::operator()(object, object)) {
|
||||||
|
EPOINT("Mock equal_to function.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(tag_) {
|
||||||
|
case 1:
|
||||||
|
return x1.tag1_ == x2.tag1_;
|
||||||
|
case 2:
|
||||||
|
return x1.tag2_ == x2.tag2_;
|
||||||
|
default:
|
||||||
|
return x1 == x2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(equal_to const& x1, equal_to const& x2) {
|
||||||
|
SCOPE(operator==(equal_to, equal_to)) {
|
||||||
|
EPOINT("Mock equal_to equality function.");
|
||||||
|
}
|
||||||
|
return x1.tag_ == x2.tag_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(equal_to const& x1, equal_to const& x2) {
|
||||||
|
SCOPE(operator!=(equal_to, equal_to)) {
|
||||||
|
EPOINT("Mock equal_to inequality function.");
|
||||||
|
}
|
||||||
|
return x1.tag_ != x2.tag_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Need to track that same allocator is used to allocate, construct,
|
||||||
|
// deconstruct and destroy objects. Also, need to check that constructed
|
||||||
|
// objects are deconstructed (Boost.Test should take care of memory leaks
|
||||||
|
// for us).
|
||||||
|
template <class T>
|
||||||
|
class allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::size_t size_type;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef T* pointer;
|
||||||
|
typedef T const* const_pointer;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef T const& const_reference;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
template <class U> struct rebind { typedef allocator<U> other; };
|
||||||
|
|
||||||
|
explicit allocator(int t = 0)
|
||||||
|
{
|
||||||
|
SCOPE(allocator::allocator()) {
|
||||||
|
EPOINT("Mock allocator default constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y> allocator(allocator<Y> const& x)
|
||||||
|
{
|
||||||
|
SCOPE(allocator::allocator()) {
|
||||||
|
EPOINT("Mock allocator template copy constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator(allocator const&)
|
||||||
|
{
|
||||||
|
SCOPE(allocator::allocator()) {
|
||||||
|
EPOINT("Mock allocator copy constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~allocator() {}
|
||||||
|
|
||||||
|
allocator& operator=(allocator const&) {
|
||||||
|
SCOPE(allocator::allocator()) {
|
||||||
|
EPOINT("Mock allocator assignment operator.");
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer address(reference r) {
|
||||||
|
// TODO: Is this no throw? Major problems if it isn't.
|
||||||
|
//SCOPE(allocator::address(reference)) {
|
||||||
|
// EPOINT("Mock allocator address function.");
|
||||||
|
//}
|
||||||
|
return pointer(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_pointer address(const_reference r) {
|
||||||
|
// TODO: Is this no throw? Major problems if it isn't.
|
||||||
|
//SCOPE(allocator::address(const_reference)) {
|
||||||
|
// EPOINT("Mock allocator const address function.");
|
||||||
|
//}
|
||||||
|
return const_pointer(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer allocate(size_type n) {
|
||||||
|
T* ptr = 0;
|
||||||
|
SCOPE(allocator::allocate(size_type)) {
|
||||||
|
EPOINT("Mock allocator allocate function.");
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
ptr = (T*) malloc(n * sizeof(T));
|
||||||
|
if(!ptr) throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
return pointer(ptr);
|
||||||
|
|
||||||
|
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer allocate(size_type n, const_pointer u)
|
||||||
|
{
|
||||||
|
T* ptr = 0;
|
||||||
|
SCOPE(allocator::allocate(size_type, const_pointer)) {
|
||||||
|
EPOINT("Mock allocator allocate function.");
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
ptr = (T*) malloc(n * sizeof(T));
|
||||||
|
if(!ptr) throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
return pointer(ptr);
|
||||||
|
|
||||||
|
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(pointer p, size_type n)
|
||||||
|
{
|
||||||
|
//::operator delete((void*) p);
|
||||||
|
if(p) {
|
||||||
|
using namespace std;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct(pointer p, T const& t) {
|
||||||
|
SCOPE(allocator::construct(pointer, T)) {
|
||||||
|
EPOINT("Mock allocator construct function.");
|
||||||
|
new(p) T(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(pointer p) { p->~T(); }
|
||||||
|
|
||||||
|
size_type max_size() const {
|
||||||
|
SCOPE(allocator::construct(pointer, T)) {
|
||||||
|
EPOINT("Mock allocator max_size function.");
|
||||||
|
}
|
||||||
|
return (std::numeric_limits<std::size_t>::max)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(allocator<T> const& x, allocator<T> const& y)
|
||||||
|
{
|
||||||
|
// TODO: I can't meet the exception requirements for swap if this
|
||||||
|
// throws. Does the standard specify that allocator comparisons can't
|
||||||
|
// throw?
|
||||||
|
//
|
||||||
|
//SCOPE(operator==(allocator, allocator)) {
|
||||||
|
// EPOINT("Mock allocator equality operator.");
|
||||||
|
//}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator!=(allocator<T> const& x, allocator<T> const& y)
|
||||||
|
{
|
||||||
|
//SCOPE(operator!=(allocator, allocator)) {
|
||||||
|
// EPOINT("Mock allocator inequality operator.");
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@@ -3,8 +3,8 @@
|
|||||||
// subject to the Boost Software License, Version 1.0. (See accompanying
|
// subject to 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER)
|
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER)
|
||||||
#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER
|
#define BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER
|
||||||
|
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
|
@@ -147,6 +147,12 @@ namespace test
|
|||||||
template <class T>
|
template <class T>
|
||||||
class allocator
|
class allocator
|
||||||
{
|
{
|
||||||
|
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||||
|
public:
|
||||||
|
# else
|
||||||
|
template <class> friend class allocator;
|
||||||
|
# endif
|
||||||
|
int tag_;
|
||||||
public:
|
public:
|
||||||
typedef std::size_t size_type;
|
typedef std::size_t size_type;
|
||||||
typedef std::ptrdiff_t difference_type;
|
typedef std::ptrdiff_t difference_type;
|
||||||
@@ -158,9 +164,9 @@ namespace test
|
|||||||
|
|
||||||
template <class U> struct rebind { typedef allocator<U> other; };
|
template <class U> struct rebind { typedef allocator<U> other; };
|
||||||
|
|
||||||
explicit allocator(int t = 0) {}
|
explicit allocator(int t = 0) : tag_(t) {}
|
||||||
template <class Y> allocator(allocator<Y> const& x) {}
|
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_) {}
|
||||||
allocator(allocator const&) {}
|
allocator(allocator const& x) : tag_(x.tag_) {}
|
||||||
~allocator() {}
|
~allocator() {}
|
||||||
|
|
||||||
pointer address(reference r) { return pointer(&r); }
|
pointer address(reference r) { return pointer(&r); }
|
||||||
@@ -183,20 +189,20 @@ namespace test
|
|||||||
void construct(pointer p, T const& t) { new(p) T(t); }
|
void construct(pointer p, T const& t) { new(p) T(t); }
|
||||||
void destroy(pointer p) { p->~T(); }
|
void destroy(pointer p) { p->~T(); }
|
||||||
|
|
||||||
size_type max_size() const { return 1000; }
|
size_type max_size() const {
|
||||||
|
return (std::numeric_limits<size_type>::max)();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(allocator const& x, allocator const& y)
|
||||||
|
{
|
||||||
|
return x.tag_ == y.tag_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(allocator const& x, allocator const& y)
|
||||||
|
{
|
||||||
|
return x.tag_ != y.tag_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline bool operator==(allocator<T> const& x, allocator<T> const& y)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline bool operator!=(allocator<T> const& x, allocator<T> const& y)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -20,4 +20,10 @@ test-suite unordered-tests
|
|||||||
[ run insert_tests.cpp ]
|
[ run insert_tests.cpp ]
|
||||||
[ run erase_tests.cpp ]
|
[ run erase_tests.cpp ]
|
||||||
[ run find_tests.cpp ]
|
[ run find_tests.cpp ]
|
||||||
|
[ run bucket_tests.cpp ]
|
||||||
|
[ run load_factor_tests.cpp ]
|
||||||
|
[ run rehash_tests.cpp ]
|
||||||
|
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=1 : swap_tests1 ]
|
||||||
|
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 : swap_tests2 ]
|
||||||
|
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=3 : swap_tests3 ]
|
||||||
;
|
;
|
||||||
|
@@ -53,9 +53,11 @@ void assign_tests2(T* = 0)
|
|||||||
typename T::hasher hf;
|
typename T::hasher hf;
|
||||||
typename T::key_equal eq;
|
typename T::key_equal eq;
|
||||||
typename T::hasher hf1(1);
|
typename T::hasher hf1(1);
|
||||||
typename T::key_equal eq1(1);
|
|
||||||
typename T::hasher hf2(2);
|
typename T::hasher hf2(2);
|
||||||
|
typename T::key_equal eq1(1);
|
||||||
typename T::key_equal eq2(2);
|
typename T::key_equal eq2(2);
|
||||||
|
typename T::allocator_type al1(1);
|
||||||
|
typename T::allocator_type al2(2);
|
||||||
|
|
||||||
std::cerr<<"assign_tests2.1\n";
|
std::cerr<<"assign_tests2.1\n";
|
||||||
{
|
{
|
||||||
@@ -68,6 +70,19 @@ void assign_tests2(T* = 0)
|
|||||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||||
check_container(x2, v);
|
check_container(x2, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cerr<<"assign_tests2.2\n";
|
||||||
|
{
|
||||||
|
// TODO: Need to generate duplicates...
|
||||||
|
test::random_values<T> v1(100), v2(100);
|
||||||
|
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||||
|
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||||
|
x2 = x1;
|
||||||
|
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||||
|
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||||
|
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||||
|
check_container(x2, v1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
60
test/unordered/bucket_tests.cpp
Normal file
60
test/unordered/bucket_tests.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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 <boost/unordered_set.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "../objects/test.hpp"
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/helpers.hpp"
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void bucket_tests(X* = 0)
|
||||||
|
{
|
||||||
|
typedef typename X::size_type size_type;
|
||||||
|
typedef typename X::const_local_iterator const_local_iterator;
|
||||||
|
test::random_values<X> v(1000);
|
||||||
|
|
||||||
|
X x(v.begin(), v.end());
|
||||||
|
|
||||||
|
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
|
||||||
|
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
|
||||||
|
|
||||||
|
for(typename test::random_values<X>::const_iterator
|
||||||
|
it = v.begin(), end = v.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||||
|
|
||||||
|
BOOST_TEST(bucket < x.bucket_count());
|
||||||
|
if(bucket < x.max_bucket_count()) {
|
||||||
|
// lit? lend?? I need a new naming scheme.
|
||||||
|
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
|
||||||
|
while(lit != lend && test::get_key<X>(*it) != test::get_key<X>(*lit)) ++lit;
|
||||||
|
BOOST_TEST(lit != lend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_type i = 0; i < x.bucket_count(); ++i) {
|
||||||
|
BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i)));
|
||||||
|
X const& x_ref(x);
|
||||||
|
BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
bucket_tests((boost::unordered_set<int>*) 0);
|
||||||
|
bucket_tests((boost::unordered_multiset<int>*) 0);
|
||||||
|
bucket_tests((boost::unordered_map<int, int>*) 0);
|
||||||
|
bucket_tests((boost::unordered_multimap<int, int>*) 0);
|
||||||
|
|
||||||
|
bucket_tests((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
bucket_tests((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
bucket_tests((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
bucket_tests((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
@@ -18,6 +18,7 @@ void constructor_tests1(T* = 0)
|
|||||||
{
|
{
|
||||||
typename T::hasher hf;
|
typename T::hasher hf;
|
||||||
typename T::key_equal eq;
|
typename T::key_equal eq;
|
||||||
|
typename T::allocator_type al;
|
||||||
|
|
||||||
std::cerr<<"Construct 1\n";
|
std::cerr<<"Construct 1\n";
|
||||||
{
|
{
|
||||||
@@ -26,6 +27,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 0);
|
BOOST_TEST(x.bucket_count() >= 0);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 2\n";
|
std::cerr<<"Construct 2\n";
|
||||||
@@ -35,6 +37,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 3\n";
|
std::cerr<<"Construct 3\n";
|
||||||
@@ -44,6 +47,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 2000);
|
BOOST_TEST(x.bucket_count() >= 2000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 4\n";
|
std::cerr<<"Construct 4\n";
|
||||||
@@ -52,6 +56,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 5\n";
|
std::cerr<<"Construct 5\n";
|
||||||
@@ -61,6 +66,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +77,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +88,7 @@ void constructor_tests1(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +98,28 @@ void constructor_tests1(T* = 0)
|
|||||||
T x(v.begin(), v.end());
|
T x(v.begin(), v.end());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
|
check_container(x, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr<<"Construct 9\n";
|
||||||
|
{
|
||||||
|
T x(0, hf, eq, al);
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST(x.bucket_count() >= 0);
|
||||||
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr<<"Construct 10\n";
|
||||||
|
{
|
||||||
|
test::random_values<T> v(1000);
|
||||||
|
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||||
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,6 +133,9 @@ void constructor_tests2(T* = 0)
|
|||||||
typename T::key_equal eq;
|
typename T::key_equal eq;
|
||||||
typename T::key_equal eq1(1);
|
typename T::key_equal eq1(1);
|
||||||
typename T::key_equal eq2(2);
|
typename T::key_equal eq2(2);
|
||||||
|
typename T::allocator_type al;
|
||||||
|
typename T::allocator_type al1(1);
|
||||||
|
typename T::allocator_type al2(2);
|
||||||
|
|
||||||
std::cerr<<"Construct 1\n";
|
std::cerr<<"Construct 1\n";
|
||||||
{
|
{
|
||||||
@@ -110,6 +143,7 @@ void constructor_tests2(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 2\n";
|
std::cerr<<"Construct 2\n";
|
||||||
@@ -119,6 +153,7 @@ void constructor_tests2(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr<<"Construct 3\n";
|
std::cerr<<"Construct 3\n";
|
||||||
@@ -127,6 +162,7 @@ void constructor_tests2(T* = 0)
|
|||||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +173,7 @@ void constructor_tests2(T* = 0)
|
|||||||
BOOST_TEST(x.bucket_count() >= 1000);
|
BOOST_TEST(x.bucket_count() >= 1000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +181,8 @@ void constructor_tests2(T* = 0)
|
|||||||
std::cerr<<"Construct 5\n";
|
std::cerr<<"Construct 5\n";
|
||||||
{
|
{
|
||||||
test::random_values<T> v(100);
|
test::random_values<T> v(100);
|
||||||
T x(v.begin(), v.end(), 0, hf, eq);
|
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||||
T y(x.begin(), x.end(), 0, hf1, eq1);
|
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
check_container(y, x);
|
check_container(y, x);
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ void copy_construct_tests1(T* = 0)
|
|||||||
{
|
{
|
||||||
typename T::hasher hf;
|
typename T::hasher hf;
|
||||||
typename T::key_equal eq;
|
typename T::key_equal eq;
|
||||||
|
typename T::allocator_type al;
|
||||||
|
|
||||||
{
|
{
|
||||||
T x;
|
T x;
|
||||||
@@ -24,6 +25,7 @@ void copy_construct_tests1(T* = 0)
|
|||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
@@ -42,15 +44,14 @@ void copy_construct_tests1(T* = 0)
|
|||||||
// In this test I drop the original containers max load factor, so it
|
// In this test I drop the original containers max load factor, so it
|
||||||
// is much lower than the load factor. The hash table is not allowed
|
// is much lower than the load factor. The hash table is not allowed
|
||||||
// to rehash, but the destination container should probably allocate
|
// to rehash, but the destination container should probably allocate
|
||||||
// enough buckets to decrease the load factor appropriately. Although,
|
// enough buckets to decrease the load factor appropriately.
|
||||||
// I don't think it has to.
|
|
||||||
test::random_values<T> v(1000);
|
test::random_values<T> v(1000);
|
||||||
T x(v.begin(), v.end());
|
T x(v.begin(), v.end());
|
||||||
x.max_load_factor(x.load_factor() / 4);
|
x.max_load_factor(x.load_factor() / 4);
|
||||||
T y(x);
|
T y(x);
|
||||||
test::unordered_equivalence_tester<T> equivalent(x);
|
test::unordered_equivalence_tester<T> equivalent(x);
|
||||||
equivalent(y);
|
equivalent(y);
|
||||||
// I don't think this is guaranteed:
|
// This isn't guaranteed:
|
||||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
@@ -63,14 +64,16 @@ void copy_construct_tests2(T* ptr = 0)
|
|||||||
|
|
||||||
typename T::hasher hf(1);
|
typename T::hasher hf(1);
|
||||||
typename T::key_equal eq(1);
|
typename T::key_equal eq(1);
|
||||||
|
typename T::allocator_type al(1);
|
||||||
|
|
||||||
{
|
{
|
||||||
// TODO: I could check how many buckets y has, it should be lower (QOI issue).
|
// TODO: I could check how many buckets y has, it should be lower (QOI issue).
|
||||||
T x(10000, hf, eq);
|
T x(10000, hf, eq, al);
|
||||||
T y(x);
|
T y(x);
|
||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
@@ -79,7 +82,7 @@ void copy_construct_tests2(T* ptr = 0)
|
|||||||
// TODO: Invariant checks are especially important here.
|
// TODO: Invariant checks are especially important here.
|
||||||
test::random_values<T> v(1000);
|
test::random_values<T> v(1000);
|
||||||
|
|
||||||
T x(v.begin(), v.end(), 0, hf, eq);
|
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||||
T y(x);
|
T y(x);
|
||||||
test::unordered_equivalence_tester<T> equivalent(x);
|
test::unordered_equivalence_tester<T> equivalent(x);
|
||||||
equivalent(y);
|
equivalent(y);
|
||||||
|
@@ -70,7 +70,7 @@ void erase_tests1(Container* = 0)
|
|||||||
pos = boost::next(prev);
|
pos = boost::next(prev);
|
||||||
}
|
}
|
||||||
next = boost::next(pos);
|
next = boost::next(pos);
|
||||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||||
std::size_t count = x.count(key);
|
std::size_t count = x.count(key);
|
||||||
BOOST_TEST(next == x.erase(pos));
|
BOOST_TEST(next == x.erase(pos));
|
||||||
--size;
|
--size;
|
||||||
@@ -137,4 +137,6 @@ int main()
|
|||||||
erase_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
erase_tests1((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
std::cerr<<"\nErase unordered_multimap<test::object,..>.\n";
|
std::cerr<<"\nErase unordered_multimap<test::object,..>.\n";
|
||||||
erase_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
erase_tests1((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
@@ -15,76 +15,94 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
template <class Container>
|
template <class X>
|
||||||
void unique_insert_tests1(Container* = 0)
|
void unique_insert_tests1(X* = 0)
|
||||||
{
|
{
|
||||||
std::cerr<<"insert(value) tests for containers with unique keys.\n";
|
std::cerr<<"insert(value) tests for containers with unique keys.\n";
|
||||||
|
|
||||||
Container x;
|
X x;
|
||||||
test::ordered<Container> tracker = test::create_ordered(x);
|
test::ordered<X> tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
std::pair<typename Container::iterator, bool> r1 = x.insert(*it);
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
std::pair<typename test::ordered<Container>::iterator, bool> r2
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
|
std::pair<typename X::iterator, bool> r1 = x.insert(*it);
|
||||||
|
std::pair<typename test::ordered<X>::iterator, bool> r2
|
||||||
= tracker.insert(*it);
|
= tracker.insert(*it);
|
||||||
|
|
||||||
BOOST_TEST(r1.second == r2.second);
|
BOOST_TEST(r1.second == r2.second);
|
||||||
BOOST_TEST(*r1.first == *r2.first);
|
BOOST_TEST(*r1.first == *r2.first);
|
||||||
|
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Container>
|
template <class X>
|
||||||
void equivalent_insert_tests1(Container* = 0)
|
void equivalent_insert_tests1(X* = 0)
|
||||||
{
|
{
|
||||||
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
||||||
|
|
||||||
Container x;
|
X x;
|
||||||
test::ordered<Container> tracker = test::create_ordered(x);
|
test::ordered<X> tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
typename Container::iterator r1 = x.insert(*it);
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
typename test::ordered<Container>::iterator r2 = tracker.insert(*it);
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
|
typename X::iterator r1 = x.insert(*it);
|
||||||
|
typename test::ordered<X>::iterator r2 = tracker.insert(*it);
|
||||||
|
|
||||||
BOOST_TEST(*r1 == *r2);
|
BOOST_TEST(*r1 == *r2);
|
||||||
|
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Container>
|
template <class X>
|
||||||
void insert_tests2(Container* = 0)
|
void insert_tests2(X* = 0)
|
||||||
{
|
{
|
||||||
typedef typename test::ordered<Container> tracker_type;
|
typedef typename test::ordered<X> tracker_type;
|
||||||
typedef typename Container::iterator iterator;
|
typedef typename X::iterator iterator;
|
||||||
typedef typename Container::const_iterator const_iterator;
|
typedef typename X::const_iterator const_iterator;
|
||||||
typedef typename tracker_type::iterator tracker_iterator;
|
typedef typename tracker_type::iterator tracker_iterator;
|
||||||
|
|
||||||
std::cerr<<"insert(begin(), value) tests.\n";
|
std::cerr<<"insert(begin(), value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Container x;
|
X x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
iterator r1 = x.insert(x.begin(), *it);
|
iterator r1 = x.insert(x.begin(), *it);
|
||||||
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
||||||
BOOST_TEST(*r1 == *r2);
|
BOOST_TEST(*r1 == *r2);
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
@@ -93,18 +111,24 @@ void insert_tests2(Container* = 0)
|
|||||||
std::cerr<<"insert(end(), value) tests.\n";
|
std::cerr<<"insert(end(), value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Container x;
|
X x;
|
||||||
Container const& x_const = x;
|
X const& x_const = x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(100);
|
test::random_values<X> v(100);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
const_iterator r1 = x.insert(x_const.end(), *it);
|
const_iterator r1 = x.insert(x_const.end(), *it);
|
||||||
tracker_iterator r2 = tracker.insert(tracker.end(), *it);
|
tracker_iterator r2 = tracker.insert(tracker.end(), *it);
|
||||||
BOOST_TEST(*r1 == *r2);
|
BOOST_TEST(*r1 == *r2);
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
@@ -113,18 +137,24 @@ void insert_tests2(Container* = 0)
|
|||||||
std::cerr<<"insert(pos, value) tests.\n";
|
std::cerr<<"insert(pos, value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Container x;
|
X x;
|
||||||
const_iterator pos = x.begin();
|
const_iterator pos = x.begin();
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
pos = x.insert(pos, *it);
|
pos = x.insert(pos, *it);
|
||||||
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
||||||
BOOST_TEST(*pos == *r2);
|
BOOST_TEST(*pos == *r2);
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
@@ -133,16 +163,22 @@ void insert_tests2(Container* = 0)
|
|||||||
std::cerr<<"insert single item range tests.\n";
|
std::cerr<<"insert single item range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Container x;
|
X x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
it != v.end(); ++it)
|
it != v.end(); ++it)
|
||||||
{
|
{
|
||||||
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
x.insert(it, boost::next(it));
|
x.insert(it, boost::next(it));
|
||||||
tracker.insert(*it);
|
tracker.insert(*it);
|
||||||
tracker.compare_key(x, *it);
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
@@ -151,10 +187,10 @@ void insert_tests2(Container* = 0)
|
|||||||
std::cerr<<"insert range tests.\n";
|
std::cerr<<"insert range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
Container x;
|
X x;
|
||||||
const_iterator pos = x.begin();
|
const_iterator pos = x.begin();
|
||||||
|
|
||||||
test::random_values<Container> v(1000);
|
test::random_values<X> v(1000);
|
||||||
x.insert(v.begin(), v.end());
|
x.insert(v.begin(), v.end());
|
||||||
check_container(x, v);
|
check_container(x, v);
|
||||||
|
|
||||||
@@ -162,6 +198,31 @@ void insert_tests2(Container* = 0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void map_tests(X* = 0)
|
||||||
|
{
|
||||||
|
X x;
|
||||||
|
test::ordered<X> tracker = test::create_ordered(x);
|
||||||
|
|
||||||
|
test::random_values<X> v(1000);
|
||||||
|
for(typename test::random_values<X>::iterator it = v.begin();
|
||||||
|
it != v.end(); ++it)
|
||||||
|
{
|
||||||
|
typename X::size_type old_bucket_count = x.bucket_count();
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
|
x[it->first] = it->second;
|
||||||
|
tracker[it->first] = it->second;
|
||||||
|
|
||||||
|
tracker.compare_key(x, *it);
|
||||||
|
|
||||||
|
if(x.size() < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
test::check_equivalent_keys(x);
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
unique_insert_tests1((boost::unordered_set<int>*) 0);
|
unique_insert_tests1((boost::unordered_set<int>*) 0);
|
||||||
@@ -184,5 +245,8 @@ int main()
|
|||||||
insert_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
insert_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
insert_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
insert_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
|
||||||
|
map_tests((boost::unordered_map<int, int>*) 0);
|
||||||
|
map_tests((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
72
test/unordered/load_factor_tests.cpp
Normal file
72
test/unordered/load_factor_tests.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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 <boost/unordered_set.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void load_factor_tests(X* = 0)
|
||||||
|
{
|
||||||
|
X x;
|
||||||
|
|
||||||
|
BOOST_TEST(x.max_load_factor() == 1.0);
|
||||||
|
BOOST_TEST(x.load_factor() == 0);
|
||||||
|
|
||||||
|
// A valid implementation could fail these tests, but I think they're
|
||||||
|
// reasonable.
|
||||||
|
x.max_load_factor(2.0); BOOST_TEST(x.max_load_factor() == 2.0);
|
||||||
|
x.max_load_factor(0.5); BOOST_TEST(x.max_load_factor() == 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void insert_test(X*, float mlf)
|
||||||
|
{
|
||||||
|
X x;
|
||||||
|
x.max_load_factor(mlf);
|
||||||
|
float b = x.max_load_factor();
|
||||||
|
|
||||||
|
test::random_values<X> values(1000);
|
||||||
|
|
||||||
|
for(typename test::random_values<X>::const_iterator
|
||||||
|
it = values.begin(), end = values.end(); it != end; ++it)
|
||||||
|
{
|
||||||
|
typename X::size_type old_size = x.size(),
|
||||||
|
old_bucket_count = x.bucket_count();
|
||||||
|
x.insert(*it);
|
||||||
|
if(old_size + 1 < b * old_bucket_count)
|
||||||
|
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void load_factor_insert_tests(X* ptr = 0)
|
||||||
|
{
|
||||||
|
insert_test(ptr, 1.0);
|
||||||
|
insert_test(ptr, 0.1);
|
||||||
|
insert_test(ptr, 100);
|
||||||
|
|
||||||
|
insert_test(ptr, (std::numeric_limits<float>::min)());
|
||||||
|
|
||||||
|
if(std::numeric_limits<float>::has_infinity)
|
||||||
|
insert_test(ptr, std::numeric_limits<float>::infinity());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
load_factor_tests((boost::unordered_set<int>*) 0);
|
||||||
|
load_factor_tests((boost::unordered_multiset<int>*) 0);
|
||||||
|
load_factor_tests((boost::unordered_map<int, int>*) 0);
|
||||||
|
load_factor_tests((boost::unordered_multimap<int, int>*) 0);
|
||||||
|
|
||||||
|
load_factor_insert_tests((boost::unordered_set<int>*) 0);
|
||||||
|
load_factor_insert_tests((boost::unordered_multiset<int>*) 0);
|
||||||
|
load_factor_insert_tests((boost::unordered_map<int, int>*) 0);
|
||||||
|
load_factor_insert_tests((boost::unordered_multimap<int, int>*) 0);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
67
test/unordered/rehash_tests.cpp
Normal file
67
test/unordered/rehash_tests.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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 <boost/unordered_set.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/tracker.hpp"
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
bool postcondition(X const& x, typename X::size_type n)
|
||||||
|
{
|
||||||
|
return x.bucket_count() > x.size() / x.max_load_factor() && x.bucket_count() >= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void rehash_empty_test1(X* = 0)
|
||||||
|
{
|
||||||
|
X x;
|
||||||
|
|
||||||
|
x.rehash(10000);
|
||||||
|
BOOST_TEST(postcondition(x, 10000));
|
||||||
|
|
||||||
|
x.rehash(0);
|
||||||
|
BOOST_TEST(postcondition(x, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void rehash_test1(X* = 0)
|
||||||
|
{
|
||||||
|
test::random_values<X> v(1000);
|
||||||
|
test::ordered<X> tracker;
|
||||||
|
tracker.insert(v.begin(), v.end());
|
||||||
|
X x(v.begin(), v.end());
|
||||||
|
|
||||||
|
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||||
|
tracker.compare(x);
|
||||||
|
|
||||||
|
x.max_load_factor(0.25);
|
||||||
|
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||||
|
tracker.compare(x);
|
||||||
|
|
||||||
|
x.max_load_factor(50.0);
|
||||||
|
x.rehash(0); BOOST_TEST(postcondition(x, 0));
|
||||||
|
tracker.compare(x);
|
||||||
|
|
||||||
|
x.rehash(1000); BOOST_TEST(postcondition(x, 1000));
|
||||||
|
tracker.compare(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void rehash_tests(X* ptr = 0)
|
||||||
|
{
|
||||||
|
rehash_empty_test1(ptr);
|
||||||
|
rehash_test1(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
rehash_tests((boost::unordered_set<int>*) 0);
|
||||||
|
rehash_tests((boost::unordered_multiset<int>*) 0);
|
||||||
|
rehash_tests((boost::unordered_map<int, int>*) 0);
|
||||||
|
rehash_tests((boost::unordered_multimap<int, int>*) 0);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
135
test/unordered/swap_tests.cpp
Normal file
135
test/unordered/swap_tests.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
|
||||||
|
// Copyright Daniel James 2006. Use, modification, and distribution are
|
||||||
|
// subject to 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 <boost/unordered_set.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/detail/lightweight_test.hpp>
|
||||||
|
#include "../objects/test.hpp"
|
||||||
|
#include "../helpers/random_values.hpp"
|
||||||
|
#include "../helpers/tracker.hpp"
|
||||||
|
#include "../helpers/invariants.hpp"
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void swap_test_impl(X& x1, X& x2)
|
||||||
|
{
|
||||||
|
test::ordered<X> tracker1 = test::create_ordered(x1);
|
||||||
|
test::ordered<X> tracker2 = test::create_ordered(x2);
|
||||||
|
tracker1.insert(x1.begin(), x1.end());
|
||||||
|
tracker2.insert(x2.begin(), x2.end());
|
||||||
|
x1.swap(x2);
|
||||||
|
tracker1.compare(x2);
|
||||||
|
tracker2.compare(x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void swap_tests1(X* = 0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
X x;
|
||||||
|
swap_test_impl(x, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X x,y;
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<X> v(1000);
|
||||||
|
X x, y(v.begin(), v.end());
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<X> vx(1000), vy(1000);
|
||||||
|
X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void swap_tests2(X* ptr = 0)
|
||||||
|
{
|
||||||
|
swap_tests1(ptr);
|
||||||
|
|
||||||
|
typedef typename X::hasher hasher;
|
||||||
|
typedef typename X::key_equal key_equal;
|
||||||
|
typedef typename X::allocator_type allocator_type;
|
||||||
|
|
||||||
|
{
|
||||||
|
X x(0, hasher(1), key_equal(1));
|
||||||
|
X y(0, hasher(2), key_equal(2));
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<X> v(1000);
|
||||||
|
X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
|
||||||
|
X y(0, hasher(2), key_equal(2));
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<X> vx(1000), vy(1000);
|
||||||
|
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
|
||||||
|
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_SWAP_METHOD == 1
|
||||||
|
{
|
||||||
|
test::random_values<X> vx(1000), vy(1000);
|
||||||
|
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
|
||||||
|
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
|
||||||
|
try {
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
BOOST_ERROR("Using swap method 1, swapping with unequal allocators didn't throw.");
|
||||||
|
} catch (std::runtime_error) {}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
test::random_values<X> vx(1000), vy(1000);
|
||||||
|
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
|
||||||
|
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<X> vx(1000), vy(1000);
|
||||||
|
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1), allocator_type(1));
|
||||||
|
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2), allocator_type(2));
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::cerr<<"Erase unordered_set<int>.\n";
|
||||||
|
swap_tests1((boost::unordered_set<int>*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_multiset<int>.\n";
|
||||||
|
swap_tests1((boost::unordered_multiset<int>*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_map<int>.\n";
|
||||||
|
swap_tests1((boost::unordered_map<int, int>*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_multimap<int>.\n";
|
||||||
|
swap_tests1((boost::unordered_multimap<int, int>*) 0);
|
||||||
|
|
||||||
|
std::cerr<<"\nErase unordered_set<test::object,..>.\n";
|
||||||
|
swap_tests2((boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_multiset<test::object,..>.\n";
|
||||||
|
swap_tests2((boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_map<test::object,..>.\n";
|
||||||
|
swap_tests2((boost::unordered_map<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
std::cerr<<"\nErase unordered_multimap<test::object,..>.\n";
|
||||||
|
swap_tests2((boost::unordered_multimap<test::object, test::object, test::hash, test::equal_to, test::allocator<test::object> >*) 0);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
Reference in New Issue
Block a user