LCOV - code coverage report
Current view: top level - src/AH/Containers - LinkedList.hpp (source / functions) Hit Total Coverage
Test: ffed98f648fe78e7aa7bdd228474317d40dadbec Lines: 92 96 95.8 %
Date: 2022-05-28 15:22:59 Functions: 177 244 72.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* ✔ */
       2             : 
       3             : #pragma once
       4             : 
       5             : #include <AH/Settings/Warnings.hpp>
       6             : 
       7             : AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
       8             : 
       9             : #include <AH/Debug/Debug.hpp>
      10             : #include <AH/Math/MinMaxFix.hpp>
      11             : #include <stdlib.h>
      12             : 
      13             : #include <AH/STL/iterator>
      14             : 
      15             : /// @addtogroup AH_Containers
      16             : /// @{
      17             : 
      18             : /**
      19             :  * @brief   A class for doubly linked lists.
      20             :  * 
      21             :  * @tparam  Node
      22             :  *          The type of the nodes of the list.
      23             :  */
      24             : template <class Node>
      25             : class DoublyLinkedList {
      26             :   public:
      27             :     /// Base class for doubly linked list iterators
      28             :     template <class INode>
      29             :     class node_iterator_base {
      30             :       public:
      31         658 :         node_iterator_base(INode *node) : node(node) {}
      32             : 
      33         643 :         bool operator!=(const node_iterator_base &rhs) const {
      34         643 :             return node != rhs.node;
      35             :         }
      36             : 
      37           0 :         bool operator==(const node_iterator_base &rhs) const {
      38           0 :             return !(*this != rhs);
      39             :         }
      40             : 
      41         493 :         INode &operator*() const {
      42             :             // TODO: check node != nullptr
      43         493 :             return *node;
      44             :         }
      45             : 
      46           0 :         INode *operator->() const {
      47             :             // TODO: check node != nullptr
      48           0 :             return node;
      49             :         }
      50             : 
      51             :       protected:
      52             :         INode *node;
      53             :     };
      54             : 
      55             :     /// Forward bidirectional doubly linked list iterator
      56             :     template <class INode>
      57             :     class node_iterator : public node_iterator_base<INode> {
      58             :       public:
      59         654 :         node_iterator(INode *node) : node_iterator_base<INode>(node) {}
      60             : 
      61             :         using difference_type = long;
      62             :         using value_type = INode;
      63             :         using pointer = INode *;
      64             :         using reference = INode &;
      65             :         using iterator_category = std::bidirectional_iterator_tag;
      66             : 
      67             :         /// Prefix increment operator
      68         304 :         node_iterator &operator++() {
      69             :             // TODO: check node != nullptr
      70         304 :             this->node = this->node->next;
      71         304 :             return *this;
      72             :         }
      73             : 
      74             :         /// Prefix decrement operator
      75             :         node_iterator &operator--() {
      76             :             // TODO: check node != nullptr
      77             :             this->node = this->node->previous;
      78             :             return *this;
      79             :         }
      80             :     };
      81             : 
      82             :     /// Reverse bidirectional doubly linked list iterator
      83             :     template <class INode>
      84             :     class reverse_node_iterator : public node_iterator_base<INode> {
      85             :       public:
      86           4 :         reverse_node_iterator(INode *node) : node_iterator_base<INode>(node) {}
      87             : 
      88             :         using difference_type = long;
      89             :         using value_type = INode;
      90             :         using pointer = INode *;
      91             :         using reference = INode &;
      92             :         using iterator_category = std::bidirectional_iterator_tag;
      93             : 
      94             :         /// Prefix increment operator
      95          10 :         reverse_node_iterator &operator++() {
      96             :             // TODO: check node != nullptr
      97          10 :             this->node = this->node->previous;
      98          10 :             return *this;
      99             :         }
     100             : 
     101             :         /// Prefix decrement operator
     102             :         reverse_node_iterator &operator--() {
     103             :             // TODO: check node != nullptr
     104             :             this->node = this->node->next;
     105             :             return *this;
     106             :         }
     107             :     };
     108             : 
     109             :     using iterator = node_iterator<Node>;
     110             :     using const_iterator = node_iterator<const Node>;
     111             :     using reverse_iterator = reverse_node_iterator<Node>;
     112             :     using const_reverse_iterator = reverse_node_iterator<const Node>;
     113             : 
     114             :     /**
     115             :      * @brief   Append a node to a linked list.
     116             :      * 
     117             :      * @param   node
     118             :      *          A pointer to the node to be appended.
     119             :      */
     120         513 :     void append(Node *node) {
     121         513 :         if (first == nullptr)
     122         361 :             first = node;
     123         513 :         node->previous = last;
     124         513 :         if (node->previous != nullptr)
     125         152 :             node->previous->next = node;
     126         513 :         last = node;
     127         513 :         node->next = nullptr;
     128         513 :     }
     129             : 
     130             :     /**
     131             :      * @brief   Append a node to a linked list.
     132             :      * 
     133             :      * @param   node
     134             :      *          A reference to the node to be appended.
     135             :      */
     136         436 :     void append(Node &node) { append(&node); }
     137             : 
     138             :     /**
     139             :      * @brief   Insert a node before another node.
     140             :      * 
     141             :      * @param   toBeInserted
     142             :      *          The new node to be inserted.
     143             :      * @param   before
     144             :      *          The node to insert the new node before. It must be in the list
     145             :      *          already.
     146             :      */
     147          27 :     void insertBefore(Node *toBeInserted, Node *before) {
     148          27 :         if (before == first)
     149           7 :             first = toBeInserted;
     150             :         else
     151          20 :             before->previous->next = toBeInserted;
     152          27 :         toBeInserted->previous = before->previous;
     153          27 :         toBeInserted->next = before;
     154          27 :         before->previous = toBeInserted;
     155          27 :     }
     156             : 
     157             :     /// @see    insertBefore(Node *, Node *)
     158          27 :     void insertBefore(Node &toBeInserted, Node &before) {
     159          27 :         insertBefore(&toBeInserted, &before);
     160          27 :     }
     161             : 
     162             :     /**
     163             :      * @brief   Insert a new node at the correct location into a sorted list.
     164             :      * 
     165             :      * @param   node 
     166             :      *          The new node to be inserted.
     167             :      * @param   cmp
     168             :      *          The function to order the nodes.
     169             :      * @tparam  Compare
     170             :      *          A functor that compares two Nodes and returns a boolean.
     171             :      */
     172             :     template <class Compare>
     173          35 :     void insertSorted(Node *node, Compare cmp) {
     174          35 :         iterator it = this->begin();
     175          35 :         iterator end = this->end();
     176         139 :         while (it != end) {
     177         129 :             if (cmp(*node, *it)) {
     178          25 :                 insertBefore(*node, *it);
     179          25 :                 return;
     180             :             }
     181         104 :             ++it;
     182             :         }
     183          10 :         append(node);
     184             :     }
     185             : 
     186             :     /**
     187             :      * @brief   Insert a new node at the correct location into a sorted list, 
     188             :      *          using `operator<`.
     189             :      * 
     190             :      * @param   node 
     191             :      *          The new node to be inserted.
     192             :      */
     193          22 :     void insertSorted(Node *node) {
     194          96 :         insertSorted(node, [](Node &lhs, Node &rhs) { return lhs < rhs; });
     195          22 :     }
     196             : 
     197             :     /**
     198             :      * @brief   Remove a node from the linked list.
     199             :      * 
     200             :      * @param   node
     201             :      *          A pointer to the node to be removed.
     202             :      */
     203         431 :     void remove(Node *node) {
     204         431 :         if (node->previous != nullptr)
     205          60 :             node->previous->next = node->next;
     206         431 :         if (node == last)
     207         397 :             last = node->previous;
     208         431 :         if (node->next != nullptr)
     209          34 :             node->next->previous = node->previous;
     210         431 :         if (node == first)
     211         371 :             first = node->next;
     212         431 :         node->previous = nullptr;
     213         431 :         node->next = nullptr;
     214         431 :     }
     215             : 
     216             :     /**
     217             :      * @brief   Remove a node from the linked list.
     218             :      * 
     219             :      * @param   node
     220             :      *          A reference to the node to be removed.
     221             :      */
     222         408 :     void remove(Node &node) { remove(&node); }
     223             : 
     224             :     /**
     225             :      * @brief   Move down the given node in the linked list.
     226             :      * 
     227             :      * For example: moving down node `C`:
     228             :      * ```
     229             :      * Before:  ... → A → B → C → D → ...
     230             :      * After:   ... → A → C → B → D → ...
     231             :      * ```
     232             :      * @param   node
     233             :      *          A pointer to the node to be moved down.
     234             :      */
     235          71 :     void moveDown(Node *node) {
     236          71 :         Node *nodeB = node->previous;
     237          71 :         if (nodeB == nullptr) // Can't move first node further down
     238          68 :             return;
     239           3 :         Node *nodeA = nodeB->previous;
     240           3 :         Node *nodeD = node->next;
     241             : 
     242           3 :         if (nodeA != nullptr)
     243           2 :             nodeA->next = node;
     244             :         else
     245           1 :             first = node;
     246           3 :         nodeB->next = nodeD;
     247           3 :         nodeB->previous = node;
     248           3 :         node->next = nodeB;
     249           3 :         node->previous = nodeA;
     250           3 :         if (nodeD != nullptr)
     251           2 :             nodeD->previous = nodeB;
     252             :         else
     253           1 :             last = nodeB;
     254             :     }
     255             : 
     256             :     /**
     257             :      * @brief   Move down the given node in the linked list.
     258             :      * 
     259             :      * For example: moving down node `C`:
     260             :      * ```
     261             :      * Before:  ... → A → B → C → D → ...
     262             :      * After:   ... → A → C → B → D → ...
     263             :      * ```
     264             :      * @param   node
     265             :      *          A reference to the node to be moved down.
     266             :      */
     267          66 :     void moveDown(Node &node) { moveDown(&node); }
     268             : 
     269             :     /** 
     270             :      * @brief   Check if the linked list could contain the given node.
     271             :      * 
     272             :      * @retval  true
     273             :      *          The given node is part of some linked list or it is the first
     274             :      *          node of the given linked list.  
     275             :      *          It could be that the node is part of a different linked list
     276             :      *          if it was ever added to a different list.
     277             :      *          However, **if this function returns true and the node was never
     278             :      *          added to another linked list, it means that this linked list 
     279             :      *          contains the given node**.
     280             :      * @retval  false
     281             :      *          The given node is not part of any linked list, or it is the 
     282             :      *          only element of a different linked list.
     283             :      */
     284         505 :     bool couldContain(const Node *node) const {
     285         623 :         return node && (node == first || node->next != nullptr ||
     286         623 :                         node->previous != nullptr);
     287             :     }
     288             : 
     289             :     /// @copydoc DoublyLinkedList::couldContain(const Node *) const
     290         490 :     bool couldContain(const Node &node) const { return couldContain(&node); }
     291             : 
     292         326 :     iterator begin() { return {first}; }
     293         326 :     iterator end() { return {nullptr}; }
     294             : 
     295           1 :     const_iterator begin() const { return {first}; }
     296           1 :     const_iterator end() const { return {nullptr}; }
     297             : 
     298           1 :     reverse_iterator rbegin() { return {last}; }
     299           1 :     reverse_iterator rend() { return {nullptr}; }
     300             : 
     301           1 :     const_reverse_iterator rbegin() const { return {last}; }
     302           1 :     const_reverse_iterator rend() const { return {nullptr}; }
     303             : 
     304             :     /// Get a pointer to the first node.
     305          14 :     Node *getFirst() const { return first; }
     306             :     /// Get a pointer to the last node.
     307         183 :     Node *getLast() const { return last; }
     308             : 
     309             :   private:
     310             :     Node *first = nullptr;
     311             :     Node *last = nullptr;
     312             : };
     313             : 
     314             : /**
     315             :  * @brief   A class that can be inherited from to allow inserting into a 
     316             :  *          DoublyLinkedList.
     317             :  * @tparam  Node
     318             :  *          The type of the nodes of the list.
     319             :  */
     320             : template <class Node>
     321             : class DoublyLinkable {
     322             :   protected:
     323             :     friend class DoublyLinkedList<Node>;
     324             :     Node *next = nullptr;
     325             :     Node *previous = nullptr;
     326         521 :     virtual ~DoublyLinkable() = default;
     327             : 
     328         521 :     DoublyLinkable() = default;
     329             :     DoublyLinkable(const DoublyLinkable &) {
     330             :         // Don't copy the pointers
     331             :     }
     332             :     DoublyLinkable &operator=(const DoublyLinkable &) {
     333             :         // Don't copy the pointers
     334             :         return *this;
     335             :     }
     336             :     DoublyLinkable(DoublyLinkable &&) {
     337             :         // Don't swap the pointers
     338             :     }
     339             :     DoublyLinkable &operator=(DoublyLinkable &&) {
     340             :         // Don't swap the pointers
     341             :         return *this;
     342             :     }
     343             : };
     344             : 
     345             : /// @}
     346             : 
     347             : AH_DIAGNOSTIC_POP()

Generated by: LCOV version 1.15