// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __IRR_LIST_H_INCLUDED__ #define __IRR_LIST_H_INCLUDED__ #include "irrTypes.h" #include "irrAllocator.h" namespace irr { namespace core { //! Doubly linked list template. template class list { private: //! List element node with pointer to previous and next element in the list. struct SKListNode { SKListNode(const T& e) : Next(0), Prev(0), Element(e) {} SKListNode* Next; SKListNode* Prev; T Element; }; public: class ConstIterator; //! List iterator. class Iterator { public: Iterator() : Current(0) {} Iterator& operator ++() { Current = Current->Next; return *this; } Iterator& operator --() { Current = Current->Prev; return *this; } Iterator operator ++(s32) { Iterator tmp = *this; Current = Current->Next; return tmp; } Iterator operator --(s32) { Iterator tmp = *this; Current = Current->Prev; return tmp; } Iterator& operator +=(s32 num) { if(num > 0) { while (num-- && this->Current != 0) ++(*this); } else { while(num++ && this->Current != 0) --(*this); } return *this; } Iterator operator + (s32 num) const { Iterator tmp = *this; return tmp += num; } Iterator& operator -=(s32 num) const { return (*this)+=(-num); } Iterator operator - (s32 num) const { return (*this)+ (-num); } bool operator ==(const Iterator& other) const { return Current == other.Current; } bool operator !=(const Iterator& other) const { return Current != other.Current; } bool operator ==(const ConstIterator& other) const { return Current == other.Current; } bool operator !=(const ConstIterator& other) const { return Current != other.Current; } #if defined (_MSC_VER) && (_MSC_VER < 1300) #pragma warning(disable:4284) // infix notation problem when using iterator operator -> #endif T & operator * () { return Current->Element; } T * operator ->() { return &Current->Element; } private: Iterator(SKListNode* begin) : Current(begin) {} SKListNode* Current; friend class list; }; //! List iterator for const access. class ConstIterator { public: ConstIterator() : Current(0) {} ConstIterator& operator ++() { Current = Current->Next; return *this; } ConstIterator& operator --() { Current = Current->Prev; return *this; } ConstIterator operator ++(s32) { ConstIterator tmp = *this; Current = Current->Next; return tmp; } ConstIterator operator --(s32) { ConstIterator tmp = *this; Current = Current->Prev; return tmp; } ConstIterator& operator +=(s32 num) { if(num > 0) { while(num-- && this->Current != 0) ++(*this); } else { while(num++ && this->Current != 0) --(*this); } return *this; } ConstIterator operator + (s32 num) const { ConstIterator tmp = *this; return tmp += num; } ConstIterator& operator -=(s32 num) const { return (*this)+=(-num); } ConstIterator operator - (s32 num) const { return (*this)+ (-num); } bool operator ==(const ConstIterator& other) const { return Current == other.Current; } bool operator !=(const ConstIterator& other) const { return Current != other.Current; } bool operator ==(const Iterator& other) const { return Current == other.Current; } bool operator !=(const Iterator& other) const { return Current != other.Current; } const T & operator * () { return Current->Element; } const T * operator ->() { return &Current->Element; } ConstIterator & operator =(const Iterator & iterator) { Current = iterator.Current; return *this; } private: ConstIterator(SKListNode* begin) : Current(begin) {} SKListNode* Current; friend class Iterator; friend class list; }; //! Default constructor for empty list. list() : First(0), Last(0), Size(0) {} //! Copy constructor. list(const list& other) : First(0), Last(0), Size(0) { *this = other; } //! Destructor ~list() { clear(); } //! Assignment operator void operator=(const list& other) { if(&other == this) { return; } clear(); SKListNode* node = other.First; while(node) { push_back(node->Element); node = node->Next; } } //! Returns amount of elements in list. /** \return Amount of elements in the list. */ u32 size() const { return Size; } u32 getSize() const { return Size; } //! Clears the list, deletes all elements in the list. /** All existing iterators of this list will be invalid. */ void clear() { while(First) { SKListNode * next = First->Next; allocator.destruct(First); allocator.deallocate(First); First = next; } //First = 0; handled by loop Last = 0; Size = 0; } //! Checks for empty list. /** \return True if the list is empty and false if not. */ bool empty() const { return (First == 0); } //! Adds an element at the end of the list. /** \param element Element to add to the list. */ void push_back(const T& element) { SKListNode* node = allocator.allocate(1); allocator.construct(node, element); ++Size; if (First == 0) First = node; node->Prev = Last; if (Last != 0) Last->Next = node; Last = node; } //! Adds an element at the begin of the list. /** \param element: Element to add to the list. */ void push_front(const T& element) { SKListNode* node = allocator.allocate(1); allocator.construct(node, element); ++Size; if (First == 0) { Last = node; First = node; } else { node->Next = First; First->Prev = node; First = node; } } //! Gets first node. /** \return A list iterator pointing to the beginning of the list. */ Iterator begin() { return Iterator(First); } //! Gets first node. /** \return A const list iterator pointing to the beginning of the list. */ ConstIterator begin() const { return ConstIterator(First); } //! Gets end node. /** \return List iterator pointing to null. */ Iterator end() { return Iterator(0); } //! Gets end node. /** \return Const list iterator pointing to null. */ ConstIterator end() const { return ConstIterator(0); } //! Gets last element. /** \return List iterator pointing to the last element of the list. */ Iterator getLast() { return Iterator(Last); } //! Gets last element. /** \return Const list iterator pointing to the last element of the list. */ ConstIterator getLast() const { return ConstIterator(Last); } //! Inserts an element after an element. /** \param it Iterator pointing to element after which the new element should be inserted. \param element The new element to be inserted into the list. */ void insert_after(const Iterator& it, const T& element) { SKListNode* node = allocator.allocate(1); allocator.construct(node, element); node->Next = it.Current->Next; if (it.Current->Next) it.Current->Next->Prev = node; node->Prev = it.Current; it.Current->Next = node; ++Size; if (it.Current == Last) Last = node; } //! Inserts an element before an element. /** \param it Iterator pointing to element before which the new element should be inserted. \param element The new element to be inserted into the list. */ void insert_before(const Iterator& it, const T& element) { SKListNode* node = allocator.allocate(1); allocator.construct(node, element); node->Prev = it.Current->Prev; if (it.Current->Prev) it.Current->Prev->Next = node; node->Next = it.Current; it.Current->Prev = node; ++Size; if (it.Current == First) First = node; } //! Erases an element. /** \param it Iterator pointing to the element which shall be erased. \return Iterator pointing to next element. */ Iterator erase(Iterator& it) { // suggest changing this to a const Iterator& and // working around line: it.Current = 0 (possibly with a mutable, or just let it be garbage?) Iterator returnIterator(it); ++returnIterator; if(it.Current == First) { First = it.Current->Next; } else { it.Current->Prev->Next = it.Current->Next; } if(it.Current == Last) { Last = it.Current->Prev; } else { it.Current->Next->Prev = it.Current->Prev; } allocator.destruct(it.Current); allocator.deallocate(it.Current); it.Current = 0; --Size; return returnIterator; } private: SKListNode* First; SKListNode* Last; u32 Size; irrAllocator allocator; }; } // end namespace core }// end namespace irr #endif