// ====================================================================== // \title Clist.hpp // \brief CFDP circular list header file // // This file is a port of CFDP circular list from the following files // from the NASA Core Flight System (cFS) CFDP (CF) Application, version 3.0.0, // adapted for use within the F-Prime (F') framework: // - cf_clist.h (CFDP circular list data structure definitions) // // ====================================================================== // // NASA Docket No. GSC-18,447-1 // // Copyright (c) 2019 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration. // All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ====================================================================== #ifndef CFDP_CLIST_HPP #define CFDP_CLIST_HPP #include #include namespace Svc { namespace Ccsds { namespace Cfdp { /** * @brief Traverse status for circular list operations */ enum CListTraverseStatus : U8 { CLIST_TRAVERSE_CONTINUE = 0, /**< \brief Continue traversing the list */ CLIST_TRAVERSE_EXIT = 1 /**< \brief Stop traversing the list */ }; /** \brief Constant indicating to continue traversal */ constexpr U8 CFDP_CLIST_CONT = CLIST_TRAVERSE_CONTINUE; /** \brief Constant indicating to stop traversal */ constexpr U8 CFDP_CLIST_EXIT = CLIST_TRAVERSE_EXIT; /** * Checks if the list traversal should continue */ static inline bool CfdpCListTraverseStatusIsContinue(CListTraverseStatus stat) { return (stat == CLIST_TRAVERSE_CONTINUE); } /** * @brief Circular linked list node structure */ struct CListNode { struct CListNode* next; /**< \brief Pointer to next node */ struct CListNode* prev; /**< \brief Pointer to previous node */ }; /** * @brief Obtains a pointer to the parent structure * * Given a pointer to a CListNode object which is known to be a member of a * larger container, this converts the pointer to that of the parent. * This is the C++ equivalent of the Linux kernel's container_of macro. */ template constexpr Container* container_of_cpp(Member* member_ptr, Member Container::* member) { // reinterpret_cast: Required for intrusive list node-to-parent pointer arithmetic (container_of idiom) return reinterpret_cast(reinterpret_cast(member_ptr) - reinterpret_cast(&(reinterpret_cast(0)->*member))); } /** * @brief Callback function type for use with CfdpCListTraverse() * * @param node Current node being traversed * @param context Opaque pointer passed through from initial call * * @returns integer status code indicating whether to continue traversal * @retval #CFDP_CLIST_CONT Indicates to continue traversing the list * @retval #CFDP_CLIST_EXIT Indicates to stop traversing the list */ using CListFunc = CListTraverseStatus (*)(CListNode*, void*); /** * @brief Callback type for list traversal * * Function pointer callback for list traversal operations. * The callback receives the node and an opaque context pointer. */ using CListTraverseCallback = CListTraverseStatus (*)(CListNode*, void*); /************************************************************************/ /** @brief Initialize a clist node. * * @param node Pointer to node structure to be initialized */ void CfdpCListInitNode(CListNode* node); /************************************************************************/ /** @brief Insert the given node into the front of a list. * * @param head Pointer to head of list to insert into * @param node Pointer to node to insert */ void CfdpCListInsertFront(CListNode** head, CListNode* node); /************************************************************************/ /** @brief Insert the given node into the back of a list. * * @param head Pointer to head of list to insert into * @param node Pointer to node to insert */ void CfdpCListInsertBack(CListNode** head, CListNode* node); /************************************************************************/ /** @brief Remove the given node from the list. * * @param head Pointer to head of list to remove from * @param node Pointer to node to remove */ void CfdpCListRemove(CListNode** head, CListNode* node); /************************************************************************/ /** @brief Remove the first node from a list and return it. * * @param head Pointer to head of list to remove from * * @returns The first node (now removed) in the list * @retval nullptr if list was empty. */ CListNode* CfdpCListPop(CListNode** head); /************************************************************************/ /** @brief Insert the given node into the last after the given start node. * * @param head Pointer to head of list to remove from * @param start Pointer to node to insert * @param after Pointer to position to insert after */ void CfdpCListInsertAfter(CListNode** head, CListNode* start, CListNode* after); /************************************************************************/ /** @brief Traverse the entire list, calling the given function on all nodes. * * @note on traversal it's ok to delete the current node, but do not delete * other nodes in the same list!! * * @param start List to traverse (first node) * @param fn Callback function to invoke for each node * @param context Opaque pointer to pass to callback */ void CfdpCListTraverse(CListNode* start, CListFunc fn, void* context); /************************************************************************/ /** @brief Reverse list traversal, starting from end, calling given function on all nodes. * * @note traverse_R will work backwards from the parameter's prev, and end on param * * @param end List to traverse (last node) * @param fn Callback function to invoke for each node * @param context Opaque pointer to pass to callback */ void CfdpCListTraverseR(CListNode* end, CListFunc fn, void* context); } // namespace Cfdp } // namespace Ccsds } // namespace Svc #endif /* !CFDP_CLIST_HPP */