cmLinkedTree.h 5.1 KB

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