/* * Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net. All rights reserved. * * Distributed under the terms of the MIT License. */ #ifndef KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H #define KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H #include /*! A doubly linked queue is like a doubly linked list, but only has a pointer to the head of the list, none to its tail. */ #ifdef __cplusplus // for convenience #define DOUBLY_LINKED_QUEUE_CLASS_NAME DoublyLinkedQueue template > class DoublyLinkedQueue { private: typedef DoublyLinkedQueue Queue; typedef DoublyLinkedListLink Link; public: class Iterator { public: Iterator(Queue *queue) : fQueue(queue) { Rewind(); } Iterator(const Iterator &other) { *this = other; } bool HasNext() const { return fNext; } Element *Next() { fCurrent = fNext; if (fNext) fNext = fQueue->GetNext(fNext); return fCurrent; } Element *Remove() { Element *element = fCurrent; if (fCurrent) { fQueue->Remove(fCurrent); fCurrent = NULL; } return element; } Iterator &operator=(const Iterator &other) { fQueue = other.fQueue; fCurrent = other.fCurrent; fNext = other.fNext; return *this; } void Rewind() { fCurrent = NULL; fNext = fQueue->First(); } private: Queue *fQueue; Element *fCurrent; Element *fNext; }; class ConstIterator { public: ConstIterator(const Queue *queue) : fQueue(queue) { Rewind(); } ConstIterator(const ConstIterator &other) { *this = other; } bool HasNext() const { return fNext; } Element *Next() { Element *element = fNext; if (fNext) fNext = fQueue->GetNext(fNext); return element; } ConstIterator &operator=(const ConstIterator &other) { fQueue = other.fQueue; fNext = other.fNext; return *this; } void Rewind() { fNext = fQueue->First(); } private: const Queue *fQueue; Element *fNext; }; public: DoublyLinkedQueue() : fFirst(NULL) {} ~DoublyLinkedQueue() {} inline bool IsEmpty() const { return (fFirst == NULL); } inline void Insert(Element *element); inline void InsertBefore(Element *before, Element *element); inline void Add(Element *element); inline void Remove(Element *element); inline void Swap(Element *a, Element *b); inline void MoveFrom(DOUBLY_LINKED_QUEUE_CLASS_NAME *fromList); inline void RemoveAll(); inline void MakeEmpty() { RemoveAll(); } inline Element *First() const { return fFirst; } inline Element *Head() const { return fFirst; } inline Element *RemoveHead(); inline Element *GetPrevious(Element *element) const; inline Element *GetNext(Element *element) const; inline int32 Size() const; // O(n)! inline Iterator GetIterator() { return Iterator(this); } inline ConstIterator GetIterator() const { return ConstIterator(this); } private: Element *fFirst; static GetLink sGetLink; }; // inline methods // Insert DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::Insert(Element *element) { if (element) { Link *elLink = sGetLink(element); elLink->previous = NULL; elLink->next = fFirst; if (fFirst) sGetLink(fFirst)->previous = element; fFirst = element; } } // Insert DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_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; } // Add DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::Add(Element *element) { Insert(element); } // Remove DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::Remove(Element *element) { if (element == NULL) return; #if DEBUG_DOUBLY_LINKED_LIST ASSERT_PRINT(fFirst != NULL, "queue: %p, element: %p\n", this, element); #endif Link *elLink = sGetLink(element); if (element == fFirst) fFirst = elLink->next; else sGetLink(elLink->previous)->next = elLink->next; if (elLink->next) sGetLink(elLink->next)->previous = elLink->previous; elLink->next = elLink->previous = NULL; } // Swap DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::Swap(Element *a, Element *b) { if (a && b && a != b) { Link *aLink = sGetLink(a); Link *bLink = sGetLink(b); Element *aPrev = aLink->previous; Element *bPrev = bLink->previous; Element *aNext = aLink->next; Element *bNext = bLink->next; // place a if (bPrev) sGetLink(bPrev)->next = a; else fFirst = a; if (bNext) sGetLink(bNext)->previous = a; aLink->previous = bPrev; aLink->next = bNext; // place b if (aPrev) sGetLink(aPrev)->next = b; else fFirst = b; if (aNext) sGetLink(aNext)->previous = b; bLink->previous = aPrev; bLink->next = aNext; } } // MoveFrom DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::MoveFrom(DOUBLY_LINKED_QUEUE_CLASS_NAME *fromList) { if (fromList && fromList->fFirst) { if (fFirst) { Element *element = fFirst; Link *elLink; while ((elLink = sGetLink(element))->next) { element = elLink->next; } elLink->next = fromList->fFirst; } else { fFirst = fromList->fFirst; } fromList->fFirst = NULL; } } // RemoveAll DOUBLY_LINKED_LIST_TEMPLATE_LIST void DOUBLY_LINKED_QUEUE_CLASS_NAME::RemoveAll() { Element *element = fFirst; while (element) { Link *elLink = sGetLink(element); element = elLink->next; elLink->previous = NULL; elLink->next = NULL; } fFirst = NULL; } // RemoveHead DOUBLY_LINKED_LIST_TEMPLATE_LIST Element * DOUBLY_LINKED_QUEUE_CLASS_NAME::RemoveHead() { Element *element = Head(); Remove(element); return element; } // GetPrevious DOUBLY_LINKED_LIST_TEMPLATE_LIST Element * DOUBLY_LINKED_QUEUE_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_QUEUE_CLASS_NAME::GetNext(Element *element) const { Element *result = NULL; if (element) result = sGetLink(element)->next; return result; } // Size DOUBLY_LINKED_LIST_TEMPLATE_LIST int32 DOUBLY_LINKED_QUEUE_CLASS_NAME::Size() const { int32 count = 0; for (Element* element = First(); element; element = GetNext(element)) count++; return count; } // sGetLink DOUBLY_LINKED_LIST_TEMPLATE_LIST GetLink DOUBLY_LINKED_QUEUE_CLASS_NAME::sGetLink; #endif /* __cplusplus */ #endif // _KERNEL_UTIL_DOUBLY_LINKED_QUEUE_H