mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-29 19:07:15 +02:00
Interim checkin of attempt at extract/insert node handles
This commit is contained in:
@ -11,6 +11,8 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_HPP
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
@ -1498,6 +1500,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void extract(const_iterator pos, element_type* p)noexcept
|
||||
{
|
||||
BOOST_ASSERT(pos!=end());
|
||||
type_policy::construct(al(),p,type_policy::move(*pos.p));
|
||||
destroy_element(pos.p);
|
||||
recover_slot(pos.pc);
|
||||
}
|
||||
|
||||
// TODO: should we accept different allocator too?
|
||||
template<typename Hash2,typename Pred2>
|
||||
void merge(table<TypePolicy,Hash2,Pred2,Allocator>& x)
|
||||
@ -1878,7 +1888,7 @@ private:
|
||||
|
||||
return emplace_impl(type_policy::move(*p));
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
|
||||
{
|
||||
@ -1903,7 +1913,7 @@ private:
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static std::size_t capacity_for(std::size_t n)
|
||||
{
|
||||
return size_policy::size(size_index_for<group_type,size_policy>(n))*N-1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
@ -36,6 +37,7 @@ namespace boost {
|
||||
template <class Key, class T> struct node_map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using raw_key_type = typename std::remove_const<Key>::type;
|
||||
using raw_mapped_type = typename std::remove_const<T>::type;
|
||||
|
||||
@ -79,8 +81,12 @@ namespace boost {
|
||||
template <class A>
|
||||
static void construct(A&, element_type* p, element_type&& x)
|
||||
{
|
||||
std::cout << "should be seeing this: construct(A&, element_type* p, "
|
||||
"element_type&& x)"
|
||||
<< std::endl;
|
||||
p->p = x.p;
|
||||
x.p = nullptr;
|
||||
std::cout << "p->p is now: " << p->p << std::endl;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
@ -111,6 +117,7 @@ namespace boost {
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
std::cout << "going to deallocate: " << p->p << std::endl;
|
||||
boost::allocator_destroy(al, p->p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
@ -119,6 +126,95 @@ namespace boost {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class NodeMapTypes, class Allocator> struct node_handle
|
||||
{
|
||||
private:
|
||||
using type_policy = NodeMapTypes;
|
||||
using element_type = typename type_policy::element_type;
|
||||
|
||||
template <class Key, class T, class Hash, class Pred, class Alloc>
|
||||
friend class boost::unordered::unordered_node_map;
|
||||
|
||||
public:
|
||||
using value_type = typename NodeMapTypes::value_type;
|
||||
using key_type = typename NodeMapTypes::key_type;
|
||||
using mapped_type = typename NodeMapTypes::mapped_type;
|
||||
using allocator_type = Allocator;
|
||||
|
||||
private:
|
||||
alignas(element_type) unsigned char x[sizeof(element_type)];
|
||||
alignas(Allocator) unsigned char a[sizeof(Allocator)];
|
||||
bool empty_;
|
||||
|
||||
element_type& element() noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *reinterpret_cast<element_type*>(x);
|
||||
}
|
||||
|
||||
element_type const& element() const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *reinterpret_cast<element_type const*>(x);
|
||||
}
|
||||
|
||||
Allocator& al() noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *reinterpret_cast<Allocator*>(a);
|
||||
}
|
||||
|
||||
Allocator const& al() const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *reinterpret_cast<Allocator const*>(a);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr node_handle() noexcept = default;
|
||||
|
||||
node_handle(node_handle&& nh) noexcept
|
||||
{
|
||||
new (a) Allocator(std::move(nh.al()));
|
||||
type_policy::construct(al(), reinterpret_cast<element_type*>(x),
|
||||
type_policy::move(nh.element()));
|
||||
|
||||
reinterpret_cast<Allocator*>(nh.a)->~Allocator();
|
||||
nh.empty_ = true;
|
||||
}
|
||||
|
||||
~node_handle()
|
||||
{
|
||||
if (!empty()) {
|
||||
type_policy::destroy(al(), reinterpret_cast<element_type*>(x));
|
||||
reinterpret_cast<Allocator*>(a)->~Allocator();
|
||||
empty_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
key_type& key() const
|
||||
{
|
||||
return const_cast<key_type&>(type_policy::extract(element()));
|
||||
}
|
||||
|
||||
mapped_type& mapped() const
|
||||
{
|
||||
return const_cast<mapped_type&>(
|
||||
type_policy::value_from(element()).second);
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const noexcept { return al(); }
|
||||
explicit operator bool() const noexcept { return !empty(); }
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept { return empty_; }
|
||||
};
|
||||
|
||||
template <class Iterator, class NodeType> struct insert_return_type
|
||||
{
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
@ -153,6 +249,9 @@ namespace boost {
|
||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||
using iterator = typename table_type::iterator;
|
||||
using const_iterator = typename table_type::const_iterator;
|
||||
using node_type = detail::node_handle<map_types, allocator_type>;
|
||||
using insert_return_type =
|
||||
detail::insert_return_type<iterator, node_type>;
|
||||
|
||||
unordered_node_map() : unordered_node_map(0) {}
|
||||
|
||||
@ -342,6 +441,22 @@ namespace boost {
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
insert_return_type insert(node_type&& nh)
|
||||
{
|
||||
if (nh.empty()) {
|
||||
return {end(), false, node_type{}};
|
||||
}
|
||||
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
auto itp = table_.emplace_impl(map_types::move(nh.element()));
|
||||
if (itp.second) {
|
||||
return {itp.first, true, node_type{}};
|
||||
} else {
|
||||
return {itp.first, false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj)
|
||||
{
|
||||
@ -498,6 +613,52 @@ namespace boost {
|
||||
table_.swap(rhs.table_);
|
||||
}
|
||||
|
||||
node_type extract(const_iterator pos)
|
||||
{
|
||||
BOOST_ASSERT(pos != end());
|
||||
node_type nh;
|
||||
table_.extract(
|
||||
pos, reinterpret_cast<typename map_types::element_type*>(nh.x));
|
||||
new (&nh.a) allocator_type(get_allocator());
|
||||
nh.empty_ = false;
|
||||
return nh;
|
||||
}
|
||||
|
||||
node_type extract(key_type const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
node_type nh;
|
||||
if (pos != end()) {
|
||||
table_.extract(
|
||||
pos, reinterpret_cast<typename map_types::element_type*>(nh.x));
|
||||
new (&nh.a) allocator_type(get_allocator());
|
||||
nh.empty_ = false;
|
||||
} else {
|
||||
nh.empty_ = true;
|
||||
}
|
||||
return nh;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_node_map>::value,
|
||||
node_type>::type
|
||||
extract(K const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
node_type nh;
|
||||
if (pos != end()) {
|
||||
table_.extract(
|
||||
pos, reinterpret_cast<typename map_types::element_type*>(nh.x));
|
||||
new (&nh.a) allocator_type(get_allocator());
|
||||
nh.empty_ = false;
|
||||
} else {
|
||||
nh.empty_ = true;
|
||||
}
|
||||
return nh;
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
void merge(
|
||||
unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&
|
||||
|
@ -142,6 +142,8 @@ build_foa erase_if ;
|
||||
build_foa scary_tests ;
|
||||
build_foa init_type_insert_tests ;
|
||||
build_foa max_load_tests ;
|
||||
build_foa extract_tests ;
|
||||
build_foa node_handle_tests ;
|
||||
|
||||
run unordered/hash_is_avalanching_test.cpp ;
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
@ -113,6 +110,18 @@ namespace extract_tests {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_node_map;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_node_map))((default_generator)(generate_collisions)))
|
||||
#else
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
@ -122,12 +131,10 @@ namespace extract_tests {
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)))
|
||||
}
|
||||
#endif
|
||||
} // namespace extract_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,12 +1,12 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2023 Christian Mazakas
|
||||
// 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 "../helpers/postfix.hpp"
|
||||
#include "../helpers/unordered.hpp"
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
@ -17,6 +17,33 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (example1_5) {
|
||||
typedef boost::unordered_node_map<int, std::string>::insert_return_type
|
||||
insert_return_type;
|
||||
|
||||
boost::unordered_node_map<int, std::string> src;
|
||||
src.emplace(1, "one");
|
||||
src.emplace(2, "two");
|
||||
src.emplace(3, "buckle my shoe");
|
||||
boost::unordered_node_map<int, std::string> dst;
|
||||
dst.emplace(3, "three");
|
||||
|
||||
dst.insert(src.extract(src.find(1)));
|
||||
dst.insert(src.extract(2));
|
||||
insert_return_type r = dst.insert(src.extract(3));
|
||||
|
||||
BOOST_TEST(src.empty());
|
||||
BOOST_TEST(dst.size() == 3);
|
||||
BOOST_TEST(dst[1] == "one");
|
||||
BOOST_TEST(dst[2] == "two");
|
||||
BOOST_TEST(dst[3] == "three");
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST(r.position == dst.find(3));
|
||||
BOOST_TEST(r.node.mapped() == "buckle my shoe");
|
||||
}
|
||||
#else
|
||||
|
||||
UNORDERED_AUTO_TEST (example1) {
|
||||
typedef boost::unordered_map<int, std::string>::insert_return_type
|
||||
insert_return_type;
|
||||
@ -547,4 +574,6 @@ UNORDERED_AUTO_TEST (insert_node_handle_unique_tests2) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
Reference in New Issue
Block a user