Main Page   Reference Manual   Namespace List   Compound List   Namespace Members   Compound Members   File Members  

cwlist.h
Go to the documentation of this file.
1 
31 #ifndef CWLIST_H
32 #define CWLIST_H
33 
34 #include <list>
35 #include <execinfo.h>
36 
37 template<typename T, typename _Alloc>
38 class CWList;
39 
40 template<typename T, typename _Alloc>
41 class CWConstListIterator;
42 
43 /*
44  * CWNode<T>
45  *
46  * The actual data stored in a std::list when using CWList<T, _Alloc>.
47  * T is the template parameter used with CWList.
48  * count are the number of iterators that currently point to this element.
49  * dead is 0 or 1, where 1 means that the element was erased from the CWList
50  * (but not yet from the internal std::list, so that any iterators to it
51  * are NOT invalidated).
52  */
53 template<typename T>
54 struct CWNode {
55  T mElement; // The user visual data.
56  mutable unsigned short count; // Number of iterators pointing to this element.
57  mutable unsigned short dead; // Whether or not the element is "erased".
58 
59  CWNode() : count(0), dead(0) { }
60  explicit CWNode(T const& __val) : mElement(__val), count(0), dead(0) { }
61 
62  // Equivalence operators.
63  // __node may not be dead. Dead nodes in the list are "skipped" (obviously), meaning that they are never equal or always unequal.
64  bool operator==(CWNode const& __node) const { LIBCWD_ASSERT(!__node.dead); return mElement == __node.mElement && !dead; }
65  bool operator!=(CWNode const& __node) const { LIBCWD_ASSERT(!__node.dead); return mElement != __node.mElement || dead; }
66 
67  // Default ordering for sort().
68  bool operator<(CWNode const& __node) const { return mElement < __node.mElement; }
69 };
70 
71 /*
72  * CWListIterator<T, _Alloc>
73  *
74  * A non-const iterator to an element of CWList<T, _Alloc>.
75  */
76 template<typename T, typename _Alloc>
77 class CWListIterator {
78  private:
79  typedef CWListIterator<T, _Alloc> _Self;
80  typedef std::list<CWNode<T>, _Alloc> _Container;
81  typedef typename _Container::iterator _Iterator;
82 
83  _Container* mContainer; // A pointer to the associated container, or NULL when (still) singular.
84  // Note that this code does not allow a container to be destructed while
85  // any non-end iterators still exist (although that could be legal).
86  // If an iterator points to end() and the container is destructed then
87  // this pointer is NOT reset to NULL.
88  _Iterator mIterator; // Internal iterator to element of mContainer (or singular when mContainer is NULL).
89  int index;
90  void* buffer[128000];
91 
92  // Increment reference counter for mIterator (if not singular and not end()).
93  void ref()
94  {
95  if (mContainer && mContainer->end() != mIterator)
96  {
97  backtrace(&buffer[index], 32);
98  index += 32;
99  index %= 128000;
100  // It would be bad a new iterator was created that pointed to a dead element.
101  // Also, as a sanity check, make sure there aren't a ridiculous number of iterators
102  // pointing to this element.
103  LIBCWD_ASSERT(!mIterator->dead && mIterator->count < 100);
104  ++(mIterator->count);
105  }
106  }
107 
108  // Decrement reference counter for mIterator (if not singular and not end()).
109  // If this was the last iterator pointing to a dead element, then really erase it.
110  void unref()
111  {
112  if (mContainer && mContainer->end() != mIterator)
113  {
114  backtrace(&buffer[index], 32);
115  index += 32;
116  index %= 128000;
117  LIBCWD_ASSERT(mIterator->count > 0);
118  if (--(mIterator->count) == 0 && mIterator->dead)
119  {
120  mContainer->erase(mIterator);
121  }
122  }
123  }
124 
125  public:
126  // Some standard typedefs that have to exist for iterators.
127  typedef typename _Iterator::difference_type difference_type;
128  typedef typename _Iterator::iterator_category iterator_category;
129  typedef T value_type;
130  typedef T* pointer;
131  typedef T& reference;
132 
133  // Construct a singular iterator.
134  CWListIterator() : mContainer(NULL), index(0) { std::memset(buffer, 0, sizeof(buffer)); }
135 
136  // Construct an iterator to a given element of std::list. Only for internal use by CWList<T, _Alloc>.
137  CWListIterator(_Container* __c, _Iterator const& __i) : mContainer(__c), mIterator(__i), index(0)
138  {
139  std::memset(buffer, 0, sizeof(buffer));
140  LIBCWD_ASSERT(mContainer);
141  ref();
142  }
143 
144  // Copy constructor.
145  CWListIterator(CWListIterator const& __i) : mContainer(__i.mContainer), mIterator(__i.mIterator), index(0)
146  {
147  std::memset(buffer, 0, sizeof(buffer));
148  ref();
149  }
150 
151  // Destructor.
152  ~CWListIterator()
153  {
154  unref();
155  }
156 
157  // Assignment operator.
158  _Self& operator=(_Self const& __x)
159  {
160  unref(); // We no longer point to whatever we were pointing.
161  mContainer = __x.mContainer;
162  mIterator = __x.mIterator;
163  LIBCWD_ASSERT(mContainer);
164  ref(); // We now point an(other) element.
165  return *this;
166  }
167 
168  // Dereference operator.
169  reference operator*() const
170  {
171  // Iterator may not be singular or dead.
172  LIBCWD_ASSERT(mContainer && !mIterator->dead);
173  return mIterator->mElement;
174  }
175 
176  // Dereference operator.
177  pointer operator->() const
178  {
179  // Iterator may not be singular or dead.
180  LIBCWD_ASSERT(mContainer && !mIterator->dead);
181  return &mIterator->mElement;
182  }
183 
184  // Pre-increment operator (not being singular is implied).
185  _Self& operator++()
186  {
187  LIBCWD_ASSERT(mContainer && mIterator != mContainer->end());
188  LIBCWD_ASSERT(mIterator->count > 0); // This iterator is still pointing to it.
189  _Iterator cur = mIterator; // Make copy of mIterator.
190  ++cur; // Advance it.
191  unref(); // We will no longer be pointing to this element. This might invalidate mIterator!
192  while(cur != mContainer->end() && cur->dead) // Advance till the first non-dead element.
193  {
194  ++cur;
195  }
196  mIterator = cur; // Put result back into mIterator.
197  ref(); // We are now pointing to a valid element again.
198  return *this;
199  }
200 
201  // Post-increment operator (not being singular is implied).
202  _Self operator++(int)
203  {
204  _Self tmp = *this;
205  this->operator++();
206  return tmp;
207  }
208 
209  // Pre-decrement operator (not being singular is implied).
210  _Self& operator--()
211  {
212  LIBCWD_ASSERT(mContainer && mIterator != mContainer->begin());
213  LIBCWD_ASSERT(mIterator->count > 0); // This iterator is still pointing to it.
214  _Iterator cur = mIterator; // See operator++().
215  --cur;
216  unref();
217  while(cur->dead)
218  {
219  --cur;
220  }
221  mIterator = cur;
222  ref();
223  return *this;
224  }
225 
226  // Post-decrement operator (not being singular is implied).
227  _Self operator--(int)
228  {
229  _Self tmp = *this;
230  this->operator--();
231  return tmp;
232  }
233 
234  // Equivalence operators.
235  // We allow comparing with dead iterators, because if one of them is not-dead
236  // then the result is "unequal" anyway, which is probably what you want.
237  bool operator==(_Self const& __x) const { return mIterator == __x.mIterator; }
238  bool operator!=(_Self const& __x) const { return mIterator != __x.mIterator; }
239 
240  friend class CWList<T, _Alloc>;
241  friend class CWConstListIterator<T, _Alloc>;
242  template<typename T2, typename A> friend bool operator==(CWListIterator<T2, A> const& __x, CWConstListIterator<T2, A> const& __y);
243  template<typename T2, typename A> friend bool operator!=(CWListIterator<T2, A> const& __x, CWConstListIterator<T2, A> const& __y);
244 
245  // Return the total number of iterators pointing to the element that this iterator is pointing to.
246  // Unless the iterator points to end, a positive number will be returned since this iterator is
247  // pointing to the element. If it points to end (or is singular) then 0 is returned.
248  int count() const
249  {
250  if (mContainer && mIterator != mContainer->end())
251  {
252  return mIterator->count;
253  }
254  return 0;
255  }
256 
257  void release()
258  {
259  // Silently destruct this operator (it was copied with memcpy).
260  // Make sure that destructing this object will not do anything to any underlaying CWNode.
261  mContainer = NULL;
262 #ifdef _GLIBCXX_DEBUG
263  // Also stop debug code from considering this a valid iterator. Setting everything to zero should make it singular.
264  memset(&mIterator, 0, sizeof(mIterator));
265 #endif
266  }
267 };
268 
269 /*
270  * CWConstListIterator<T, _Alloc>
271  *
272  * A const iterator to an element of CWList<T, _Alloc>.
273  *
274  * Because this class is very simular to CWListIterator<T, _Alloc>, see above for detailed comments.
275  */
276 template<typename T, typename _Alloc = std::allocator<T> >
277 class CWConstListIterator {
278  private:
279  typedef CWConstListIterator<T, _Alloc> _Self;
280  typedef std::list<CWNode<T>, _Alloc> _Container;
281  typedef typename _Container::iterator _Iterator;
282  typedef typename _Container::const_iterator _ConstIterator;
283  typedef CWListIterator<T, _Alloc> iterator;
284 
285  _Container const* mContainer;
286  _Iterator mConstIterator; // This has to be an _Iterator instead of _ConstIterator, because the compiler doesn't accept a const_iterator for erase yet (C++11 does).
287 
288  void ref()
289  {
290  if (mContainer && mContainer->end() != mConstIterator)
291  {
292  LIBCWD_ASSERT(mConstIterator->count < 100);
293  mConstIterator->count++;
294  }
295  }
296 
297  void unref()
298  {
299  if (mContainer && mContainer->end() != mConstIterator)
300  {
301  LIBCWD_ASSERT(mConstIterator->count > 0);
302  mConstIterator->count--;
303  if (mConstIterator->count == 0 && mConstIterator->dead)
304  {
305  const_cast<_Container*>(mContainer)->erase(mConstIterator);
306  }
307  }
308  }
309 
310  public:
311  typedef typename _ConstIterator::difference_type difference_type;
312  typedef typename _ConstIterator::iterator_category iterator_category;
313  typedef T value_type;
314  typedef T const* pointer;
315  typedef T const& reference;
316 
317  CWConstListIterator() : mContainer(NULL) { }
318  CWConstListIterator(_Container const* __c, _Iterator const& __i) : mContainer(__c), mConstIterator(__i)
319  {
320  LIBCWD_ASSERT(mContainer);
321  ref();
322  }
323  // Allow to construct a const_iterator from an iterator.
324  CWConstListIterator(iterator const& __x) : mContainer(__x.mContainer), mConstIterator(__x.mIterator)
325  {
326  ref();
327  }
328  CWConstListIterator(CWConstListIterator const& __i) : mContainer(__i.mContainer), mConstIterator(__i.mConstIterator)
329  {
330  ref();
331  }
332  ~CWConstListIterator()
333  {
334  unref();
335  }
336 
337  _Self& operator=(_Self const& __x)
338  {
339  unref();
340  mContainer = __x.mContainer;
341  mConstIterator = __x.mConstIterator;
342  LIBCWD_ASSERT(mContainer);
343  ref();
344  return *this;
345  }
346 
347  // Allow to assign from a non-const iterator.
348  _Self& operator=(iterator const& __x)
349  {
350  unref();
351  mContainer = __x.mContainer;
352  mConstIterator = __x.mIterator;
353  LIBCWD_ASSERT(mContainer);
354  ref();
355  return *this;
356  }
357 
358  reference operator*() const
359  {
360  LIBCWD_ASSERT(mContainer && !mConstIterator->dead);
361  return mConstIterator->mElement;
362  }
363 
364  pointer operator->() const
365  {
366  LIBCWD_ASSERT(mContainer && !mConstIterator->dead);
367  return &mConstIterator->mElement;
368  }
369 
370  _Self& operator++()
371  {
372  _Iterator cur = mConstIterator;
373  ++cur;
374  unref();
375  while(cur != mContainer->end() && cur->dead)
376  {
377  ++cur;
378  }
379  mConstIterator = cur;
380  ref();
381  return *this;
382  }
383 
384  _Self operator++(int)
385  {
386  _Self tmp = *this;
387  this->operator++();
388  return tmp;
389  }
390 
391  _Self& operator--()
392  {
393  _Iterator cur = mConstIterator;
394  --cur;
395  unref();
396  while(cur->dead)
397  {
398  --cur;
399  }
400  mConstIterator = cur;
401  ref();
402  return *this;
403  }
404 
405  _Self operator--(int)
406  {
407  _Self tmp = *this;
408  this->operator--();
409  return tmp;
410  }
411 
412  bool operator==(_Self const& __x) const { return mConstIterator == __x.mConstIterator; }
413  bool operator!=(_Self const& __x) const { return mConstIterator != __x.mConstIterator; }
414  bool operator==(iterator const& __x) const { return mConstIterator == __x.mIterator; }
415  bool operator!=(iterator const& __x) const { return mConstIterator != __x.mIterator; }
416 
417  template<typename T2, typename A> friend bool operator==(CWListIterator<T2, A> const& __x, CWConstListIterator<T2, A> const& __y);
418  template<typename T2, typename A> friend bool operator!=(CWListIterator<T2, A> const& __x, CWConstListIterator<T2, A> const& __y);
419 
420  int count() const
421  {
422  if (mContainer && mConstIterator != mContainer->end())
423  {
424  return mConstIterator->count;
425  }
426  return 0;
427  }
428 };
429 
430 template<typename T, typename _Alloc>
431 inline bool operator==(CWListIterator<T, _Alloc> const& __x, CWConstListIterator<T, _Alloc> const& __y)
432 {
433  return __x.mIterator == __y.mConstIterator;
434 }
435 
436 template<typename T, typename _Alloc>
437 inline bool operator!=(CWListIterator<T, _Alloc> const& __x, CWConstListIterator<T, _Alloc> const& __y)
438 {
439  return __x.mIterator != __y.mConstIterator;
440 }
441 
442 /*
443  * CWList<T, _Alloc>
444  *
445  * A linked list that allows elements to be erased while one or more iterators
446  * are still pointing to that element, after which pre-increment and pre-decrement
447  * operators still work.
448  *
449  * For example:
450  *
451  * for (CWList<int>::iterator i = l.begin(); i != l.end(); ++i)
452  * {
453  * int x = *i;
454  * f(i); // Might erase any element of list l.
455  * // Should not dereference i anymore here (because it might be erased).
456  * }
457  */
458 template<typename T, typename _Alloc>
459 class CWList {
460  private:
461  typedef std::list<CWNode<T>, _Alloc> _Container;
462  typedef typename _Container::iterator _Iterator;
463  typedef typename _Container::const_iterator _ConstIterator;
464 
465  _Container mContainer;
466  size_t mSize;
467 
468  public:
469  typedef T value_type;
470  typedef T* pointer;
471  typedef T const* const_pointer;
472  typedef T& reference;
473  typedef T const& const_reference;
474  typedef CWListIterator<T, _Alloc> iterator;
475  typedef CWConstListIterator<T, _Alloc> const_iterator;
476  typedef std::reverse_iterator<iterator> reverse_iterator;
477  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
478  typedef size_t size_type;
479  typedef ptrdiff_t difference_type;
480 
481  // Default constructor. Create an empty list.
482  CWList() : mSize(0) { }
483 #ifdef CWDEBUG_DEBUGM
484  // Destructor calls clear() to check if there are no iterators left pointing to this list. Destructing an empty list is trivial.
485  ~CWList() { clear(); }
486 #endif
487 
488  // Construct a list with __n elements of __val.
489  explicit CWList(size_type __n, value_type const& __val = value_type()) : mContainer(__n, CWNode<T>(__val)), mSize(__n) { }
490 
491  // Copy constructor.
492  CWList(CWList const& __list) : mSize(0)
493  {
494  for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
495  {
496  if (!__i->dead)
497  {
498  mContainer.push_back(CWNode<T>(__i->mElement));
499  ++mSize;
500  }
501  }
502  }
503 
504  // Construct a list from the range [__first, __last>.
505  template<typename _InputIterator>
506  CWList(_InputIterator __first, _InputIterator __last) : mSize(0)
507  {
508  for (_InputIterator __i = __first; __i != __last; ++__i)
509  {
510  mContainer.push_back(CWNode<T>(*__i));
511  ++mSize;
512  }
513  }
514 
515  // Assign from another list.
516  CWList& operator=(CWList const& __list)
517  {
518  clear();
519  for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
520  {
521  if (!__i->dead)
522  {
523  mContainer.push_back(CWNode<T>(__i->mElement));
524  ++mSize;
525  }
526  }
527  return *this;
528  }
529 
530  iterator begin()
531  {
532  _Iterator __i = mContainer.begin();
533  while(__i != mContainer.end() && __i->dead)
534  {
535  ++__i;
536  }
537  return iterator(&mContainer, __i);
538  }
539 
540  const_iterator begin() const
541  {
542  _Iterator __i = const_cast<_Container&>(mContainer).begin();
543  while(__i != mContainer.end() && __i->dead)
544  {
545  ++__i;
546  }
547  return const_iterator(&mContainer, __i);
548  }
549 
550  iterator end() { return iterator(&mContainer, mContainer.end()); }
551  const_iterator end() const { return const_iterator(&mContainer, const_cast<_Container&>(mContainer).end()); }
552  reverse_iterator rbegin() { return reverse_iterator(end()); }
553  const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
554  reverse_iterator rend() { return reverse_iterator(begin()); }
555  const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
556 
557  bool empty() const { return mSize == 0; }
558  size_type size() const { return mSize; }
559  size_type max_size() const { return mContainer.max_size(); }
560 
561  reference front() { iterator __i = begin(); return *__i; }
562  const_reference front() const { const_iterator __i = begin(); return *__i; }
563  reference back() { iterator __i = end(); --__i; return *__i; }
564  const_reference back() const { const_iterator __i = end(); --__i; return *__i; }
565 
566  void push_front(value_type const& __x)
567  {
568  mContainer.push_front(CWNode<T>(__x));
569  ++mSize;
570  }
571  void pop_front()
572  {
573  iterator __i = begin();
574  erase(__i);
575  }
576  void push_back(value_type const& __x)
577  {
578  mContainer.push_back(CWNode<T>(__x));
579  ++mSize;
580  }
581  void pop_back()
582  {
583  iterator __i = end();
584  --__i;
585  erase(__i);
586  }
587 
588  iterator insert(iterator __position, value_type const& __x)
589  {
590  assert(__position.mContainer == &mContainer && (__position.mIterator == mContainer.end() || !__position.mIterator->dead));
591  ++mSize;
592  return iterator(&mContainer, mContainer.insert(__position.mIterator, CWNode<T>(__x)));
593  }
594 
595  void clear()
596  {
597 #ifdef CWDEBUG_DEBUGM
598  // There should be no iterators left pointing at any element here.
599  for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
600  {
601  LIBCWD_ASSERT(__i->count == 0);
602  }
603 #endif
604  mContainer.clear();
605  mSize = 0;
606  }
607 
608  void erase(iterator __position)
609  {
610  // Mark the element __position points to as being erased.
611  // Iterator may not be singular, point to end, or be dead already.
612  // Obviously count must be larger than zero since __position is still pointing to it.
613  LIBCWD_ASSERT(__position.mContainer == &mContainer && __position.mIterator != mContainer.end() && __position.mIterator->count > 0 && !__position.mIterator->dead);
614  __position.mIterator->dead = 1;
615  --mSize;
616  }
617 
618  // Remove all elements, designated by the iterator where, for which *where == __val.
619  void remove(value_type const& __val)
620  {
621  _Iterator const __e = mContainer.end();
622  for (_Iterator __i = mContainer.begin(); __i != __e;)
623  {
624  if (!__i->dead && __i->mElement == __val)
625  {
626  --mSize;
627  if (__i->count == 0)
628  {
629  mContainer.erase(__i++);
630  continue;
631  }
632  // Mark the element as being erased.
633  __i->dead = 1;
634  }
635  ++__i;
636  }
637  }
638 
639  void sort()
640  {
641 #ifdef CWDEBUG_DEBUGM
642  // There should be no iterators left pointing at any element here.
643  for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
644  {
645  LIBCWD_ASSERT(__i->count == 0);
646  }
647 #endif
648  mContainer.sort();
649  }
650  template<typename _StrictWeakOrdering>
651  struct PredWrapper
652  {
653  _StrictWeakOrdering mPred;
654  PredWrapper(_StrictWeakOrdering const& pred) : mPred(pred) { }
655  bool operator()(CWNode<T> const& __x, CWNode<T> const& __y) const { return mPred(__x.mElement, __y.mElement); }
656  };
657  template<typename _StrictWeakOrdering>
658  void sort(_StrictWeakOrdering const& pred)
659  {
660 #ifdef CWDEBUG_DEBUGM
661  // There should be no iterators left pointing at any element here.
662  for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
663  {
664  LIBCWD_ASSERT(__i->count == 0);
665  }
666 #endif
667  mContainer.sort(PredWrapper<_StrictWeakOrdering>(pred));
668  }
669 };
670 
671 #endif
Copyright © 2001 - 2004 Carlo Wood.  All rights reserved.