LCOV - code coverage report
Current view: top level - structures - linked_list.h (source / functions) Coverage Total Hit
Test: hashbrowns Coverage Lines: 100.0 % 156 156
Test Date: 2026-04-10 19:00:18 Functions: 100.0 % 48 48
Legend: Lines: hit not hit

            Line data    Source code
       1              : #ifndef HASHBROWNS_LINKED_LIST_H
       2              : #define HASHBROWNS_LINKED_LIST_H
       3              : 
       4              : #include "core/data_structure.h"
       5              : #include "core/memory_manager.h"
       6              : #include <utility>
       7              : #include <string>
       8              : #include <stdexcept>
       9              : #include <cstddef>
      10              : #include <type_traits>
      11              : 
      12              : namespace hashbrowns {
      13              : 
      14              : // Singly-linked list with memory pool allocation
      15              : template<typename T = std::pair<int, std::string>>
      16              : class SinglyLinkedList : public DataStructure {
      17              : private:
      18              :     struct Node {
      19              :         T value;
      20              :         Node* next;
      21              :         explicit Node(const T& v) : value(v), next(nullptr) {}
      22          287 :         explicit Node(T&& v) : value(std::move(v)), next(nullptr) {}
      23              :     };
      24              : 
      25              :     Node* head_ = nullptr;
      26              :     Node* tail_ = nullptr;
      27              :     size_t size_ = 0;
      28              :     MemoryPool<Node> pool_;
      29              : 
      30              : public:
      31           19 :     SinglyLinkedList() = default;
      32           34 :     ~SinglyLinkedList() override { clear(); }
      33              : 
      34            1 :     SinglyLinkedList(const SinglyLinkedList& other) {
      35            3 :         for (Node* n = other.head_; n; n = n->next) {
      36            2 :             push_back(n->value);
      37              :         }
      38            1 :     }
      39              : 
      40            1 :     SinglyLinkedList& operator=(const SinglyLinkedList& other) {
      41            1 :         if (this != &other) {
      42            1 :             clear();
      43            3 :             for (Node* n = other.head_; n; n = n->next) {
      44            2 :                 push_back(n->value);
      45              :             }
      46              :         }
      47            1 :         return *this;
      48              :     }
      49              : 
      50            1 :     SinglyLinkedList(SinglyLinkedList&& other) noexcept {
      51            1 :         head_ = other.head_;
      52            1 :         tail_ = other.tail_;
      53            1 :         size_ = other.size_;
      54            1 :         other.head_ = other.tail_ = nullptr;
      55            1 :         other.size_ = 0;
      56            1 :     }
      57              : 
      58            1 :     SinglyLinkedList& operator=(SinglyLinkedList&& other) noexcept {
      59            1 :         if (this != &other) {
      60            1 :             clear();
      61            1 :             head_ = other.head_;
      62            1 :             tail_ = other.tail_;
      63            1 :             size_ = other.size_;
      64            1 :             other.head_ = other.tail_ = nullptr;
      65            1 :             other.size_ = 0;
      66              :         }
      67            1 :         return *this;
      68              :     }
      69              : 
      70              :     // DataStructure interface
      71          283 :     void insert(int key, const std::string& value) override {
      72              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
      73          283 :             push_back(std::make_pair(key, value));
      74              :         } else {
      75              :             throw std::invalid_argument("SinglyLinkedList<T> insert only supported for T=std::pair<int,std::string>");
      76              :         }
      77          283 :     }
      78              : 
      79          212 :     bool search(int key, std::string& value) const override {
      80              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
      81         4198 :             for (Node* n = head_; n; n = n->next) {
      82         4193 :                 if (n->value.first == key) { value = n->value.second; return true; }
      83              :             }
      84              :         }
      85            5 :         return false;
      86              :     }
      87              : 
      88          204 :     bool remove(int key) override {
      89              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
      90          204 :             Node* prev = nullptr;
      91          204 :             Node* cur = head_;
      92         2015 :             while (cur) {
      93         2014 :                 if (cur->value.first == key) {
      94          203 :                     if (prev) prev->next = cur->next; else head_ = cur->next;
      95          203 :                     if (cur == tail_) tail_ = prev;
      96          203 :                     destroy_and_release(cur);
      97          203 :                     --size_;
      98          203 :                     return true;
      99              :                 }
     100         1811 :                 prev = cur; cur = cur->next;
     101              :             }
     102              :         }
     103            1 :         return false;
     104              :     }
     105              : 
     106           14 :     size_t size() const override { return size_; }
     107            5 :     bool empty() const override { return size_ == 0; }
     108           24 :     void clear() override {
     109           24 :         Node* n = head_;
     110          108 :         while (n) {
     111           84 :             Node* next = n->next;
     112           84 :             destroy_and_release(n);
     113           84 :             n = next;
     114              :         }
     115           24 :         head_ = tail_ = nullptr;
     116           24 :         size_ = 0;
     117           24 :     }
     118              : 
     119            3 :     size_t memory_usage() const override {
     120            3 :         return size_ * sizeof(Node) + sizeof(*this);
     121              :     }
     122              : 
     123            3 :     std::string type_name() const override { return "SinglyLinkedList"; }
     124            3 :     std::string insert_complexity() const override { return "O(1) amortized at tail"; }
     125            3 :     std::string search_complexity() const override { return "O(n)"; }
     126            3 :     std::string remove_complexity() const override { return "O(n)"; }
     127              : 
     128              :     // List-specific API
     129            4 :     void push_back(const T& v) { emplace_back(v); }
     130          283 :     void push_back(T&& v) { emplace_back(std::move(v)); }
     131              : 
     132              :     template<typename... Args>
     133          287 :     void emplace_back(Args&&... args) {
     134          287 :         Node* raw = pool_.allocate();
     135              :         // placement-new construct
     136          287 :         new (raw) Node(T(std::forward<Args>(args)...));
     137          287 :         raw->next = nullptr;
     138          287 :         if (!tail_) { head_ = tail_ = raw; }
     139          271 :         else { tail_->next = raw; tail_ = raw; }
     140          287 :         ++size_;
     141          287 :     }
     142              : 
     143              : private:
     144          287 :     void destroy_and_release(Node* node) {
     145          287 :         if (!node) return;
     146          287 :         node->~Node();
     147          287 :         pool_.deallocate(node);
     148              :     }
     149              : };
     150              : 
     151              : // Doubly-linked list with memory pool allocation
     152              : template<typename T = std::pair<int, std::string>>
     153              : class DoublyLinkedList : public DataStructure {
     154              : private:
     155              :     struct Node {
     156              :         T value;
     157              :         Node* prev;
     158              :         Node* next;
     159              :         explicit Node(const T& v) : value(v), prev(nullptr), next(nullptr) {}
     160           55 :         explicit Node(T&& v) : value(std::move(v)), prev(nullptr), next(nullptr) {}
     161              :     };
     162              : 
     163              :     Node* head_ = nullptr;
     164              :     Node* tail_ = nullptr;
     165              :     size_t size_ = 0;
     166              :     MemoryPool<Node> pool_;
     167              : 
     168              : public:
     169            9 :     DoublyLinkedList() = default;
     170           14 :     ~DoublyLinkedList() override { clear(); }
     171              : 
     172            1 :     DoublyLinkedList(const DoublyLinkedList& other) {
     173            3 :         for (Node* n = other.head_; n; n = n->next) {
     174            2 :             push_back(n->value);
     175              :         }
     176            1 :     }
     177              : 
     178            1 :     DoublyLinkedList& operator=(const DoublyLinkedList& other) {
     179            1 :         if (this != &other) {
     180            1 :             clear();
     181            3 :             for (Node* n = other.head_; n; n = n->next) {
     182            2 :                 push_back(n->value);
     183              :             }
     184              :         }
     185            1 :         return *this;
     186              :     }
     187              : 
     188            1 :     DoublyLinkedList(DoublyLinkedList&& other) noexcept {
     189            1 :         head_ = other.head_;
     190            1 :         tail_ = other.tail_;
     191            1 :         size_ = other.size_;
     192            1 :         other.head_ = other.tail_ = nullptr;
     193            1 :         other.size_ = 0;
     194            1 :     }
     195              : 
     196            1 :     DoublyLinkedList& operator=(DoublyLinkedList&& other) noexcept {
     197            1 :         if (this != &other) {
     198            1 :             clear();
     199            1 :             head_ = other.head_;
     200            1 :             tail_ = other.tail_;
     201            1 :             size_ = other.size_;
     202            1 :             other.head_ = other.tail_ = nullptr;
     203            1 :             other.size_ = 0;
     204              :         }
     205            1 :         return *this;
     206              :     }
     207              : 
     208              :     // DataStructure interface
     209           51 :     void insert(int key, const std::string& value) override {
     210              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
     211           51 :             push_back(std::make_pair(key, value));
     212              :         } else {
     213              :             throw std::invalid_argument("DoublyLinkedList<T> insert only supported for T=std::pair<int,std::string>");
     214              :         }
     215           51 :     }
     216              : 
     217           34 :     bool search(int key, std::string& value) const override {
     218              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
     219          239 :             for (Node* n = head_; n; n = n->next) {
     220          234 :                 if (n->value.first == key) { value = n->value.second; return true; }
     221              :             }
     222              :         }
     223            5 :         return false;
     224              :     }
     225              : 
     226           26 :     bool remove(int key) override {
     227              :         if constexpr (std::is_same_v<T, std::pair<int, std::string>>) {
     228           28 :             for (Node* n = head_; n; n = n->next) {
     229           27 :                 if (n->value.first == key) {
     230           25 :                     if (n->prev) n->prev->next = n->next; else head_ = n->next;
     231           25 :                     if (n->next) n->next->prev = n->prev; else tail_ = n->prev;
     232           25 :                     destroy_and_release(n);
     233           25 :                     --size_;
     234           25 :                     return true;
     235              :                 }
     236              :             }
     237              :         }
     238            1 :         return false;
     239              :     }
     240              : 
     241           14 :     size_t size() const override { return size_; }
     242            5 :     bool empty() const override { return size_ == 0; }
     243           14 :     void clear() override {
     244           14 :         Node* n = head_;
     245           44 :         while (n) {
     246           30 :             Node* next = n->next;
     247           30 :             destroy_and_release(n);
     248           30 :             n = next;
     249              :         }
     250           14 :         head_ = tail_ = nullptr;
     251           14 :         size_ = 0;
     252           14 :     }
     253              : 
     254            1 :     size_t memory_usage() const override {
     255            1 :         return size_ * sizeof(Node) + sizeof(*this);
     256              :     }
     257              : 
     258            3 :     std::string type_name() const override { return "DoublyLinkedList"; }
     259            3 :     std::string insert_complexity() const override { return "O(1) amortized at tail"; }
     260            3 :     std::string search_complexity() const override { return "O(n)"; }
     261            3 :     std::string remove_complexity() const override { return "O(1) when node known; O(n) to find"; }
     262              : 
     263              :     // List-specific API
     264            4 :     void push_back(const T& v) { emplace_back(v); }
     265           51 :     void push_back(T&& v) { emplace_back(std::move(v)); }
     266              : 
     267              :     template<typename... Args>
     268           55 :     void emplace_back(Args&&... args) {
     269           55 :         Node* raw = pool_.allocate();
     270           55 :         new (raw) Node(T(std::forward<Args>(args)...));
     271           55 :         raw->prev = tail_;
     272           55 :         raw->next = nullptr;
     273           55 :         if (!tail_) { head_ = tail_ = raw; }
     274           47 :         else { tail_->next = raw; tail_ = raw; }
     275           55 :         ++size_;
     276           55 :     }
     277              : 
     278              : private:
     279           55 :     void destroy_and_release(Node* node) {
     280           55 :         if (!node) return;
     281           55 :         node->~Node();
     282           55 :         pool_.deallocate(node);
     283              :     }
     284              : };
     285              : 
     286              : } // namespace hashbrowns
     287              : 
     288              : #endif // HASHBROWNS_LINKED_LIST_H
        

Generated by: LCOV version 2.0-1