edelib 1.0

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List

List.h
1 /*
2 * $Id: List.h 3250 2012-04-15 15:26:53Z karijes $
3 *
4 * STL-like list class
5 * Copyright (c) 2005-2007 edelib authors
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifndef __EDELIB_LIST_H__
22 #define __EDELIB_LIST_H__
23
24 #include "Debug.h"
25
26 EDELIB_NS_BEGIN
27
28 #ifndef SKIP_DOCS
29
30 struct ListNode {
31 void* value;
32 ListNode* next;
33 ListNode* prev;
34 ListNode() : value(0), next(0), prev(0) { }
35 };
36
37 template <typename T>
38 struct ListIterator {
39 typedef ListNode NodeType;
40 NodeType* node;
41
42 ListIterator(NodeType* n) : node(n) { }
43 ListIterator() : node(0) { }
44
45 T& operator*(void) const {
46 E_ASSERT(node != 0 && "Bad code! Access to zero node!!!");
47 E_ASSERT(node->value != 0 && "Bad code! Dereferencing NULL value!!!");
48 return *(T*)node->value;
49 }
50
51 T* operator->(void) const {
52 E_ASSERT(node != 0 && "Bad code! Access to zero node!!!");
53 E_ASSERT(node->value != 0 && "Bad code! Dereferencing NULL value!!!");
54 return (T*)node->value;
55 }
56
57 bool operator!=(const ListIterator& other) const { return node != other.node; }
58 bool operator==(const ListIterator& other) const { return node == other.node; }
59 ListIterator& operator++(void) { node = node->next; return *this; }
60 ListIterator& operator--(void) { node = node->prev; return *this; }
61 };
62
63 #ifndef USE_SMALL_LIST
64 template <typename T>
65 struct ListConstIterator {
66 typedef ListNode NodeType;
67 NodeType* node;
68
69 ListConstIterator(NodeType* n) : node(n) { }
70 ListConstIterator() : node(0) { }
71
72 // stupid language constructs !!!
73 ListConstIterator(const ListIterator<T>& i) : node(i.node) { }
74
75 const T& operator*(void) const {
76 E_ASSERT(node != 0 && "Bad code! Access to zero node!!!");
77 E_ASSERT(node->value != 0 && "Bad code! Dereferencing NULL value!!!");
78 return *(T*)node->value;
79 }
80
81 const T* operator->(void) const {
82 E_ASSERT(node != 0 && "Bad code! Access to zero node!!!");
83 E_ASSERT(node->value != 0 && "Bad code! Dereferencing NULL value!!!");
84 return (T*)node->value;
85 }
86
87 bool operator!=(const ListConstIterator& other) const { return node != other.node; }
88 bool operator==(const ListConstIterator& other) const { return node == other.node; }
89 ListConstIterator& operator++(void) { node = node->next; return *this; }
90 ListConstIterator& operator--(void) { node = node->prev; return *this; }
91 };
92 #endif
93
94 #endif
95
159 template <typename T>
160 class list {
161 public:
162 #ifndef SKIP_DOCS
163 typedef unsigned int size_type;
164 #endif
165 private:
166 typedef ListNode Node;
167 typedef bool (SortCmp)(const T& val1, const T& val2);
168
169 size_type sz;
170 Node* tail;
171
172 E_DISABLE_CLASS_COPY(list)
173
174 static bool default_sort_cmp(const T& val1, const T& val2) { return val1 < val2; }
175
176 Node* merge_nodes(Node* a, Node* b, SortCmp* cmp) {
177 Node head;
178 Node* c = &head;
179 Node* cprev = 0;
180
181 while(a != 0 && b != 0) {
182 // compare values
183 if(cmp(*(T*)a->value, *(T*)b->value)) {
184 c->next = a;
185 a = a->next;
186 } else {
187 c->next = b;
188 b = b->next;
189 }
190
191 c = c->next;
192 c->prev = cprev;
193 cprev = c;
194 }
195
196 if(a == 0)
197 c->next = b;
198 else
199 c->next = a;
200
201 c->next->prev = c;
202 return head.next;
203 }
204
205 Node* mergesort(Node* c, SortCmp* cmp) {
206 Node* a, *b;
207 if(c->next == 0)
208 return c;
209 a = c;
210 b = c->next;
211
212 while((b != 0) && (b->next != 0)) {
213 c = c->next;
214 b = b->next->next;
215 }
216
217 b = c->next;
218 c->next = 0;
219 return merge_nodes(mergesort(a, cmp), mergesort(b, cmp), cmp);
220 }
221
222 public:
223 /*
224 * This comment is not part of documentation, and in short explains
225 * implementation details.
226 *
227 * List is implemented as circular doubly linked list, which means
228 * that last node is pointing back to the first one (and reverse).
229 * Due the nature of traversing in circular lists, additional node
230 * (dummy node) is created so traversal (first != last) can be done.
231 *
232 * As you can see, only one node (tail) is used; it always pointing
233 * to dummy node (which is always latest node). To get first element node,
234 * tail->first is used, and to get last (user visible), tail->prev is used.
235 * This implementation is needed so cases like --end() can return valid
236 * iterator to last element in the list.
237 *
238 * I tried to avoid dummy node creation, but implementing circular list
239 * will be pain in the ass. Also, contrary popular std::list implementations I could
240 * find, this node will be created only when insert()/push_back()/push_front()
241 * are called; without those calls, list will not allocate it.
242 */
243 #ifndef SKIP_DOCS
244 typedef ListIterator<T> iterator;
245 #ifndef USE_SMALL_LIST
246 typedef ListConstIterator<T> const_iterator;
247 #else
248 typedef ListIterator<T> const_iterator;
249 #endif
250 #endif
251
255 list() : sz(0), tail(0) { }
256
260 ~list() { clear(); }
261
265 void clear(void) {
266 if(!tail) {
267 E_ASSERT(sz == 0 && "Internal error! size() != 0, but list is empty !?!!");
268 return;
269 }
270
271 Node* p = tail->next;
272 Node* t;
273 while(p != tail) {
274 t = p->next;
275 delete (T*)p->value;
276 delete p;
277 p = t;
278 }
279
280 // delete dummy node
281 delete tail;
282
283 tail = 0;
284 sz = 0;
285 }
286
295 iterator insert(iterator it, const T& val) {
296 // [23.2.2.3] insert() does not affect validity of iterators
297 Node* tmp = new Node;
298 tmp->value = new T(val);
299
300 if(!tail) {
301 // dummy node first
302 tail = new Node;
303 tail->next = tail->prev = tmp;
304 tmp->next = tmp->prev = tail;
305 } else {
306 tmp->next = it.node;
307 tmp->prev = it.node->prev;
308 it.node->prev->next = tmp;
309 it.node->prev = tmp;
310 }
311
312 sz++;
313 return iterator(tmp);
314 }
315
322 iterator erase(iterator it) {
323 // do not allow erase(l.end())
324 E_ASSERT(it.node != tail && "Bad code! erase() on end()!!!");
325
326 // [23.2.2.3] erase() invalidates only the iterators
327 it.node->prev->next = it.node->next;
328 it.node->next->prev = it.node->prev;
329
330 iterator ret(it.node);
331 ++ret;
332 sz--;
333
334 delete (T*)it.node->value;
335 delete it.node;
336
337 return ret;
338 }
339
344 void push_back(const T& val) { insert(end(), val); }
345
350 void push_front(const T& val) { insert(begin(), val); }
351
355 iterator begin(void) { return iterator(tail ? tail->next : 0); }
356
360 const_iterator begin(void) const { return const_iterator(tail ? tail->next : 0); }
361
367 iterator end(void) { return iterator(tail); }
368
374 const_iterator end(void) const { return const_iterator(tail); }
375
379 T& front(void) { return *(begin()); }
380
384 const T& front(void) const { return *(begin()); }
385
389 T& back(void) { return *(--end()); }
390
394 const T& back(void) const { return *(--end()); }
395
399 size_type size(void) const { return sz; }
400
404 bool empty(void) const { return sz == 0; }
405
409 bool operator==(list<T>& other) {
410 if(size() != other.size())
411 return false;
412
413 iterator it = begin(), it_end = end(), it2 = other.begin();
414 for(; it != it_end; ++it, ++it2) {
415 if((*it) != (*it2))
416 return false;
417 }
418
419 return true;
420 }
421
425 bool operator!=(list<T>& other) { return !operator==(other); }
426
431 void sort(SortCmp* cmp = default_sort_cmp) {
432 if(size() <= 1)
433 return;
434
435 // unlink nodes first making first->prev and last->next zero
436 tail->prev->next = 0;
437
438 Node* nn = mergesort(tail->next, cmp);
439
440 tail->next = nn;
441 nn->prev = tail;
442
443 /*
444 * Search last node and let tail points to it.
445 * Althought this looks like overhead, this sort is still twice faster that std::list sort.
446 * Alternative optimization would be that __mergesort() returns end node.
447 */
448 while(1) {
449 if(nn->next)
450 nn = nn->next;
451 else {
452 nn->next = tail;
453 tail->prev = nn;
454 break;
455 }
456 }
457 }
458 };
459
460 #if 0
461 // list specialization for pointers
462 #ifndef SKIP_DOCS
463 #ifndef NO_LIST_SPECIALIZATION
464
465 // explicit instantation
466 template class list<void*>;
467 template class ListIterator<void*>;
468
469 template <typename T>
470 struct ListIterator<T*> {
471 private:
472 ListIterator<void*> impl;
473
474 public:
475 // implicit conversion; some magic. Yuck !
476 operator ListIterator<void*> () { return impl; }
477
478 ListIterator(const ListIterator<void*>& b) : impl(b) { }
479 typedef ListNode NodeType;
480
481 ListIterator() { }
482 ListIterator(NodeType* n) : impl(n) { }
483
484 T* operator*(void) const { return (T*)*impl; }
485
486 bool operator!=(const ListIterator& other) const { return impl != other.impl; }
487 bool operator==(const ListIterator& other) const { return impl == other.impl; }
488
489 ListIterator& operator++(void) { ++impl; return *this; }
490 ListIterator& operator--(void) { --impl; return *this; }
491 };
492
493 template <typename T>
494 class list<T*> {
495 private:
496 list<void*> impl;
497 static bool default_sort_cmp(const T* val1, const T* val2) { return *val1 < *val2; }
498
499 public:
500 typedef unsigned int size_type;
501
502 typedef T* value_type;
503 typedef const value_type& const_reference;
504 typedef value_type& reference;
505 typedef value_type* pointer;
506 typedef const value_type* const_pointer;
507
508 typedef bool (SortCmp)(const_reference val1, const_reference val2);
509
510 typedef ListIterator<T*> iterator;
511 typedef ListIterator<T*> const_iterator;
512
513 void clear(void) { impl.clear(); }
514
515 iterator insert(iterator it, const_reference val) { return impl.insert(it, val); }
516 iterator erase(iterator it) { return impl.erase(it); }
517
518 void push_back(const_reference val) { impl.push_back((void*)val); }
519 void push_front(const_reference val) { impl.push_front((void*)val); }
520
521 iterator begin(void) { return impl.begin(); }
522 const_iterator begin(void) const { return impl.begin(); }
523
524 iterator end(void) { return impl.end(); }
525 const_iterator end(void) const { return impl.end(); }
526
527 pointer front(void) { return impl.front(); }
528 const_pointer front(void) const { return impl.front(); }
529
530 pointer back(void) { return impl.back(); }
531 const_pointer back(void) const { return impl.back(); }
532
533 size_type size(void) const { return impl.size(); }
534 bool empty(void) const { return impl.empty(); }
535
536 bool operator==(list<T*>& other) { return impl.operator==(other); }
537 bool operator!=(list<T*>& other) { return impl.operator!=(other); }
538
539 //void sort(SortCmp* cmp = default_sort_cmp) { impl.sort( (bool (*)(void* const&, void* const&)) cmp); }
540 void sort(SortCmp* cmp) { impl.sort((bool (*)(void* const&, void* const&)) cmp); }
541 };
542
543 #endif // NO_LIST_SPECIALIZATION
544 #endif // SKIP_DOCS
545 #endif
546
547 EDELIB_NS_END
548 #endif