/* *********************************************************************************************************************** * * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * **********************************************************************************************************************/ /** *********************************************************************************************************************** * @file palIntrusiveList.h * @brief PAL utility collection IntrusiveList and IntrusiveListIterator class declarations. *********************************************************************************************************************** */ #pragma once #include "palUtil.h" #include "palAssert.h" namespace Util { // Forward declarations. template class IntrusiveList; template class IntrusiveListIterator; /** *********************************************************************************************************************** * @brief Encapsulates one node of an intrusive double-linked-list. * * A node is associated with one data pointer at construction. The data pointer cannot be changed and must be non-null. * * Note that InList() allows intrusive list users to verify if a given value has been stored in a list without iterating * over the list provided that each node object has been designated for a particular list. *********************************************************************************************************************** */ template class IntrusiveListNode { public: /// @param [in,out] pData Address of the data element which contains this intrusive node. explicit IntrusiveListNode(T* pData); /// Returns true if this node is present in an intrusive list. bool InList() const; private: // This special constructor is provided for IntrusiveList's sentinel node which must have a null data pointer. IntrusiveListNode(); T*const m_pData; // The data object that contains this node. IntrusiveListNode* m_pPrev; // Previous node in the list or null if this node is not in a list. IntrusiveListNode* m_pNext; // Next node in the list or null if this node is not in a list. PAL_DISALLOW_COPY_AND_ASSIGN(IntrusiveListNode); // Although this is a transgression of coding standards, it prevents IntrusiveListNode from requiring public // accessor functions. The added encapsulation this provides is worthwhile. friend class IntrusiveList; friend class IntrusiveListIterator; }; /** *********************************************************************************************************************** * @brief Iterator for traversal of elements in a List collection. * * Allows traversal of all elements in a List going either forwards or backwards. *********************************************************************************************************************** */ template class IntrusiveListIterator { public: ~IntrusiveListIterator() { } /// Returns true unless the iterator has advanced past the end of the list. bool IsValid() const { return m_pCurrent != m_pSentinel; } /// Returns a pointer to the current element. Returns null if the iterator is invalid. T* Get() const { return m_pCurrent->m_pData; } /// Advances the iterator to the previous position (move backward). void Prev() { m_pCurrent = m_pCurrent->m_pPrev; } /// Advances the iterator to the next position (move forward). void Next() { m_pCurrent = m_pCurrent->m_pNext; } /// Moves the iterator back to the start of the list. void Restart() { m_pCurrent = m_pSentinel->m_pNext; } private: IntrusiveListIterator(const IntrusiveListNode*const pSentinel, IntrusiveListNode* pStart); const IntrusiveListNode*const m_pSentinel; // We need the sentinel to locate the list boundaries. IntrusiveListNode* m_pCurrent; // Pointer to the current node. PAL_DISALLOW_DEFAULT_CTOR(IntrusiveListIterator); // Although this is a transgression of coding standards, it means that List does not need to have a public interface // specifically to implement this class. The added encapsulation this provides is worthwhile. friend class IntrusiveList; }; /** *********************************************************************************************************************** * @brief Templated, doubly-linked, intrusive, list container. * * This is meant for storing non-null pointers to elements of an arbitrary type using externally managed nodes. * Operations which this class supports are: * * - Insertion at any point * - Deletion at any point * - Forwards and reverse iteration * * @warning This class is not thread-safe. *********************************************************************************************************************** */ template class IntrusiveList { public: /// A convenient shorthand for IntrusiveListNode. typedef IntrusiveListNode Node; /// A convenient shorthand for IntrusiveListIterator. typedef IntrusiveListIterator Iter; IntrusiveList(); /// Returns the number of elements in the list, not counting the sentinel. size_t NumElements() const { return m_numElements; } /// Returns true if the list is empty. bool IsEmpty() const { return m_sentinel.m_pNext == &m_sentinel; } /// Returns an iterator pointing to the first element in the list. If the list is empty, the iterator starts out /// pointing at the permanent sentinel node. /// /// @returns An iterator pointing at the front end of the list. Iter Begin() const { return Iter(&m_sentinel, m_sentinel.m_pNext); } /// Returns an iterator pointing to the last element in the list. If the list is empty, the iterator starts out /// pointing at the permanent sentinel node. /// /// @returns An iterator pointing at the back end of the list. Iter End() const { return Iter(&m_sentinel, m_sentinel.m_pPrev); } /// Returns the data pointer at the front of the list. /// /// @returns The data pointer at the front of the list or null if the list is empty. T* Front() const { return m_sentinel.m_pNext->m_pData; } /// Returns the data pointer at the back of the list. /// /// @returns The data pointer at the back of the list or null if the list is empty. T* Back() const { return m_sentinel.m_pPrev->m_pData; } /// Pushes the specified node onto the front of the list. /// /// @param [in] pNode Externally-owned list node to link into the list. void PushFront(Node* pNode) { InsertBefore(m_sentinel.m_pNext, pNode); } /// Pushes the specified node onto the back of the list. /// /// @param [in] pNode Externally-owned list node to link into the list. void PushBack(Node* pNode) { InsertBefore(&m_sentinel, pNode); } /// Pushes the contents of pSource onto the front of this list. The ordering of pSource is preserved, meaning that /// the front of pSource will be the new front of this list. Note that pSource will be left entirely empty. /// /// It is illegal to call this function with an empty pSource. /// /// @param [in] pSource The contents of pSource will be pushed in-order onto the front of this list. void PushFrontList(IntrusiveList* pSource); /// Pushes the contents of pSource onto the back of this list. The ordering of pSource is preserved, meaning that /// the end of pSource will be the new end of this list. Note that pSource will be left entirely empty. /// /// It is illegal to call this function with an empty pSource. /// /// @param [in] pSource The contents of pSource will be pushed in-order onto the back of this list. void PushBackList(IntrusiveList* pSource); /// Inserts the specified node before a particular node in a list. /// /// If the iterator has advanced off the end of the list (i.e., the iterator is invalid), the added node will be the /// new tail node. /// /// @param [in] iter Identifies a node where the insertion should take place. The iterator will point to the same /// spot in the list after insertion. /// @param [in] pNode Externally-owned list node to link into the list. void InsertBefore(const Iter& iter, Node* pNode); /// Removes the node at the specified position from the list. /// /// It is illegal to call this function with an iterator that has already advanced off the end of the list. /// /// @param [in,out] pIter Iterator identifying the node to be removed. After the node is removed, this iterator /// will be advanced to the next node. If this call removes the final remaining node in the /// list then the iterator will point at the sentinel and will be invalid. void Erase(Iter* pIter); /// Removes the node at the specified position from the list. It is illegal to call this function with a Node that /// not in this list. /// /// @param [in] pNode Node to be removed. void Erase(Node* pNode); /// Removes all nodes from the list. void EraseAll(); /// Truncates the list without touching the elements void InvalidateList() { m_sentinel.m_pNext = &m_sentinel; m_sentinel.m_pPrev = &m_sentinel; m_numElements = 0; } private: void InsertBefore(Node* pBeforeMe, Node* pNode); void Unlink(Node* pNode); Node m_sentinel; // Ties the head to the tail and signifies the boundary of the list. size_t m_numElements; // Number of elements. PAL_DISALLOW_COPY_AND_ASSIGN(IntrusiveList); }; // ===================================================================================================================== // This is the public node constructor; it must be given a non-null data pointer. template IntrusiveListNode::IntrusiveListNode( T* pData) : m_pData(pData), m_pPrev(nullptr), m_pNext(nullptr) { PAL_ASSERT(pData != nullptr); } // ===================================================================================================================== // This is the private node constructor which is used exclusively for sentinel nodes. template IntrusiveListNode::IntrusiveListNode() : m_pData(nullptr), m_pPrev(nullptr), m_pNext(nullptr) { } // ===================================================================================================================== // Returns true if this node is present in an intrusive list. template bool IntrusiveListNode::InList() const { // The node pointers should always be null or non-null together. PAL_DEBUG_BUILD_ONLY_ASSERT((m_pPrev == nullptr) == (m_pNext == nullptr)); return (m_pNext != nullptr); } // ===================================================================================================================== template IntrusiveListIterator::IntrusiveListIterator( const IntrusiveListNode*const pSentinel, IntrusiveListNode* pStart) : m_pSentinel(pSentinel), m_pCurrent(pStart) { } } // Util