util/Intrusive{List,HashSet}: add "tag" for base hooks
This commit is contained in:
parent
57d9cffc42
commit
10940da381
@ -19,7 +19,11 @@ struct IntrusiveHashSetOptions {
|
|||||||
bool zero_initialized = false;
|
bool zero_initialized = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<IntrusiveHookMode mode=IntrusiveHookMode::NORMAL>
|
/**
|
||||||
|
* @param Tag an arbitrary tag type to allow using multiple base hooks
|
||||||
|
*/
|
||||||
|
template<IntrusiveHookMode mode=IntrusiveHookMode::NORMAL,
|
||||||
|
typename Tag=void>
|
||||||
struct IntrusiveHashSetHook {
|
struct IntrusiveHashSetHook {
|
||||||
using SiblingsHook = IntrusiveListHook<mode>;
|
using SiblingsHook = IntrusiveListHook<mode>;
|
||||||
|
|
||||||
@ -36,12 +40,14 @@ struct IntrusiveHashSetHook {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* For classes which embed #IntrusiveHashSetHook as base class.
|
* For classes which embed #IntrusiveHashSetHook as base class.
|
||||||
|
*
|
||||||
|
* @param Tag selector for which #IntrusiveHashSetHook to use
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T, typename Tag=void>
|
||||||
struct IntrusiveHashSetBaseHookTraits {
|
struct IntrusiveHashSetBaseHookTraits {
|
||||||
/* a never-called helper function which is used by _Cast() */
|
/* a never-called helper function which is used by _Cast() */
|
||||||
template<IntrusiveHookMode mode>
|
template<IntrusiveHookMode mode>
|
||||||
static constexpr IntrusiveHashSetHook<mode> _Identity(const IntrusiveHashSetHook<mode> &) noexcept;
|
static constexpr IntrusiveHashSetHook<mode, Tag> _Identity(const IntrusiveHashSetHook<mode, Tag> &) noexcept;
|
||||||
|
|
||||||
/* another never-called helper function which "calls"
|
/* another never-called helper function which "calls"
|
||||||
_Identity(), implicitly casting the item to the
|
_Identity(), implicitly casting the item to the
|
||||||
|
@ -35,9 +35,13 @@ struct IntrusiveListNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<IntrusiveHookMode _mode=IntrusiveHookMode::NORMAL>
|
/**
|
||||||
|
* @param Tag an arbitrary tag type to allow using multiple base hooks
|
||||||
|
*/
|
||||||
|
template<IntrusiveHookMode _mode=IntrusiveHookMode::NORMAL,
|
||||||
|
typename Tag=void>
|
||||||
class IntrusiveListHook {
|
class IntrusiveListHook {
|
||||||
template<typename T> friend struct IntrusiveListBaseHookTraits;
|
template<typename, typename> friend struct IntrusiveListBaseHookTraits;
|
||||||
template<auto member> friend struct IntrusiveListMemberHookTraits;
|
template<auto member> friend struct IntrusiveListMemberHookTraits;
|
||||||
template<typename T, typename HookTraits, IntrusiveListOptions> friend class IntrusiveList;
|
template<typename T, typename HookTraits, IntrusiveListOptions> friend class IntrusiveList;
|
||||||
|
|
||||||
@ -91,12 +95,14 @@ using AutoUnlinkIntrusiveListHook =
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* For classes which embed #IntrusiveListHook as base class.
|
* For classes which embed #IntrusiveListHook as base class.
|
||||||
|
*
|
||||||
|
* @param Tag selector for which #IntrusiveHashSetHook to use
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T, typename Tag=void>
|
||||||
struct IntrusiveListBaseHookTraits {
|
struct IntrusiveListBaseHookTraits {
|
||||||
/* a never-called helper function which is used by _Cast() */
|
/* a never-called helper function which is used by _Cast() */
|
||||||
template<IntrusiveHookMode mode>
|
template<IntrusiveHookMode mode>
|
||||||
static constexpr IntrusiveListHook<mode> _Identity(const IntrusiveListHook<mode> &) noexcept;
|
static constexpr IntrusiveListHook<mode, Tag> _Identity(const IntrusiveListHook<mode, Tag> &) noexcept;
|
||||||
|
|
||||||
/* another never-called helper function which "calls"
|
/* another never-called helper function which "calls"
|
||||||
_Identity(), implicitly casting the item to the
|
_Identity(), implicitly casting the item to the
|
||||||
|
@ -149,3 +149,74 @@ TEST(IntrusiveHashSet, Multi)
|
|||||||
ASSERT_EQ(set.remove_and_dispose_key(b, [](auto*){}), 0U);
|
ASSERT_EQ(set.remove_and_dispose_key(b, [](auto*){}), 0U);
|
||||||
ASSERT_EQ(set.find(b), set.end());
|
ASSERT_EQ(set.find(b), set.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(IntrusiveHashSet, Tag)
|
||||||
|
{
|
||||||
|
struct A {};
|
||||||
|
struct B {};
|
||||||
|
|
||||||
|
struct TaggedItem final
|
||||||
|
: IntrusiveHashSetHook<IntrusiveHookMode::NORMAL, A>,
|
||||||
|
IntrusiveHashSetHook<IntrusiveHookMode::NORMAL, B> {
|
||||||
|
int a, b;
|
||||||
|
|
||||||
|
TaggedItem(int _a, int _b) noexcept
|
||||||
|
:a(_a), b(_b) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetA {
|
||||||
|
int operator()(const TaggedItem &item) const noexcept {
|
||||||
|
return item.a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetB {
|
||||||
|
int operator()(const TaggedItem &item) const noexcept {
|
||||||
|
return item.b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TaggedItem one{1, 11}, two{2, 22};
|
||||||
|
|
||||||
|
IntrusiveHashSet<TaggedItem, 3,
|
||||||
|
IntrusiveHashSetOperators<std::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
GetA>,
|
||||||
|
IntrusiveHashSetBaseHookTraits<TaggedItem, A>> a;
|
||||||
|
|
||||||
|
IntrusiveHashSet<TaggedItem, 3,
|
||||||
|
IntrusiveHashSetOperators<std::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
GetB>,
|
||||||
|
IntrusiveHashSetBaseHookTraits<TaggedItem, B>> b;
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
|
||||||
|
a.insert(one);
|
||||||
|
a.insert(two);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
|
||||||
|
b.insert(one);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
a.clear();
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
a.insert(two);
|
||||||
|
a.insert(one);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
b.erase(b.iterator_to(one));
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
}
|
||||||
|
@ -166,6 +166,51 @@ TEST(IntrusiveList, AutoUnlink)
|
|||||||
ASSERT_TRUE(b.is_linked());
|
ASSERT_TRUE(b.is_linked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(IntrusiveList, Tag)
|
||||||
|
{
|
||||||
|
struct A {};
|
||||||
|
struct B {};
|
||||||
|
|
||||||
|
struct TaggedItem
|
||||||
|
: public IntrusiveListHook<IntrusiveHookMode::NORMAL, A>,
|
||||||
|
public IntrusiveListHook<IntrusiveHookMode::NORMAL, B> {};
|
||||||
|
|
||||||
|
TaggedItem one, two;
|
||||||
|
|
||||||
|
IntrusiveList<TaggedItem, IntrusiveListBaseHookTraits<TaggedItem, A>> a;
|
||||||
|
IntrusiveList<TaggedItem, IntrusiveListBaseHookTraits<TaggedItem, B>> b;
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
|
||||||
|
a.push_back(one);
|
||||||
|
a.push_back(two);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
|
||||||
|
b.push_back(one);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
a.clear();
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
a.push_back(two);
|
||||||
|
a.push_back(one);
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_FALSE(b.empty());
|
||||||
|
|
||||||
|
b.erase(b.iterator_to(one));
|
||||||
|
|
||||||
|
EXPECT_FALSE(a.empty());
|
||||||
|
EXPECT_TRUE(b.empty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(IntrusiveList, Merge)
|
TEST(IntrusiveList, Merge)
|
||||||
{
|
{
|
||||||
using Item = CharItem<IntrusiveHookMode::NORMAL>;
|
using Item = CharItem<IntrusiveHookMode::NORMAL>;
|
||||||
|
Loading…
Reference in New Issue
Block a user