2cd5f4cd3e
Preparing to add a key extraction function. Without this "Operators" template parameter, we'd have even more template parameters, and that parameter list would grow too complex. Better wrap it in one single template that contains all operators. This is an API change which all callers need to adjust to, but it will be worth it.
121 lines
2.8 KiB
C++
121 lines
2.8 KiB
C++
// SPDX-License-Identifier: BSD-2-Clause
|
|
// author: Max Kellermann <max.kellermann@gmail.com>
|
|
|
|
#include "util/IntrusiveHashSet.hxx"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
struct IntItem final : IntrusiveHashSetHook<IntrusiveHookMode::TRACK> {
|
|
int value;
|
|
|
|
IntItem(int _value) noexcept:value(_value) {}
|
|
|
|
struct Hash {
|
|
constexpr std::size_t operator()(const IntItem &i) const noexcept {
|
|
return i.value;
|
|
}
|
|
|
|
constexpr std::size_t operator()(int i) const noexcept {
|
|
return i;
|
|
}
|
|
};
|
|
|
|
struct Equal {
|
|
constexpr bool operator()(const IntItem &a,
|
|
const IntItem &b) const noexcept {
|
|
return a.value == b.value;
|
|
}
|
|
};
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
TEST(IntrusiveHashSet, Basic)
|
|
{
|
|
IntItem a{1}, b{2}, c{3}, d{4}, e{5}, f{1};
|
|
|
|
IntrusiveHashSet<IntItem, 3,
|
|
IntrusiveHashSetOperators<IntItem::Hash,
|
|
IntItem::Equal>> set;
|
|
|
|
{
|
|
auto [position, inserted] = set.insert_check(2);
|
|
ASSERT_TRUE(inserted);
|
|
set.insert_commit(position, b);
|
|
}
|
|
|
|
ASSERT_FALSE(set.insert_check(2).second);
|
|
ASSERT_FALSE(set.insert_check(b).second);
|
|
|
|
{
|
|
auto [position, inserted] = set.insert_check(a);
|
|
ASSERT_TRUE(inserted);
|
|
set.insert_commit(position, a);
|
|
}
|
|
|
|
set.insert(c);
|
|
|
|
ASSERT_EQ(set.size(), 3);
|
|
|
|
ASSERT_NE(set.find(c), set.end());
|
|
ASSERT_EQ(set.find(c), set.iterator_to(c));
|
|
ASSERT_NE(set.find(3), set.end());
|
|
ASSERT_EQ(set.find(3), set.iterator_to(c));
|
|
|
|
ASSERT_EQ(set.find(4), set.end());
|
|
ASSERT_EQ(set.find(d), set.end());
|
|
|
|
set.erase(set.iterator_to(c));
|
|
|
|
ASSERT_EQ(set.size(), 2);
|
|
ASSERT_EQ(set.find(3), set.end());
|
|
ASSERT_EQ(set.find(c), set.end());
|
|
|
|
set.insert(c);
|
|
set.insert(d);
|
|
set.insert(e);
|
|
|
|
ASSERT_EQ(set.size(), 5);
|
|
ASSERT_FALSE(set.insert_check(1).second);
|
|
ASSERT_EQ(set.insert_check(1).first, set.iterator_to(a));
|
|
ASSERT_FALSE(set.insert_check(f).second);
|
|
ASSERT_EQ(set.insert_check(f).first, set.iterator_to(a));
|
|
|
|
ASSERT_EQ(set.find(1), set.iterator_to(a));
|
|
ASSERT_EQ(set.find(2), set.iterator_to(b));
|
|
ASSERT_EQ(set.find(3), set.iterator_to(c));
|
|
ASSERT_EQ(set.find(4), set.iterator_to(d));
|
|
ASSERT_EQ(set.find(5), set.iterator_to(e));
|
|
|
|
ASSERT_EQ(set.find(a), set.iterator_to(a));
|
|
ASSERT_EQ(set.find(b), set.iterator_to(b));
|
|
ASSERT_EQ(set.find(c), set.iterator_to(c));
|
|
ASSERT_EQ(set.find(d), set.iterator_to(d));
|
|
ASSERT_EQ(set.find(e), set.iterator_to(e));
|
|
|
|
set.erase(set.find(1));
|
|
|
|
{
|
|
auto [position, inserted] = set.insert_check(f);
|
|
ASSERT_TRUE(inserted);
|
|
set.insert_commit(position, f);
|
|
}
|
|
|
|
ASSERT_EQ(set.find(a), set.iterator_to(f));
|
|
ASSERT_EQ(set.find(f), set.iterator_to(f));
|
|
ASSERT_EQ(set.find(1), set.iterator_to(f));
|
|
|
|
set.clear_and_dispose([](auto *i){ i->value = -1; });
|
|
|
|
ASSERT_EQ(a.value, 1);
|
|
ASSERT_EQ(b.value, -1);
|
|
ASSERT_EQ(c.value, -1);
|
|
ASSERT_EQ(d.value, -1);
|
|
ASSERT_EQ(e.value, -1);
|
|
ASSERT_EQ(f.value, -1);
|
|
}
|