util/IntrusiveList: add hook class SafeLinkIntrusiveListHook

Similar to boost::intrusive::safe_link.
This commit is contained in:
Max Kellermann 2021-02-24 20:28:47 +01:00
parent 8fe8f09027
commit 1048f23680

View File

@ -65,21 +65,15 @@ private:
}; };
/** /**
* A variant of #IntrusiveListHook which auto-unlinks itself from the * A variant of #IntrusiveListHook which keeps track of whether it is
* list upon destruction. As a side effect, it has an is_linked() * currently in a list.
* method.
*/ */
class AutoUnlinkIntrusiveListHook : public IntrusiveListHook { class SafeLinkIntrusiveListHook : public IntrusiveListHook {
public: public:
AutoUnlinkIntrusiveListHook() noexcept { SafeLinkIntrusiveListHook() noexcept {
siblings.next = nullptr; siblings.next = nullptr;
} }
~AutoUnlinkIntrusiveListHook() noexcept {
if (is_linked())
unlink();
}
void unlink() noexcept { void unlink() noexcept {
IntrusiveListHook::unlink(); IntrusiveListHook::unlink();
siblings.next = nullptr; siblings.next = nullptr;
@ -90,6 +84,19 @@ public:
} }
}; };
/**
* A variant of #IntrusiveListHook which auto-unlinks itself from the
* list upon destruction. As a side effect, it has an is_linked()
* method.
*/
class AutoUnlinkIntrusiveListHook : public SafeLinkIntrusiveListHook {
public:
~AutoUnlinkIntrusiveListHook() noexcept {
if (is_linked())
unlink();
}
};
template<typename T> template<typename T>
class IntrusiveList { class IntrusiveList {
IntrusiveListNode head{&head, &head}; IntrusiveListNode head{&head, &head};
@ -140,7 +147,7 @@ public:
} }
~IntrusiveList() noexcept { ~IntrusiveList() noexcept {
if constexpr (std::is_base_of<AutoUnlinkIntrusiveListHook, T>::value) if constexpr (std::is_base_of<SafeLinkIntrusiveListHook, T>::value)
clear(); clear();
} }
@ -151,8 +158,8 @@ public:
} }
void clear() noexcept { void clear() noexcept {
if constexpr (std::is_base_of<AutoUnlinkIntrusiveListHook, T>::value) { if constexpr (std::is_base_of<SafeLinkIntrusiveListHook, T>::value) {
/* for AutoUnlinkIntrusiveListHook, we need to /* for SafeLinkIntrusiveListHook, we need to
remove each item manually, or else its remove each item manually, or else its
is_linked() method will not work */ is_linked() method will not work */
while (!empty()) while (!empty())