/* * MOST NetServices "Light" V3.2.7.0.1796 MultiInstance Patch * * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * You may also obtain this software under a propriety license from Microchip. * Please contact Microchip for further information. * */ /*! * \file * \brief Implementation of the doubly linked list. * * \cond MNS_INTERNAL_DOC * \addtogroup G_DL * @{ */ /*------------------------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------------------------*/ #include "mns_dl.h" #include "mns_trace.h" /*------------------------------------------------------------------------------------------------*/ /* Implementation of class CDlList */ /*------------------------------------------------------------------------------------------------*/ /*! \brief Constructor of the doubly linked list class. * \param self Instance pointer * \param mns_inst_id MOST NetServices instance ID */ void Dl_Ctor(CDlList *self, uint8_t mns_inst_id) { self->head = NULL; self->tail = NULL; self->size = 0U; self->mns_inst_id = mns_inst_id; } /*! \brief Inserts a new node after an arbitrary node. * \param self Instance pointer * \param node Reference of the initial node * \param new_node Reference of the new node are to be inserted */ void Dl_InsertAfter(CDlList *self, CDlNode *node, CDlNode *new_node) { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU)); new_node->prev = node; new_node->next = node->next; if(node->next == NULL) /* Is initial node last node in list? */ { self->tail = new_node; /* Set new node as tail of list */ } else { node->next->prev = new_node; /* Adjust follower node */ } node->next = new_node; /* Adjust parent node */ new_node->in_use = true; /* Signals that node is part of a list */ self->size++; /* Increment number of nodes */ } /*! \brief Inserts a new node before an arbitrary node. * \param self Instance pointer * \param node Reference of the initial node * \param new_node Reference of the new node are to be inserted */ void Dl_InsertBefore(CDlList *self, CDlNode *node, CDlNode *new_node) { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU)); new_node->prev = node->prev; new_node->next = node; if(node->prev == NULL) /* Is initial node first node in list? */ { self->head = new_node; /* Set new node as head of list */ } else { node->prev->next = new_node; /* Adjust parent node */ } node->prev = new_node; /* Adjust follower node */ new_node->in_use = true; /* Signals that node is part of a list */ self->size++; /* Increment number of nodes */ } /*! \brief Sets the new node as head of a doubly linked list. * \param self Instance pointer * \param new_node Reference of the new node are to be placed as head of the list */ void Dl_InsertHead(CDlList *self, CDlNode *new_node) { if(self->head == NULL) /* Is list empty? */ { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size <= 0xFFFFU)); self->head = new_node; self->tail = new_node; new_node->prev = NULL; new_node->next = NULL; new_node->in_use = true; /* Signals that node is part of a list */ self->size++; /* Increment number of nodes */ } else { Dl_InsertBefore(self, self->head, new_node); } } /*! \brief Inserts the new node at the end of a doubly linked list. * \param self Instance pointer * \param new_node Reference of the new node are to be placed at the end of the list */ void Dl_InsertTail(CDlList *self, CDlNode *new_node) { if(self->tail == NULL) /* Is list empty? */ { Dl_InsertHead(self, new_node); } else { Dl_InsertAfter(self, self->tail, new_node); } } /*! \brief Removes an arbitrary node from a doubly linked list. * \param self Instance pointer * \param node Reference of the node are to be removed from the list * \return \c DL_OK: No error * \return \c DL_UNKNOWN_NODE: Given node is not part of this list */ Dl_Ret_t Dl_Remove(CDlList *self, CDlNode *node) { Dl_Ret_t ret_val = DL_UNKNOWN_NODE; if(Dl_IsNodeInList(self, node) != false) /* Is node part of list? */ { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U)); if(node->prev == NULL) /* First node in list? */ { self->head = node->next; /* Replace head node with next node in list */ } else /* -> Not first node in list */ { node->prev->next = node->next; /* Set next pointer of previous node to next node */ } if(node->next == NULL) /* Last node in list? */ { self->tail = node->prev; /* Replace tail node with previous node in list */ } else /* -> Not last node in list */ { node->next->prev = node->prev; /* Set previous ptr of next node to previous node */ } node->prev = NULL; node->next = NULL; node->in_use = false; /* Signals that node is not part of a list */ ret_val = DL_OK; self->size--; /* Decrement number of nodes */ } return ret_val; } /*! \brief Removes the first node in a doubly linked list. * \param self Instance pointer * \return The reference of the removed head node or \c NULL if the list is empty. */ CDlNode * Dl_PopHead(CDlList *self) { CDlNode *node = self->head; if(NULL != node) /* Is list not empty? */ { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U)); self->head = node->next; /* Replace head node with next node in list */ if(node->next == NULL) /* Last node in list? */ { self->tail = NULL; /* Replace tail node and set list's tail pointer * to NULL */ } else /* -> Not last node in list */ { node->next->prev = NULL; /* Set previous pointer of next node to NULL */ } node->prev = NULL; node->next = NULL; node->in_use = false; /* Signals that node is not part of a list */ self->size--; /* Decrement number of nodes */ } return node; } /*! \brief Removes the last node in a doubly linked list. * \param self Instance pointer * \return The reference of the removed tail node or \c NULL if the list is empty. */ CDlNode * Dl_PopTail(CDlList *self) { CDlNode *node = self->tail; if(NULL != node) /* Is list not empty? */ { TR_ASSERT(self->mns_inst_id, "[DL]", (self->size > 0U)); if(node->prev == NULL) /* First node in list? */ { self->head = NULL; /* Replace head node and set list's head pointer * to NULL */ } else /* -> Not first node in list */ { node->prev->next = NULL; /* Set next pointer of previous node to NULL */ } self->tail = node->prev; /* Replace tail node with previous node in list */ node->prev = NULL; node->next = NULL; node->in_use = false;