mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 03:17:15 +02:00
Add cfoa tests for emplace(k,v)
This commit is contained in:
@ -4,6 +4,7 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
#include "../helpers/count.hpp"
|
||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
@ -293,4 +294,174 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using converting_key_type = basic_raii<struct converting_key_tag_>;
|
||||||
|
using converting_value_type = basic_raii<struct converting_value_tag_>;
|
||||||
|
|
||||||
|
class counted_key_type : public basic_raii<struct counted_key_tag_>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using basic_raii::basic_raii;
|
||||||
|
counted_key_type() = default;
|
||||||
|
counted_key_type(const converting_key_type& k) : counted_key_type(k.x_) {}
|
||||||
|
};
|
||||||
|
class counted_value_type : public basic_raii<struct counted_value_tag_>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using basic_raii::basic_raii;
|
||||||
|
counted_value_type() = default;
|
||||||
|
counted_value_type(const converting_value_type& v)
|
||||||
|
: counted_value_type(v.x_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset_counts()
|
||||||
|
{
|
||||||
|
counted_key_type::reset_counts();
|
||||||
|
counted_value_type::reset_counts();
|
||||||
|
converting_key_type::reset_counts();
|
||||||
|
converting_value_type::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
using test::smf_count;
|
||||||
|
|
||||||
|
template <class T> smf_count count_for()
|
||||||
|
{
|
||||||
|
return test::smf_count{
|
||||||
|
(int)T::default_constructor.load(std::memory_order_relaxed),
|
||||||
|
(int)T::copy_constructor.load(std::memory_order_relaxed),
|
||||||
|
(int)T::move_constructor.load(std::memory_order_relaxed),
|
||||||
|
(int)T::copy_assignment.load(std::memory_order_relaxed),
|
||||||
|
(int)T::move_assignment.load(std::memory_order_relaxed),
|
||||||
|
(int)T::destructor.load(std::memory_order_relaxed)};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum emplace_kind
|
||||||
|
{
|
||||||
|
copy,
|
||||||
|
move
|
||||||
|
};
|
||||||
|
|
||||||
|
enum emplace_status
|
||||||
|
{
|
||||||
|
fail,
|
||||||
|
success
|
||||||
|
};
|
||||||
|
|
||||||
|
struct counted_key_checker_type
|
||||||
|
{
|
||||||
|
using key_type = counted_key_type;
|
||||||
|
void operator()(emplace_kind kind, emplace_status status)
|
||||||
|
{
|
||||||
|
int copies = (kind == copy && status == success) ? 1 : 0;
|
||||||
|
int moves = (kind == move && status == success) ? 1 : 0;
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<counted_key_type>(), (smf_count{0, copies, moves, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
} counted_key_checker;
|
||||||
|
|
||||||
|
struct converting_key_checker_type
|
||||||
|
{
|
||||||
|
using key_type = converting_key_type;
|
||||||
|
void operator()(emplace_kind, emplace_status status)
|
||||||
|
{
|
||||||
|
int moves = (status == success) ? 1 : 0;
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<counted_key_type>(), (smf_count{1, 0, moves, 0, 0, 1}));
|
||||||
|
}
|
||||||
|
} converting_key_checker;
|
||||||
|
|
||||||
|
struct counted_value_checker_type
|
||||||
|
{
|
||||||
|
using mapped_type = counted_value_type;
|
||||||
|
void operator()(emplace_kind kind, emplace_status status)
|
||||||
|
{
|
||||||
|
int copies = (kind == copy && status == success) ? 1 : 0;
|
||||||
|
int moves = (kind == move && status == success) ? 1 : 0;
|
||||||
|
BOOST_TEST_EQ(count_for<counted_value_type>(),
|
||||||
|
(smf_count{0, copies, moves, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
} counted_value_checker;
|
||||||
|
|
||||||
|
struct converting_value_checker_type
|
||||||
|
{
|
||||||
|
using mapped_type = converting_value_type;
|
||||||
|
void operator()(emplace_kind, emplace_status status)
|
||||||
|
{
|
||||||
|
int ctors = (status == success) ? 1 : 0;
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<counted_value_type>(), (smf_count{ctors, 0, 0, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
} converting_value_checker;
|
||||||
|
|
||||||
|
template <class X, class KC, class VC>
|
||||||
|
void emplace_map_key_value(
|
||||||
|
X*, emplace_kind kind, KC key_checker, VC value_checker)
|
||||||
|
{
|
||||||
|
using container = X;
|
||||||
|
using key_type = typename KC::key_type;
|
||||||
|
using mapped_type = typename VC::mapped_type;
|
||||||
|
|
||||||
|
container x;
|
||||||
|
key_type key{};
|
||||||
|
key_type key2 = key;
|
||||||
|
mapped_type value{};
|
||||||
|
mapped_type value2 = value;
|
||||||
|
|
||||||
|
{
|
||||||
|
reset_counts();
|
||||||
|
auto ret = (kind == copy) ? x.emplace(key, value)
|
||||||
|
: x.emplace(std::move(key), std::move(value));
|
||||||
|
BOOST_TEST_EQ(ret, true);
|
||||||
|
key_checker(kind, success);
|
||||||
|
value_checker(kind, success);
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_key_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_value_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
reset_counts();
|
||||||
|
bool ret = x.emplace(key2, value2);
|
||||||
|
BOOST_TEST_EQ(ret, false);
|
||||||
|
key_checker(kind, fail);
|
||||||
|
value_checker(kind, fail);
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_key_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_value_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
reset_counts();
|
||||||
|
bool ret = x.emplace(std::move(key2), std::move(value2));
|
||||||
|
BOOST_TEST_EQ(ret, false);
|
||||||
|
key_checker(kind, fail);
|
||||||
|
value_checker(kind, fail);
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_key_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
count_for<converting_value_type>(), (smf_count{0, 0, 0, 0, 0, 0}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unordered::concurrent_flat_map<counted_key_type, counted_value_type>*
|
||||||
|
test_counted_flat_map = {};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
emplace_map_key_value,
|
||||||
|
((test_counted_flat_map))
|
||||||
|
((copy)(move))
|
||||||
|
((counted_key_checker)(converting_key_checker))
|
||||||
|
((counted_value_checker)(converting_value_checker))
|
||||||
|
)
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -207,7 +207,8 @@ template <class T> struct stateful_allocator2
|
|||||||
bool operator!=(stateful_allocator2 const& rhs) const { return x_ != rhs.x_; }
|
bool operator!=(stateful_allocator2 const& rhs) const { return x_ != rhs.x_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct raii
|
template <class Tag>
|
||||||
|
struct basic_raii
|
||||||
{
|
{
|
||||||
static std::atomic<std::uint32_t> default_constructor;
|
static std::atomic<std::uint32_t> default_constructor;
|
||||||
static std::atomic<std::uint32_t> copy_constructor;
|
static std::atomic<std::uint32_t> copy_constructor;
|
||||||
@ -219,17 +220,17 @@ struct raii
|
|||||||
|
|
||||||
int x_ = -1;
|
int x_ = -1;
|
||||||
|
|
||||||
raii() { ++default_constructor; }
|
basic_raii() { ++default_constructor; }
|
||||||
raii(int const x) : x_{x} { ++default_constructor; }
|
basic_raii(int const x) : x_{x} { ++default_constructor; }
|
||||||
raii(raii const& rhs) : x_{rhs.x_} { ++copy_constructor; }
|
basic_raii(basic_raii const& rhs) : x_{rhs.x_} { ++copy_constructor; }
|
||||||
raii(raii&& rhs) noexcept : x_{rhs.x_}
|
basic_raii(basic_raii&& rhs) noexcept : x_{rhs.x_}
|
||||||
{
|
{
|
||||||
rhs.x_ = -1;
|
rhs.x_ = -1;
|
||||||
++move_constructor;
|
++move_constructor;
|
||||||
}
|
}
|
||||||
~raii() { ++destructor; }
|
~basic_raii() { ++destructor; }
|
||||||
|
|
||||||
raii& operator=(raii const& rhs)
|
basic_raii& operator=(basic_raii const& rhs)
|
||||||
{
|
{
|
||||||
++copy_assignment;
|
++copy_assignment;
|
||||||
if (this != &rhs) {
|
if (this != &rhs) {
|
||||||
@ -238,7 +239,7 @@ struct raii
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
raii& operator=(raii&& rhs) noexcept
|
basic_raii& operator=(basic_raii&& rhs) noexcept
|
||||||
{
|
{
|
||||||
++move_assignment;
|
++move_assignment;
|
||||||
if (this != &rhs) {
|
if (this != &rhs) {
|
||||||
@ -248,37 +249,37 @@ struct raii
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(raii const& lhs, raii const& rhs)
|
friend bool operator==(basic_raii const& lhs, basic_raii const& rhs)
|
||||||
{
|
{
|
||||||
return lhs.x_ == rhs.x_;
|
return lhs.x_ == rhs.x_;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator!=(raii const& lhs, raii const& rhs)
|
friend bool operator!=(basic_raii const& lhs, basic_raii const& rhs)
|
||||||
{
|
{
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(raii const& lhs, int const x) { return lhs.x_ == x; }
|
friend bool operator==(basic_raii const& lhs, int const x) { return lhs.x_ == x; }
|
||||||
friend bool operator!=(raii const& lhs, int const x)
|
friend bool operator!=(basic_raii const& lhs, int const x)
|
||||||
{
|
{
|
||||||
return !(lhs.x_ == x);
|
return !(lhs.x_ == x);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(int const x, raii const& rhs) { return rhs.x_ == x; }
|
friend bool operator==(int const x, basic_raii const& rhs) { return rhs.x_ == x; }
|
||||||
|
|
||||||
friend bool operator!=(int const x, raii const& rhs)
|
friend bool operator!=(int const x, basic_raii const& rhs)
|
||||||
{
|
{
|
||||||
return !(rhs.x_ == x);
|
return !(rhs.x_ == x);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, raii const& rhs)
|
friend std::ostream& operator<<(std::ostream& os, basic_raii const& rhs)
|
||||||
{
|
{
|
||||||
os << "{ x_: " << rhs.x_ << " }";
|
os << "{ x_: " << rhs.x_ << " }";
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(
|
friend std::ostream& operator<<(
|
||||||
std::ostream& os, std::pair<raii const, raii> const& rhs)
|
std::ostream& os, std::pair<basic_raii const, basic_raii> const& rhs)
|
||||||
{
|
{
|
||||||
os << "pair<" << rhs.first << ", " << rhs.second << ">";
|
os << "pair<" << rhs.first << ", " << rhs.second << ">";
|
||||||
return os;
|
return os;
|
||||||
@ -294,16 +295,30 @@ struct raii
|
|||||||
move_assignment = 0;
|
move_assignment = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend void swap(raii& lhs, raii& rhs) { std::swap(lhs.x_, rhs.x_); }
|
friend void swap(basic_raii& lhs, basic_raii& rhs) { std::swap(lhs.x_, rhs.x_); }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::atomic<std::uint32_t> raii::default_constructor{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::default_constructor(0);
|
||||||
std::atomic<std::uint32_t> raii::copy_constructor{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::copy_constructor(0);
|
||||||
std::atomic<std::uint32_t> raii::move_constructor{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::move_constructor(0);
|
||||||
std::atomic<std::uint32_t> raii::destructor{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::destructor(0);
|
||||||
std::atomic<std::uint32_t> raii::copy_assignment{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::copy_assignment(0);
|
||||||
std::atomic<std::uint32_t> raii::move_assignment{0};
|
template <class Tag> std::atomic<std::uint32_t> basic_raii<Tag>::move_assignment(0);
|
||||||
|
|
||||||
|
struct raii_tag_
|
||||||
|
{
|
||||||
|
};
|
||||||
|
class raii : public basic_raii<raii_tag_>
|
||||||
|
{
|
||||||
|
using basic_raii::basic_raii;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Tag>
|
||||||
|
std::size_t hash_value(basic_raii<Tag> const& r) noexcept
|
||||||
|
{
|
||||||
|
boost::hash<int> hasher;
|
||||||
|
return hasher(r.x_);
|
||||||
|
}
|
||||||
std::size_t hash_value(raii const& r) noexcept
|
std::size_t hash_value(raii const& r) noexcept
|
||||||
{
|
{
|
||||||
boost::hash<int> hasher;
|
boost::hash<int> hasher;
|
||||||
@ -311,6 +326,13 @@ std::size_t hash_value(raii const& r) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
template <class Tag> struct hash<basic_raii<Tag>>
|
||||||
|
{
|
||||||
|
std::size_t operator()(basic_raii<Tag> const& r) const noexcept
|
||||||
|
{
|
||||||
|
return hash_value(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
template <> struct hash<raii>
|
template <> struct hash<raii>
|
||||||
{
|
{
|
||||||
std::size_t operator()(raii const& r) const noexcept
|
std::size_t operator()(raii const& r) const noexcept
|
||||||
|
Reference in New Issue
Block a user