File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/CPP/panda/lib.x/i/panda/lib/owning_list.h
Criterion Covered Total %
statement 55 57 96.4
branch 25 40 62.5
condition n/a
subroutine n/a
pod n/a
total 80 97 82.4


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