LCOV - code coverage report
Current view: top level - corosio/detail - intrusive.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 95.6 % 68 65 3
Test Date: 2026-03-26 16:40:44 Functions: 100.0 % 58 58

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/cppalliance/corosio
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_COROSIO_DETAIL_INTRUSIVE_HPP
      11                 : #define BOOST_COROSIO_DETAIL_INTRUSIVE_HPP
      12                 : 
      13                 : namespace boost::corosio::detail {
      14                 : 
      15                 : /** An intrusive doubly linked list.
      16                 : 
      17                 :     This container provides O(1) push and pop operations for
      18                 :     elements that derive from @ref node. Elements are not
      19                 :     copied or moved; they are linked directly into the list.
      20                 : 
      21                 :     @tparam T The element type. Must derive from `intrusive_list<T>::node`.
      22                 : */
      23                 : template<class T>
      24                 : class intrusive_list
      25                 : {
      26                 : public:
      27                 :     /** Base class for list elements.
      28                 : 
      29                 :         Derive from this class to make a type usable with
      30                 :         @ref intrusive_list. The `next_` and `prev_` pointers
      31                 :         are private and accessible only to the list.
      32                 :     */
      33                 :     class node
      34                 :     {
      35                 :         friend class intrusive_list;
      36                 : 
      37                 :     private:
      38                 :         T* next_;
      39                 :         T* prev_;
      40                 :     };
      41                 : 
      42                 : private:
      43                 :     T* head_ = nullptr;
      44                 :     T* tail_ = nullptr;
      45                 : 
      46                 : public:
      47 HIT        3878 :     intrusive_list() = default;
      48                 : 
      49                 :     intrusive_list(intrusive_list&& other) noexcept
      50                 :         : head_(other.head_)
      51                 :         , tail_(other.tail_)
      52                 :     {
      53                 :         other.head_ = nullptr;
      54                 :         other.tail_ = nullptr;
      55                 :     }
      56                 : 
      57                 :     intrusive_list(intrusive_list const&)            = delete;
      58                 :     intrusive_list& operator=(intrusive_list const&) = delete;
      59                 :     intrusive_list& operator=(intrusive_list&&)      = delete;
      60                 : 
      61              32 :     bool empty() const noexcept
      62                 :     {
      63              32 :         return head_ == nullptr;
      64                 :     }
      65                 : 
      66           41148 :     void push_back(T* w) noexcept
      67                 :     {
      68           41148 :         auto* n = static_cast<node*>(w);
      69           41148 :         n->next_ = nullptr;
      70           41148 :         n->prev_ = tail_;
      71           41148 :         if (tail_)
      72           23880 :             static_cast<node*>(tail_)->next_ = w;
      73                 :         else
      74           17268 :             head_ = w;
      75           41148 :         tail_ = w;
      76           41148 :     }
      77                 : 
      78                 :     void splice_back(intrusive_list& other) noexcept
      79                 :     {
      80                 :         if (other.empty())
      81                 :             return;
      82                 :         if (tail_)
      83                 :         {
      84                 :             static_cast<node*>(tail_)->next_        = other.head_;
      85                 :             static_cast<node*>(other.head_)->prev_  = tail_;
      86                 :             tail_                                   = other.tail_;
      87                 :         }
      88                 :         else
      89                 :         {
      90                 :             head_ = other.head_;
      91                 :             tail_ = other.tail_;
      92                 :         }
      93                 :         other.head_ = nullptr;
      94                 :         other.tail_ = nullptr;
      95                 :     }
      96                 : 
      97          193446 :     T* pop_front() noexcept
      98                 :     {
      99          193446 :         if (!head_)
     100          176678 :             return nullptr;
     101           16768 :         T* w  = head_;
     102           16768 :         head_ = static_cast<node*>(head_)->next_;
     103           16768 :         if (head_)
     104              40 :             static_cast<node*>(head_)->prev_ = nullptr;
     105                 :         else
     106           16728 :             tail_ = nullptr;
     107                 :         // Defensive: clear stale linkage so remove() on a
     108                 :         // popped node cannot corrupt the list.
     109           16768 :         auto* n = static_cast<node*>(w);
     110           16768 :         n->next_ = nullptr;
     111           16768 :         n->prev_ = nullptr;
     112           16768 :         return w;
     113                 :     }
     114                 : 
     115           24380 :     void remove(T* w) noexcept
     116                 :     {
     117           24380 :         auto* n = static_cast<node*>(w);
     118                 :         // Already detached — nothing to do.
     119           24380 :         if (!n->next_ && !n->prev_ && head_ != w && tail_ != w)
     120 MIS           0 :             return;
     121 HIT       24380 :         if (n->prev_)
     122            7892 :             static_cast<node*>(n->prev_)->next_ = n->next_;
     123                 :         else
     124           16488 :             head_ = n->next_;
     125           24380 :         if (n->next_)
     126           15970 :             static_cast<node*>(n->next_)->prev_ = n->prev_;
     127                 :         else
     128            8410 :             tail_ = n->prev_;
     129           24380 :         n->next_ = nullptr;
     130           24380 :         n->prev_ = nullptr;
     131                 :     }
     132                 : 
     133                 :     /// Invoke @p f for each element in the list.
     134                 :     template<class F>
     135              67 :     void for_each(F f)
     136                 :     {
     137              67 :         for (T* p = head_; p; p = static_cast<node*>(p)->next_)
     138 MIS           0 :             f(p);
     139 HIT          67 :     }
     140                 : };
     141                 : 
     142                 : /** An intrusive singly linked FIFO queue.
     143                 : 
     144                 :     This container provides O(1) push and pop operations for
     145                 :     elements that derive from @ref node. Elements are not
     146                 :     copied or moved; they are linked directly into the queue.
     147                 : 
     148                 :     Unlike @ref intrusive_list, this uses only a single `next_`
     149                 :     pointer per node, saving memory at the cost of not supporting
     150                 :     O(1) removal of arbitrary elements.
     151                 : 
     152                 :     @tparam T The element type. Must derive from `intrusive_queue<T>::node`.
     153                 : */
     154                 : template<class T>
     155                 : class intrusive_queue
     156                 : {
     157                 : public:
     158                 :     /** Base class for queue elements.
     159                 : 
     160                 :         Derive from this class to make a type usable with
     161                 :         @ref intrusive_queue. The `next_` pointer is private
     162                 :         and accessible only to the queue.
     163                 :     */
     164                 :     class node
     165                 :     {
     166                 :         friend class intrusive_queue;
     167                 : 
     168                 :     private:
     169                 :         T* next_;
     170                 :     };
     171                 : 
     172                 : private:
     173                 :     T* head_ = nullptr;
     174                 :     T* tail_ = nullptr;
     175                 : 
     176                 : public:
     177            1447 :     intrusive_queue() = default;
     178                 : 
     179                 :     intrusive_queue(intrusive_queue&& other) noexcept
     180                 :         : head_(other.head_)
     181                 :         , tail_(other.tail_)
     182                 :     {
     183                 :         other.head_ = nullptr;
     184                 :         other.tail_ = nullptr;
     185                 :     }
     186                 : 
     187                 :     intrusive_queue(intrusive_queue const&)            = delete;
     188                 :     intrusive_queue& operator=(intrusive_queue const&) = delete;
     189                 :     intrusive_queue& operator=(intrusive_queue&&)      = delete;
     190                 : 
     191         1571996 :     bool empty() const noexcept
     192                 :     {
     193         1571996 :         return head_ == nullptr;
     194                 :     }
     195                 : 
     196          491756 :     void push(T* w) noexcept
     197                 :     {
     198          491756 :         w->next_ = nullptr;
     199          491756 :         if (tail_)
     200          207861 :             tail_->next_ = w;
     201                 :         else
     202          283895 :             head_ = w;
     203          491756 :         tail_ = w;
     204          491756 :     }
     205                 : 
     206          259985 :     void splice(intrusive_queue& other) noexcept
     207                 :     {
     208          259985 :         if (other.empty())
     209 MIS           0 :             return;
     210 HIT      259985 :         if (tail_)
     211          118737 :             tail_->next_ = other.head_;
     212                 :         else
     213          141248 :             head_ = other.head_;
     214          259985 :         tail_       = other.tail_;
     215          259985 :         other.head_ = nullptr;
     216          259985 :         other.tail_ = nullptr;
     217                 :     }
     218                 : 
     219          653715 :     T* pop() noexcept
     220                 :     {
     221          653715 :         if (!head_)
     222          161959 :             return nullptr;
     223          491756 :         T* w  = head_;
     224          491756 :         head_ = head_->next_;
     225          491756 :         if (!head_)
     226          165158 :             tail_ = nullptr;
     227                 :         // Defensive: clear stale linkage on popped node.
     228          491756 :         w->next_ = nullptr;
     229          491756 :         return w;
     230                 :     }
     231                 : };
     232                 : 
     233                 : } // namespace boost::corosio::detail
     234                 : 
     235                 : #endif
        

Generated by: LCOV version 2.3