mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-31 03:47:16 +02:00
Add transparent insert_or_assign
This commit is contained in:
@ -16,6 +16,7 @@
|
|||||||
#define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP
|
#define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP
|
||||||
|
|
||||||
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
||||||
|
#include <boost/unordered/detail/type_traits.hpp>
|
||||||
|
|
||||||
#include <boost/container_hash/hash.hpp>
|
#include <boost/container_hash/hash.hpp>
|
||||||
#include <boost/core/allocator_access.hpp>
|
#include <boost/core/allocator_access.hpp>
|
||||||
@ -163,6 +164,17 @@ namespace boost {
|
|||||||
std::forward<M>(obj));
|
std::forward<M>(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class K, class M>
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
|
insert_or_assign(K&& k, M&& obj)
|
||||||
|
{
|
||||||
|
return table_.try_emplace_or_visit(
|
||||||
|
std::forward<K>(k),
|
||||||
|
[&](value_type& m) { m.second = std::forward<M>(obj); },
|
||||||
|
std::forward<M>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
/// Hash Policy
|
/// Hash Policy
|
||||||
///
|
///
|
||||||
void rehash(size_type n) { table_.rehash(n); }
|
void rehash(size_type n) { table_.rehash(n); }
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
|
|
||||||
#include <boost/container_hash/hash.hpp>
|
#include <boost/container_hash/hash.hpp>
|
||||||
|
#include <boost/core/ignore_unused.hpp>
|
||||||
#include <boost/core/span.hpp>
|
#include <boost/core/span.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/unordered/unordered_flat_map.hpp>
|
||||||
|
|
||||||
@ -19,6 +20,26 @@
|
|||||||
|
|
||||||
constexpr std::size_t const num_threads = 16;
|
constexpr std::size_t const num_threads = 16;
|
||||||
|
|
||||||
|
struct transparent_hash
|
||||||
|
{
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
|
template <class T> std::size_t operator()(T const& t) const noexcept
|
||||||
|
{
|
||||||
|
return boost::hash<T>()(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct transparent_key_equal
|
||||||
|
{
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
|
template <class T, class U> bool operator()(T const& lhs, U const& rhs) const
|
||||||
|
{
|
||||||
|
return lhs == rhs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct raii
|
struct raii
|
||||||
{
|
{
|
||||||
static std::atomic_int default_constructor;
|
static std::atomic_int default_constructor;
|
||||||
@ -70,6 +91,25 @@ struct raii
|
|||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator==(raii const& lhs, int const x)
|
||||||
|
{
|
||||||
|
return lhs.x_ == x;
|
||||||
|
}
|
||||||
|
friend bool operator!=(raii const& lhs, int const x)
|
||||||
|
{
|
||||||
|
return !(lhs.x_ == x);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(int const x, raii const& rhs)
|
||||||
|
{
|
||||||
|
return rhs.x_ == x;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(int const x, raii const& rhs)
|
||||||
|
{
|
||||||
|
return !(rhs.x_ == x);
|
||||||
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, raii const& rhs)
|
friend std::ostream& operator<<(std::ostream& os, raii const& rhs)
|
||||||
{
|
{
|
||||||
os << "{ x_: " << rhs.x_ << " }";
|
os << "{ x_: " << rhs.x_ << " }";
|
||||||
@ -300,6 +340,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size());
|
||||||
// don't check move construction count here because of rehashing
|
// don't check move construction count here because of rehashing
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0);
|
BOOST_TEST_GT(raii::move_constructor, 0);
|
||||||
@ -318,6 +359,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0);
|
BOOST_TEST_EQ(raii::copy_assignment, 0);
|
||||||
@ -335,6 +377,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
||||||
@ -352,11 +395,62 @@ namespace {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0);
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0);
|
BOOST_TEST_EQ(raii::copy_assignment, 0);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
||||||
}
|
}
|
||||||
} rvalue_insert_or_assign_move_assign;
|
} rvalue_insert_or_assign_move_assign;
|
||||||
|
|
||||||
|
struct transparent_insert_or_assign_copy_assign_type
|
||||||
|
{
|
||||||
|
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||||
|
{
|
||||||
|
using is_transparent =
|
||||||
|
typename boost::make_void<typename X::hasher::is_transparent,
|
||||||
|
typename X::key_equal::is_transparent>::type;
|
||||||
|
|
||||||
|
boost::ignore_unused<is_transparent>();
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0);
|
||||||
|
|
||||||
|
thread_runner(values, [&x](boost::span<T> s) {
|
||||||
|
for (auto& r : s) {
|
||||||
|
x.insert_or_assign(r.first.x_, r.second);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
|
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
||||||
|
BOOST_TEST_EQ(raii::move_assignment, 0);
|
||||||
|
}
|
||||||
|
} transparent_insert_or_assign_copy_assign;
|
||||||
|
|
||||||
|
struct transparent_insert_or_assign_move_assign_type
|
||||||
|
{
|
||||||
|
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||||
|
{
|
||||||
|
using is_transparent =
|
||||||
|
typename boost::make_void<typename X::hasher::is_transparent,
|
||||||
|
typename X::key_equal::is_transparent>::type;
|
||||||
|
|
||||||
|
boost::ignore_unused<is_transparent>();
|
||||||
|
|
||||||
|
thread_runner(values, [&x](boost::span<T> s) {
|
||||||
|
for (auto& r : s) {
|
||||||
|
x.insert_or_assign(r.first.x_, std::move(r.second));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
|
BOOST_TEST_EQ(raii::copy_constructor, 0);
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, 2 * x.size()); // rehashing
|
||||||
|
BOOST_TEST_EQ(raii::copy_assignment, 0);
|
||||||
|
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
||||||
|
}
|
||||||
|
} transparent_insert_or_assign_move_assign;
|
||||||
|
|
||||||
template <class X, class G, class F>
|
template <class X, class G, class F>
|
||||||
void insert(X*, G gen, F inserter, test::random_generator rg)
|
void insert(X*, G gen, F inserter, test::random_generator rg)
|
||||||
{
|
{
|
||||||
@ -454,6 +548,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
||||||
|
boost::unordered::concurrent_flat_map<raii, raii, transparent_hash,
|
||||||
|
transparent_key_equal>* transparent_map;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -488,6 +584,13 @@ UNORDERED_TEST(
|
|||||||
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
||||||
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
insert,
|
||||||
|
((transparent_map))
|
||||||
|
((init_type_generator))
|
||||||
|
((transparent_insert_or_assign_copy_assign)(transparent_insert_or_assign_move_assign))
|
||||||
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
Reference in New Issue
Block a user