File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/libpanda.x/i/panda/owning_list.h
Criterion Covered Total %
statement 70 77 90.9
branch 113 352 32.1
condition n/a
subroutine n/a
pod n/a
total 183 429 42.6


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             struct owning_list {
29 144 50         struct node_t : Refcnt {
    50          
    50          
    0          
    50          
    50          
    50          
    0          
30 36 50         node_t(const T& value) : value(value), valid(true), next(nullptr), prev(nullptr) {}
    50          
    50          
    50          
    50          
    50          
    0          
    0          
31              
32             T value;
33             bool valid;
34             iptr next;
35             node_t* prev;
36             };
37             using node_sp = iptr;
38              
39 52           static void next_strategy(node_sp& node) {
40 52           node = node->next;
41 52 0         while (node && !node->valid) {
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
42 0           node = node->next;
43             }
44 52           }
45              
46 0           static void prev_strategy(node_sp& node) {
47 0           node = node->prev;
48 0 0         while (node && !node->valid) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
49 0           node = node->prev;
50             }
51 0           }
52             void remove_node(node_t* node);
53              
54             using inc_strategy_t = void(*)(node_sp&);
55              
56             template
57 456           struct base_iterator {
58             node_sp node;
59              
60 344           base_iterator(const node_sp& node) : node(node) {}
61 32           T& operator*() {
62 32           return node->value;
63             }
64 4           T* operator->() {
65 4           return &node->value;
66             }
67 52           base_iterator& operator++() {
68 52           inc(node);
69 52           return *this;
70             }
71             base_iterator operator++(int) {
72             base_iterator res = *this;
73             inc(node);
74             return res;
75             }
76              
77 112           bool operator ==(const base_iterator& oth) const {
78 112           return node == oth.node;
79             }
80              
81 86           bool operator !=(const base_iterator& oth) const {
82 86           return !operator==(oth);
83             }
84             };
85              
86             using reverse_iterator = base_iterator;
87             using iterator = base_iterator;
88              
89 16           owning_list() : _size(0), first(nullptr), last(nullptr) {}
90 8           ~owning_list() {
91 8           clear(); // do not remove! we must invalidate all elements to make ++ on any iterator correct
92 8           }
93              
94 56           iterator begin() {
95 56           return first;
96             }
97              
98 108           iterator end() {
99 108 50         return iterator(nullptr);
    50          
    50          
    50          
    50          
    50          
    50          
    50          
100             }
101              
102 4           reverse_iterator rbegin() {
103 4           return last;
104             }
105              
106 4           reverse_iterator rend() {
107 4           return reverse_iterator(nullptr);
108             }
109              
110             template
111 2           void push_back(TT&& val) {
112 4 0         node_sp node = new node_t(std::forward(val));
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
113 2 0         if (last) {
    0          
    0          
    0          
    100          
    0          
    0          
    0          
114 1           node->prev = last;
115 1           last->next = node;
116 1           last = node;
117             } else {
118 1           first = last = node;
119             }
120 2           ++_size;
121 2           }
122              
123             template
124 34           void push_front(TT&& val) {
125 68 50         node_sp node = new node_t(std::forward(val));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
126 34 100         if (first) {
    50          
    100          
    50          
    100          
    100          
    0          
    0          
127 10           node->next = first;
128 10           first->prev = node;
129 10           first = node;
130             } else {
131 24           first = last = node;
132             }
133 34           ++_size;
134 34           }
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 4           void erase(base_iterator iter) {
150 4           remove_node(iter.node);
151 4           }
152              
153 30           void clear() {
154 62 50         for (auto iter = begin(); iter != end(); ++iter) {
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
    50          
155 32           iter.node->valid = false;
156             }
157 30           first = nullptr;
158 30           last = nullptr;
159 30           _size = 0;
160 30           }
161              
162 8           size_t size() const {
163 8           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 4           void owning_list::remove_node(owning_list::node_t* node) {
178 4           node->valid = false;
179 4 100         if (node->prev) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
180 2           node->prev->next = node->next;
181             } else {
182 2           first = node->next;
183             }
184 4 50         if (node->next) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
185 0           node->next->prev = node->prev;
186             } else { // it is last value
187 4           last = node->prev;
188             }
189 4           _size--;
190 4           }
191              
192             }