The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
smart_list.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file A list whose iterators never invalidate.
17  */
18 
19 #ifndef UTILS_SMART_LIST_HPP_INCLUDED
20 #define UTILS_SMART_LIST_HPP_INCLUDED
21 
22 #include <cassert>
23 #include <iterator>
24 #include <vector>
25 
26 namespace utils
27 {
28 
29 
30 /* ** smart_list ** */
31 
32 /// This is a variant on a list that never invalidates iterators (unless, of
33 /// course, the list ceases to exist). In particular, an erase() will only flag
34 /// an element for removal from the list. Flagged elements are ignored by list
35 /// functions, but they still exist from the perspective of iterators that had
36 /// pointed (and still point) to the element.
37 ///
38 /// Assignment is incompatible with the goal of preserving iterators, so it is
39 /// not implemented (declared private though, to emphasize that this is
40 /// intentional).
41 ///
42 /// The insert() and erase() members are static, as they do not require a
43 /// reference to the list.
44 ///
45 /// Instead of being undefined, ++end() is equal to begin(), and --begin() is
46 /// equal to end().
47 template <class Data>
49 {
50  /// Nodes in the smart list.
51  struct node_t
52  {
53  /// Default constructor. This is for creating the root of a list.
54  node_t() : dat_ptr(nullptr), ref_count(1), next(this), prev(this)
55  {}
56  /// Initialized constructor. This is for creating a node in a list.
57  explicit node_t(const Data & d) : dat_ptr(new Data(d)), ref_count(1), next(nullptr), prev(nullptr)
58  {}
59  /// Destructor.
60  ~node_t();
61 
62  /// The data of the node. This is nullptr for a list's root.
63  Data * const dat_ptr;
64  /// ref_count counts 1 for the list and 2 for each iterator pointing to
65  /// this node. (So nodes are flagged for deletion when ref_count is even.)
66  mutable size_t ref_count;
67  // List linking.
70 
71  private: // Disallowed (and unneeded) functions (declared but not implemented).
72  /// No assignments.
73  node_t & operator=(const node_t &);
74  /// No copying.
75  node_t(const node_t & that);
76  };
77 
78  /// The base for the list's iterator classes.
79  /// Value is the value type of this iterator.
80  /// Reversed is true for the reverse iterators.
81  /// The actual iterators must have neither data nor destructors.
82  template <class Value, bool Reversed>
84  {
85  friend class smart_list<Data>;
86  typedef typename smart_list<Data>::node_t node_t;
87 
88  public:
89  // Types required of an iterator:
90  typedef Value value_type;
91  typedef value_type * pointer;
92  typedef value_type & reference;
93  typedef std::bidirectional_iterator_tag iterator_category;
94  typedef ptrdiff_t difference_type;
95 
96  protected: // Construct this via derived classes.
97  /// Default constructor
98  iterator_base() : ptr_(nullptr) {}
99  /// Initialized constructor
100  explicit iterator_base(node_t * ptr) : ptr_(ptr)
101  { skip_flagged(); refer(); }
102  /// Conversion constructors.
103  template <class V, bool R>
105  { refer(); }
106  /// Copy constructor (the default overrides the conversion template).
107  iterator_base(const iterator_base & that) : ptr_(that.ptr_)
108  { refer(); }
109  public:
110  /// Destructor
111  /// (Not virtual, since the derived classes are mere shells.)
113 
114  // Assignment
116  // NOTE: This is defined here because MSVC was unable to match the
117  // definition to the declaration when they were separate.
118  {
119  // Update our pointer.
120  node_t * old_ptr = ptr_;
121  ptr_ = that.ptr_;
122 
123  // Update reference counts.
124  refer();
125  unref(old_ptr);
126 
127  return *this;
128  }
129 
130  // Comparison:
131  bool operator==(const iterator_base & that) const { return ptr_ == that.ptr_; }
132  bool operator!=(const iterator_base & that) const { return ptr_ != that.ptr_; }
133 
134  // Dereference:
135  reference operator*() const { return *ptr_->dat_ptr; }
136  pointer operator->() const { return ptr_->dat_ptr; }
137 
138  // Increment/decrement:
139  iterator_base & operator++() { advance(Reversed); return *this; }
140  iterator_base & operator--() { advance(!Reversed); return *this; }
142  // NOTE: This is defined here because MSVC was unable to match the
143  // definition to the declaration when they were separate.
144  {
145  iterator_base retval(*this);
146  advance(Reversed);
147  return retval;
148  }
150  // NOTE: This is defined here because MSVC was unable to match the
151  // definition to the declaration when they were separate.
152  {
153  iterator_base retval(*this);
154  advance(!Reversed);
155  return retval;
156  }
157 
158  /// Test for being in a list, rather than past-the-end (or unassigned).
159  bool derefable() const { return derefable(ptr_); }
160 
161 
162  private: // functions
163  /// Test for being in a list, rather than past-the-end (or unassigned).
164  static bool derefable(node_t * ptr){ return ptr && ptr->dat_ptr; }
165  /// Advances our pointer to an unflagged node, possibly in the reverse direction.
166  void advance(bool reverse);
167  /// Advances our pointer one step, possibly in the reverse direction.
168  void inc(bool reverse) { ptr_ = reverse ? ptr_->prev : ptr_->next; }
169  /// Make sure we are not pointing to a flagged node.
170  void skip_flagged(bool reverse=Reversed);
171  /// Add a reference.
172  void refer() const;
173  /// Remove a reference.
174  static void unref(node_t * old_ptr);
175 
176  private: // data
177  node_t * ptr_;
178  };
179  template <class Value, bool Reversed> friend class iterator_base;
180 
181 public: // The standard list interface, minus assignment.
182  typedef Data value_type;
183  typedef value_type * pointer;
184  typedef value_type & reference;
185  typedef const value_type & const_reference;
186  typedef size_t size_type;
187 
188  // Making these structs instead of typedefs cuts down on the length of
189  // compiler messages and helps define which conversions are allowed.
190  struct iterator : public iterator_base<Data, false> {
191  /// Default constructor
192  iterator() : iterator_base<Data, false>() {}
193  /// Initialized constructor
194  explicit iterator(node_t * ptr) : iterator_base<Data, false>(ptr) {}
195  /// Copy constructor.
196  iterator(const iterator & that) : iterator_base<Data, false>(that) {}
197  /// Conversion from reverse_iterator.
198  explicit iterator(const iterator_base<Data, true> & that) : iterator_base<Data, false>(that) {}
199  };
200  struct const_iterator : public iterator_base<const Data, false> {
201  /// Default constructor
202  const_iterator() : iterator_base<const Data, false>() {}
203  /// Initialized constructor
204  explicit const_iterator(node_t * ptr) : iterator_base<const Data, false>(ptr) {}
205  /// Copy constructor.
206  const_iterator(const const_iterator & that) : iterator_base<const Data, false>(that) {}
207  /// Conversion from iterator.
208  const_iterator(const iterator_base<Data, false> & that) : iterator_base<const Data, false>(that) {}
209  /// Conversion from const_reverse_iterator.
210  explicit const_iterator(const iterator_base<const Data, true> & that) : iterator_base<const Data, false>(that) {}
211  };
212  struct reverse_iterator : public iterator_base<Data, true> {
213  /// Default constructor
214  reverse_iterator() : iterator_base<Data, true>() {}
215  /// Initialized constructor
216  explicit reverse_iterator(node_t * ptr) : iterator_base<Data, true>(ptr) {}
217  /// Copy constructor.
218  reverse_iterator(const reverse_iterator & that) : iterator_base<Data, true>(that) {}
219  /// Conversion from iterator.
220  explicit reverse_iterator(const iterator_base<Data, false> & that) : iterator_base<Data, true>(that) {}
221  };
222  struct const_reverse_iterator : public iterator_base<const Data, true> {
223  /// Default constructor
224  const_reverse_iterator() : iterator_base<const Data, true>() {}
225  /// Initialized constructor
226  explicit const_reverse_iterator(node_t * ptr) : iterator_base<const Data, true>(ptr) {}
227  /// Copy constructor.
228  const_reverse_iterator(const const_reverse_iterator & that) : iterator_base<const Data, true>(that) {}
229  /// Conversion from reverse_iterator.
230  const_reverse_iterator(const iterator_base<Data, true> & that) : iterator_base<const Data, true>(that) {}
231  /// Conversion from const_iterator.
232  explicit const_reverse_iterator(const iterator_base<const Data, false> & that) : iterator_base<const Data, true>(that) {}
233  };
234 
235 
236  smart_list() : root_() {}
237  smart_list(size_type n);
238  smart_list(size_type n, const value_type & d);
239  smart_list(const smart_list & that);
240  template <class InputIterator>
241  smart_list(const InputIterator & f, const InputIterator & l);
243 
245  iterator end() { return iterator(&root_); }
246  const_iterator begin() const { return const_iterator(root_.next); }
247  const_iterator end() const { return const_iterator(const_cast<node_t *>(&root_)); }
248  reverse_iterator rbegin() { return reverse_iterator(root_.prev); }
249  reverse_iterator rend() { return reverse_iterator(&root_); }
250  const_reverse_iterator rbegin() const { return const_reverse_iterator(root_.prev); }
251  const_reverse_iterator rend() const { return const_reverse_iterator(const_cast<node_t *>(&root_)); }
252 
253  size_type size() const;
254  size_type max_size() const { return size_type(-1); }
255  /// Note: if empty() returns true, the list might still contain nodes
256  /// flagged for deletion.
257  bool empty() const { return begin() == end(); }
258 
259  // Note: these functions use iterators so flagged nodes are skipped.
260  reference front() { return *begin(); }
261  const_reference front() const { return *begin(); }
262  reference back() { return *rbegin(); }
263  const_reference back() const { return *rbegin(); }
264  void push_front(const value_type & d) { insert(root_.next, d); }
265  void push_back(const value_type & d) { insert(&root_, d); }
266  void pop_front() { erase(begin()); }
267  void pop_back() { erase(iterator(rbegin())); }
268 
269  void swap(smart_list & that);
270 
271  static iterator insert(const iterator & pos, const value_type & d);
272  template <class InputIterator>
273  static void insert(const iterator & pos, const InputIterator & f, const InputIterator & l);
274  static void insert(const iterator & pos, size_type n, const value_type & d);
275 
276  static iterator erase(const iterator & pos);
277  static iterator erase(const iterator & start, const iterator & stop);
278  void clear() { erase(begin(), end()); }
279 
280  void resize(size_type n) { resize(n, value_type()); }
281  void resize(size_type n, const value_type & d);
282 
283  void splice(const iterator & pos, smart_list & L);
284  void splice(const iterator & pos, smart_list & L, const iterator & i);
285  void splice(const iterator & pos, smart_list & L, const iterator & f, const iterator & l);
286 
287  void remove(const value_type & value);
288  template <class Predicate>
289  void remove_if(const Predicate & p);
290 
291  void unique() { unique(std::equal_to<value_type>()); }
292  template <class BinaryPredicate>
293  void unique(const BinaryPredicate p);
294 
295  void merge(smart_list & L) { merge(L, std::less<value_type>()); }
296  template <class BinaryPredicate>
297  void merge(smart_list & L, const BinaryPredicate & p);
298 
299  void sort() { sort(std::less<value_type>()); }
300  template <class BinaryPredicate>
301  void sort(const BinaryPredicate & p);
302 
303 private: // functions
304  /// No implementation of operator=() since that would not preserve iterators.
305  smart_list & operator=(const smart_list &);
306 
307  /// Returns true if @a node has been flagged for deletion.
308  static bool flagged(const node_t & node) { return node.ref_count % 2 == 0; }
309  /// Flags @a node for deletion.
310  static void flag(const node_t & node) { node.ref_count &= ~size_t(1); }
311 
312  // Low-level implementations. The list is designed so that a reference
313  // to the list itself is not needed.
314  static node_t * insert(node_t * const pos, const value_type & d);
315  static node_t * check_erase(node_t * const pos);
316  static void link(node_t * const pos, node_t & begin_link, node_t & end_link);
317  static void unlink(node_t & begin_unlink, node_t & end_unlink);
318  static void splice(node_t * const pos, node_t & f, node_t & l);
319 
320 
321 private: // data
322  /// Root of the list.
323  node_t root_;
324  // I started doing this using STL and Boost, but it was taking longer than
325  // it would take for me to write stuff from scratch.
326 };
327 
328 /** Sized constructor */
329 template <class Data>
331 {
332  for ( size_type i = 0; i < n; ++i )
334 }
335 /** Sized constructor with a value */
336 template <class Data>
338 {
339  for ( size_type i = 0; i < n; ++i )
340  push_back(d);
341 }
342 /** Copy constructor */
343 template <class Data>
344 inline smart_list<Data>::smart_list(const smart_list & that) : root_()
345 {
346  // Copy non-flagged nodes.
347  for ( const_iterator it = that.begin(); it.derefable(); ++it )
348  push_back(*it);
349 }
350 /** Constructor from a range */
351 template <class Data> template <class InputIterator>
352 inline smart_list<Data>::smart_list(const InputIterator & f, const InputIterator & l) :
353  root_()
354 {
355  for ( InputIterator it = f; f != l; ++f )
356  push_back(*it);
357 }
358 
359 
360 /** The size of the list, not counting flagged nodes. */
361 template <class Data>
363 {
364  size_type count = 0;
365  // Look for nodes not flagged for deletion.
366  for ( const_iterator it = begin(); it.derefable(); ++it )
367  ++count;
368  return count;
369 }
370 
371 /** Swaps two lists. Done in constant time, with no iterator invalidation. */
372 template <class Data>
374 {
375  smart_list temp_list;
376 
377  // Swap, using splices instead of assignments.
378  temp_list.splice(temp_list.end(), that);
379  that.splice(that.end(), *this);
380  splice(end(), temp_list);
381 }
382 
383 /** Insert a node before @a pos. */
384 template <class Data>
386  (const iterator & pos, const value_type & d)
387 {
388  return iterator(insert(pos.ptr_, d));
389 }
390 /** Insert a range before @a pos. */
391 template <class Data>
392 template <class InputIterator>
393 inline void smart_list<Data>::insert(const iterator & pos, const InputIterator & f,
394  const InputIterator & l)
395 {
396  for ( InputIterator it = f; it != l; ++it )
397  insert(pos.ptr_, *it);
398 }
399 /** Insert @a n copies of @a d at @a pos. */
400 template <class Data>
401 inline void smart_list<Data>::insert(const iterator & pos, size_type n,
402  const value_type & d)
403 {
404  for ( size_type i = 0; i < n; ++i )
405  insert(pos.ptr_, d);
406 }
407 
408 /** Erase the node at @a pos. */
409 template <class Data>
411  (const iterator & pos)
412 {
413  flag(*pos.ptr_); // We know *pos cannot get deleted yet because pos points to it.
414  return iterator(pos.ptr_->next);
415 }
416 /** Erase a range of nodes. */
417 template <class Data>
419  (const iterator & start, const iterator & stop)
420 {
421  // Loop through all nodes from start to stop.
422  // We cannot rely on iterators because *stop might be flagged.
423  node_t * node_ptr = start.ptr_;
424  while ( node_ptr != stop.ptr_ && iterator::derefable(node_ptr) ) {
425  flag(*node_ptr);
426  node_ptr = check_erase(node_ptr);
427  }
428 
429  // node_ptr is more reliable than stop because of the derefable() condition.
430  return iterator(node_ptr);
431 }
432 
433 /**
434  * Resize the list.
435  * This does not count flagged nodes.
436  */
437 template <class Data>
439 {
440  size_type count = 0;
441  iterator it = begin();
442  iterator _end = end();
443 
444  // See how our current size compares to n.
445  // (Not calling size(), since that would do at least as much work.)
446  while ( it != _end && count < n ) {
447  ++it;
448  ++count;
449  }
450 
451  if ( count < n )
452  // We need more nodes.
453  insert(_end, n - count, d);
454  else if ( it != _end )
455  // We need to remove nodes.
456  erase(it, _end);
457 }
458 
459 /** Splice all of @a L into *this before @a pos. */
460 template <class Data>
461 inline void smart_list<Data>::splice(const iterator & pos, smart_list & L)
462 {
463  if ( L.root_.next != &L.root ) // if L has nodes to splice.
464  splice(pos.ptr_, *L.root_.next, *L.root_.prev);
465 }
466 /** Splice the node @a i points to (assumed from @a L) into *this before @a pos. */
467 template <class Data>
468 inline void smart_list<Data>::splice(const iterator & pos, smart_list & /*L*/,
469  const iterator & i)
470 {
471  if ( i.ptr_.derefable() )
472  splice(pos.ptr_, *i.ptr_, *i.ptr_);
473 }
474 /** Splice a range (assumed from @a L) into *this before @a pos. */
475 template <class Data>
476 inline void smart_list<Data>::splice(const iterator & pos, smart_list & /*L*/,
477  const iterator & f, const iterator & l)
478 {
479  // Abort on degenerate cases.
480  if ( !f.derefable() || f == l )
481  return;
482 
483  // Splice from f to the node before l.
484  splice(pos.ptr_, *(f.ptr_), *(l.ptr_->prev));
485 }
486 
487 /** Remove all nodes whose data equals @a value. */
488 template <class Data>
490 {
491  // Look for elements to erase.
492  iterator it = begin(), _end = end();
493  while ( it != _end )
494  if ( *it == value )
495  it = erase(it);
496  else
497  ++it;
498 }
499 /** Remove all nodes whose data satisfies @a p. */
500 template <class Data>
501 template <class Predicate>
502 inline void smart_list<Data>::remove_if(const Predicate & p)
503 {
504  // Look for elements to erase.
505  iterator it = begin(), _end = end();
506  while ( it != _end() )
507  if ( p(*it) )
508  it = erase(it);
509  else
510  ++it;
511 }
512 
513 /** Remove nodes equal (under @a p) to their immediate predecessor. */
514 template <class Data>
515 template <class BinaryPredicate>
516 inline void smart_list<Data>::unique(const BinaryPredicate p)
517 {
518  // Initial state.
519  iterator _end = end();
520  iterator cur = begin();
521  iterator prev = cur;
522  // Look at the second node, making the first node "previous".
523  if ( cur != _end )
524  ++cur;
525 
526  // Look for elements equal to their predecessors.
527  while ( cur != _end )
528  if ( p(*prev, *cur) )
529  // Duplicate. Remove it.
530  cur = erase(cur);
531  else
532  // Update the tracking of our previous element.
533  prev = cur++;
534 }
535 
536 /**
537  * Merge @a L into *this, using @a p to determine order.
538  * If both lists are sorted under @a p, then so is the merged list.
539  * This is stable; equivalent nodes retain their order, with nodes of *this
540  * considered to come before elements of @a L.
541  */
542 template <class Data>
543 template <class BinaryPredicate>
544 inline void smart_list<Data>::merge(smart_list & L, const BinaryPredicate & p)
545 {
546  // Merging a list into itself is a no-op, not a duplication.
547  if ( this == &L )
548  return;
549 
550  node_t * dest = root_.next;
551  node_t * source = L.root_.next;
552 
553  // Basic merge loop. Continues until one of the lists is depleted.
554  while ( iterator::derefable(dest) && iterator::derefable(source) ) {
555  if ( p(*(source->dat_ptr), *(dest->dat_ptr)) ) {
556  // We found something to merge in. See if we can merge multiple
557  // nodes at once.
558  node_t * end_merge = source->next;
559  while ( iterator::derefable(end_merge) && p(*(end_merge->dat_ptr), *(dest->dat_ptr)) )
560  end_merge = end_merge->next;
561  // Now end_merge is one past the nodes to merge.
562  // Move the nodes over.
563  splice(dest, *source, *(end_merge->prev));
564  // Advance the source.
565  source = end_merge;
566  }
567  else
568  // Advance the destination.
569  dest = dest->next;
570  }
571 
572  // Append any remaining nodes from L.
573  if ( iterator::derefable(source) ) // hence, we made it to our end.
574  splice(&root_, *source, *(L.root_.prev));
575 }
576 
577 /**
578  * Sort *this, using the order given by @a p.
579  * This is stable; equivalent nodes retain their order.
580  * This is an efficient sort, O(n lg n).
581  */
582 template <class Data>
583 template <class BinaryPredicate>
584 inline void smart_list<Data>::sort(const BinaryPredicate & p)
585 {
586  // We'll leverage merge() to do a merge sort.
587 
588  // First, get the real size of the list, so we can allocate memory before
589  // altering *this (exception safety).
590  size_type count = 0;
591  for ( node_t * node_ptr = root_.next; iterator::derefable(node_ptr); node_ptr = node_ptr->next )
592  ++count;
593  // Abort on trivial cases.
594  if ( count < 2 )
595  return;
596 
597  // Split *this into 1-length pieces.
598  std::vector<smart_list> sorter(count); // No memory allocations after this point.
599  for ( size_type i = 0; i < count; ++i )
600  sorter[i].splice(&(sorter[i].root_), *(root_.next), *(root_.next));
601 
602  // At the start of each iteration, step will be the distance between lists
603  // containing data. (There will be O(lg n) iterations.)
604  for ( size_type step = 1; step < count; step *= 2 )
605  // Merge consecutive data-bearing lists. Summing over all iterations of
606  // this (inner) loop, there will be O(n) comparisons made.
607  for ( size_type i = 0; i + step < count; i += 2*step )
608  sorter[i].merge(sorter[i+step], p);
609 
610  // The entire (sorted) list is now in the first element of the vector.
611  swap(sorter[0]);
612 }
613 
614 
615 /**
616  * Low-level insertion.
617  * The insertion will occur before @a pos. Pass &root_ to append to the list.
618  */
619 template <class Data>
621  (node_t * const pos, const value_type & d)
622 {
623  node_t * new_node = new node_t(d);
624  // The new node is essentially a 1-node list.
625  link(pos, *new_node, *new_node);
626  // Return a pointer to the new node.
627  return new_node;
628 }
629 /**
630  * Low-level erasure.
631  * The node will only be erased if its ref_count is 0. (So the caller must
632  * remove their reference before calling this.)
633  * @returns the next node in the list (could be a flagged node).
634  */
635 template <class Data>
637  (node_t * const pos)
638 {
639  // Sanity check.
640  if ( !iterator::derefable(pos) )
641  return nullptr;
642 
643  // Remember our successor.
644  node_t * ret_val = pos->next;
645 
646  // Can we actually erase?
647  if ( pos->ref_count == 0 ) {
648  // Disconnect *pos from the list.
649  unlink(*pos, *pos);
650  // Now we can delete.
651  delete pos;
652  }
653 
654  return ret_val;
655 }
656 
657 /**
658  * Assuming the nodes from @a begin_link to @a end_link are linked, they will
659  * be inserted into *this before @a pos. (Pass &root_ to append to the list.)
660  * Note that *end_link is included in the insert; this is not exactly
661  * analogous to a range of iterators.
662  * This is a constant-time operation; reference counts are not updated.
663  */
664 template <class Data>
665 inline void smart_list<Data>::link(node_t * const pos, node_t & begin_link, node_t & end_link)
666 {
667  // Link the new nodes into the list.
668  begin_link.prev = pos->prev;
669  end_link.next = pos;
670 
671  // Link the list to the new nodes.
672  begin_link.prev->next = &begin_link;
673  end_link.next->prev = &end_link;
674 }
675 /**
676  * Assuming @a begin_unlink and @a end_unlink are nodes from *this, with
677  * @a end_unlink a successor of @a begin_unlink, that chain of nodes will
678  * be removed from *this.
679  * Ownership of the removed chain is transferred to the caller, who becomes
680  * repsonsible for not leaving the nodes in limbo.
681  * This is a constant-time operation; reference counts are not updated.
682  */
683 template <class Data>
684 inline void smart_list<Data>::unlink(node_t & begin_unlink, node_t & end_unlink)
685 {
686  // Disconnect the list from the nodes.
687  begin_unlink.prev->next = end_unlink.next;
688  end_unlink.next->prev = begin_unlink.prev;
689 
690  // Disconnect the nodes from the list. This leaves the nodes in limbo.
691  end_unlink.next = nullptr;
692  begin_unlink.prev = nullptr;
693 }
694 
695 /**
696  * Low-level splice of the chain from @a b to @a e (including b and e)
697  * to the spot before @a pos.
698  */
699 template <class Data>
700 inline void smart_list<Data>::splice(node_t * const pos, node_t & b, node_t & e)
701 {
702  // Remove from the old list.
703  unlink(b, e);
704  // Splice into the new list.
705  link(pos, b, e);
706 }
707 
708 
709 /**
710  * Equality, if lists contain equal elements in the same order.
711  */
712 template <class Data>
713 inline bool operator==(const smart_list<Data> & a, const smart_list<Data> & b)
714 {
715  typename smart_list<Data>::const_iterator end_a = a.end();
716  typename smart_list<Data>::const_iterator end_b = b.end();
717  typename smart_list<Data>::const_iterator it_a = a.begin();
718  typename smart_list<Data>::const_iterator it_b = b.begin();
719 
720  for ( ; it_a != end_a && it_b != end_b; ++it_a, ++it_b )
721  if ( *it_a != *it_b )
722  // mismatch
723  return false;
724 
725  // All comparisons were equal, so they are the same if we compared everything.
726  return it_a == end_a && it_b == end_b;
727 }
728 /**
729  * Lexicographical order.
730  */
731 template <class Data>
732 inline bool operator<(const smart_list<Data> & a, const smart_list<Data> & b)
733 {
734  typename smart_list<Data>::const_iterator end_a = a.end();
735  typename smart_list<Data>::const_iterator end_b = b.end();
736  typename smart_list<Data>::const_iterator it_a = a.begin();
737  typename smart_list<Data>::const_iterator it_b = b.begin();
738 
739  for ( ; it_a != end_a && it_b != end_b; ++it_a, ++it_b )
740  if ( *it_a < *it_b )
741  // a is less than b.
742  return true;
743  else if ( *it_b < *it_a )
744  // b is less than a.
745  return false;
746 
747  // All comparisons were equal, so a is less than b if a is shorter.
748  return it_b != end_b;
749 }
750 
751 
752 /* ** smart_list::node_t ** */
753 
754 template <class Data>
756 {
757  // Some safety checks.
758  if ( dat_ptr == nullptr )
759  // Root node: make sure there are no lingering iterators to the list.
760  assert(next == this);
761  else {
762  // Normal node: make sure we are not still in a list.
763  assert(next == nullptr && prev == nullptr);
764  // Make sure no iterators point to us.
765  assert(ref_count == 0);
766  }
767 
768  delete dat_ptr;
769 }
770 
771 
772 /* ** smart_list::iterator_base ** */
773 
774 /**
775  * Advances our pointer to an unflagged node, possibly in the reverse direction.
776  * This will advance at least one step, and will not stop on a flagged node.
777  * In addition, this takes care of updating reference counts.
778  * (This is the code shared by increments and decrements.)
779  */
780 template <class Data>
781 template <class Value, bool Reversed>
783 {
784  node_t * old_ptr = ptr_;
785 
786  // Guarantee a change.
787  inc(reverse);
788  // Skip as necessary.
789  skip_flagged(reverse);
790 
791  // Update reference counts.
792  refer();
793  unref(old_ptr);
794 }
795 
796 /** Make sure we are not pointing to a flagged node. */
797 template <class Data>
798 template <class Value, bool Reversed>
800  (bool reverse)
801 {
802  while ( derefable() && smart_list<Data>::flagged(*ptr_) )
803  inc(reverse);
804 }
805 
806 /** Add a reference to that to which we point. */
807 template <class Data>
808 template <class Value, bool Reversed>
810 {
811  if ( derefable() )
812  ptr_->ref_count += 2;
813 }
814 
815 /**
816  * Remove a reference.
817  * May delete old_ptr. So call this after updating ptr_ to a new value.
818  */
819 template <class Data>
820 template <class Value, bool Reversed>
822 {
823  if ( derefable(old_ptr) ) {
824  // Remove a reference.
825  old_ptr->ref_count -= 2;
827  }
828 }
829 
830 }// namespace util
831 
832 #endif // UTILS_SMART_LIST_HPP_INCLUDED
833 
const_iterator end() const
Definition: smart_list.hpp:247
friend class iterator_base
Definition: smart_list.hpp:179
void skip_flagged(bool reverse=Reversed)
Make sure we are not pointing to a flagged node.
Definition: smart_list.hpp:800
const value_type & const_reference
Definition: smart_list.hpp:185
iterator_base(const iterator_base< V, R > &that)
Conversion constructors.
Definition: smart_list.hpp:104
reference back()
Definition: smart_list.hpp:262
reverse_iterator(const reverse_iterator &that)
Copy constructor.
Definition: smart_list.hpp:218
static bool derefable(node_t *ptr)
Test for being in a list, rather than past-the-end (or unassigned).
Definition: smart_list.hpp:164
bool derefable() const
Test for being in a list, rather than past-the-end (or unassigned).
Definition: smart_list.hpp:159
bool operator!=(const iterator_base &that) const
Definition: smart_list.hpp:132
size_type max_size() const
Definition: smart_list.hpp:254
const_reverse_iterator(const const_reverse_iterator &that)
Copy constructor.
Definition: smart_list.hpp:228
const_reverse_iterator rend() const
Definition: smart_list.hpp:251
void refer() const
Add a reference.
Definition: smart_list.hpp:809
int pos
Definition: formula.cpp:800
const_iterator(const iterator_base< Data, false > &that)
Conversion from iterator.
Definition: smart_list.hpp:208
bool empty() const
Note: if empty() returns true, the list might still contain nodes flagged for deletion.
Definition: smart_list.hpp:257
This is a variant on a list that never invalidates iterators (unless, of course, the list ceases to e...
Definition: smart_list.hpp:48
const_reverse_iterator rbegin() const
Definition: smart_list.hpp:250
const_reference front() const
Definition: smart_list.hpp:261
static bool flagged(const node_t &node)
Returns true if node has been flagged for deletion.
Definition: smart_list.hpp:308
value_type * pointer
Definition: smart_list.hpp:183
#define d
~iterator_base()
Destructor (Not virtual, since the derived classes are mere shells.)
Definition: smart_list.hpp:112
iterator_base()
Default constructor.
Definition: smart_list.hpp:98
node_t root_
Root of the list.
Definition: smart_list.hpp:323
const_reverse_iterator(node_t *ptr)
Initialized constructor.
Definition: smart_list.hpp:226
iterator_base & operator=(const iterator_base &that)
Definition: smart_list.hpp:115
GLdouble l
Definition: glew.h:6966
smart_list< Data >::node_t node_t
Definition: smart_list.hpp:86
Definition: lobject.h:387
const_reverse_iterator(const iterator_base< const Data, false > &that)
Conversion from const_iterator.
Definition: smart_list.hpp:232
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
iterator(const iterator_base< Data, true > &that)
Conversion from reverse_iterator.
Definition: smart_list.hpp:198
const_reference back() const
Definition: smart_list.hpp:263
iterator_base(const iterator_base &that)
Copy constructor (the default overrides the conversion template).
Definition: smart_list.hpp:107
GLuint GLuint end
Definition: glew.h:1221
const_reverse_iterator()
Default constructor.
Definition: smart_list.hpp:224
static void flag(const node_t &node)
Flags node for deletion.
Definition: smart_list.hpp:310
reverse_iterator()
Default constructor.
Definition: smart_list.hpp:214
void remove_if(const Predicate &p)
Remove all nodes whose data satisfies p.
Definition: smart_list.hpp:502
Nodes in the smart list.
Definition: smart_list.hpp:51
GLsizei const GLfloat * value
Definition: glew.h:1817
iterator()
Default constructor.
Definition: smart_list.hpp:192
std::bidirectional_iterator_tag iterator_category
Definition: smart_list.hpp:93
GLuint start
Definition: glew.h:1221
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
void erase(const std::string &key)
node_t(const Data &d)
Initialized constructor. This is for creating a node in a list.
Definition: smart_list.hpp:57
const_iterator begin() const
Definition: smart_list.hpp:246
iterator(node_t *ptr)
Initialized constructor.
Definition: smart_list.hpp:194
GLfloat GLfloat p
Definition: glew.h:12766
iterator(const iterator &that)
Copy constructor.
Definition: smart_list.hpp:196
GLuint GLuint GLsizei count
Definition: glew.h:1221
const_iterator(const iterator_base< const Data, true > &that)
Conversion from const_reverse_iterator.
Definition: smart_list.hpp:210
iterator_base(node_t *ptr)
Initialized constructor.
Definition: smart_list.hpp:100
reverse_iterator(const iterator_base< Data, false > &that)
Conversion from iterator.
Definition: smart_list.hpp:220
static void unlink(node_t &begin_unlink, node_t &end_unlink)
Assuming begin_unlink and end_unlink are nodes from *this, with end_unlink a successor of begin_unlin...
Definition: smart_list.hpp:684
reverse_iterator rbegin()
Definition: smart_list.hpp:248
reverse_iterator rend()
Definition: smart_list.hpp:249
The base for the list's iterator classes.
Definition: smart_list.hpp:83
value_type & reference
Definition: smart_list.hpp:184
const_iterator(const const_iterator &that)
Copy constructor.
Definition: smart_list.hpp:206
node_t()
Default constructor. This is for creating the root of a list.
Definition: smart_list.hpp:54
const_iterator()
Default constructor.
Definition: smart_list.hpp:202
static node_t * check_erase(node_t *const pos)
Low-level erasure.
Definition: smart_list.hpp:637
static iterator erase(const iterator &pos)
Erase the node at pos.
Definition: smart_list.hpp:411
void push_back(const value_type &d)
Definition: smart_list.hpp:265
size_t i
Definition: function.cpp:1057
void splice(const iterator &pos, smart_list &L)
Splice all of L into *this before pos.
Definition: smart_list.hpp:461
iterator begin()
Definition: smart_list.hpp:244
void advance(bool reverse)
Advances our pointer to an unflagged node, possibly in the reverse direction.
Definition: smart_list.hpp:782
void inc(bool reverse)
Advances our pointer one step, possibly in the reverse direction.
Definition: smart_list.hpp:168
const_reverse_iterator(const iterator_base< Data, true > &that)
Conversion from reverse_iterator.
Definition: smart_list.hpp:230
node_t & operator=(const node_t &)
No assignments.
reverse_iterator(node_t *ptr)
Initialized constructor.
Definition: smart_list.hpp:216
GLclampd n
Definition: glew.h:5903
bool operator==(const smart_list< Data > &a, const smart_list< Data > &b)
Equality, if lists contain equal elements in the same order.
Definition: smart_list.hpp:713
size_t ref_count
ref_count counts 1 for the list and 2 for each iterator pointing to this node.
Definition: smart_list.hpp:66
map_location prev
Definition: astarsearch.cpp:67
void swap(game_board &one, game_board &other)
Definition: game_board.cpp:56
Data *const dat_ptr
The data of the node. This is nullptr for a list's root.
Definition: smart_list.hpp:63
void merge(smart_list &L)
Definition: smart_list.hpp:295
bool operator==(const iterator_base &that) const
Definition: smart_list.hpp:131
utf8::string & insert(utf8::string &str, const size_t pos, const utf8::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:101
#define e
void remove(const value_type &value)
Remove all nodes whose data equals value.
Definition: smart_list.hpp:489
void resize(size_type n)
Definition: smart_list.hpp:280
const_iterator(node_t *ptr)
Initialized constructor.
Definition: smart_list.hpp:204
size_type size() const
The size of the list, not counting flagged nodes.
Definition: smart_list.hpp:362
void swap(smart_list &that)
Swaps two lists.
Definition: smart_list.hpp:373
smart_list & operator=(const smart_list &)
No implementation of operator=() since that would not preserve iterators.
static void unref(node_t *old_ptr)
Remove a reference.
Definition: smart_list.hpp:821
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
reference front()
Definition: smart_list.hpp:260
GLsizei GLsizei GLchar * source
Definition: glew.h:1800
static iterator insert(const iterator &pos, const value_type &d)
Insert a node before pos.
Definition: smart_list.hpp:386
static void link(node_t *const pos, node_t &begin_link, node_t &end_link)
Assuming the nodes from begin_link to end_link are linked, they will be inserted into *this before po...
Definition: smart_list.hpp:665
void push_front(const value_type &d)
Definition: smart_list.hpp:264
GLclampf f
Definition: glew.h:3024