ROSE  0.11.145.0
IndexedList.h
1 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
2 // be clobbered by the next update from Sawyer. The Sawyer repository is at
3 // https://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef Sawyer_IndexedList_H
9 #define Sawyer_IndexedList_H
10 
11 #include <Sawyer/Assert.h>
12 #include <Sawyer/DefaultAllocator.h>
13 #include <Sawyer/Optional.h>
14 #include <Sawyer/Sawyer.h>
15 
16 #include <boost/range/iterator_range.hpp>
17 #include <boost/serialization/access.hpp>
18 #include <boost/serialization/nvp.hpp>
19 #include <boost/serialization/split_member.hpp>
20 #include <iterator>
21 #include <vector>
22 
23 namespace Sawyer {
24 namespace Container {
25 
27 template<class T>
29  typedef typename T::NodeIterator NodeIterator;
30  typedef typename T::ValueIterator ValueIterator;
31 };
32 
33 template<class T>
34 struct IndexedListTraits<const T> {
35  typedef typename T::ConstNodeIterator NodeIterator;
36  typedef typename T::ConstValueIterator ValueIterator;
37 };
38 
77 template<class T, class Alloc = DefaultAllocator>
78 class IndexedList {
79 public:
80  typedef T Value;
81  typedef Alloc Allocator;
82  class Node;
84 private:
85 
86  static const size_t NO_ID = (size_t)(-1);
87 
88 
89  // Forms a circular list. ProtoNode is the first part of a Node so that we can static_cast from ProtoNode to Node.
90  class ProtoNode {
91  public:
92  size_t id; // Unique, small, contiguous ID numbers
93  ProtoNode *next, *prev; // Linkage to neighoring nodes
94  explicit ProtoNode(size_t id=NO_ID): id(id), next(this), prev(this) {}
95  bool isHead() const { return id==NO_ID; } // implies no Node memory is attached; don't static_cast to Node!
96  void insert(ProtoNode &newNode) { // insert newNode before this node
97  ASSERT_forbid(newNode.isHead());
98  ASSERT_require(newNode.next==&newNode);
99  ASSERT_require(newNode.prev==&newNode);
100  prev->next = &newNode;
101  newNode.prev = prev;
102  prev = &newNode;
103  newNode.next = this;
104  }
105  void remove() { // remove this node from the list
106  ASSERT_forbid(isHead());
107  prev->next = next;
108  next->prev = prev;
109  next = prev = this;
110  }
111  Node& dereference() {
112  ASSERT_forbid(isHead());
113  Node *node = (Node*)this; // ProtoNode must be first data member of Node
114  ASSERT_require(&node->linkage_ == this); // it wasn't first
115  return *node;
116  }
117  const Node& dereference() const {
118  ASSERT_forbid(isHead());
119  const Node *node = (const Node*)this; // ProtoNode must be first data member of Node
120  ASSERT_require(&node->linkage_ == this); // it wasn't first
121  return *node;
122  }
123  };
124 
125 public:
130  class Node {
131  ProtoNode linkage_; // This member MUST BE FIRST so ProtoNode::dereference works
132  Value value_; // User-supplied data for each node
133  private:
134  friend class IndexedList;
135  Node(size_t id, const Value &value): linkage_(id), value_(value) { ASSERT_forbid(linkage_.isHead()); }
136  public:
143  const size_t& id() const { return linkage_.id; }
144 
151  Value& value() { return value_; }
152  const Value& value() const { return value_; }
153  Value& operator*() { return value_; }
154  const Value& operator*() const { return value_; }
155  Value* operator->() { return &value_; }
156  const Value* operator->() const { return &value_; }
158  };
159 
161  // Iterators
163 private:
164  template<class Derived, class Value, class BaseIterator>
165  class IteratorBase {
166  public:
167  // Five standard iterator types
168  using iterator_category = std::bidirectional_iterator_tag;
169  using value_type = Value;
170  using difference_type = std::ptrdiff_t;
171  using pointer = Value*;
172  using reference = Value&;
173 
174  protected:
175  BaseIterator base_;
176  IteratorBase() { base_ = NULL; }
177  IteratorBase(const IteratorBase &other): base_(other.base_) {}
178  IteratorBase(const BaseIterator &base): base_(base) {}
179  public:
180  IteratorBase& operator=(const IteratorBase &other) { base_ = other.base_; return *this; }
181  bool isAtEnd() const { return base_->isHead(); }
182  Derived& operator++() { base_ = base_->next; return *derived(); }
183  Derived operator++(int) { Derived old(this->base_); base_ = base_->next; return old; }
184  Derived& operator--() { base_ = base_->prev; return *derived(); }
185  Derived operator--(int) { Derived old(this->base_); base_ = base_->prev; return old; }
186  template<class OtherIter> bool operator==(const OtherIter &other) const { return base_ == other.base(); }
187  template<class OtherIter> bool operator!=(const OtherIter &other) const { return base_ != other.base(); }
188  protected:
189  Derived* derived() { return static_cast<Derived*>(this); }
190  const Derived* derived() const { return static_cast<const Derived*>(this); }
191  public:
192  const BaseIterator& base() const { return base_; }
193  };
194 
195 public:
210  class NodeIterator: public IteratorBase<NodeIterator, Node, ProtoNode*> {
211  typedef IteratorBase<NodeIterator, Node, ProtoNode*> Super;
212  public:
213  NodeIterator() {}
214  NodeIterator(const NodeIterator &other): Super(other) {}
215  NodeIterator& operator=(const NodeIterator &other) { this->Super::operator=(other); return *this; }
216  Node& operator*() const { return this->base_->dereference(); }
217  Node* operator->() const { return &this->base_->dereference(); }
218  private:
219  friend class IndexedList;
220  NodeIterator(ProtoNode *base): Super(base) {}
221  NodeIterator(Node *node): Super(&node->linkage_) {}
222  };
223 
238  class ConstNodeIterator: public IteratorBase<ConstNodeIterator, const Node, const ProtoNode*> {
239  typedef IteratorBase<ConstNodeIterator, const Node, const ProtoNode*> Super;
240  public:
241  ConstNodeIterator() {}
242  ConstNodeIterator(const ConstNodeIterator &other): Super(other) {}
243  ConstNodeIterator(const NodeIterator &other): Super(other.base()) {}
244  ConstNodeIterator& operator=(const ConstNodeIterator &other) { this->Super::operator=(other); return *this; }
245  const Node& operator*() const { return this->base_->dereference(); }
246  const Node* operator->() const { return &this->base_->dereference(); }
247  private:
248  friend class IndexedList;
249  ConstNodeIterator(const ProtoNode *base): Super(base) {}
250  ConstNodeIterator(const Node *node): Super(&node->linkage_) {}
251  };
252 
263  class ValueIterator: public IteratorBase<ValueIterator, Value, ProtoNode*> {
264  typedef IteratorBase<ValueIterator, Value, ProtoNode*> Super;
265  public:
266  ValueIterator() {}
267  ValueIterator(const ValueIterator &other): Super(other) {}
268  ValueIterator(const NodeIterator &other): Super(other.base()) {}
269  ValueIterator& operator=(const ValueIterator &other) { this->Super::operator=(other); return *this; }
270  Value& operator*() const { return this->base()->dereference().value(); }
271  Value* operator->() const { return &this->base()->dereference().value(); }
272  private:
273  friend class IndexedList;
274  ValueIterator(ProtoNode *base): Super(base) {}
275  ValueIterator(Node *node): Super(&node->linkage_) {}
276  };
277 
288  class ConstValueIterator: public IteratorBase<ConstValueIterator, const Value, const ProtoNode*> {
289  typedef IteratorBase<ConstValueIterator, const Value, const ProtoNode*> Super;
290  public:
291  ConstValueIterator() {}
292  ConstValueIterator(const ConstValueIterator &other): Super(other) {}
293  ConstValueIterator(const NodeIterator &other): Super(other.base()) {}
294  ConstValueIterator(const ConstNodeIterator &other): Super(other.base()) {}
295  ConstValueIterator(const ValueIterator &other): Super(other.base()) {}
296  ConstValueIterator& operator=(const ConstValueIterator &other) { this->Super::operator=(other); return *this; }
297  const Value& operator*() const { return this->base()->dereference().value(); }
298  const Value* operator->() const { return &this->base()->dereference().value(); }
299  private:
300  friend class IndexedList;
301  ConstValueIterator(const ProtoNode *base): Super(base) {}
302  ConstValueIterator(const Node *node): Super(&node->linkage_) {}
303  };
306 private:
307  Allocator allocator_; // provided allocator for list nodes
308  ProtoNode *head_; // always point to a list head, not a true node (normal allocator)
309  typedef std::vector<Node*> Index; // allocated with provided allocator
310  Index index_; // allocated with normal allocator
311 
313  // Serialization
315 private:
316  friend class boost::serialization::access;
317 
318  template<class S>
319  void save(S &s, const unsigned /*version*/) const {
320  size_t n = size();
321  s <<BOOST_SERIALIZATION_NVP(n);
322  for (const ProtoNode *pnode = head_->next; pnode != head_; pnode = pnode->next) {
323  ASSERT_require(n-- > 0);
324  size_t id = pnode->dereference().id();
325  const Value &value = pnode->dereference().value();
326  s <<BOOST_SERIALIZATION_NVP(id);
327  s <<BOOST_SERIALIZATION_NVP(value);
328  }
329  }
330 
331  template<class S>
332  void load(S &s, const unsigned /*version*/) {
333  clear();
334  size_t n = 0;
335  s >>BOOST_SERIALIZATION_NVP(n);
336  ASSERT_require(index_.empty());
337  index_.resize(n, NULL);
338  for (size_t i=0; i<n; ++i) {
339  size_t id = 0;
340  s >>BOOST_SERIALIZATION_NVP(id);
341  Node *node = new (allocator_.allocate(sizeof(Node))) Node(id, Value());
342  s >>boost::serialization::make_nvp("value", node->value());
343 
344  ASSERT_require(id < index_.size());
345  ASSERT_require(index_[id] == NULL);
346  index_[id] = node;
347 
348  head_->insert(node->linkage_); // append to end of node list
349  }
350  }
351 
352  BOOST_SERIALIZATION_SPLIT_MEMBER();
353 
354 
356  // Initialization
358 public:
359 
363  explicit IndexedList(const Allocator &allocator = Allocator())
364  : allocator_(allocator), head_(new ProtoNode) {}
365 
370  IndexedList(const IndexedList &other): allocator_(other.allocator_), head_(new ProtoNode) {
371  for (ConstValueIterator otherIter=other.values().begin(); otherIter!=other.values().end(); ++otherIter)
372  pushBack(*otherIter);
373  }
374 
376  template<class T2, class Alloc2>
377  IndexedList(const IndexedList<T2, Alloc2> &other, const Allocator &/*allocator*/ = Allocator())
378  : allocator_(Allocator()), head_(new ProtoNode) {
379  typedef typename IndexedList<T2>::ConstValueIterator OtherIter;
380  for (OtherIter otherIter=other.values().begin(); otherIter!=other.values().end(); ++otherIter)
381  pushBack(Value(*otherIter));
382  }
383 
387  explicit IndexedList(size_t nElmts, const Value &val = Value(), const Allocator &allocator = Allocator())
388  : allocator_(allocator), head_(new ProtoNode) {
389  index_.reserve(nElmts);
390  for (size_t i=0; i<nElmts; ++i)
391  pushBack(val);
392  }
393 
399  clear();
400  insertMultiple(nodes().begin(), other.values());
401  return *this;
402  }
403 
408  template<class T2>
410  clear();
411  insert(nodes().begin(), other.values());
412  return *this;
413  }
414 
415  ~IndexedList() {
416  clear();
417  delete head_;
418  }
419 
423  const Allocator& allocator() const {
424  return allocator_;
425  }
426 
428  // Iteration
430 public:
431 
437  boost::iterator_range<NodeIterator> nodes() {
438  return boost::iterator_range<NodeIterator>(NodeIterator(head_->next), NodeIterator(head_));
439  }
440  boost::iterator_range<ConstNodeIterator> nodes() const {
441  return boost::iterator_range<ConstNodeIterator>(ConstNodeIterator(head_->next), ConstNodeIterator(head_));
442  }
443  boost::iterator_range<ValueIterator> values() {
444  return boost::iterator_range<ValueIterator>(ValueIterator(head_->next), ValueIterator(head_));
445  }
446  boost::iterator_range<ConstValueIterator> values() const {
447  return boost::iterator_range<ConstValueIterator>(ConstValueIterator(head_->next), ConstValueIterator(head_));
448  }
451 private:
452  bool isLocalIterator(const ConstValueIterator &iter) const {
453  const ProtoNode *pn = iter.base();
454  ASSERT_not_null(pn);
455  if (pn == head_)
456  return true; // local end iterator
457  const Node *node = &pn->dereference();
458  size_t id = node->id();
459  return id<index_.size() && node==index_[id];
460  }
461 
462 
464  // Size and capacity
466 public:
467 
471  bool isEmpty() const {
472  return index_.empty();
473  }
474 
478  size_t size() const {
479  return index_.size();
480  }
481 
489  size_t capacity() const {
490  return index_.capacity();
491  }
492  void capacity(size_t n) {
493  index_.reserve(n);
494  }
498  // Searching
501 public:
502 
509  NodeIterator find(size_t id) {
510  ASSERT_require(id < index_.size());
511  ASSERT_not_null(index_[id]);
512  return NodeIterator(index_[id]);
513  }
514  ConstNodeIterator find(size_t id) const {
515  ASSERT_require(id < index_.size());
516  ASSERT_not_null(index_[id]);
517  return ConstNodeIterator(index_[id]);
518  }
522  // Accessors
525 public:
526 
532  Node& frontNode() {
533  ASSERT_forbid(isEmpty());
534  return head_->next->dereference();
535  }
536  const Node& frontNode() const {
537  ASSERT_forbid(isEmpty());
538  return head_->next->dereference();
539  }
540  Value& frontValue() {
541  return frontNode().value();
542  }
543  const Value& frontValue() const {
544  return frontNode().value();
545  }
553  Node& backNode() {
554  ASSERT_forbid(isEmpty());
555  return head_->prev->dereference();
556  }
557  const Node& backNode() const {
558  ASSERT_forbid(isEmpty());
559  return head_->prev->dereference();
560  }
561  Value& backValue() {
562  return backNode().value();
563  }
564  const Value& backValue() const {
565  return backNode().value();
566  }
575  Node& indexedNode(size_t id) {
576  ASSERT_require(id < size());
577  ASSERT_not_null(index_[id]);
578  return *index_[id];
579  }
580  const Node& indexedNode(size_t id) const {
581  ASSERT_require(id < size());
582  ASSERT_not_null(index_[id]);
583  return *index_[id];
584  }
585  Value& indexedValue(size_t id) {
586  return indexedNode(id).value();
587  }
588  const Value& indexedValue(size_t id) const {
589  return indexedNode(id).value();
590  }
591  Value& operator[](size_t id) {
592  return indexedValue(id);
593  }
594  const Value& operator[](size_t id) const {
595  return indexedValue(id);
596  }
597 
598  Optional<Value> getOptional(size_t id) const {
599  return id < size() ? Optional<Value>(indexedValue(id)) : Optional<Value>();
600  }
601 
602  Value& getOrElse(size_t id, Value &dflt) {
603  return id < size() ? indexedValue(id) : dflt;
604  }
605  const Value& getOrElse(size_t id, const Value &dflt) const {
606  return id < size() ? indexedValue(id) : dflt;
607  }
608 
609  const Value& getOrDefault(size_t id) const {
610  static const Value dflt;
611  return id < size() ? indexedValue(id) : dflt;
612  }
615  // Mutators
618 public:
619 
624  IndexedList& pushFront(const Value &value) {
625  insert(nodes().begin(), value);
626  return *this;
627  }
628 
633  IndexedList& pushBack(const Value &value) {
634  insert(nodes().end(), value);
635  return *this;
636  }
637 
642  NodeIterator insert(const ValueIterator &position, const Value &value) {
643  ProtoNode *pos = position.base();
644  Node *node = new (allocator_.allocate(sizeof(Node))) Node(index_.size(), value);
645  index_.push_back(node);
646  pos->insert(node->linkage_);
647  return NodeIterator(node);
648  }
649 
655  IndexedList& insert(const ValueIterator &position, size_t nElmts, const Value &value) {
656  for (size_t i=0; i<nElmts; ++i)
657  insert(position, value);
658  return *this;
659  }
660 
667  template<class OtherValueIterator>
668  IndexedList& insertMultiple(const ValueIterator &position, const boost::iterator_range<OtherValueIterator> &range) {
669  for (OtherValueIterator otherIter=range.begin(); otherIter!=range.end(); ++otherIter)
670  insert(position, Value(*otherIter));
671  return *this;
672  }
673 
674 
678  void clear() {
679  for (size_t i=0; i<index_.size(); ++i) {
680  index_[i]->~Node();
681  allocator_.deallocate((void*)index_[i], sizeof(Node));
682  }
683  index_.clear();
684  head_->next = head_->prev = head_;
685  }
686 
690  NodeIterator erase(size_t id) {
691  ASSERT_require(id < size());
692  return eraseAt(find(id));
693  }
694 
699  NodeIterator eraseAt(const ValueIterator &position) {
700  ASSERT_require(isLocalIterator(position));
701  ProtoNode *pos = position.base();
702  ProtoNode *next = pos->next; // to build the return value
703  pos->remove(); // remove node from the doubly linked list w/out deleting
704  size_t id = pos->id;
705  if (id + 1 < index_.size()) {
706  std::swap(index_.back(), index_[id]);
707  index_[id]->linkage_.id = id;
708  }
709  index_.back()->~Node();
710  allocator_.deallocate(index_.back(), sizeof(Node));
711  index_.pop_back();
712  return NodeIterator(next);
713  }
714 
715  // range must be a range within this container
716  NodeIterator eraseAtMultiple(const boost::iterator_range<NodeIterator> &range) {
717  boost::iterator_range<ValueIterator> valueRange(range.begin(), range.end());
718  return eraseAtMultiple(valueRange);
719  }
720  NodeIterator eraseAtMultiple(const boost::iterator_range<ValueIterator> &range) {
721  ValueIterator otherIter = range.begin();
722  while (otherIter!=range.end())
723  otherIter = eraseAt(otherIter);
724  return NodeIterator(range.end().base());
725  }
726 
727  // debugging
728  void dump(std::ostream &o) const {
729  o <<"list contents:\n"
730  <<" index:\n";
731  for (size_t i=0; i<index_.size(); ++i)
732  o <<" [" <<i <<"]=" <<index_[i] <<"\n";
733  o <<" list:\n";
734  ProtoNode *pn = head_;
735  for (size_t i=0; i<index_.size()+1; ++i, pn=pn->next) {
736  o <<" " <<pn <<"\t" <<pn->next <<"\t" <<pn->prev <<"\t" <<pn->id <<"\n";
737  ASSERT_require(pn->isHead() || index_[pn->id]==&pn->dereference());
738  ASSERT_require(pn->next->prev == pn);
739  ASSERT_require(pn->prev->next == pn);
740  }
741  }
742 };
743 
744 } // namespace
745 } // namespace
746 
747 #endif
size_t size() const
Number of elements in list.
Definition: IndexedList.h:478
T Value
Type of values stored in this container.
Definition: IndexedList.h:80
const Node & indexedNode(size_t id) const
Element reference by ID.
Definition: IndexedList.h:580
Node & backNode()
Last element of list.
Definition: IndexedList.h:553
IndexedList(const Allocator &allocator=Allocator())
Default constructor.
Definition: IndexedList.h:363
size_t capacity() const
Allocated capacity of the index.
Definition: IndexedList.h:489
bool isEmpty() const
Determines if this list is empty.
Definition: IndexedList.h:471
IndexedList & operator=(const IndexedList &other)
Assignment from another list.
Definition: IndexedList.h:398
Node & indexedNode(size_t id)
Element reference by ID.
Definition: IndexedList.h:575
Value & backValue()
Last element of list.
Definition: IndexedList.h:561
boost::iterator_range< ConstValueIterator > values() const
All elements.
Definition: IndexedList.h:446
const Value & indexedValue(size_t id) const
Element reference by ID.
Definition: IndexedList.h:588
IndexedList & insertMultiple(const ValueIterator &position, const boost::iterator_range< OtherValueIterator > &range)
Insert elements at position.
Definition: IndexedList.h:668
boost::iterator_range< ValueIterator > values()
All elements.
Definition: IndexedList.h:443
Value & getOrElse(size_t id, Value &dflt)
Element reference by ID.
Definition: IndexedList.h:602
Alloc Allocator
Allocator for the storage nodes.
Definition: IndexedList.h:81
NodeIterator erase(size_t id)
Erase one element.
Definition: IndexedList.h:690
List const value bidirectional iterator.
Definition: IndexedList.h:288
Value & value()
Accessor for user-defined value.
Definition: IndexedList.h:151
IndexedList & insert(const ValueIterator &position, size_t nElmts, const Value &value)
Insert multiple copies at position.
Definition: IndexedList.h:655
Value & indexedValue(size_t id)
Element reference by ID.
Definition: IndexedList.h:585
const Value & getOrDefault(size_t id) const
Element reference by ID.
Definition: IndexedList.h:609
Node & frontNode()
First element of list.
Definition: IndexedList.h:532
const Allocator & allocator() const
Allocator.
Definition: IndexedList.h:423
Name space for the entire library.
Definition: FeasiblePath.h:767
boost::iterator_range< NodeIterator > nodes()
All elements.
Definition: IndexedList.h:437
NodeIterator find(size_t id)
Lookup by ID.
Definition: IndexedList.h:509
const Value & getOrElse(size_t id, const Value &dflt) const
Element reference by ID.
Definition: IndexedList.h:605
void clear()
Empties the list.
Definition: IndexedList.h:678
void capacity(size_t n)
Allocated capacity of the index.
Definition: IndexedList.h:492
IndexedList & pushBack(const Value &value)
Insert at the back of the list.
Definition: IndexedList.h:633
IndexedList(const IndexedList< T2, Alloc2 > &other, const Allocator &=Allocator())
Copy constructor.
Definition: IndexedList.h:377
List const node bidirectional iterator.
Definition: IndexedList.h:238
IndexedList(const IndexedList &other)
Copy constructor.
Definition: IndexedList.h:370
Doubly-linked list with constant-time indexing.
Definition: IndexedList.h:78
const Value * operator->() const
Accessor for user-defined value.
Definition: IndexedList.h:156
Value & frontValue()
First element of list.
Definition: IndexedList.h:540
List value bidirectional iterator.
Definition: IndexedList.h:263
const Value & operator*() const
Accessor for user-defined value.
Definition: IndexedList.h:154
IndexedList(size_t nElmts, const Value &val=Value(), const Allocator &allocator=Allocator())
Filling constructor.
Definition: IndexedList.h:387
Value & operator*()
Accessor for user-defined value.
Definition: IndexedList.h:153
const Node & frontNode() const
First element of list.
Definition: IndexedList.h:536
Value * operator->()
Accessor for user-defined value.
Definition: IndexedList.h:155
NodeIterator insert(const ValueIterator &position, const Value &value)
Insert element at position.
Definition: IndexedList.h:642
const Value & frontValue() const
First element of list.
Definition: IndexedList.h:543
const size_t & id() const
Unique identification number.
Definition: IndexedList.h:143
Value & operator[](size_t id)
Element reference by ID.
Definition: IndexedList.h:591
NodeIterator eraseAt(const ValueIterator &position)
Remove one element.
Definition: IndexedList.h:699
Optional< Value > getOptional(size_t id) const
Element reference by ID.
Definition: IndexedList.h:598
ConstNodeIterator find(size_t id) const
Lookup by ID.
Definition: IndexedList.h:514
Traits for indexed lists.
Definition: IndexedList.h:28
const Value & backValue() const
Last element of list.
Definition: IndexedList.h:564
boost::iterator_range< ConstNodeIterator > nodes() const
All elements.
Definition: IndexedList.h:440
const Value & operator[](size_t id) const
Element reference by ID.
Definition: IndexedList.h:594
IndexedList & operator=(const IndexedList< T2 > &other)
Assignment from another list.
Definition: IndexedList.h:409
List node bidirectional iterator.
Definition: IndexedList.h:210
Combination user-defined value and ID number.
Definition: IndexedList.h:130
IndexedList & pushFront(const Value &value)
Insert at the front of the list.
Definition: IndexedList.h:624
const Node & backNode() const
Last element of list.
Definition: IndexedList.h:557
const Value & value() const
Accessor for user-defined value.
Definition: IndexedList.h:152