Compare commits

...

5 Commits

Author SHA1 Message Date
Beman Dawes 1f71b041e9 Release 1.47.0
[SVN r73007]
2011-07-11 22:16:03 +00:00
Daniel James 3fd5635d7d Unordered: Fix some overly strict tests.
[SVN r70443]
2011-03-23 00:07:17 +00:00
Daniel James 147181530d Add copy constructors and assignment operators when using rvalue references. Fixes #5119.
[SVN r69469]
2011-03-02 08:47:34 +00:00
Daniel James 54f9626c12 Merge unordered from trunk.
- Avoid using operator& with the value type.
- More comments in headers.
- Remove old clang workaround.
- Adjust use of inline to make Borland a little happier.
- Avoid `-Wconversion` warnings.


[SVN r67663]
2011-01-04 23:05:55 +00:00
Daniel James dc8e65043b Merge fix for unordered container insertion bug.
[SVN r66151]
2010-10-23 12:02:18 +00:00
22 changed files with 465 additions and 151 deletions
+3
View File
@@ -3,6 +3,9 @@
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
using boostbook ;
using quickbook ;
path-constant images_location : ../ ;
path-constant admonishment_location : ../../../../doc/src/images ;
+5
View File
@@ -129,4 +129,9 @@ First official release.
* Use Boost.Exception.
* Stop using deprecated `BOOST_HAS_*` macros.
[h2 Boost 1.45.0]
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
iterators which returns `value_type` by copy.
[endsect]
+1 -1
View File
@@ -64,7 +64,7 @@ namespace boost { namespace unordered_detail {
inline void hash_buckets<A, G>::delete_node(node_ptr b)
{
node* raw_ptr = static_cast<node*>(&*b);
boost::unordered_detail::destroy(&raw_ptr->value());
boost::unordered_detail::destroy(raw_ptr->value_ptr());
real_node_ptr n(node_alloc().address(*raw_ptr));
node_alloc().destroy(n);
node_alloc().deallocate(n, 1);
+108 -32
View File
@@ -21,14 +21,14 @@
// This header defines most of the classes used to implement the unordered
// containers. It doesn't include the insert methods as they require a lot
// of preprocessor metaprogramming - they are in insert.hpp
// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp.
// Template parameters:
//
// H = Hash Function
// P = Predicate
// A = Value Allocator
// G = Grouped/Ungrouped
// G = Bucket group policy, 'grouped' or 'ungrouped'
// E = Key Extractor
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
@@ -90,7 +90,37 @@ namespace boost { namespace unordered_detail {
#pragma warning(pop)
#endif
////////////////////////////////////////////////////////////////////////////
//
// This section implements buckets and nodes. Here's a rough
// inheritance diagram, to show how they pull together.
//
// For unordered_set/unordered_map:
//
// hash_bucket<A>
// |
// ungrouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, ungrouped>
//
// For unordered_multiset/unordered_multimap:
//
// hash_bucket<A>
// |
// grouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, grouped>
// hash_bucket
//
// hash_bucket is used for both the buckets and as a base class for
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
// to either a bucket or a node. This is used later to implement a
// sentinel at the end of the bucket array.
template <class A>
class hash_bucket
@@ -109,6 +139,16 @@ namespace boost { namespace unordered_detail {
hash_bucket() : next_() {}
};
// In containers with equivalent keys (unordered_multimap and
// unordered_multiset) equivalent nodes are grouped together, in
// containers with unique keys (unordered_map and unordered_set)
// individual nodes are treated as groups of one. The following two
// classes implement the data structure.
// This is used for containers with unique keys. There are no groups
// so it doesn't add any extra members, and just treats individual
// nodes as groups of one.
template <class A>
struct ungrouped_node_base : hash_bucket<A> {
typedef hash_bucket<A> bucket;
@@ -125,6 +165,10 @@ namespace boost { namespace unordered_detail {
static void unlink_nodes(bucket& b, node_ptr end);
};
// This is used for containers with equivalent keys. It implements a
// circular list running in the opposite direction to the linked
// list through the nodes.
template <class A>
struct grouped_node_base : hash_bucket<A>
{
@@ -151,6 +195,10 @@ namespace boost { namespace unordered_detail {
}
};
// These two classes implement an easy way to pass around the node
// group policy classes without the messy template parameters.
// Whenever you see the template parameter 'G' it's one of these.
struct ungrouped
{
template <class A>
@@ -167,6 +215,8 @@ namespace boost { namespace unordered_detail {
};
};
// The space used to store values in a node.
template <class ValueType>
struct value_base
{
@@ -181,6 +231,9 @@ namespace boost { namespace unordered_detail {
value_type& value() {
return *(ValueType*) this;
}
value_type* value_ptr() {
return (ValueType*) this;
}
private:
value_base& operator=(value_base const&);
};
@@ -199,11 +252,20 @@ namespace boost { namespace unordered_detail {
static value_type& get_value(node_ptr p) {
return static_cast<hash_node&>(*p).value();
}
static value_type* get_value_ptr(node_ptr p) {
return static_cast<hash_node&>(*p).value_ptr();
}
private:
hash_node& operator=(hash_node const&);
};
////////////////////////////////////////////////////////////////////////////
//
// Iterator Base
//
// This is the iterator used internally, the external iterators are
// provided by lightweight wrappers (hash_iterator and
// hast_const_iterator) which provide the full iterator interface.
template <class A, class G>
class hash_iterator_base
@@ -248,12 +310,24 @@ namespace boost { namespace unordered_detail {
}
};
////////////////////////////////////////////////////////////////////////////
//
// Now the main data structure:
//
// hash_buckets<A, G> hash_buffered_functions<H, P>
// | |
// +-------------+--------------+
// |
// hash_table<T>
//
// T is a class which contains typedefs for all the types we need.
// hash_buckets
//
// This is responsible for allocating and deallocating buckets and nodes.
//
// Notes:
// 1. For the sake exception safety the allocators themselves don't allocate
// 1. For the sake exception safety the consturctors don't allocate
// anything.
// 2. It's the callers responsibility to allocate the buckets before calling
// any of the methods (other than getters and setters).
@@ -327,6 +401,17 @@ namespace boost { namespace unordered_detail {
std::size_t delete_to_bucket_end(node_ptr begin);
};
// Assigning and swapping the equality and hash function objects
// needs strong exception safety. To implement that normally we'd
// require one of them to be known to not throw and the other to
// guarantee strong exception safety. Unfortunately they both only
// have basic exception safety. So to acheive strong exception
// safety we have storage space for two copies, and assign the new
// copies to the unused space. Then switch to using that to use
// them. This is implemented in 'set_hash_functions' which
// atomically assigns the new function objects in a strongly
// exception safe manner.
template <class H, class P> class set_hash_functions;
template <class H, class P>
@@ -429,6 +514,12 @@ namespace boost { namespace unordered_detail {
}
};
// This implements almost all of the required functionality, apart
// from some things that are specific to containers with unique and
// equivalent keys which is implemented in hash_unique_table and
// hash_equivalent_table. See unique.hpp and equivalent.hpp for
// their declaration and implementation.
template <class T>
class hash_table : public T::buckets, public T::buffered_functions
{
@@ -569,9 +660,13 @@ namespace boost { namespace unordered_detail {
node_constructor&, std::size_t);
};
// Iterator Access
///////////////////////////////////////////////////////////////////
//
// Iterators
// iterator_access is used to access the internal iterator without
// making it publicly available.
#if !defined(__clang__)
class iterator_access
{
public:
@@ -582,30 +677,6 @@ namespace boost { namespace unordered_detail {
return it.base_;
}
};
#else
class iterator_access
{
public:
// Note: we access Iterator::base here, rather than in the function
// signature to work around a bug in the friend support of an
// early version of clang.
template <class Iterator>
struct base
{
typedef BOOST_DEDUCED_TYPENAME Iterator::base type;
};
template <class Iterator>
static BOOST_DEDUCED_TYPENAME base<Iterator>::type const&
get(Iterator const& it)
{
return it.base_;
}
};
#endif
// Iterators
template <class A, class G> class hash_iterator;
template <class A, class G> class hash_const_iterator;
@@ -644,7 +715,7 @@ namespace boost { namespace unordered_detail {
return node::get_value(ptr_);
}
value_type* operator->() const {
return &node::get_value(ptr_);
return node::get_value_ptr(ptr_);
}
hash_local_iterator& operator++() {
ptr_ = ptr_->next_; return *this;
@@ -694,7 +765,7 @@ namespace boost { namespace unordered_detail {
return node::get_value(ptr_);
}
value_type const* operator->() const {
return &node::get_value(ptr_);
return node::get_value_ptr(ptr_);
}
hash_const_local_iterator& operator++() {
ptr_ = ptr_->next_; return *this;
@@ -716,7 +787,7 @@ namespace boost { namespace unordered_detail {
}
};
// iterators
// Iterators
//
// all no throw
@@ -823,7 +894,12 @@ namespace boost { namespace unordered_detail {
}
};
////////////////////////////////////////////////////////////////////////////
//
// types
//
// This is used to convieniently pass around a container's typedefs
// without having 7 template parameters.
template <class K, class V, class H, class P, class A, class E, class G>
struct types
+38 -25
View File
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2010 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -99,6 +99,8 @@ namespace boost { namespace unordered_detail {
template <class InputIt>
void insert_range_impl(key_type const&, InputIt i, InputIt j);
template <class InputIt>
void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j);
template <class InputIt>
void insert_range_impl(no_key, InputIt i, InputIt j);
};
@@ -420,6 +422,36 @@ namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Insert range methods
template <class T>
template <class InputIt>
inline void hash_unique_table<T>::insert_range_impl2(
node_constructor& a, key_type const& k, InputIt i, InputIt j)
{
// No side effects in this initial code
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = this->find_iterator(bucket, k);
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->size_ + 1 >= this->max_load_) {
this->reserve_for_insert(this->size_ + insert_size(i, j));
bucket = this->bucket_ptr_from_hash(hash_value);
}
// Nothing after this point can throw.
add_node(a, bucket);
}
}
template <class T>
template <class InputIt>
inline void hash_unique_table<T>::insert_range_impl(
@@ -435,33 +467,14 @@ namespace boost { namespace unordered_detail {
}
do {
// No side effects in this initial code
// Note: can't use get_key as '*i' might not be value_type - it
// could be a pair with first_types as key_type without const or a
// different second_type.
key_type const& k = extractor::extract(*i);
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = this->find_iterator(bucket, k);
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->size_ + 1 >= this->max_load_) {
this->reserve_for_insert(this->size_ + insert_size(i, j));
bucket = this->bucket_ptr_from_hash(hash_value);
}
// Nothing after this point can throw.
add_node(a, bucket);
}
//
// TODO: Might be worth storing the value_type instead of the key
// here. Could be more efficient if '*i' is expensive. Could be
// less efficient if copying the full value_type is expensive.
insert_range_impl2(a, extractor::extract(*i), i, j);
} while(++i != j);
}
+2 -2
View File
@@ -299,7 +299,7 @@ namespace boost { namespace unordered_detail {
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
struct dummy { hash_node<Alloc, Grouped> x; };
#endif
boost::unordered_detail::destroy(&node_->value());
boost::unordered_detail::destroy(node_->value_ptr());
}
if (node_constructed_)
@@ -322,7 +322,7 @@ namespace boost { namespace unordered_detail {
}
else {
BOOST_ASSERT(node_constructed_ && value_constructed_);
boost::unordered_detail::destroy(&node_->value());
boost::unordered_detail::destroy(node_->value_ptr());
value_constructed_ = false;
}
}
+22
View File
@@ -160,6 +160,11 @@ namespace boost
~unordered_map() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_map(unordered_map const& other)
: table_(other.table_)
{
}
unordered_map(unordered_map&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
{
@@ -170,6 +175,12 @@ namespace boost
{
}
unordered_map& operator=(unordered_map const& x)
{
table_ = x.table_;
return *this;
}
unordered_map& operator=(unordered_map&& x)
{
table_.move(x.table_);
@@ -705,6 +716,11 @@ namespace boost
~unordered_multimap() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multimap(unordered_multimap const& other)
: table_(other.table_)
{
}
unordered_multimap(unordered_multimap&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
{
@@ -715,6 +731,12 @@ namespace boost
{
}
unordered_multimap& operator=(unordered_multimap const& x)
{
table_ = x.table_;
return *this;
}
unordered_multimap& operator=(unordered_multimap&& x)
{
table_.move(x.table_);
@@ -24,13 +24,13 @@ namespace boost
class A = std::allocator<std::pair<const K, T> > >
class unordered_map;
template <class K, class T, class H, class P, class A>
bool operator==(unordered_map<K, T, H, P, A> const&,
inline bool operator==(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
bool operator!=(unordered_map<K, T, H, P, A> const&,
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
void swap(unordered_map<K, T, H, P, A>&,
inline void swap(unordered_map<K, T, H, P, A>&,
unordered_map<K, T, H, P, A>&);
template <class K,
@@ -40,13 +40,13 @@ namespace boost
class A = std::allocator<std::pair<const K, T> > >
class unordered_multimap;
template <class K, class T, class H, class P, class A>
bool operator==(unordered_multimap<K, T, H, P, A> const&,
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
bool operator!=(unordered_multimap<K, T, H, P, A> const&,
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
void swap(unordered_multimap<K, T, H, P, A>&,
inline void swap(unordered_multimap<K, T, H, P, A>&,
unordered_multimap<K, T, H, P, A>&);
}
+22
View File
@@ -154,6 +154,11 @@ namespace boost
~unordered_set() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_set(unordered_set const& other)
: table_(other.table_)
{
}
unordered_set(unordered_set&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
{
@@ -164,6 +169,12 @@ namespace boost
{
}
unordered_set& operator=(unordered_set const& x)
{
table_ = x.table_;
return *this;
}
unordered_set& operator=(unordered_set&& x)
{
table_.move(x.table_);
@@ -651,6 +662,11 @@ namespace boost
~unordered_multiset() {}
#if !defined(BOOST_NO_RVALUE_REFERENCES)
unordered_multiset(unordered_multiset const& other)
: table_(other.table_)
{
}
unordered_multiset(unordered_multiset&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
{
@@ -661,6 +677,12 @@ namespace boost
{
}
unordered_multiset& operator=(unordered_multiset const& x)
{
table_ = x.table_;
return *this;
}
unordered_multiset& operator=(unordered_multiset&& x)
{
table_.move(x.table_);
@@ -23,13 +23,13 @@ namespace boost
class A = std::allocator<T> >
class unordered_set;
template <class T, class H, class P, class A>
bool operator==(unordered_set<T, H, P, A> const&,
inline bool operator==(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
bool operator!=(unordered_set<T, H, P, A> const&,
inline bool operator!=(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
void swap(unordered_set<T, H, P, A> &m1,
inline void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2);
template <class T,
@@ -38,13 +38,13 @@ namespace boost
class A = std::allocator<T> >
class unordered_multiset;
template <class T, class H, class P, class A>
bool operator==(unordered_multiset<T, H, P, A> const&,
inline bool operator==(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
bool operator!=(unordered_multiset<T, H, P, A> const&,
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
void swap(unordered_multiset<T, H, P, A> &m1,
inline void swap(unordered_multiset<T, H, P, A> &m1,
unordered_multiset<T, H, P, A> &m2);
}
+15 -1
View File
@@ -148,6 +148,19 @@ struct input_range_construct_test : public range<T>, objects
}
};
template <class T>
struct copy_range_construct_test : public range<T>, objects
{
copy_range_construct_test() : range<T>(60) {}
void run() const {
T x(test::copy_iterator(this->values.begin()),
test::copy_iterator(this->values.end()),
0, hash, equal_to, allocator);
avoid_unused_warning(x);
}
};
RUN_EXCEPTION_TESTS(
(construct_test1)
(construct_test2)
@@ -160,5 +173,6 @@ RUN_EXCEPTION_TESTS(
(range_construct_test3)
(range_construct_test4)
(range_construct_test5)
(input_range_construct_test),
(input_range_construct_test)
(copy_range_construct_test),
CONTAINER_SEQ)
+91 -1
View File
@@ -1,5 +1,5 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2005-2010 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -69,6 +69,96 @@ namespace test
{
return input_iterator_adaptor<Iterator>(it);
}
template <class Iterator>
struct copy_iterator_adaptor
: public boost::iterator<
BOOST_DEDUCED_TYPENAME boost::iterator_category<Iterator>::type,
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
BOOST_DEDUCED_TYPENAME boost::iterator_difference<Iterator>::type,
BOOST_DEDUCED_TYPENAME boost::iterator_pointer<Iterator>::type,
proxy<Iterator>
>
{
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type
value_type;
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<Iterator>::type
difference_type;
copy_iterator_adaptor()
: base_() {}
explicit copy_iterator_adaptor(Iterator const& it)
: base_(it) {}
value_type operator*() const {
return *base_;
}
value_type* operator->() const {
return &*base_;
}
value_type operator[](difference_type d) {
return base_[d];
}
copy_iterator_adaptor& operator++() {
++base_; return *this;
}
copy_iterator_adaptor operator++(int) {
copy_iterator_adaptor tmp(*this); ++base_; return tmp;
}
copy_iterator_adaptor& operator--() {
--base_; return *this;
}
copy_iterator_adaptor operator--(int) {
copy_iterator_adaptor tmp(*this); --base_; return tmp;
}
copy_iterator_adaptor operator+=(difference_type x) {
base_ += x;
return *this;
}
copy_iterator_adaptor operator-=(difference_type x) {
base_ -= x;
return *this;
}
copy_iterator_adaptor operator+(difference_type n) {
return copy_iterator_adaptor(base_+n);
}
copy_iterator_adaptor operator-(difference_type n) {
return copy_iterator_adaptor(base_-n);
}
friend copy_iterator_adaptor operator+(
difference_type n, copy_iterator_adaptor x) {
return x+n;
}
difference_type operator-(copy_iterator_adaptor const& other) {
return base_-other.base_;
}
bool operator==(copy_iterator_adaptor const& x) const {
return base_ == x.base_;
}
bool operator!=(copy_iterator_adaptor const& x) const {
return base_ != x.base_;
}
bool operator<(copy_iterator_adaptor const& x) const {
return base_ < x.base_;
}
bool operator>(copy_iterator_adaptor const& x) const {
return base_ > x.base_;
}
bool operator<=(copy_iterator_adaptor const& x) const {
return base_ <= x.base_;
}
bool operator>=(copy_iterator_adaptor const& x) const {
return base_ >= x.base_;
}
private:
Iterator base_;
};
template <class Iterator>
copy_iterator_adaptor<Iterator> copy_iterator(Iterator const& it)
{
return copy_iterator_adaptor<Iterator>(it);
}
}
#endif
+20
View File
@@ -26,6 +26,8 @@ namespace minimal
class default_copy_constructible;
class assignable;
struct ampersand_operator_used {};
template <class T> class hash;
template <class T> class equal_to;
template <class T> class ptr;
@@ -63,6 +65,7 @@ namespace minimal
copy_constructible_equality_comparable& operator=(
copy_constructible_equality_comparable const&);
copy_constructible_equality_comparable() {}
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
bool operator==(
@@ -98,9 +101,11 @@ namespace minimal
~default_copy_constructible()
{
}
private:
default_copy_constructible& operator=(
default_copy_constructible const&);
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
class assignable
@@ -110,8 +115,11 @@ namespace minimal
assignable(assignable const&) {}
assignable& operator=(assignable const&) { return *this; }
~assignable() {}
private:
assignable() {}
// TODO: This messes up a concept check in the tests.
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@@ -125,6 +133,8 @@ namespace minimal
~hash() {}
std::size_t operator()(T const&) const { return 0; }
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@@ -138,6 +148,8 @@ namespace minimal
~equal_to() {}
bool operator()(T const&, T const&) const { return true; }
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T> class ptr;
@@ -182,6 +194,9 @@ namespace minimal
bool operator>(const_ptr<T> const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr<T> const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr<T> const& x) const { return ptr_ >= x.ptr_; }
private:
// TODO:
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@@ -221,6 +236,9 @@ namespace minimal
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
private:
// TODO:
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
@@ -278,6 +296,8 @@ namespace minimal
#else
private: allocator& operator=(allocator const&);
#endif
private:
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
};
template <class T>
+27 -38
View File
@@ -20,11 +20,13 @@ namespace test
// Note that the default hash function will work for any equal_to (but not
// very well).
class object;
class implicitly_convertible;
class hash;
class less;
class equal_to;
template <class T> class allocator;
object generate(object const*);
implicitly_convertible generate(implicitly_convertible const*);
class object : globally_counted_object
{
@@ -64,6 +66,31 @@ namespace test
}
};
class implicitly_convertible : globally_counted_object
{
int tag1_, tag2_;
public:
explicit implicitly_convertible(int t1 = 0, int t2 = 0)
: tag1_(t1), tag2_(t2)
{}
operator object() const
{
return object(tag1_, tag2_);
}
friend implicitly_convertible generate(implicitly_convertible const*) {
int* x = 0;
return implicitly_convertible(generate(x), generate(x));
}
friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o)
{
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
}
};
class hash
{
int type_;
@@ -279,44 +306,6 @@ namespace test
{
return x == y;
}
#if BOOST_WORKAROUND(__GNUC__, < 3)
void swap(test::object& x, test::object& y) {
test::object tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::hash& x, test::hash& y) {
test::hash tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::less& x, test::less& y) {
test::less tmp;
tmp = x;
x = y;
y = tmp;
}
void swap(test::equal_to& x, test::equal_to& y) {
test::equal_to tmp;
tmp = x;
x = y;
y = tmp;
}
template <class T>
void swap(test::allocator<T>& x, test::allocator<T>& y) {
test::allocator<T> tmp;
tmp = x;
x = y;
y = tmp;
}
#endif
}
#endif
+3 -3
View File
@@ -9,8 +9,8 @@ project unordered-test/unordered
: requirements
<warnings>all
<toolset>intel:<warnings>on
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
<toolset>gcc:<define>_GLIBCXX_DEBUG
#<toolset>darwin:<define>_GLIBCXX_DEBUG
<toolset>msvc:<warnings-as-errors>on
@@ -30,7 +30,7 @@ test-suite unordered
[ run equivalent_keys_tests.cpp ]
[ run constructor_tests.cpp ]
[ run copy_tests.cpp ]
[ run move_tests.cpp : : : <test-info>always_show_run_output ]
[ run move_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_stable_tests.cpp ]
+14 -1
View File
@@ -1,5 +1,5 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2006-2010 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -260,6 +260,19 @@ void constructor_tests2(T*,
test::check_equivalent_keys(y);
}
std::cerr<<"Construct 8.5 - from copy iterator\n";
{
test::random_values<T> v(100, generator);
T x(test::copy_iterator(v.begin()),
test::copy_iterator(v.end()), 0, hf1, eq1);
T y(test::copy_iterator(x.begin()),
test::copy_iterator(x.end()), 0, hf2, eq2);
test::check_container(x, v);
test::check_container(y, x);
test::check_equivalent_keys(x);
test::check_equivalent_keys(y);
}
std::cerr<<"Construct 9\n";
{
test::random_values<T> v(100, generator);
+27 -10
View File
@@ -7,37 +7,54 @@
#include <boost/unordered/unordered_map_fwd.hpp>
typedef boost::unordered_map<int, int> int_map;
void call_swap(int_map& x, int_map& y) {
template <typename T>
void call_swap(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
swap(x,y);
}
bool call_equals(int_map& x, int_map& y) {
template <typename T>
bool call_equals(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
return x == y;
}
bool call_not_equals(int_map& x, int_map& y) {
template <typename T>
bool call_not_equals(boost::unordered_map<T,T>& x,
boost::unordered_map<T,T>& y)
{
return x != y;
}
typedef boost::unordered_multimap<int, int> int_multimap;
void call_swap(int_multimap& x, int_multimap& y) {
template <typename T>
void call_swap(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
swap(x,y);
}
bool call_equals(int_multimap& x, int_multimap& y) {
template <typename T>
bool call_equals(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
return x == y;
}
bool call_not_equals(int_multimap& x, int_multimap& y) {
template <typename T>
bool call_not_equals(boost::unordered_multimap<T,T>& x,
boost::unordered_multimap<T,T>& y)
{
return x != y;
}
#include <boost/unordered_map.hpp>
#include "../helpers/test.hpp"
typedef boost::unordered_map<int, int> int_map;
typedef boost::unordered_multimap<int, int> int_multimap;
UNORDERED_AUTO_TEST(use_map_fwd_declared_function) {
int_map x, y;
x[1] = 2;
+27 -10
View File
@@ -16,36 +16,53 @@ template <class Value, class Hash, class Pred, class Alloc>
true_type is_unordered_set_impl(
boost::unordered_set<Value, Hash, Pred, Alloc>*);
typedef boost::unordered_set<int> int_set;
void call_swap(int_set& x, int_set& y) {
template<typename T>
void call_swap(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
swap(x,y);
}
bool call_equals(int_set& x, int_set& y) {
template<typename T>
bool call_equals(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
return x == y;
}
bool call_not_equals(int_set& x, int_set& y) {
template<typename T>
bool call_not_equals(boost::unordered_set<T>& x,
boost::unordered_set<T>& y)
{
return x != y;
}
typedef boost::unordered_multiset<int> int_multiset;
void call_swap(int_multiset& x, int_multiset& y) {
template<typename T>
void call_swap(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
swap(x,y);
}
bool call_equals(int_multiset& x, int_multiset& y) {
template<typename T>
bool call_equals(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
return x == y;
}
bool call_not_equals(int_multiset& x, int_multiset& y) {
template<typename T>
bool call_not_equals(boost::unordered_multiset<T>& x,
boost::unordered_multiset<T>& y)
{
return x != y;
}
#include "../helpers/test.hpp"
typedef boost::unordered_set<int> int_set;
typedef boost::unordered_multiset<int> int_multiset;
UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) {
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0))
== sizeof(true_type));
+24 -12
View File
@@ -1,5 +1,5 @@
// Copyright 2006-2009 Daniel James.
// Copyright 2006-2010 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -52,7 +52,7 @@ void unique_insert_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -83,7 +83,7 @@ void equivalent_insert_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -118,7 +118,7 @@ void insert_tests2(X*,
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -145,7 +145,7 @@ void insert_tests2(X*,
BOOST_TEST(*r1 == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -172,7 +172,7 @@ void insert_tests2(X*,
BOOST_TEST(*pos == *r2);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -197,7 +197,7 @@ void insert_tests2(X*,
tracker.insert(*it);
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -229,6 +229,18 @@ void insert_tests2(X*,
test::check_equivalent_keys(x);
}
std::cerr<<"insert copy iterator range tests.\n";
{
X x;
test::random_values<X> v(1000, generator);
x.insert(test::copy_iterator(v.begin()), test::copy_iterator(v.end()));
test::check_container(x, v);
test::check_equivalent_keys(x);
}
}
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
@@ -263,7 +275,7 @@ void unique_emplace_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -294,7 +306,7 @@ void equivalent_emplace_tests1(X*,
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -323,7 +335,7 @@ void map_tests(X*, test::random_generator generator = test::default_generator)
tracker.compare_key(x, *it);
if(x.size() < b * old_bucket_count)
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
@@ -360,10 +372,10 @@ void map_insert_range_test2(X*,
std::cerr<<"map_insert_range_test2\n";
typedef test::list<
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, int>
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, test::implicitly_convertible>
> list;
test::random_values<
boost::unordered_map<BOOST_DEDUCED_TYPENAME X::key_type, int>
boost::unordered_map<BOOST_DEDUCED_TYPENAME X::key_type, test::implicitly_convertible>
> v(1000, generator);
list l(v.begin(), v.end());
+1 -1
View File
@@ -51,7 +51,7 @@ void insert_test(X*, float mlf,
BOOST_DEDUCED_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)
if(static_cast<double>(old_size + 1) < b * static_cast<double>(old_bucket_count))
BOOST_TEST(x.bucket_count() == old_bucket_count);
}
}
+2 -1
View File
@@ -19,7 +19,8 @@ test::seed_t seed(2974);
template <class X>
bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
{
return x.bucket_count() > x.size() / x.max_load_factor() &&
return static_cast<double>(x.bucket_count()) >
static_cast<double>(x.size()) / x.max_load_factor() &&
x.bucket_count() >= n;
}
+1 -1
View File
@@ -261,7 +261,7 @@ namespace unnecessary_copy_tests
// copied.
reset();
x.emplace(source<std::pair<count_copies, count_copies> >());
COPY_COUNT(2); MOVE_COUNT(0);
COPY_COUNT(2); MOVE_COUNT_RANGE(0,2);
// TODO: This doesn't work on older versions of gcc.
//count_copies part;