|
1
|
1 #pragma once
|
|
|
2 #include "iterators.h"
|
|
|
3
|
|
|
4 namespace pfc {
|
|
|
5
|
|
|
6 template<typename t_item>
|
|
|
7 class __chain_list_elem : public _list_node<t_item> {
|
|
|
8 public:
|
|
|
9 typedef _list_node<t_item> t_node;
|
|
|
10 template<typename ... arg_t > __chain_list_elem( arg_t && ... args ) : t_node( std::forward<arg_t>(args) ... ) {m_prev = m_next = NULL;}
|
|
|
11
|
|
|
12 typedef __chain_list_elem<t_item> t_self;
|
|
|
13
|
|
|
14 t_self * m_prev, * m_next;
|
|
|
15
|
|
|
16 t_node * prev() throw() {return m_prev;}
|
|
|
17 t_node * next() throw() {return m_next;}
|
|
|
18
|
|
|
19 //helper wrappers
|
|
|
20 void add_ref() throw() {this->refcount_add_ref();}
|
|
|
21 void release() throw() {this->refcount_release();}
|
|
|
22 //workaround for cross-list-relinking case - never actually deletes p_elem
|
|
|
23 void __release_temporary() throw() {this->_refcount_release_temporary();}
|
|
|
24 };
|
|
|
25
|
|
|
26 //! Differences between chain_list_v2_t<> and old chain_list_t<>: \n
|
|
|
27 //! Iterators pointing to removed items as well as to items belonging to no longer existing list objects remain valid but they're no longer walkable - as if the referenced item was the only item in the list. The old class invalidated iterators on deletion instead.
|
|
|
28 template<typename _t_item>
|
|
|
29 class chain_list_v2_t {
|
|
|
30 public:
|
|
|
31 typedef _t_item t_item;
|
|
|
32 typedef chain_list_v2_t<t_item> t_self;
|
|
|
33 typedef ::pfc::iterator<t_item> iterator;
|
|
|
34 typedef ::pfc::const_iterator<t_item> const_iterator;
|
|
|
35 typedef ::pfc::forward_iterator<t_item> forward_iterator;
|
|
|
36 typedef ::pfc::forward_const_iterator<t_item> forward_const_iterator;
|
|
|
37 typedef __chain_list_elem<t_item> t_elem;
|
|
|
38
|
|
|
39 chain_list_v2_t() {}
|
|
|
40 chain_list_v2_t(const t_self & p_source) {
|
|
|
41 try {
|
|
|
42 *this = p_source;
|
|
|
43 } catch(...) {
|
|
|
44 remove_all();
|
|
|
45 throw;
|
|
|
46 }
|
|
|
47 }
|
|
|
48
|
|
|
49 chain_list_v2_t(t_self && p_source) {
|
|
|
50 append_move_from( p_source );
|
|
|
51 }
|
|
|
52
|
|
|
53 template<typename t_in> void _set(const t_in & in) {
|
|
|
54 remove_all(); _add(in);
|
|
|
55 }
|
|
|
56 template<typename t_in> void _add(const t_in & in) {
|
|
|
57 for(typename t_in::const_iterator iter = in.first(); iter.is_valid(); ++in) add_item(*iter);
|
|
|
58 }
|
|
|
59 template<typename t_in> t_self & operator=(const t_in & in) {_set(in); return *this;}
|
|
|
60
|
|
|
61 t_self & operator=(const t_self & p_other) {
|
|
|
62 remove_all();
|
|
|
63 for(t_elem * walk = p_other.m_first; walk != NULL; walk = walk->m_next) {
|
|
|
64 add_item(walk->m_content);
|
|
|
65 }
|
|
|
66 return *this;
|
|
|
67 }
|
|
|
68 t_self & operator=(t_self && p_other) {
|
|
|
69 move_from(p_other); return *this;
|
|
|
70 }
|
|
|
71
|
|
|
72 // templated constructors = spawn of satan
|
|
|
73 // template<typename t_other> chain_list_v2_t(const t_other & in) { try {_add(in);} catch(...) {remove_all(); throw;} }
|
|
|
74
|
|
|
75 t_size get_count() const {return m_count;}
|
|
|
76
|
|
|
77 iterator first() {return iterator(m_first);}
|
|
|
78 iterator last() {return iterator(m_last);}
|
|
|
79 const_iterator first() const {return const_iterator(m_first);}
|
|
|
80 const_iterator last() const {return const_iterator(m_last);}
|
|
|
81 const_iterator cfirst() const {return const_iterator(m_first);}
|
|
|
82 const_iterator clast() const {return const_iterator(m_last);}
|
|
|
83
|
|
|
84 forward_iterator begin() { return first(); }
|
|
|
85 forward_const_iterator begin() const { return first(); }
|
|
|
86 forward_iterator end() {return forward_iterator(); }
|
|
|
87 forward_const_iterator end() const { return forward_const_iterator(); }
|
|
|
88
|
|
|
89 void remove_single(const_iterator const & p_iter) {
|
|
|
90 PFC_ASSERT(p_iter.is_valid());
|
|
|
91 __unlink(_elem(p_iter));
|
|
|
92 }
|
|
|
93
|
|
|
94 void remove(const_iterator const & p_iter) {
|
|
|
95 PFC_ASSERT(p_iter.is_valid());
|
|
|
96 __unlink(_elem(p_iter));
|
|
|
97 }
|
|
|
98
|
|
|
99 void remove_all() throw() {
|
|
|
100 while(m_first != NULL) __unlink(m_first);
|
|
|
101 PFC_ASSERT(m_count == 0);
|
|
|
102 }
|
|
|
103 void remove_range(const_iterator const & p_from,const_iterator const & p_to) {
|
|
|
104 for(t_elem * walk = _elem(p_from);;) {
|
|
|
105 if (walk == NULL) {PFC_ASSERT(!"Should not get here"); break;}//should not happen unless there is a bug in calling code
|
|
|
106 t_elem * next = walk->m_next;
|
|
|
107 __unlink(walk);
|
|
|
108 if (walk == _elem(p_to)) break;
|
|
|
109 walk = next;
|
|
|
110 }
|
|
|
111 }
|
|
|
112
|
|
|
113 template<typename t_callback> void enumerate(t_callback & p_callback) const {__enumerate_chain<const t_elem>(m_first,p_callback);}
|
|
|
114 template<typename t_callback> void enumerate(t_callback & p_callback) {__enumerate_chain<t_elem>(m_first,p_callback);}
|
|
|
115
|
|
|
116 template<typename t_source> bool remove_item(const t_source & p_item) {
|
|
|
117 t_elem * elem;
|
|
|
118 if (__find(elem,p_item)) {
|
|
|
119 __unlink(elem);
|
|
|
120 return true;
|
|
|
121 } else {
|
|
|
122 return false;
|
|
|
123 }
|
|
|
124 }
|
|
|
125
|
|
|
126 ~chain_list_v2_t() {remove_all();}
|
|
|
127
|
|
|
128 template<typename ... arg_t>
|
|
|
129 inline void add_item(arg_t && ... arg) {
|
|
|
130 __link_last(new t_elem(std::forward<arg_t>(arg) ... ));
|
|
|
131 }
|
|
|
132 template<typename t_source>
|
|
|
133 inline t_self & operator+=(t_source && p_source) {
|
|
|
134 add_item(std::forward<t_source>(p_source)); return *this;
|
|
|
135 }
|
|
|
136 iterator insert_last() {return __link_last(new t_elem);}
|
|
|
137 iterator insert_first() {return __link_first(new t_elem);}
|
|
|
138 iterator insert_after(const_iterator const & p_iter) {return __link_next(_elem(p_iter),new t_elem);}
|
|
|
139 iterator insert_before(const_iterator const & p_iter) {return __link_prev(_elem(p_iter),new t_elem);}
|
|
|
140 template<typename ... arg_t> iterator insert_last(arg_t && ... arg) {return __link_last(new t_elem(std::forward<arg_t>(arg) ...));}
|
|
|
141 template<typename ... arg_t> iterator insert_first(arg_t && ... arg) {return __link_first(new t_elem(std::forward<arg_t>(arg) ...));}
|
|
|
142 template<typename ... arg_t> iterator insert_after(const_iterator const & p_iter,arg_t && ... arg) {return __link_next(_elem(p_iter),new t_elem(std::forward<arg_t>(arg) ... ));}
|
|
|
143 template<typename ... arg_t> iterator insert_before(const_iterator const & p_iter,arg_t && ... arg) {return __link_prev(_elem(p_iter),new t_elem(std::forward<arg_t>(arg) ... ));}
|
|
|
144
|
|
|
145 template<typename t_source> const_iterator find_item(const t_source & p_item) const {
|
|
|
146 t_elem * elem;
|
|
|
147 if (!__find(elem,p_item)) return const_iterator();
|
|
|
148 return const_iterator(elem);
|
|
|
149 }
|
|
|
150
|
|
|
151 template<typename t_source> iterator find_item(const t_source & p_item) {
|
|
|
152 t_elem * elem;
|
|
|
153 if (!__find(elem,p_item)) return iterator();
|
|
|
154 return iterator(elem);
|
|
|
155 }
|
|
|
156
|
|
|
157 template<typename t_source> bool have_item(const t_source & p_item) const {
|
|
|
158 t_elem * dummy;
|
|
|
159 return __find(dummy,p_item);
|
|
|
160 }
|
|
|
161 template<typename t_source> void set_single(const t_source & p_item) {
|
|
|
162 remove_all(); add_item(p_item);
|
|
|
163 }
|
|
|
164
|
|
|
165 //! Slow!
|
|
|
166 const_iterator by_index(t_size p_index) const {return __by_index(p_index);}
|
|
|
167 //! Slow!
|
|
|
168 iterator by_index(t_size p_index) {return __by_index(p_index);}
|
|
|
169
|
|
|
170 t_self & operator<<(t_self & p_other) {
|
|
|
171 while(p_other.m_first != NULL) {
|
|
|
172 __link_last( p_other.__unlink_temporary(p_other.m_first) );
|
|
|
173 }
|
|
|
174 return *this;
|
|
|
175 }
|
|
|
176 t_self & operator>>(t_self & p_other) {
|
|
|
177 while(m_last != NULL) {
|
|
|
178 p_other.__link_first(__unlink_temporary(m_last));
|
|
|
179 }
|
|
|
180 return p_other;
|
|
|
181 }
|
|
|
182 //! Links an object that has been unlinked from another list. Unsafe.
|
|
|
183 void _link_last(const_iterator const& iter) {
|
|
|
184 PFC_ASSERT(iter.is_valid());
|
|
|
185 PFC_ASSERT( _elem(iter)->m_prev == NULL && _elem(iter)->m_next == NULL );
|
|
|
186 __link_last(_elem(iter));
|
|
|
187 }
|
|
|
188 //! Links an object that has been unlinked from another list. Unsafe.
|
|
|
189 void _link_first(const_iterator const& iter) {
|
|
|
190 PFC_ASSERT(iter.is_valid());
|
|
|
191 PFC_ASSERT( _elem(iter)->m_prev == NULL && _elem(iter)->m_next == NULL );
|
|
|
192 __link_first(_elem(iter));
|
|
|
193 }
|
|
|
194 void append_move_from( t_self & p_other ) {
|
|
|
195 while (p_other.m_first != NULL) {
|
|
|
196 __link_last(p_other.__unlink_temporary(p_other.m_first));
|
|
|
197 }
|
|
|
198 }
|
|
|
199 void move_from( t_self & p_other ) {
|
|
|
200 remove_all();
|
|
|
201 append_move_from( p_other );
|
|
|
202 }
|
|
|
203 private:
|
|
|
204 static t_elem * _elem(const_iterator const & iter) {
|
|
|
205 return static_cast<t_elem*>(iter._node());
|
|
|
206 }
|
|
|
207 t_elem * __by_index(t_size p_index) const {
|
|
|
208 t_elem * walk = m_first;
|
|
|
209 while(p_index > 0 && walk != NULL) {
|
|
|
210 p_index--;
|
|
|
211 walk = walk->m_next;
|
|
|
212 }
|
|
|
213 return walk;
|
|
|
214 }
|
|
|
215 template<typename t_elemwalk,typename t_callback>
|
|
|
216 static void __enumerate_chain(t_elemwalk * p_elem,t_callback & p_callback) {
|
|
|
217 t_elemwalk * walk = p_elem;
|
|
|
218 while(walk != NULL) {
|
|
|
219 p_callback(walk->m_content);
|
|
|
220 walk = walk->m_next;
|
|
|
221 }
|
|
|
222 }
|
|
|
223
|
|
|
224 template<typename t_source> bool __find(t_elem * & p_elem,const t_source & p_item) const {
|
|
|
225 for(t_elem * walk = m_first; walk != NULL; walk = walk->m_next) {
|
|
|
226 if (walk->m_content == p_item) {
|
|
|
227 p_elem = walk; return true;
|
|
|
228 }
|
|
|
229 }
|
|
|
230 return false;
|
|
|
231 }
|
|
|
232
|
|
|
233 void __unlink_helper(t_elem * p_elem) throw() {
|
|
|
234 (p_elem->m_prev == NULL ? m_first : p_elem->m_prev->m_next) = p_elem->m_next;
|
|
|
235 (p_elem->m_next == NULL ? m_last : p_elem->m_next->m_prev) = p_elem->m_prev;
|
|
|
236 p_elem->m_next = p_elem->m_prev = NULL;
|
|
|
237 }
|
|
|
238
|
|
|
239 //workaround for cross-list-relinking case - never actually deletes p_elem
|
|
|
240 t_elem * __unlink_temporary(t_elem * p_elem) throw() {
|
|
|
241 __unlink_helper(p_elem);
|
|
|
242 --m_count; p_elem->__release_temporary();
|
|
|
243 return p_elem;
|
|
|
244 }
|
|
|
245
|
|
|
246 t_elem * __unlink(t_elem * p_elem) throw() {
|
|
|
247 __unlink_helper(p_elem);
|
|
|
248 --m_count; p_elem->release();
|
|
|
249 return p_elem;
|
|
|
250 }
|
|
|
251 void __on_link(t_elem * p_elem) throw() {
|
|
|
252 p_elem->add_ref(); ++m_count;
|
|
|
253 }
|
|
|
254 t_elem * __link_first(t_elem * p_elem) throw() {
|
|
|
255 __on_link(p_elem);
|
|
|
256 p_elem->m_next = m_first;
|
|
|
257 p_elem->m_prev = NULL;
|
|
|
258 (m_first == NULL ? m_last : m_first->m_prev) = p_elem;
|
|
|
259 m_first = p_elem;
|
|
|
260 return p_elem;
|
|
|
261 }
|
|
|
262 t_elem * __link_last(t_elem * p_elem) throw() {
|
|
|
263 __on_link(p_elem);
|
|
|
264 p_elem->m_prev = m_last;
|
|
|
265 p_elem->m_next = NULL;
|
|
|
266 (m_last == NULL ? m_first : m_last->m_next) = p_elem;
|
|
|
267 m_last = p_elem;
|
|
|
268 return p_elem;
|
|
|
269 }
|
|
|
270 t_elem * __link_next(t_elem * p_prev,t_elem * p_elem) throw() {
|
|
|
271 __on_link(p_elem);
|
|
|
272 p_elem->m_prev = p_prev;
|
|
|
273 p_elem->m_next = p_prev->m_next;
|
|
|
274 (p_prev->m_next != NULL ? p_prev->m_next->m_prev : m_last) = p_elem;
|
|
|
275 p_prev->m_next = p_elem;
|
|
|
276 return p_elem;
|
|
|
277 }
|
|
|
278 t_elem * __link_prev(t_elem * p_next,t_elem * p_elem) throw() {
|
|
|
279 __on_link(p_elem);
|
|
|
280 p_elem->m_next = p_next;
|
|
|
281 p_elem->m_prev = p_next->m_prev;
|
|
|
282 (p_next->m_prev != NULL ? p_next->m_prev->m_next : m_first) = p_elem;
|
|
|
283 p_next->m_prev = p_elem;
|
|
|
284 return p_elem;
|
|
|
285 }
|
|
|
286 t_elem * m_first = nullptr, * m_last = nullptr;
|
|
|
287 t_size m_count = 0;
|
|
|
288 };
|
|
|
289
|
|
|
290
|
|
|
291 template<typename t_item> class traits_t<chain_list_v2_t<t_item> > : public traits_default_movable {};
|
|
|
292
|
|
|
293 class __chain_list_iterator_traits : public traits_default_movable {
|
|
|
294 public:
|
|
|
295 enum {
|
|
|
296 constructor_may_fail = false
|
|
|
297 };
|
|
|
298 };
|
|
|
299
|
|
|
300 template<typename t_item> class traits_t<const_iterator<t_item> > : public traits_t<refcounted_object_ptr_t<_list_node<t_item> > > {};
|
|
|
301
|
|
|
302 template<typename t_item> class traits_t<iterator<t_item> > : public traits_t<const_iterator<t_item> > {};
|
|
|
303
|
|
|
304 }//namespace pfc
|