Add foa-based node containers to node_handle_tests

This commit is contained in:
Christian Mazakas
2023-02-08 15:08:51 -08:00
parent 9636875596
commit b96dd2184f
4 changed files with 252 additions and 43 deletions

View File

@ -142,27 +142,57 @@ struct node_handle_base
}
public:
constexpr node_handle_base() noexcept = default;
constexpr node_handle_base()noexcept=default;
node_handle_base(node_handle_base&& nh) noexcept
{
if (!nh.empty()) {
if (!nh.empty()){
// neither of these move constructors are allowed to throw exceptions
// so we can get away with rote placement new
//
new (a_) Allocator(std::move(nh.al()));
new (x_) element_type(std::move(nh.element()));
empty_ = false;
new(a_)Allocator(std::move(nh.al()));
new(x_)element_type(std::move(nh.element()));
empty_=false;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_ = true;
}
}
node_handle_base& operator=(node_handle_base&& nh)noexcept
{
bool const pocma=
boost::allocator_propagate_on_container_move_assignment<
Allocator>::type::value;
if(!empty()){
type_policy::destroy(al(),reinterpret_cast<element_type*>(x_));
reinterpret_cast<element_type*>(x_)->~element_type();
if (pocma&&!nh.empty()){al()=std::move(nh.al());}
}
if(!nh.empty()){
new(x_)element_type(std::move(nh.element()));
if(empty()){new(a_)Allocator(std::move(nh.al()));}
empty_=false;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_=true;
}else if (!empty()){
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
}
return *this;
}
~node_handle_base()
{
if(!empty()){
type_policy::destroy(al(),reinterpret_cast<element_type*>(x_));
reinterpret_cast<element_type*>(x_)->~element_type();
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
}
@ -171,6 +201,55 @@ struct node_handle_base
allocator_type get_allocator()const noexcept{return al();}
explicit operator bool()const noexcept{ return !empty();}
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return empty_;}
void swap(node_handle_base& nh) noexcept(
boost::allocator_is_always_equal<Allocator>::type::value||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
{
using std::swap;
bool const pocs=
boost::allocator_propagate_on_container_swap<Allocator>::type::value;
if (!empty()&&!nh.empty()){
BOOST_ASSERT(pocs || al()==nh.al());
element().swap(nh.element());
if(pocs){
swap(al(),nh.al());
}
return;
}
if (empty()&&nh.empty()){return;}
if (empty()){
new(x_)element_type(std::move(nh.element()));
new(a_)Allocator(nh.al());
empty_=false;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_=true;
}else{
new(nh.x_)element_type(std::move(element()));
new(nh.a_)Allocator(al());
nh.empty_=false;
reinterpret_cast<element_type*>(x_)->~element_type();
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
}
}
friend
void swap(node_handle_base& lhs,node_handle_base& rhs)
noexcept(noexcept(lhs.swap(rhs)))
{
return lhs.swap(rhs);
}
};
static const std::size_t default_bucket_count = 0;

View File

@ -60,6 +60,10 @@ namespace boost {
p = rhs.p;
rhs.p = nullptr;
}
void swap(element_type& rhs) noexcept {
std::swap(p, rhs.p);
}
};
static value_type& value_from(element_type const& x) { return *(x.p); }
@ -135,21 +139,23 @@ namespace boost {
detail::foa::node_handle_base<NodeMapTypes, Allocator>;
using base_type::element;
using base_type::type_policy;
using typename base_type::type_policy;
template <class Key, class T, class Hash, class Pred, class Alloc>
friend class boost::unordered::unordered_node_map;
public:
using base_type::empty;
using base_type::swap;
using key_type = typename NodeMapTypes::key_type;
using mapped_type = typename NodeMapTypes::mapped_type;
public:
using base_type::empty;
constexpr node_map_handle() noexcept = default;
node_map_handle(node_map_handle&& nh) noexcept = default;
node_map_handle& operator=(node_map_handle&&) noexcept = default;
key_type& key() const
{
BOOST_ASSERT(!empty());

View File

@ -56,6 +56,10 @@ namespace boost {
p = rhs.p;
rhs.p = nullptr;
}
void swap(element_type& rhs) noexcept {
std::swap(p, rhs.p);
}
};
static value_type& value_from(element_type const& x) { return *x.p; }
@ -117,19 +121,20 @@ namespace boost {
detail::foa::node_handle_base<NodeSetTypes, Allocator>;
using base_type::element;
using base_type::type_policy;
using typename base_type::type_policy;
template <class Key, class Hash, class Pred, class Alloc>
friend class boost::unordered::unordered_node_set;
public:
using value_type = typename NodeSetTypes::value_type;
public:
using base_type::empty;
using base_type::swap;
using value_type = typename NodeSetTypes::value_type;
constexpr node_set_handle() noexcept = default;
node_set_handle(node_set_handle&& nh) noexcept = default;
node_set_handle& operator=(node_set_handle&&) noexcept = default;
value_type& value() const
{

View File

@ -166,23 +166,6 @@ static void failed_insertion_with_hint()
}
}
#ifdef BOOST_UNORDERED_FOA_TESTS
UNORDERED_AUTO_TEST (examples) {
example1<boost::unordered_node_map>();
example2<boost::unordered_node_set>();
example3<boost::unordered_node_set>();
failed_insertion_with_hint<boost::unordered_node_map,
boost::unordered_node_set>();
}
#else
UNORDERED_AUTO_TEST (examples) {
example1<boost::unordered_map>();
example2<boost::unordered_set>();
example3<boost::unordered_set>();
failed_insertion_with_hint<boost::unordered_map, boost::unordered_set>();
}
template <typename NodeHandle>
bool node_handle_compare(
NodeHandle const& nh, typename NodeHandle::value_type const& x)
@ -269,20 +252,38 @@ template <typename Container> void node_handle_tests_impl(Container& c)
BOOST_TEST(!n4);
}
UNORDERED_AUTO_TEST (node_handle_tests) {
boost::unordered_set<int> x1;
template <template <class Key, class T, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, T> > >
class Map,
template <class Key, class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
class Set>
static void node_handle_tests()
{
Set<int> x1;
x1.emplace(100);
x1.emplace(140);
x1.emplace(-55);
node_handle_tests_impl(x1);
boost::unordered_map<int, std::string> x2;
Map<int, std::string> x2;
x2.emplace(10, "ten");
x2.emplace(-23, "twenty");
x2.emplace(-76, "thirty");
node_handle_tests_impl(x2);
}
#ifdef BOOST_UNORDERED_FOA_TESTS
template <class X> typename X::iterator insert_empty_node(X& x)
{
typedef typename X::node_type node_type;
return x.insert(node_type()).position;
}
#else
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
typename boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>::iterator
insert_empty_node(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& c)
@ -326,8 +327,10 @@ insert_empty_node(boost::unordered_multiset<T, Hash, KeyEqual, Allocator>& c)
return c.insert(node_type());
}
#endif
template <typename Container1, typename Container2>
void insert_node_handle_unique(Container1& c1, Container2& c2)
static void insert_node_handle_unique(Container1& c1, Container2& c2)
{
typedef typename Container1::node_type node_type;
typedef typename Container1::value_type value_type;
@ -368,7 +371,7 @@ void insert_node_handle_unique(Container1& c1, Container2& c2)
}
template <typename Container1, typename Container2>
void insert_node_handle_unique2(Container1& c1, Container2& c2)
static void insert_node_handle_unique2(Container1& c1, Container2& c2)
{
typedef typename Container1::node_type node_type;
typedef typename Container1::value_type value_type;
@ -400,6 +403,130 @@ void insert_node_handle_unique2(Container1& c1, Container2& c2)
}
}
struct hash_thing
{
std::size_t operator()(int x) const
{
return static_cast<std::size_t>(x * 13 + 5);
}
};
#ifdef BOOST_UNORDERED_FOA_TESTS
UNORDERED_AUTO_TEST (examples) {
example1<boost::unordered_node_map>();
example2<boost::unordered_node_set>();
example3<boost::unordered_node_set>();
failed_insertion_with_hint<boost::unordered_node_map,
boost::unordered_node_set>();
node_handle_tests<boost::unordered_node_map, boost::unordered_node_set>();
}
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests) {
{
boost::unordered_node_set<int> x1;
boost::unordered_node_set<int> x2;
x1.emplace(100);
x1.emplace(140);
x1.emplace(-55);
x2.emplace(140);
insert_node_handle_unique(x1, x2);
BOOST_TEST(x2.size() == 3);
}
{
boost::unordered_node_set<int> x1;
boost::unordered_node_set<int> x2;
x1.emplace(100);
x1.emplace(140);
x1.emplace(-55);
x2.emplace(140);
insert_node_handle_unique(x1, x2);
BOOST_TEST(x2.size() == 3);
}
{
boost::unordered_node_map<int, int, hash_thing> x1;
boost::unordered_node_map<int, int> x2;
x1.emplace(67, 50);
x1.emplace(23, 45);
x1.emplace(18, 19);
x2.emplace(23, 50);
x2.emplace(12, 49);
insert_node_handle_unique(x1, x2);
BOOST_TEST(x2.size() == 4);
}
{
boost::unordered_node_map<int, int, hash_thing> x1;
boost::unordered_node_map<int, int> x2;
x1.emplace(67, 50);
x1.emplace(23, 45);
x1.emplace(18, 19);
x2.emplace(23, 50);
x2.emplace(12, 49);
insert_node_handle_unique(x1, x2);
BOOST_TEST(x2.size() == 4);
}
}
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests2) {
{
boost::unordered_node_set<int> x1;
boost::unordered_node_set<int> x2;
x1.emplace(100);
x1.emplace(140);
x1.emplace(-55);
x2.emplace(140);
insert_node_handle_unique2(x1, x2);
BOOST_TEST(x2.size() == 3);
}
{
boost::unordered_node_set<int> x1;
boost::unordered_node_set<int> x2;
x1.emplace(100);
x1.emplace(140);
x1.emplace(-55);
x2.emplace(140);
insert_node_handle_unique2(x1, x2);
BOOST_TEST(x2.size() == 3);
}
{
boost::unordered_node_map<int, int, hash_thing> x1;
boost::unordered_node_map<int, int> x2;
x1.emplace(67, 50);
x1.emplace(23, 45);
x1.emplace(18, 19);
x2.emplace(23, 50);
x2.emplace(12, 49);
insert_node_handle_unique2(x1, x2);
BOOST_TEST(x2.size() == 4);
}
{
boost::unordered_node_map<int, int, hash_thing> x1;
boost::unordered_node_map<int, int> x2;
x1.emplace(67, 50);
x1.emplace(23, 45);
x1.emplace(18, 19);
x2.emplace(23, 50);
x2.emplace(12, 49);
insert_node_handle_unique2(x1, x2);
BOOST_TEST(x2.size() == 4);
}
}
#else
UNORDERED_AUTO_TEST (examples) {
example1<boost::unordered_map>();
example2<boost::unordered_set>();
example3<boost::unordered_set>();
failed_insertion_with_hint<boost::unordered_map, boost::unordered_set>();
node_handle_tests<boost::unordered_map, boost::unordered_set>();
}
template <typename Container1, typename Container2>
void insert_node_handle_equiv(Container1& c1, Container2& c2)
{
@ -427,14 +554,6 @@ void insert_node_handle_equiv(Container1& c1, Container2& c2)
}
}
struct hash_thing
{
std::size_t operator()(int x) const
{
return static_cast<std::size_t>(x * 13 + 5);
}
};
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests) {
{
boost::unordered_set<int> x1;