Mercurial > foo_out_sdl
comparison foosdk/sdk/pfc/chain_list_v2.h @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 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 |
