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-06-02 22:30:31 Functions: 100.0 % 82 82

           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       10606 :     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              38 :     bool empty() const noexcept
      62                 :     {
      63              38 :         return head_ == nullptr;
      64                 :     }
      65                 : 
      66                 :     /// Peek at the head element without removing it.
      67                 :     T* front() const noexcept
      68                 :     {
      69                 :         return head_;
      70                 :     }
      71                 : 
      72           19346 :     void push_back(T* w) noexcept
      73                 :     {
      74           19346 :         auto* n = static_cast<node*>(w);
      75           19346 :         n->next_ = nullptr;
      76           19346 :         n->prev_ = tail_;
      77           19346 :         if (tail_)
      78           10505 :             static_cast<node*>(tail_)->next_ = w;
      79                 :         else
      80            8841 :             head_ = w;
      81           19346 :         tail_ = w;
      82           19346 :     }
      83                 : 
      84                 :     void splice_back(intrusive_list& other) noexcept
      85                 :     {
      86                 :         if (other.empty())
      87                 :             return;
      88                 :         if (tail_)
      89                 :         {
      90                 :             static_cast<node*>(tail_)->next_        = other.head_;
      91                 :             static_cast<node*>(other.head_)->prev_  = tail_;
      92                 :             tail_                                   = other.tail_;
      93                 :         }
      94                 :         else
      95                 :         {
      96                 :             head_ = other.head_;
      97                 :             tail_ = other.tail_;
      98                 :         }
      99                 :         other.head_ = nullptr;
     100                 :         other.tail_ = nullptr;
     101                 :     }
     102                 : 
     103          236981 :     T* pop_front() noexcept
     104                 :     {
     105          236981 :         if (!head_)
     106          229191 :             return nullptr;
     107            7790 :         T* w  = head_;
     108            7790 :         head_ = static_cast<node*>(head_)->next_;
     109            7790 :         if (head_)
     110              41 :             static_cast<node*>(head_)->prev_ = nullptr;
     111                 :         else
     112            7749 :             tail_ = nullptr;
     113                 :         // Defensive: clear stale linkage so remove() on a
     114                 :         // popped node cannot corrupt the list.
     115            7790 :         auto* n = static_cast<node*>(w);
     116            7790 :         n->next_ = nullptr;
     117            7790 :         n->prev_ = nullptr;
     118            7790 :         return w;
     119                 :     }
     120                 : 
     121           11556 :     void remove(T* w) noexcept
     122                 :     {
     123           11556 :         auto* n = static_cast<node*>(w);
     124                 :         // Already detached — nothing to do.
     125           11556 :         if (!n->next_ && !n->prev_ && head_ != w && tail_ != w)
     126 MIS           0 :             return;
     127 HIT       11556 :         if (n->prev_)
     128            3491 :             static_cast<node*>(n->prev_)->next_ = n->next_;
     129                 :         else
     130            8065 :             head_ = n->next_;
     131           11556 :         if (n->next_)
     132            7020 :             static_cast<node*>(n->next_)->prev_ = n->prev_;
     133                 :         else
     134            4536 :             tail_ = n->prev_;
     135           11556 :         n->next_ = nullptr;
     136           11556 :         n->prev_ = nullptr;
     137                 :     }
     138                 : 
     139                 :     /// Invoke @p f for each element in the list.
     140                 :     template<class F>
     141             122 :     void for_each(F f)
     142                 :     {
     143             122 :         for (T* p = head_; p; p = static_cast<node*>(p)->next_)
     144 MIS           0 :             f(p);
     145 HIT         122 :     }
     146                 : };
     147                 : 
     148                 : /** An intrusive singly linked FIFO queue.
     149                 : 
     150                 :     This container provides O(1) push and pop operations for
     151                 :     elements that derive from @ref node. Elements are not
     152                 :     copied or moved; they are linked directly into the queue.
     153                 : 
     154                 :     Unlike @ref intrusive_list, this uses only a single `next_`
     155                 :     pointer per node, saving memory at the cost of not supporting
     156                 :     O(1) removal of arbitrary elements.
     157                 : 
     158                 :     @tparam T The element type. Must derive from `intrusive_queue<T>::node`.
     159                 : */
     160                 : template<class T>
     161                 : class intrusive_queue
     162                 : {
     163                 : public:
     164                 :     /** Base class for queue elements.
     165                 : 
     166                 :         Derive from this class to make a type usable with
     167                 :         @ref intrusive_queue. The `next_` pointer is private
     168                 :         and accessible only to the queue.
     169                 :     */
     170                 :     class node
     171                 :     {
     172                 :         friend class intrusive_queue;
     173                 : 
     174                 :     private:
     175                 :         T* next_;
     176                 :     };
     177                 : 
     178                 : private:
     179                 :     T* head_ = nullptr;
     180                 :     T* tail_ = nullptr;
     181                 : 
     182                 : public:
     183            2758 :     intrusive_queue() = default;
     184                 : 
     185                 :     intrusive_queue(intrusive_queue&& other) noexcept
     186                 :         : head_(other.head_)
     187                 :         , tail_(other.tail_)
     188                 :     {
     189                 :         other.head_ = nullptr;
     190                 :         other.tail_ = nullptr;
     191                 :     }
     192                 : 
     193                 :     intrusive_queue(intrusive_queue const&)            = delete;
     194                 :     intrusive_queue& operator=(intrusive_queue const&) = delete;
     195                 :     intrusive_queue& operator=(intrusive_queue&&)      = delete;
     196                 : 
     197         1944717 :     bool empty() const noexcept
     198                 :     {
     199         1944717 :         return head_ == nullptr;
     200                 :     }
     201                 : 
     202          595008 :     void push(T* w) noexcept
     203                 :     {
     204          595008 :         w->next_ = nullptr;
     205          595008 :         if (tail_)
     206          258868 :             tail_->next_ = w;
     207                 :         else
     208          336140 :             head_ = w;
     209          595008 :         tail_ = w;
     210          595008 :     }
     211                 : 
     212          325824 :     void splice(intrusive_queue& other) noexcept
     213                 :     {
     214          325824 :         if (other.empty())
     215 MIS           0 :             return;
     216 HIT      325824 :         if (tail_)
     217          134315 :             tail_->next_ = other.head_;
     218                 :         else
     219          191509 :             head_ = other.head_;
     220          325824 :         tail_       = other.tail_;
     221          325824 :         other.head_ = nullptr;
     222          325824 :         other.tail_ = nullptr;
     223                 :     }
     224                 : 
     225          825407 :     T* pop() noexcept
     226                 :     {
     227          825407 :         if (!head_)
     228          230399 :             return nullptr;
     229          595008 :         T* w  = head_;
     230          595008 :         head_ = head_->next_;
     231          595008 :         if (!head_)
     232          201825 :             tail_ = nullptr;
     233                 :         // Defensive: clear stale linkage on popped node.
     234          595008 :         w->next_ = nullptr;
     235          595008 :         return w;
     236                 :     }
     237                 : };
     238                 : 
     239                 : } // namespace boost::corosio::detail
     240                 : 
     241                 : #endif
        

Generated by: LCOV version 2.3