cmLinkedTree.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #ifndef cmLinkedTree_h
  4. #define cmLinkedTree_h
  5. #include "cmConfigure.h" // IWYU pragma: keep
  6. #include <assert.h>
  7. #include <iterator>
  8. #include <vector>
  9. /**
  10. @brief A adaptor for traversing a tree structure in a vector
  11. This class is not intended to be wholly generic like a standard library
  12. container adaptor. Mostly it exists to facilitate code sharing for the
  13. needs of the cmState. For example, the Truncate() method is a specific
  14. requirement of the cmState.
  15. An empty cmLinkedTree provides a Root() method, and an Push() method,
  16. each of which return iterators. A Tree can be built up by extending
  17. from the root, and then extending from any other iterator.
  18. An iterator resulting from this tree construction can be
  19. forward-only-iterated toward the root. Extending the tree never
  20. invalidates existing iterators.
  21. */
  22. template <typename T>
  23. class cmLinkedTree
  24. {
  25. typedef typename std::vector<T>::size_type PositionType;
  26. typedef T* PointerType;
  27. typedef T& ReferenceType;
  28. public:
  29. class iterator : public std::iterator<std::forward_iterator_tag, T>
  30. {
  31. friend class cmLinkedTree;
  32. cmLinkedTree* Tree;
  33. // The Position is always 'one past the end'.
  34. PositionType Position;
  35. iterator(cmLinkedTree* tree, PositionType pos)
  36. : Tree(tree)
  37. , Position(pos)
  38. {
  39. }
  40. public:
  41. iterator()
  42. : Tree(nullptr)
  43. , Position(0)
  44. {
  45. }
  46. void operator++()
  47. {
  48. assert(this->Tree);
  49. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  50. assert(this->Position <= this->Tree->Data.size());
  51. assert(this->Position > 0);
  52. this->Position = this->Tree->UpPositions[this->Position - 1];
  53. }
  54. PointerType operator->() const
  55. {
  56. assert(this->Tree);
  57. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  58. assert(this->Position <= this->Tree->Data.size());
  59. assert(this->Position > 0);
  60. return this->Tree->GetPointer(this->Position - 1);
  61. }
  62. PointerType operator->()
  63. {
  64. assert(this->Tree);
  65. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  66. assert(this->Position <= this->Tree->Data.size());
  67. assert(this->Position > 0);
  68. return this->Tree->GetPointer(this->Position - 1);
  69. }
  70. ReferenceType operator*() const
  71. {
  72. assert(this->Tree);
  73. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  74. assert(this->Position <= this->Tree->Data.size());
  75. assert(this->Position > 0);
  76. return this->Tree->GetReference(this->Position - 1);
  77. }
  78. ReferenceType operator*()
  79. {
  80. assert(this->Tree);
  81. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  82. assert(this->Position <= this->Tree->Data.size());
  83. assert(this->Position > 0);
  84. return this->Tree->GetReference(this->Position - 1);
  85. }
  86. bool operator==(iterator other) const
  87. {
  88. assert(this->Tree);
  89. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  90. assert(this->Tree == other.Tree);
  91. return this->Position == other.Position;
  92. }
  93. bool operator!=(iterator other) const
  94. {
  95. assert(this->Tree);
  96. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  97. return !(*this == other);
  98. }
  99. bool IsValid() const
  100. {
  101. if (!this->Tree) {
  102. return false;
  103. }
  104. return this->Position <= this->Tree->Data.size();
  105. }
  106. bool StrictWeakOrdered(iterator other) const
  107. {
  108. assert(this->Tree);
  109. assert(this->Tree == other.Tree);
  110. return this->Position < other.Position;
  111. }
  112. };
  113. iterator Root() const
  114. {
  115. return iterator(const_cast<cmLinkedTree*>(this), 0);
  116. }
  117. iterator Push(iterator it) { return Push_impl(it, T()); }
  118. iterator Push(iterator it, T t) { return Push_impl(it, std::move(t)); }
  119. bool IsLast(iterator it) { return it.Position == this->Data.size(); }
  120. iterator Pop(iterator it)
  121. {
  122. assert(!this->Data.empty());
  123. assert(this->UpPositions.size() == this->Data.size());
  124. bool const isLast = this->IsLast(it);
  125. ++it;
  126. // If this is the last entry then no other entry can refer
  127. // to it so we can drop its storage.
  128. if (isLast) {
  129. this->Data.pop_back();
  130. this->UpPositions.pop_back();
  131. }
  132. return it;
  133. }
  134. iterator Truncate()
  135. {
  136. assert(!this->UpPositions.empty());
  137. this->UpPositions.erase(this->UpPositions.begin() + 1,
  138. this->UpPositions.end());
  139. assert(!this->Data.empty());
  140. this->Data.erase(this->Data.begin() + 1, this->Data.end());
  141. return iterator(this, 1);
  142. }
  143. void Clear()
  144. {
  145. this->UpPositions.clear();
  146. this->Data.clear();
  147. }
  148. private:
  149. T& GetReference(PositionType pos) { return this->Data[pos]; }
  150. T* GetPointer(PositionType pos) { return &this->Data[pos]; }
  151. iterator Push_impl(iterator it, T&& t)
  152. {
  153. assert(this->UpPositions.size() == this->Data.size());
  154. assert(it.Position <= this->UpPositions.size());
  155. this->UpPositions.push_back(it.Position);
  156. this->Data.push_back(std::move(t));
  157. return iterator(this, this->UpPositions.size());
  158. }
  159. std::vector<T> Data;
  160. std::vector<PositionType> UpPositions;
  161. };
  162. #endif