File Coverage

src/panda/owning_list.h
Criterion Covered Total %
statement 74 76 97.3
branch 96 172 55.8
condition n/a
subroutine n/a
pod n/a
total 170 248 68.5


line stmt bran cond sub pod time code
1             #pragma once
2             #include "refcnt.h"
3              
4             namespace panda {
5             /**
6             * owning_list where iterators share owning of nodes with list.
7             * Removing of any iterator never invalidates value under it.
8             * Forward iterator never invalidates, even if all list cleared.
9             * Backward iterator keep valid value, but operator++ may lead to invalid iterator if no one keep reference to it
10             * Removeing of element just fork list
11             * 1 -> 2 -> 3
12             * remove(2)
13             * 1 -> 3
14             * ^
15             * 2
16             * Node will be deleted when all strong reference to it will be forgotten
17             * Reference to previous node is weak
18             * 1-> 2-> 3
19             * iter = last; // it is 3
20             * remove(2)
21             * remove(3)
22             * *iter is still valid and == 3
23             * ++iter is invalid, because nobody keeps reference to node 2 and it was removed
24             * Like in std::list don't try using reverse_iterator after removing its node, but you can do it wit forward iterator
25             * You can use removed reversed_iterator if it is only removed and you are sure than prev is still valid
26             */
27             template
28 2           struct owning_list {
29 160 50         struct node_t : Refcnt {
    50          
    50          
    50          
    50          
30 40 50         node_t(const T& value) : value(value), valid(true), next(nullptr), prev(nullptr) {}
    50          
    50          
    50          
    50          
31              
32             T value;
33             bool valid;
34             iptr next;
35             node_t* prev;
36             };
37             using node_sp = iptr;
38              
39 60           static void next_strategy(node_sp& node) {
40 60           node = node->next;
41 62 100         while (node && !node->valid) {
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    100          
    100          
    100          
42 2           node = node->next;
43             }
44 60           }
45              
46 1           static void prev_strategy(node_sp& node) {
47 1           node = node->prev;
48 1 50         while (node && !node->valid) {
    50          
    50          
49 0           node = node->prev;
50             }
51 1           }
52             void remove_node(node_t* node);
53              
54             using inc_strategy_t = void(*)(node_sp&);
55              
56             template
57 526           struct base_iterator {
58             node_sp node;
59              
60 398           base_iterator(const node_sp& node) : node(node) {}
61 32           T& operator*() {
62 32           return node->value;
63             }
64 11           T* operator->() {
65 11           return &node->value;
66             }
67 61           base_iterator& operator++() {
68 61           inc(node);
69 61           return *this;
70             }
71             base_iterator operator++(int) {
72             base_iterator res = *this;
73             inc(node);
74             return res;
75             }
76              
77 130           bool operator ==(const base_iterator& oth) const {
78 130           return node == oth.node;
79             }
80              
81 96           bool operator !=(const base_iterator& oth) const {
82 96           return !operator==(oth);
83             }
84             };
85              
86             using reverse_iterator = base_iterator;
87             using iterator = base_iterator;
88              
89 46           owning_list() : _size(0), first(nullptr), last(nullptr) {}
90 24           ~owning_list() {
91 24           clear(); // do not remove! we must invalidate all elements to make ++ on any iterator correct
92 24           }
93              
94 59           iterator begin() {
95 59           return first;
96             }
97              
98 119           iterator end() {
99 119 50         return iterator(nullptr);
100             }
101              
102 10           reverse_iterator rbegin() {
103 10           return last;
104             }
105              
106 11           reverse_iterator rend() {
107 11           return reverse_iterator(nullptr);
108             }
109              
110             template
111 4           void push_back(TT&& val) {
112 8 0         node_sp node = new node_t(std::forward(val));
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
113 4 0         if (last) {
    0          
    0          
    50          
    100          
114 3           node->prev = last;
115 3           last->next = node;
116 3           last = node;
117             } else {
118 1           first = last = node;
119             }
120 4           ++_size;
121 4           }
122              
123             template
124 36           void push_front(TT&& val) {
125 72 50         node_sp node = new node_t(std::forward(val));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
126 36 100         if (first) {
    100          
    100          
    100          
    100          
127 15           node->next = first;
128 15           first->prev = node;
129 15           first = node;
130             } else {
131 21           first = last = node;
132             }
133 36           ++_size;
134 36           }
135              
136              
137             void remove(const T& val) {
138             node_sp node = first;
139             while (node) {
140             if (node->value == val) {
141             remove_node(node);
142             return;
143             }
144             node = node->next;
145             }
146             }
147              
148             template
149 10           void erase(base_iterator iter) {
150 10           remove_node(iter.node);
151 10           }
152              
153 25           void clear() {
154 56 50         for (auto iter = begin(); iter != end(); ++iter) {
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
155 31           iter.node->valid = false;
156             }
157 25           first = nullptr;
158 25           last = nullptr;
159 25           _size = 0;
160 25           }
161              
162             size_t size() const {
163             return _size;
164             }
165              
166             bool empty() const {
167             return _size == 0;
168             }
169              
170             private:
171             size_t _size;
172             node_sp first;
173             node_sp last;
174             };
175              
176             template
177 10           void owning_list::remove_node(owning_list::node_t* node) {
178 10           node->valid = false;
179 10 50         if (node->prev) {
180 0           node->prev->next = node->next;
181             } else {
182 10           first = node->next;
183             }
184 10 100         if (node->next) {
185 1           node->next->prev = node->prev;
186             } else { // it is last value
187 9           last = node->prev;
188             }
189 10           _size--;
190 10           }
191              
192             }