mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 19:37:14 +02:00
More tests for unordered associative containers.
[SVN r2959]
This commit is contained in:
@ -5,3 +5,4 @@
|
||||
|
||||
build-project container ;
|
||||
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
|
||||
{
|
||||
template <class T>
|
||||
bool equivalent(T const& x, T const& y) {
|
||||
bool equivalent_impl(T const& x, T const& y) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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>
|
||||
class unordered_equivalence_tester
|
||||
{
|
||||
@ -56,8 +74,8 @@ namespace test
|
||||
bool operator()(Container const& x) const
|
||||
{
|
||||
if(!((size_ == x.size()) &&
|
||||
(test::equivalent(hasher_, x.hash_function())) &&
|
||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
||||
(test::equivalent_impl(hasher_, x.hash_function())) &&
|
||||
(test::equivalent_impl(key_equal_, x.key_eq())) &&
|
||||
(max_load_factor_ == x.max_load_factor()) &&
|
||||
(values_.size() == x.size()))) return false;
|
||||
|
||||
|
@ -51,23 +51,30 @@ namespace test
|
||||
if(x1.count(key) != count)
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
|
||||
// Check that the keys are in the correct bucket and are adjacent in
|
||||
// the bucket.
|
||||
typename X::size_type bucket = x1.bucket(key);
|
||||
typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||
for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||
if(lit == lend)
|
||||
BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
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;
|
||||
}
|
||||
}
|
||||
// I'm not bothering with the following test for now, as the
|
||||
// previous test is probably more enough to catch the kind of
|
||||
// errors that this would catch (if an element was in the wrong
|
||||
// bucket it not be found by the call to count, if elements are not
|
||||
// adjacent then they would be caught when checking against
|
||||
// found_.
|
||||
|
||||
// // Check that the keys are in the correct bucket and are
|
||||
// // adjacent in the bucket.
|
||||
// typename X::size_type bucket = x1.bucket(key);
|
||||
// typename X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||
// if(lit == lend)
|
||||
// BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
// 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.
|
||||
|
@ -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
|
||||
// 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
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER
|
||||
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER
|
||||
|
||||
namespace test
|
||||
{
|
||||
|
@ -147,6 +147,12 @@ namespace test
|
||||
template <class T>
|
||||
class allocator
|
||||
{
|
||||
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
# else
|
||||
template <class> friend class allocator;
|
||||
# endif
|
||||
int tag_;
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
@ -158,9 +164,9 @@ namespace test
|
||||
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
|
||||
explicit allocator(int t = 0) {}
|
||||
template <class Y> allocator(allocator<Y> const& x) {}
|
||||
allocator(allocator const&) {}
|
||||
explicit allocator(int t = 0) : tag_(t) {}
|
||||
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_) {}
|
||||
allocator(allocator const& x) : tag_(x.tag_) {}
|
||||
~allocator() {}
|
||||
|
||||
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 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
|
||||
|
@ -20,4 +20,10 @@ test-suite unordered-tests
|
||||
[ run insert_tests.cpp ]
|
||||
[ run erase_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::key_equal eq;
|
||||
typename T::hasher hf1(1);
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::hasher hf2(2);
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::key_equal eq2(2);
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
std::cerr<<"assign_tests2.1\n";
|
||||
{
|
||||
@ -68,6 +70,19 @@ void assign_tests2(T* = 0)
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
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()
|
||||
|
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::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
std::cerr<<"Construct 1\n";
|
||||
{
|
||||
@ -26,6 +27,7 @@ void constructor_tests1(T* = 0)
|
||||
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 2\n";
|
||||
@ -35,6 +37,7 @@ void constructor_tests1(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
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 3\n";
|
||||
@ -44,6 +47,7 @@ void constructor_tests1(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 2000);
|
||||
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 4\n";
|
||||
@ -52,6 +56,7 @@ void constructor_tests1(T* = 0)
|
||||
BOOST_TEST(x.empty());
|
||||
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 5\n";
|
||||
@ -61,6 +66,7 @@ void constructor_tests1(T* = 0)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -71,6 +77,7 @@ void constructor_tests1(T* = 0)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -81,6 +88,7 @@ void constructor_tests1(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -90,6 +98,28 @@ void constructor_tests1(T* = 0)
|
||||
T x(v.begin(), v.end());
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -103,6 +133,9 @@ void constructor_tests2(T* = 0)
|
||||
typename T::key_equal eq;
|
||||
typename T::key_equal eq1(1);
|
||||
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";
|
||||
{
|
||||
@ -110,6 +143,7 @@ void constructor_tests2(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 2\n";
|
||||
@ -119,6 +153,7 @@ void constructor_tests2(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 3\n";
|
||||
@ -127,6 +162,7 @@ void constructor_tests2(T* = 0)
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
check_container(x, v);
|
||||
}
|
||||
|
||||
@ -137,6 +173,7 @@ void constructor_tests2(T* = 0)
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
check_container(x, v);
|
||||
}
|
||||
|
||||
@ -144,8 +181,8 @@ void constructor_tests2(T* = 0)
|
||||
std::cerr<<"Construct 5\n";
|
||||
{
|
||||
test::random_values<T> v(100);
|
||||
T x(v.begin(), v.end(), 0, hf, eq);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1);
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||
check_container(x, v);
|
||||
check_container(y, x);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ void copy_construct_tests1(T* = 0)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
T x;
|
||||
@ -24,6 +25,7 @@ void copy_construct_tests1(T* = 0)
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
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());
|
||||
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
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately. Although,
|
||||
// I don't think it has to.
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
// I don't think this is guaranteed:
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
@ -63,14 +64,16 @@ void copy_construct_tests2(T* ptr = 0)
|
||||
|
||||
typename T::hasher hf(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).
|
||||
T x(10000, hf, eq);
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
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());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
@ -79,7 +82,7 @@ void copy_construct_tests2(T* ptr = 0)
|
||||
// TODO: Invariant checks are especially important here.
|
||||
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);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
equivalent(y);
|
||||
|
@ -70,7 +70,7 @@ void erase_tests1(Container* = 0)
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
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);
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--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);
|
||||
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);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
@ -15,76 +15,94 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <class Container>
|
||||
void unique_insert_tests1(Container* = 0)
|
||||
template <class X>
|
||||
void unique_insert_tests1(X* = 0)
|
||||
{
|
||||
std::cerr<<"insert(value) tests for containers with unique keys.\n";
|
||||
|
||||
Container x;
|
||||
test::ordered<Container> tracker = test::create_ordered(x);
|
||||
X x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
test::random_values<X> v(1000);
|
||||
for(typename test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
{
|
||||
std::pair<typename Container::iterator, bool> r1 = x.insert(*it);
|
||||
std::pair<typename test::ordered<Container>::iterator, bool> r2
|
||||
typename X::size_type old_bucket_count = x.bucket_count();
|
||||
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);
|
||||
|
||||
BOOST_TEST(r1.second == r2.second);
|
||||
BOOST_TEST(*r1.first == *r2.first);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void equivalent_insert_tests1(Container* = 0)
|
||||
template <class X>
|
||||
void equivalent_insert_tests1(X* = 0)
|
||||
{
|
||||
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
||||
|
||||
Container x;
|
||||
test::ordered<Container> tracker = test::create_ordered(x);
|
||||
X x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
test::random_values<X> v(1000);
|
||||
for(typename test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
{
|
||||
typename Container::iterator r1 = x.insert(*it);
|
||||
typename test::ordered<Container>::iterator r2 = tracker.insert(*it);
|
||||
typename X::size_type old_bucket_count = x.bucket_count();
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void insert_tests2(Container* = 0)
|
||||
template <class X>
|
||||
void insert_tests2(X* = 0)
|
||||
{
|
||||
typedef typename test::ordered<Container> tracker_type;
|
||||
typedef typename Container::iterator iterator;
|
||||
typedef typename Container::const_iterator const_iterator;
|
||||
typedef typename test::ordered<X> tracker_type;
|
||||
typedef typename X::iterator iterator;
|
||||
typedef typename X::const_iterator const_iterator;
|
||||
typedef typename tracker_type::iterator tracker_iterator;
|
||||
|
||||
std::cerr<<"insert(begin(), value) tests.\n";
|
||||
|
||||
{
|
||||
Container x;
|
||||
X x;
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
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();
|
||||
|
||||
iterator r1 = x.insert(x.begin(), *it);
|
||||
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
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);
|
||||
@ -93,18 +111,24 @@ void insert_tests2(Container* = 0)
|
||||
std::cerr<<"insert(end(), value) tests.\n";
|
||||
|
||||
{
|
||||
Container x;
|
||||
Container const& x_const = x;
|
||||
X x;
|
||||
X const& x_const = x;
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(100);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
test::random_values<X> v(100);
|
||||
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();
|
||||
|
||||
const_iterator r1 = x.insert(x_const.end(), *it);
|
||||
tracker_iterator r2 = tracker.insert(tracker.end(), *it);
|
||||
BOOST_TEST(*r1 == *r2);
|
||||
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);
|
||||
@ -113,18 +137,24 @@ void insert_tests2(Container* = 0)
|
||||
std::cerr<<"insert(pos, value) tests.\n";
|
||||
|
||||
{
|
||||
Container x;
|
||||
X x;
|
||||
const_iterator pos = x.begin();
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
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();
|
||||
|
||||
pos = x.insert(pos, *it);
|
||||
tracker_iterator r2 = tracker.insert(tracker.begin(), *it);
|
||||
BOOST_TEST(*pos == *r2);
|
||||
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);
|
||||
@ -133,16 +163,22 @@ void insert_tests2(Container* = 0)
|
||||
std::cerr<<"insert single item range tests.\n";
|
||||
|
||||
{
|
||||
Container x;
|
||||
X x;
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
for(typename test::random_values<Container>::iterator it = v.begin();
|
||||
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.insert(it, boost::next(it));
|
||||
tracker.insert(*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);
|
||||
@ -151,10 +187,10 @@ void insert_tests2(Container* = 0)
|
||||
std::cerr<<"insert range tests.\n";
|
||||
|
||||
{
|
||||
Container x;
|
||||
X x;
|
||||
const_iterator pos = x.begin();
|
||||
|
||||
test::random_values<Container> v(1000);
|
||||
test::random_values<X> v(1000);
|
||||
x.insert(v.begin(), v.end());
|
||||
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()
|
||||
{
|
||||
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_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();
|
||||
}
|
||||
|
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