#ifndef SEAD_TLIST_H_ #define SEAD_TLIST_H_ #include namespace sead { template class TListNode; template class TList : public ListImpl { public: using CompareCallback = int (*)(const T*, const T*); TList() : ListImpl() {} void pushBack(TListNode* item) { item->erase(); item->mList = this; ListImpl::pushBack(item); } void pushFront(TListNode* item) { item->erase(); item->mList = this; ListImpl::pushFront(item); } TListNode* popBack() { return static_cast*>(ListImpl::popBack()); } TListNode* popFront() { return static_cast*>(ListImpl::popFront()); } void insertBefore(TListNode* node, TListNode* node_to_insert) { ListImpl::insertBefore(node, node_to_insert); } void insertAfter(TListNode* node, TListNode* node_to_insert) { ListImpl::insertAfter(node, node_to_insert); } void erase(TListNode* item) { if (!item->mList) return; item->mList = nullptr; ListImpl::erase(item); } TListNode* front() const { return static_cast*>(ListImpl::front()); } TListNode* back() const { return static_cast*>(ListImpl::back()); } TListNode* nth(int n) const { return static_cast*>(ListImpl::nth(n)); } s32 indexOf(const TListNode* node) const { return ListImpl::indexOf(node); } void swap(TListNode* n1, TListNode* n2) { ListImpl::swap(n1, n2); } void moveAfter(TListNode* basis, TListNode* n) { ListImpl::moveAfter(basis, n); } void moveBefore(TListNode* basis, TListNode* n) { ListImpl::moveBefore(basis, n); } void sort(s32 offset, CompareCallback cmp) { ListImpl::sort(offset, cmp); } void mergeSort(s32 offset, CompareCallback cmp) { ListImpl::mergeSort(offset, cmp); } TListNode* find(const void* ptr, s32 offset, CompareCallback cmp) const { return static_cast*>(ListImpl::find(ptr, offset, cmp)); } void uniq(s32 offset, CompareCallback cmp) { ListImpl::uniq(offset, cmp); } void clear() { ListImpl::clear(); } TListNode* prev(const TListNode* node) const { auto prev_node = static_cast*>(node->prev()); if (prev_node == &mStartEnd) return nullptr; return prev_node; } TListNode* next(const TListNode* node) const { auto next_node = static_cast*>(node->next()); if (next_node == &mStartEnd) return nullptr; return next_node; } class iterator { public: iterator(TListNode* ptr) : mPtr(ptr) {} iterator& operator++() { mPtr = static_cast*>(mPtr->next()); return *this; } iterator& operator--() { mPtr = static_cast*>(mPtr->prev()); return *this; } T& operator*() const { return mPtr->mData; } T* operator->() const { return &mPtr->mData; } friend bool operator==(iterator it1, iterator it2) { return it1.mPtr == it2.mPtr; } friend bool operator!=(iterator it1, iterator it2) { return !(it1 == it2); } private: TListNode* mPtr; }; iterator begin() const { return iterator(static_cast*>(mStartEnd.next())); } iterator end() const { return iterator(static_cast*>(const_cast(&mStartEnd))); } /// An iterator that is safe to use even if the list is mutated during iteration. /// Unlike the regular iterator class, this exposes ListNode rather than T /// to make it easier to modify the list. class robustIterator { public: explicit robustIterator(TListNode* ptr) : mPtr(ptr) { mPtrNext = static_cast*>(mPtr->next()); } robustIterator& operator++() { mPtr = mPtrNext; mPtrNext = static_cast*>(mPtrNext->next()); return *this; } robustIterator operator++(int) { robustIterator copy = *this; mPtr = mPtrNext; mPtrNext = static_cast*>(mPtr->next()); return copy; } TListNode& operator*() const { return *mPtr; } TListNode* operator->() const { return mPtr; } friend bool operator==(robustIterator it1, robustIterator it2) { return it1.mPtr == it2.mPtr; } friend bool operator!=(robustIterator it1, robustIterator it2) { return !(it1 == it2); } private: TListNode* mPtr; TListNode* mPtrNext; }; robustIterator robustBegin() const { return robustIterator(static_cast*>(mStartEnd.next())); } robustIterator robustEnd() const { return robustIterator(static_cast*>(const_cast(&mStartEnd))); } struct RobustRange { auto begin() const { return mList.robustBegin(); } auto end() const { return mList.robustEnd(); } const TList& mList; }; RobustRange robustRange() const { return {*this}; } private: static int compareT(const T* a, const T* b) { if (*a < *b) return -1; if (*a > *b) return 1; return 0; } }; template class TListNode : public ListNode { public: TListNode() : ListNode() { mData = nullptr; mList = NULL; } TListNode(T data) : ListNode(), mData(data), mList(nullptr) {} void erase() { TList* list = mList; if (list != NULL) list->erase(this); } T mData; TList* mList; }; } // namespace sead #endif // SEAD_TLIST_H_