Merge remote-tracking branch 'origin/develop'

This commit is contained in:
Daniel James
2015-02-22 15:12:28 +00:00
7 changed files with 113 additions and 49 deletions

View File

@@ -257,7 +257,16 @@ C++11 support has resulted in some breaking changes:
* Fix the `pointer` typedef in iterators ([ticket 10672]). * Fix the `pointer` typedef in iterators ([ticket 10672]).
* Fix Coverity warning * Fix Coverity warning
([@https://github.com/boostorg/unordered/pull/2 GitHub #2]). ([@https://github.com/boostorg/unordered/pull/2 GitHub #2]).
[h2 Boost 1.58.0]
* Remove unnecessary template parameter from const iterators.
* Rename private `iterator` typedef in some iterator classes, as it * Rename private `iterator` typedef in some iterator classes, as it
confuses some traits classes. confuses some traits classes.
* Fix move assignment with stateful, propagate_on_container_move_assign
allocators ([ticket 10777]).
* Fix rare exception safety issue in move assignment.
* Fix potential overflow when calculating number of buckets to allocate
([@https://github.com/boostorg/unordered/pull/4 GitHub #4]).
[endsect] [endsect]

View File

@@ -45,9 +45,9 @@ namespace boost { namespace unordered { namespace iterator_detail {
// all no throw // all no throw
template <typename Node> struct iterator; template <typename Node> struct iterator;
template <typename Node, typename ConstNodePointer> struct c_iterator; template <typename Node> struct c_iterator;
template <typename Node, typename Policy> struct l_iterator; template <typename Node, typename Policy> struct l_iterator;
template <typename Node, typename ConstNodePointer, typename Policy> template <typename Node, typename Policy>
struct cl_iterator; struct cl_iterator;
// Local Iterators // Local Iterators
@@ -64,12 +64,12 @@ namespace boost { namespace unordered { namespace iterator_detail {
typename Node::value_type&> typename Node::value_type&>
{ {
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename Node2, typename ConstNodePointer, typename Policy2> template <typename Node2, typename Policy2>
friend struct boost::unordered::iterator_detail::cl_iterator; friend struct boost::unordered::iterator_detail::cl_iterator;
private: private:
#endif #endif
typedef typename Node::node_pointer node_pointer; typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator; typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
node_pointer ptr_; node_pointer ptr_;
std::size_t bucket_; std::size_t bucket_;
std::size_t bucket_count_; std::size_t bucket_count_;
@@ -80,7 +80,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
l_iterator() BOOST_NOEXCEPT : ptr_() {} l_iterator() BOOST_NOEXCEPT : ptr_() {}
l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT l_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
: ptr_(x.node_), bucket_(b), bucket_count_(c) {} : ptr_(x.node_), bucket_(b), bucket_count_(c) {}
value_type& operator*() const { value_type& operator*() const {
@@ -114,7 +114,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
} }
}; };
template <typename Node, typename ConstNodePointer, typename Policy> template <typename Node, typename Policy>
struct cl_iterator struct cl_iterator
: public boost::iterator< : public boost::iterator<
std::forward_iterator_tag, std::forward_iterator_tag,
@@ -128,7 +128,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
private: private:
typedef typename Node::node_pointer node_pointer; typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator; typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
node_pointer ptr_; node_pointer ptr_;
std::size_t bucket_; std::size_t bucket_;
std::size_t bucket_count_; std::size_t bucket_count_;
@@ -139,7 +139,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
cl_iterator() BOOST_NOEXCEPT : ptr_() {} cl_iterator() BOOST_NOEXCEPT : ptr_() {}
cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT : cl_iterator(n_iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
ptr_(x.node_), bucket_(b), bucket_count_(c) {} ptr_(x.node_), bucket_(b), bucket_count_(c) {}
cl_iterator(boost::unordered::iterator_detail::l_iterator< cl_iterator(boost::unordered::iterator_detail::l_iterator<
@@ -192,11 +192,11 @@ namespace boost { namespace unordered { namespace iterator_detail {
typename Node::value_type&> typename Node::value_type&>
{ {
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename, typename> template <typename>
friend struct boost::unordered::iterator_detail::c_iterator; friend struct boost::unordered::iterator_detail::c_iterator;
template <typename, typename> template <typename, typename>
friend struct boost::unordered::iterator_detail::l_iterator; friend struct boost::unordered::iterator_detail::l_iterator;
template <typename, typename, typename> template <typename, typename>
friend struct boost::unordered::iterator_detail::cl_iterator; friend struct boost::unordered::iterator_detail::cl_iterator;
template <typename> template <typename>
friend struct boost::unordered::detail::table; friend struct boost::unordered::detail::table;
@@ -223,7 +223,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
} }
value_type* operator->() const { value_type* operator->() const {
return &node_->value(); return node_->value_ptr();
} }
iterator& operator++() { iterator& operator++() {
@@ -246,7 +246,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
} }
}; };
template <typename Node, typename ConstNodePointer> template <typename Node>
struct c_iterator struct c_iterator
: public boost::iterator< : public boost::iterator<
std::forward_iterator_tag, std::forward_iterator_tag,
@@ -268,7 +268,7 @@ namespace boost { namespace unordered { namespace iterator_detail {
private: private:
#endif #endif
typedef typename Node::node_pointer node_pointer; typedef typename Node::node_pointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<Node> iterator; typedef boost::unordered::iterator_detail::iterator<Node> n_iterator;
node_pointer node_; node_pointer node_;
public: public:
@@ -280,14 +280,14 @@ namespace boost { namespace unordered { namespace iterator_detail {
explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT : explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
node_(static_cast<node_pointer>(x)) {} node_(static_cast<node_pointer>(x)) {}
c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {} c_iterator(n_iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
value_type const& operator*() const { value_type const& operator*() const {
return node_->value(); return node_->value();
} }
value_type const* operator->() const { value_type const* operator->() const {
return &node_->value(); return node_->value_ptr();
} }
c_iterator& operator++() { c_iterator& operator++() {

View File

@@ -191,11 +191,11 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::iterator_detail:: typedef boost::unordered::iterator_detail::
iterator<node> iterator; iterator<node> iterator;
typedef boost::unordered::iterator_detail:: typedef boost::unordered::iterator_detail::
c_iterator<node, const_node_pointer> c_iterator; c_iterator<node> c_iterator;
typedef boost::unordered::iterator_detail:: typedef boost::unordered::iterator_detail::
l_iterator<node, policy> l_iterator; l_iterator<node, policy> l_iterator;
typedef boost::unordered::iterator_detail:: typedef boost::unordered::iterator_detail::
cl_iterator<node, const_node_pointer, policy> cl_iterator; cl_iterator<node, policy> cl_iterator;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Members // Members
@@ -343,7 +343,7 @@ namespace boost { namespace unordered { namespace detail {
return policy::new_bucket_count( return policy::new_bucket_count(
boost::unordered::detail::double_to_size(floor( boost::unordered::detail::double_to_size(floor(
static_cast<double>(size) / static_cast<double>(size) /
static_cast<double>(mlf_))) + 1); static_cast<double>(mlf_)) + 1));
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@@ -500,9 +500,11 @@ namespace boost { namespace unordered { namespace detail {
op2.commit(); op2.commit();
} }
// Only call with nodes allocated with the currect allocator, or
// one that is equal to it. (Can't assert because other's
// allocators might have already been moved).
void move_buckets_from(table& other) void move_buckets_from(table& other)
{ {
BOOST_ASSERT(node_alloc() == other.node_alloc());
BOOST_ASSERT(!buckets_); BOOST_ASSERT(!buckets_);
buckets_ = other.buckets_; buckets_ = other.buckets_;
bucket_count_ = other.bucket_count_; bucket_count_ = other.bucket_count_;
@@ -710,15 +712,25 @@ namespace boost { namespace unordered { namespace detail {
void move_assign(table& x, true_type) void move_assign(table& x, true_type)
{ {
delete_buckets(); delete_buckets();
set_hash_functions new_func_this(*this, x);
allocators_.move_assign(x.allocators_); allocators_.move_assign(x.allocators_);
move_assign_no_alloc(x); // No throw from here.
mlf_ = x.mlf_;
max_load_ = x.max_load_;
move_buckets_from(x);
new_func_this.commit();
} }
void move_assign(table& x, false_type) void move_assign(table& x, false_type)
{ {
if (node_alloc() == x.node_alloc()) { if (node_alloc() == x.node_alloc()) {
delete_buckets(); delete_buckets();
move_assign_no_alloc(x); set_hash_functions new_func_this(*this, x);
// No throw from here.
mlf_ = x.mlf_;
max_load_ = x.max_load_;
move_buckets_from(x);
new_func_this.commit();
} }
else { else {
set_hash_functions new_func_this(*this, x); set_hash_functions new_func_this(*this, x);
@@ -743,16 +755,6 @@ namespace boost { namespace unordered { namespace detail {
table_impl::fill_buckets(nodes.begin(), *this, node_creator); table_impl::fill_buckets(nodes.begin(), *this, node_creator);
} }
} }
void move_assign_no_alloc(table& x)
{
set_hash_functions new_func_this(*this, x);
// No throw from here.
mlf_ = x.mlf_;
max_load_ = x.max_load_;
move_buckets_from(x);
new_func_this.commit();
}
// Accessors // Accessors

View File

@@ -19,6 +19,12 @@
#pragma warning(disable:4100) // unreferenced formal parameter #pragma warning(disable:4100) // unreferenced formal parameter
#endif #endif
#if !BOOST_WORKAROUND(BOOST_MSVC, == 1500)
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 1
#else
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 0
#endif
namespace test namespace test
{ {
namespace minimal namespace minimal
@@ -29,7 +35,9 @@ namespace minimal
class default_assignable; class default_assignable;
class assignable; class assignable;
struct ampersand_operator_used {}; struct ampersand_operator_used {
ampersand_operator_used() { BOOST_TEST(false); }
};
template <class T> class hash; template <class T> class hash;
template <class T> class equal_to; template <class T> class equal_to;
@@ -48,6 +56,7 @@ namespace minimal
public: public:
destructible(constructor_param const&) {} destructible(constructor_param const&) {}
~destructible() {} ~destructible() {}
void dummy_member() const {}
private: private:
destructible(destructible const&); destructible(destructible const&);
destructible& operator=(destructible const&); destructible& operator=(destructible const&);
@@ -59,6 +68,7 @@ namespace minimal
copy_constructible(constructor_param const&) {} copy_constructible(constructor_param const&) {}
copy_constructible(copy_constructible const&) {} copy_constructible(copy_constructible const&) {}
~copy_constructible() {} ~copy_constructible() {}
void dummy_member() const {}
private: private:
copy_constructible& operator=(copy_constructible const&); copy_constructible& operator=(copy_constructible const&);
copy_constructible() {} copy_constructible() {}
@@ -78,11 +88,15 @@ namespace minimal
{ {
} }
void dummy_member() const {}
private: private:
copy_constructible_equality_comparable& operator=( copy_constructible_equality_comparable& operator=(
copy_constructible_equality_comparable const&); copy_constructible_equality_comparable const&);
copy_constructible_equality_comparable() {} copy_constructible_equality_comparable() {}
ampersand_operator_used operator&() const { return ampersand_operator_used(); } #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
#endif
}; };
bool operator==( bool operator==(
@@ -121,9 +135,12 @@ namespace minimal
{ {
} }
private: void dummy_member() const {}
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
ampersand_operator_used operator&() const { ampersand_operator_used operator&() const {
return ampersand_operator_used(); } return ampersand_operator_used(); }
#endif
}; };
class assignable class assignable
@@ -133,11 +150,13 @@ namespace minimal
assignable(assignable const&) {} assignable(assignable const&) {}
assignable& operator=(assignable const&) { return *this; } assignable& operator=(assignable const&) { return *this; }
~assignable() {} ~assignable() {}
void dummy_member() const {}
private: private:
assignable() {} assignable() {}
// TODO: This messes up a concept check in the tests. #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
//ampersand_operator_used operator&() const { return ampersand_operator_used(); } ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
#endif
}; };
struct movable_init {}; struct movable_init {};
@@ -153,6 +172,7 @@ namespace minimal
movable1(BOOST_RV_REF(movable1)) {} movable1(BOOST_RV_REF(movable1)) {}
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; } movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
~movable1() {} ~movable1() {}
void dummy_member() const {}
}; };
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
@@ -164,6 +184,7 @@ namespace minimal
movable2(movable2&&) {} movable2(movable2&&) {}
~movable2() {} ~movable2() {}
movable2& operator=(movable2&&) { return *this; } movable2& operator=(movable2&&) { return *this; }
void dummy_member() const {}
private: private:
movable2() {} movable2() {}
movable2(movable2 const&); movable2(movable2 const&);
@@ -184,8 +205,10 @@ namespace minimal
~hash() {} ~hash() {}
std::size_t operator()(T const&) const { return 0; } std::size_t operator()(T const&) const { return 0; }
private: #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
ampersand_operator_used operator&() const { return ampersand_operator_used(); } ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
#endif
}; };
template <class T> template <class T>
@@ -199,8 +222,10 @@ namespace minimal
~equal_to() {} ~equal_to() {}
bool operator()(T const&, T const&) const { return true; } bool operator()(T const&, T const&) const { return true; }
private: #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
ampersand_operator_used operator&() const { return ampersand_operator_used(); } ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
#endif
}; };
template <class T> class ptr; template <class T> class ptr;
@@ -288,9 +313,10 @@ namespace minimal
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; } bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; } bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; } bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
private: #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
// TODO: ampersand_operator_used operator&() const {
//ampersand_operator_used operator&() const { return ampersand_operator_used(); } return ampersand_operator_used(); }
#endif
}; };
template <class T> template <class T>
@@ -325,9 +351,10 @@ 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_; } 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: #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
// TODO: ampersand_operator_used operator&() const {
//ampersand_operator_used operator&() const { return ampersand_operator_used(); } return ampersand_operator_used(); }
#endif
}; };
template <class T> template <class T>
@@ -387,8 +414,10 @@ namespace minimal
#else #else
private: allocator& operator=(allocator const&); private: allocator& operator=(allocator const&);
#endif #endif
private: #if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
ampersand_operator_used operator&() const { return ampersand_operator_used(); } ampersand_operator_used operator&() const {
return ampersand_operator_used(); }
#endif
}; };
template <class T> template <class T>

View File

@@ -202,6 +202,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_unique_test(map, map_value); unordered_unique_test(map, map_value);
unordered_map_test(map, assignable, assignable); unordered_map_test(map, assignable, assignable);
unordered_copyable_test(map, assignable, map_value, hash, equal_to); unordered_copyable_test(map, assignable, map_value, hash, equal_to);
unordered_map_member_test(map, map_value);
boost::unordered_map< boost::unordered_map<
test::minimal::assignable, test::minimal::assignable,
@@ -226,6 +227,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_equivalent_test(multimap, map_value); unordered_equivalent_test(multimap, map_value);
unordered_map_test(multimap, assignable, assignable); unordered_map_test(multimap, assignable, assignable);
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to); unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
unordered_map_member_test(multimap, map_value);
} }
RUN_TESTS() RUN_TESTS()

View File

@@ -183,6 +183,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_unique_test(set, assignable); unordered_unique_test(set, assignable);
unordered_set_test(set, assignable); unordered_set_test(set, assignable);
unordered_copyable_test(set, assignable, assignable, hash, equal_to); unordered_copyable_test(set, assignable, assignable, hash, equal_to);
unordered_set_member_test(set, assignable);
std::cout<<"Test unordered_multiset.\n"; std::cout<<"Test unordered_multiset.\n";
@@ -195,6 +196,7 @@ UNORDERED_AUTO_TEST(test2)
unordered_equivalent_test(multiset, assignable); unordered_equivalent_test(multiset, assignable);
unordered_set_test(multiset, assignable); unordered_set_test(multiset, assignable);
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to); unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
unordered_set_member_test(multiset, assignable);
} }
UNORDERED_AUTO_TEST(movable1_tests) UNORDERED_AUTO_TEST(movable1_tests)

View File

@@ -554,3 +554,23 @@ void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
sink(a8); sink(a8);
sink(a10); sink(a10);
} }
template <class X, class T>
void unordered_set_member_test(X& x, T& t)
{
X x1(x);
x1.insert(t);
x1.begin()->dummy_member();
x1.cbegin()->dummy_member();
}
template <class X, class T>
void unordered_map_member_test(X& x, T& t)
{
X x1(x);
x1.insert(t);
x1.begin()->first.dummy_member();
x1.cbegin()->first.dummy_member();
x1.begin()->second.dummy_member();
x1.cbegin()->second.dummy_member();
}