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

Generated by: LCOV version 1.14-6-g40580cd