util/IntrusiveTreeSet: new class
This commit is contained in:

committed by
Max Kellermann

parent
6a99f20828
commit
5a0bad3b2f
190
test/util/TestIntrusiveTreeSet.cxx
Normal file
190
test/util/TestIntrusiveTreeSet.cxx
Normal file
@@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
// Copyright CM4all GmbH
|
||||
// author: Max Kellermann <mk@cm4all.com>
|
||||
|
||||
#include "util/IntrusiveTreeSet.hxx"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
struct IntItem final : IntrusiveTreeSetHook<IntrusiveHookMode::TRACK> {
|
||||
int value;
|
||||
|
||||
IntItem(int _value) noexcept:value(_value) {}
|
||||
|
||||
struct GetKey {
|
||||
constexpr int operator()(const IntItem &item) const noexcept {
|
||||
return item.value;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(IntrusiveTreeSet, Basic)
|
||||
{
|
||||
IntItem a{1}, b{2}, c{3}, d{4}, e{5}, f{1};
|
||||
|
||||
IntrusiveTreeSet<IntItem,
|
||||
IntrusiveTreeSetOperators<IntItem, IntItem::GetKey>> set;
|
||||
|
||||
EXPECT_EQ(set.size(), 0U);
|
||||
EXPECT_TRUE(set.empty());
|
||||
|
||||
EXPECT_FALSE(a.is_linked());
|
||||
EXPECT_FALSE(b.is_linked());
|
||||
|
||||
set.insert(b);
|
||||
|
||||
EXPECT_FALSE(a.is_linked());
|
||||
EXPECT_TRUE(b.is_linked());
|
||||
|
||||
EXPECT_EQ(set.size(), 1U);
|
||||
EXPECT_EQ(set.find(2), set.iterator_to(b));
|
||||
EXPECT_EQ(&set.front(), &b);
|
||||
|
||||
set.insert(a);
|
||||
EXPECT_EQ(&set.front(), &a);
|
||||
|
||||
EXPECT_TRUE(a.is_linked());
|
||||
EXPECT_TRUE(b.is_linked());
|
||||
|
||||
set.insert(c);
|
||||
EXPECT_EQ(&set.front(), &a);
|
||||
|
||||
EXPECT_EQ(set.size(), 3U);
|
||||
|
||||
EXPECT_NE(set.find(3), set.end());
|
||||
EXPECT_EQ(set.find(3), set.iterator_to(c));
|
||||
|
||||
EXPECT_EQ(set.find(4), set.end());
|
||||
|
||||
EXPECT_TRUE(c.is_linked());
|
||||
|
||||
set.erase(set.iterator_to(c));
|
||||
|
||||
EXPECT_FALSE(c.is_linked());
|
||||
|
||||
EXPECT_EQ(set.size(), 2U);
|
||||
EXPECT_EQ(set.find(3), set.end());
|
||||
EXPECT_EQ(&set.front(), &a);
|
||||
|
||||
set.insert(c);
|
||||
set.insert(d);
|
||||
set.insert(e);
|
||||
|
||||
EXPECT_EQ(set.size(), 5U);
|
||||
EXPECT_EQ(&set.front(), &a);
|
||||
|
||||
EXPECT_EQ(set.find(1), set.iterator_to(a));
|
||||
EXPECT_EQ(set.find(2), set.iterator_to(b));
|
||||
EXPECT_EQ(set.find(3), set.iterator_to(c));
|
||||
EXPECT_EQ(set.find(4), set.iterator_to(d));
|
||||
EXPECT_EQ(set.find(5), set.iterator_to(e));
|
||||
|
||||
EXPECT_TRUE(a.is_linked());
|
||||
EXPECT_FALSE(f.is_linked());
|
||||
|
||||
set.erase(set.iterator_to(a));
|
||||
EXPECT_FALSE(a.is_linked());
|
||||
EXPECT_FALSE(f.is_linked());
|
||||
EXPECT_EQ(set.find(1), set.end());
|
||||
EXPECT_EQ(set.size(), 4U);
|
||||
EXPECT_EQ(&set.front(), &b);
|
||||
|
||||
set.insert(f);
|
||||
EXPECT_FALSE(a.is_linked());
|
||||
EXPECT_TRUE(f.is_linked());
|
||||
EXPECT_EQ(set.find(1), set.iterator_to(f));
|
||||
EXPECT_EQ(set.size(), 5U);
|
||||
EXPECT_EQ(&set.front(), &f);
|
||||
|
||||
set.pop_front();
|
||||
EXPECT_FALSE(f.is_linked());
|
||||
|
||||
set.clear_and_dispose([](auto *i){ i->value = -1; });
|
||||
|
||||
EXPECT_EQ(set.size(), 0U);
|
||||
EXPECT_TRUE(set.empty());
|
||||
|
||||
EXPECT_EQ(a.value, 1);
|
||||
EXPECT_EQ(b.value, -1);
|
||||
EXPECT_EQ(c.value, -1);
|
||||
EXPECT_EQ(d.value, -1);
|
||||
EXPECT_EQ(e.value, -1);
|
||||
EXPECT_EQ(f.value, 1);
|
||||
}
|
||||
|
||||
template<int... values>
|
||||
static constexpr auto
|
||||
MakeIntItems(std::integer_sequence<int, values...>) noexcept
|
||||
-> std::array<IntItem, sizeof...(values)>
|
||||
{
|
||||
return {values...};
|
||||
}
|
||||
|
||||
TEST(IntrusiveTreeSet, RandomOrder)
|
||||
{
|
||||
auto items = MakeIntItems(std::make_integer_sequence<int, 32>());
|
||||
|
||||
IntrusiveTreeSet<IntItem,
|
||||
IntrusiveTreeSetOperators<IntItem, IntItem::GetKey>> set;
|
||||
|
||||
set.insert(items[0]);
|
||||
set.insert(items[5]);
|
||||
set.insert(items[10]);
|
||||
set.insert(items[15]);
|
||||
set.insert(items[20]);
|
||||
set.insert(items[25]);
|
||||
set.insert(items[30]);
|
||||
set.insert(items[1]);
|
||||
set.insert(items[2]);
|
||||
set.insert(items[3]);
|
||||
set.insert(items[31]);
|
||||
set.insert(items[4]);
|
||||
set.insert(items[6]);
|
||||
set.insert(items[7]);
|
||||
set.insert(items[21]);
|
||||
set.insert(items[22]);
|
||||
set.insert(items[23]);
|
||||
set.insert(items[24]);
|
||||
set.insert(items[26]);
|
||||
set.insert(items[8]);
|
||||
set.insert(items[9]);
|
||||
set.insert(items[11]);
|
||||
set.insert(items[12]);
|
||||
set.insert(items[13]);
|
||||
set.insert(items[14]);
|
||||
set.insert(items[27]);
|
||||
set.insert(items[28]);
|
||||
set.insert(items[29]);
|
||||
set.insert(items[16]);
|
||||
set.insert(items[17]);
|
||||
set.insert(items[18]);
|
||||
set.insert(items[19]);
|
||||
|
||||
EXPECT_EQ(set.size(), items.size());
|
||||
|
||||
for (const auto &i : items) {
|
||||
EXPECT_TRUE(i.is_linked());
|
||||
}
|
||||
|
||||
int expected = 0;
|
||||
for (const auto &i : set) {
|
||||
EXPECT_EQ(i.value, expected++);
|
||||
}
|
||||
|
||||
for (std::size_t remove = 0; remove < items.size(); ++remove) {
|
||||
EXPECT_TRUE(items[remove].is_linked());
|
||||
set.pop_front();
|
||||
EXPECT_FALSE(items[remove].is_linked());
|
||||
|
||||
expected = remove + 1;
|
||||
for (const auto &i : set) {
|
||||
EXPECT_EQ(i.value, expected++);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user