It is currently proposed that insert, erase and rehash should be stable. Change insert(hint, value) so that it inserts at the end of a group of

equivalent keys (all the other functions were already stable).


[SVN r4146]
This commit is contained in:
Daniel James
2007-05-20 17:37:27 +00:00
parent bd1477fa25
commit ef2f5116dd
4 changed files with 84 additions and 7 deletions

View File

@ -118,12 +118,7 @@ should probably change it to a slow swap.
[h3 [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#518
518. Are insert and erase stable for unordered_multiset and unordered_multimap?]]
In this implementation, erase is stable. All inserts are stable, except for
inserting with a hint, which has slightly surprising behaviour. If the hint
points to the first element in the correct equal range it inserts at the end of
the range, for all other elements in the range it inserts immediately before
the element. I am very tempted to change insert with a hint to just ignore the
hint completely.
The current proposal is that insert and erase are stable - so they are here.
[h3 [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#528
528. TR1: issue 6.19 vs 6.3.4.3/2 (and 6.3.4.5/2)]]

View File

@ -1561,6 +1561,13 @@ namespace boost {
return insert(v);
}
else {
// Find the first node in the group - so that the node
// will be inserted at the end of the group.
local_iterator_base start(it.local_);
while(prev_in_group(start.node_)->next_ == start.node_)
start.node_ = prev_in_group(start.node_);
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(this->allocators_);
@ -1574,7 +1581,7 @@ namespace boost {
// Nothing after this point can throw
link_ptr n = a.release();
this->link_node(n, it.local_);
this->link_node(n, start);
return iterator_base(base, n);
}

View File

@ -18,6 +18,7 @@ test-suite unordered-tests
[ run copy_tests.cpp ]
[ run assign_tests.cpp ]
[ run insert_tests.cpp ]
[ run insert_stable_tests.cpp ]
[ run unnecessary_copy_tests.cpp ]
[ run erase_tests.cpp ]
[ run erase_equiv_tests.cpp ]

View File

@ -0,0 +1,74 @@
// Copyright 2007 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
struct member {
int tag1_;
int tag2_;
member() : tag1_(0), tag2_(0) {}
member(int t1, int t2) : tag1_(t1), tag2_(t2) {}
friend bool operator==(member const& x, member const& y) {
return x.tag1_ == y.tag1_;
}
friend bool operator!=(member const& x, member const& y) {
return x.tag1_ != y.tag1_;
}
};
std::size_t hash_value(member const& x) {
return static_cast<std::size_t>(x.tag1_);
}
void stable_insert_test1() {
boost::unordered_multiset<member> x;
x.insert(member(1,1));
x.insert(member(1,2));
x.insert(member(1,3));
boost::unordered_multiset<member>::const_iterator it = x.begin(), end = x.end();
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 1); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 2); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->tag2_ == 3); ++it; }
BOOST_TEST(it == end);
}
void stable_insert_test2() {
boost::unordered_multimap<member, int> x;
typedef boost::unordered_multimap<member, int>::const_iterator iterator;
iterator it = x.insert(x.end(), std::make_pair(member(1,1), 1));
it = x.insert(it, std::make_pair(member(1,2), 2));
it = x.insert(it, std::make_pair(member(1,3), 3));
it = x.begin();
iterator end = x.end();
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 1 && it->second == 1); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 2 && it->second == 2); ++it; }
BOOST_TEST(it != end);
if(it != end) { BOOST_TEST(it->first.tag2_ == 3 && it->second == 3); ++it; }
BOOST_TEST(it == end);
}
int main()
{
stable_insert_test1();
stable_insert_test2();
return boost::report_errors();
}