AK: Make IntrusiveList work with NonnullRefPtr's

This commit is contained in:
Ali Mohammad Pur 2021-04-20 13:01:27 +04:30 committed by Linus Groh
parent 3857148028
commit 88b97f5367

View file

@ -33,15 +33,32 @@
namespace AK {
namespace Detail {
template<typename T, typename Container = RawPtr<T>>
class IntrusiveListNode;
template<typename T, typename Container>
struct SubstituteIntrusiveListNodeContainerType {
using Type = Container;
};
template<typename T>
struct SubstituteIntrusiveListNodeContainerType<T, NonnullRefPtr<T>> {
using Type = RefPtr<T>;
};
}
template<typename T, typename Container = RawPtr<T>>
using IntrusiveListNode = Detail::IntrusiveListNode<T, typename Detail::SubstituteIntrusiveListNodeContainerType<T, Container>::Type>;
template<typename T, typename Container>
class IntrusiveListStorage {
private:
friend class IntrusiveListNode<T, Container>;
friend class Detail::IntrusiveListNode<T, Container>;
template<class T_, typename Container_, IntrusiveListNode<T_, Container_> T_::*member>
friend class IntrusiveList;
IntrusiveListNode<T, Container>* m_first { nullptr };
IntrusiveListNode<T, Container>* m_last { nullptr };
};
@ -132,6 +149,8 @@ template<typename Contained>
struct SelfReferenceIfNeeded<Contained, true> {
};
namespace Detail {
template<typename T, typename Container>
class IntrusiveListNode {
public:
@ -141,15 +160,22 @@ public:
static constexpr bool IsRaw = IsPointer<Container>;
// Note: For some reason, clang does not consider `member` as declared here, and as declared above (`IntrusiveListNode<T, Container> T::*`)
// to be of equal types. so for now, just make the members public on clang.
#ifndef __clang__
private:
template<class T_, typename Container_, IntrusiveListNode<T_, Container_> T_::*member>
friend class IntrusiveList;
friend class ::AK::IntrusiveList;
#endif
IntrusiveListStorage<T, Container>* m_storage = nullptr;
IntrusiveListNode<T, Container>* m_next = nullptr;
IntrusiveListNode<T, Container>* m_prev = nullptr;
SelfReferenceIfNeeded<Container, IsRaw> m_self;
};
}
template<class T, typename Container, IntrusiveListNode<T, Container> T::*member>
inline typename IntrusiveList<T, Container, member>::Iterator& IntrusiveList<T, Container, member>::Iterator::erase()
{
@ -309,6 +335,8 @@ inline T* IntrusiveList<T, Container, member>::node_to_value(IntrusiveListNode<T
return bit_cast<T*>(bit_cast<unsigned char*>(&node) - bit_cast<unsigned char*>(member));
}
namespace Detail {
template<typename T, typename Container>
inline IntrusiveListNode<T, Container>::~IntrusiveListNode()
{
@ -341,12 +369,11 @@ inline bool IntrusiveListNode<T, Container>::is_in_list() const
return m_storage != nullptr;
}
// Specialise IntrusiveList(Node) for NonnullRefPtr
}
// Specialise IntrusiveList for NonnullRefPtr
// By default, intrusive lists cannot contain null entries anyway, so switch to RefPtr
// and just make the user-facing functions deref the pointers.
template<typename T>
struct IntrusiveListNode<T, NonnullRefPtr<T>> : public IntrusiveListNode<T, RefPtr<T>> {
};
template<class T, IntrusiveListNode<T, NonnullRefPtr<T>> T::*member>
class IntrusiveList<T, NonnullRefPtr<T>, member> : public IntrusiveList<T, RefPtr<T>, member> {