mirror of
https://review.haiku-os.org/haiku
synced 2025-01-18 20:48:48 +01:00
254894210c
"Move" now sounds like it has 'move' semantics (i.e. replaces this structure's data with the other structure's data), while MoveFrom() really had 'move+append' semantics (appends the other list's elements to this list, and clears the other list.) To make this clearer, it's here renamed to "TakeFrom". This should reduce confusion with the other move-related APIs that are starting to show up in the Haiku tree (e.g. "MoveFrom" in BRegion.) Change-Id: Ib0a61a9c12fe8812020efd55a2a0818883883e2a Reviewed-on: https://review.haiku-os.org/c/haiku/+/8634 Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org> Reviewed-by: waddlesplash <waddlesplash@gmail.com> Reviewed-by: X512 X512 <danger_mail@list.ru>
615 lines
11 KiB
C++
615 lines
11 KiB
C++
/*
|
|
* Copyright 2005-2007, Ingo Weinhold, bonefish@users.sf.net. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#ifndef KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|
|
#define KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|
|
|
|
|
|
#include "fssh_types.h"
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
|
namespace FSShell {
|
|
|
|
|
|
// DoublyLinkedListLink
|
|
template<typename Element>
|
|
class DoublyLinkedListLink {
|
|
public:
|
|
DoublyLinkedListLink() : next(NULL), previous(NULL) {}
|
|
~DoublyLinkedListLink() {}
|
|
|
|
Element *next;
|
|
Element *previous;
|
|
};
|
|
|
|
// DoublyLinkedListLinkImpl
|
|
template<typename Element>
|
|
class DoublyLinkedListLinkImpl {
|
|
private:
|
|
typedef DoublyLinkedListLink<Element> DLL_Link;
|
|
|
|
public:
|
|
DoublyLinkedListLinkImpl() : fDoublyLinkedListLink() {}
|
|
~DoublyLinkedListLinkImpl() {}
|
|
|
|
DLL_Link *GetDoublyLinkedListLink()
|
|
{ return &fDoublyLinkedListLink; }
|
|
const DLL_Link *GetDoublyLinkedListLink() const
|
|
{ return &fDoublyLinkedListLink; }
|
|
|
|
private:
|
|
DLL_Link fDoublyLinkedListLink;
|
|
};
|
|
|
|
// DoublyLinkedListStandardGetLink
|
|
template<typename Element>
|
|
class DoublyLinkedListStandardGetLink {
|
|
private:
|
|
typedef DoublyLinkedListLink<Element> Link;
|
|
|
|
public:
|
|
inline Link *operator()(Element *element) const
|
|
{
|
|
return element->GetDoublyLinkedListLink();
|
|
}
|
|
|
|
inline const Link *operator()(const Element *element) const
|
|
{
|
|
return element->GetDoublyLinkedListLink();
|
|
}
|
|
};
|
|
|
|
// DoublyLinkedListMemberGetLink
|
|
template<typename Element,
|
|
DoublyLinkedListLink<Element> Element::* LinkMember = &Element::fLink>
|
|
class DoublyLinkedListMemberGetLink {
|
|
private:
|
|
typedef DoublyLinkedListLink<Element> Link;
|
|
|
|
public:
|
|
inline Link *operator()(Element *element) const
|
|
{
|
|
return &(element->*LinkMember);
|
|
}
|
|
|
|
inline const Link *operator()(const Element *element) const
|
|
{
|
|
return &(element->*LinkMember);
|
|
}
|
|
};
|
|
|
|
// DoublyLinkedListCLink - interface to struct list
|
|
template<typename Element>
|
|
class DoublyLinkedListCLink {
|
|
private:
|
|
typedef DoublyLinkedListLink<Element> Link;
|
|
|
|
public:
|
|
inline Link *operator()(Element *element) const
|
|
{
|
|
return (Link *)&element->link;
|
|
}
|
|
|
|
inline const Link *operator()(const Element *element) const
|
|
{
|
|
return (const Link *)&element->link;
|
|
}
|
|
};
|
|
|
|
// for convenience
|
|
#define DOUBLY_LINKED_LIST_TEMPLATE_LIST \
|
|
template<typename Element, typename GetLink>
|
|
#define DOUBLY_LINKED_LIST_CLASS_NAME DoublyLinkedList<Element, GetLink>
|
|
|
|
// DoublyLinkedList
|
|
template<typename Element,
|
|
typename GetLink = DoublyLinkedListStandardGetLink<Element> >
|
|
class DoublyLinkedList {
|
|
private:
|
|
typedef DoublyLinkedList<Element, GetLink> List;
|
|
typedef DoublyLinkedListLink<Element> Link;
|
|
|
|
public:
|
|
class Iterator {
|
|
public:
|
|
Iterator(List *list)
|
|
:
|
|
fList(list)
|
|
{
|
|
Rewind();
|
|
}
|
|
|
|
Iterator(const Iterator &other)
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
bool HasNext() const
|
|
{
|
|
return fNext;
|
|
}
|
|
|
|
Element *Next()
|
|
{
|
|
fCurrent = fNext;
|
|
if (fNext)
|
|
fNext = fList->GetNext(fNext);
|
|
return fCurrent;
|
|
}
|
|
|
|
Element *Current()
|
|
{
|
|
return fCurrent;
|
|
}
|
|
|
|
Element *Remove()
|
|
{
|
|
Element *element = fCurrent;
|
|
if (fCurrent) {
|
|
fList->Remove(fCurrent);
|
|
fCurrent = NULL;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
Iterator &operator=(const Iterator &other)
|
|
{
|
|
fList = other.fList;
|
|
fCurrent = other.fCurrent;
|
|
fNext = other.fNext;
|
|
return *this;
|
|
}
|
|
|
|
void Rewind()
|
|
{
|
|
fCurrent = NULL;
|
|
fNext = fList->First();
|
|
}
|
|
|
|
private:
|
|
List *fList;
|
|
Element *fCurrent;
|
|
Element *fNext;
|
|
};
|
|
|
|
class ConstIterator {
|
|
public:
|
|
ConstIterator(const List *list)
|
|
:
|
|
fList(list)
|
|
{
|
|
Rewind();
|
|
}
|
|
|
|
ConstIterator(const ConstIterator &other)
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
bool HasNext() const
|
|
{
|
|
return fNext;
|
|
}
|
|
|
|
Element *Next()
|
|
{
|
|
Element *element = fNext;
|
|
if (fNext)
|
|
fNext = fList->GetNext(fNext);
|
|
return element;
|
|
}
|
|
|
|
ConstIterator &operator=(const ConstIterator &other)
|
|
{
|
|
fList = other.fList;
|
|
fNext = other.fNext;
|
|
return *this;
|
|
}
|
|
|
|
void Rewind()
|
|
{
|
|
fNext = fList->First();
|
|
}
|
|
|
|
private:
|
|
const List *fList;
|
|
Element *fNext;
|
|
};
|
|
|
|
class ReverseIterator {
|
|
public:
|
|
ReverseIterator(List *list)
|
|
:
|
|
fList(list)
|
|
{
|
|
Rewind();
|
|
}
|
|
|
|
ReverseIterator(const ReverseIterator &other)
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
bool HasNext() const
|
|
{
|
|
return fNext;
|
|
}
|
|
|
|
Element *Next()
|
|
{
|
|
fCurrent = fNext;
|
|
if (fNext)
|
|
fNext = fList->GetPrevious(fNext);
|
|
return fCurrent;
|
|
}
|
|
|
|
Element *Remove()
|
|
{
|
|
Element *element = fCurrent;
|
|
if (fCurrent) {
|
|
fList->Remove(fCurrent);
|
|
fCurrent = NULL;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
ReverseIterator &operator=(const ReverseIterator &other)
|
|
{
|
|
fList = other.fList;
|
|
fCurrent = other.fCurrent;
|
|
fNext = other.fNext;
|
|
return *this;
|
|
}
|
|
|
|
void Rewind()
|
|
{
|
|
fCurrent = NULL;
|
|
fNext = fList->Last();
|
|
}
|
|
|
|
private:
|
|
List *fList;
|
|
Element *fCurrent;
|
|
Element *fNext;
|
|
};
|
|
|
|
class ConstReverseIterator {
|
|
public:
|
|
ConstReverseIterator(const List *list)
|
|
:
|
|
fList(list)
|
|
{
|
|
Rewind();
|
|
}
|
|
|
|
ConstReverseIterator(const ConstReverseIterator &other)
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
bool HasNext() const
|
|
{
|
|
return fNext;
|
|
}
|
|
|
|
Element *Next()
|
|
{
|
|
Element *element = fNext;
|
|
if (fNext)
|
|
fNext = fList->GetPrevious(fNext);
|
|
return element;
|
|
}
|
|
|
|
ConstReverseIterator &operator=(const ConstReverseIterator &other)
|
|
{
|
|
fList = other.fList;
|
|
fNext = other.fNext;
|
|
return *this;
|
|
}
|
|
|
|
void Rewind()
|
|
{
|
|
fNext = fList->Last();
|
|
}
|
|
|
|
private:
|
|
const List *fList;
|
|
Element *fNext;
|
|
};
|
|
|
|
public:
|
|
DoublyLinkedList() : fFirst(NULL), fLast(NULL) {}
|
|
~DoublyLinkedList() {}
|
|
|
|
inline bool IsEmpty() const { return (fFirst == NULL); }
|
|
|
|
inline void InsertBefore(Element* insertBefore, Element* element);
|
|
inline void InsertAfter(Element* insertAfter, Element* element);
|
|
inline void Insert(Element* element, bool back = true);
|
|
inline void Add(Element *element, bool back = true);
|
|
inline void Remove(Element *element);
|
|
|
|
inline void Swap(Element *a, Element *b);
|
|
|
|
inline void TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME *fromList);
|
|
|
|
inline void RemoveAll();
|
|
inline void MakeEmpty() { RemoveAll(); }
|
|
|
|
inline Element *First() const { return fFirst; }
|
|
inline Element *Last() const { return fLast; }
|
|
|
|
inline Element *Head() const { return fFirst; }
|
|
inline Element *Tail() const { return fLast; }
|
|
|
|
inline Element *RemoveHead();
|
|
|
|
inline Element *GetPrevious(Element *element) const;
|
|
inline Element *GetNext(Element *element) const;
|
|
|
|
inline int32_t Size() const;
|
|
// O(n)!
|
|
|
|
inline Iterator GetIterator() { return Iterator(this); }
|
|
inline ConstIterator GetIterator() const { return ConstIterator(this); }
|
|
|
|
inline ReverseIterator GetReverseIterator()
|
|
{ return ReverseIterator(this); }
|
|
inline ConstReverseIterator GetReverseIterator() const
|
|
{ return ConstReverseIterator(this); }
|
|
|
|
private:
|
|
inline void Insert(Element* before, Element* element);
|
|
// TODO: Obsolete! Use InsertBefore() instead!
|
|
|
|
private:
|
|
Element *fFirst;
|
|
Element *fLast;
|
|
|
|
static GetLink sGetLink;
|
|
};
|
|
|
|
|
|
// inline methods
|
|
|
|
// Insert
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element *element, bool back)
|
|
{
|
|
if (element) {
|
|
if (back) {
|
|
// append
|
|
Link *elLink = sGetLink(element);
|
|
elLink->previous = fLast;
|
|
elLink->next = NULL;
|
|
if (fLast)
|
|
sGetLink(fLast)->next = element;
|
|
else
|
|
fFirst = element;
|
|
fLast = element;
|
|
} else {
|
|
// prepend
|
|
Link *elLink = sGetLink(element);
|
|
elLink->previous = NULL;
|
|
elLink->next = fFirst;
|
|
if (fFirst)
|
|
sGetLink(fFirst)->previous = element;
|
|
else
|
|
fLast = element;
|
|
fFirst = element;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::InsertBefore(Element* before, Element* element)
|
|
{
|
|
if (before == NULL) {
|
|
Insert(element);
|
|
return;
|
|
}
|
|
if (element == NULL)
|
|
return;
|
|
|
|
Link *beforeLink = sGetLink(before);
|
|
Link *link = sGetLink(element);
|
|
|
|
link->next = before;
|
|
link->previous = beforeLink->previous;
|
|
if (link->previous != NULL)
|
|
sGetLink(link->previous)->next = element;
|
|
beforeLink->previous = element;
|
|
|
|
if (fFirst == before)
|
|
fFirst = element;
|
|
}
|
|
|
|
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::InsertAfter(Element* after, Element* element)
|
|
{
|
|
ASSERT(element != NULL);
|
|
|
|
if (after == NULL) {
|
|
Insert(element, false);
|
|
return;
|
|
}
|
|
|
|
Link* afterLink = sGetLink(after);
|
|
Link* link = sGetLink(element);
|
|
|
|
link->previous = after;
|
|
link->next = afterLink->next;
|
|
afterLink->next = element;
|
|
|
|
if (link->next != NULL)
|
|
sGetLink(link->next)->previous = element;
|
|
else
|
|
fLast = element;
|
|
}
|
|
|
|
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element* before, Element* element)
|
|
{
|
|
InsertBefore(before, element);
|
|
}
|
|
|
|
|
|
// Add
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Add(Element *element, bool back)
|
|
{
|
|
Insert(element, back);
|
|
}
|
|
|
|
// Remove
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Remove(Element *element)
|
|
{
|
|
if (element) {
|
|
Link *elLink = sGetLink(element);
|
|
if (elLink->previous)
|
|
sGetLink(elLink->previous)->next = elLink->next;
|
|
else
|
|
fFirst = elLink->next;
|
|
if (elLink->next)
|
|
sGetLink(elLink->next)->previous = elLink->previous;
|
|
else
|
|
fLast = elLink->previous;
|
|
elLink->previous = NULL;
|
|
elLink->next = NULL;
|
|
}
|
|
}
|
|
|
|
// Swap
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Swap(Element *a, Element *b)
|
|
{
|
|
if (a && b && a != b) {
|
|
Element *aNext = sGetLink(a)->next;
|
|
Element *bNext = sGetLink(b)->next;
|
|
if (a == bNext) {
|
|
Remove(a);
|
|
Insert(b, a);
|
|
} else if (b == aNext) {
|
|
Remove(b);
|
|
Insert(a, b);
|
|
} else {
|
|
Remove(a);
|
|
Remove(b);
|
|
Insert(aNext, b);
|
|
Insert(bNext, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TakeFrom
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME *fromList)
|
|
{
|
|
if (fromList && fromList->fFirst) {
|
|
if (fFirst) {
|
|
sGetLink(fLast)->next = fromList->fFirst;
|
|
sGetLink(fromList->fFirst)->previous = fLast;
|
|
fLast = fromList->fLast;
|
|
} else {
|
|
fFirst = fromList->fFirst;
|
|
fLast = fromList->fLast;
|
|
}
|
|
fromList->fFirst = NULL;
|
|
fromList->fLast = NULL;
|
|
}
|
|
}
|
|
|
|
// RemoveAll
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
void
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::RemoveAll()
|
|
{
|
|
Element *element = fFirst;
|
|
while (element) {
|
|
Link *elLink = sGetLink(element);
|
|
element = elLink->next;
|
|
elLink->previous = NULL;
|
|
elLink->next = NULL;
|
|
}
|
|
fFirst = NULL;
|
|
fLast = NULL;
|
|
}
|
|
|
|
// RemoveHead
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
Element *
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::RemoveHead()
|
|
{
|
|
Element *element = Head();
|
|
Remove(element);
|
|
return element;
|
|
}
|
|
|
|
// GetPrevious
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
Element *
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::GetPrevious(Element *element) const
|
|
{
|
|
Element *result = NULL;
|
|
if (element)
|
|
result = sGetLink(element)->previous;
|
|
return result;
|
|
}
|
|
|
|
// GetNext
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
Element *
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::GetNext(Element *element) const
|
|
{
|
|
Element *result = NULL;
|
|
if (element)
|
|
result = sGetLink(element)->next;
|
|
return result;
|
|
}
|
|
|
|
// Size
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
int32_t
|
|
DOUBLY_LINKED_LIST_CLASS_NAME::Size() const
|
|
{
|
|
int32_t count = 0;
|
|
for (Element* element = First(); element; element = GetNext(element))
|
|
count++;
|
|
return count;
|
|
}
|
|
|
|
// sGetLink
|
|
DOUBLY_LINKED_LIST_TEMPLATE_LIST
|
|
GetLink DOUBLY_LINKED_LIST_CLASS_NAME::sGetLink;
|
|
|
|
|
|
} // namespace FSShell
|
|
|
|
using FSShell::DoublyLinkedListLink;
|
|
using FSShell::DoublyLinkedListLinkImpl;
|
|
using FSShell::DoublyLinkedListStandardGetLink;
|
|
using FSShell::DoublyLinkedListMemberGetLink;
|
|
using FSShell::DoublyLinkedListCLink;
|
|
using FSShell::DoublyLinkedList;
|
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
#endif // _KERNEL_UTIL_DOUBLY_LINKED_LIST_H
|