cmLinkedTree.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2015 Stephen Kelly <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #ifndef cmLinkedTree_h
  11. #define cmLinkedTree_h
  12. #include <cmConfigure.h>
  13. #include "cmStandardIncludes.h"
  14. #include <assert.h>
  15. /**
  16. @brief A adaptor for traversing a tree structure in a vector
  17. This class is not intended to be wholly generic like a standard library
  18. container adaptor. Mostly it exists to facilitate code sharing for the
  19. needs of the cmState. For example, the Truncate() method is a specific
  20. requirement of the cmState.
  21. An empty cmLinkedTree provides a Root() method, and an Push() method,
  22. each of which return iterators. A Tree can be built up by extending
  23. from the root, and then extending from any other iterator.
  24. An iterator resulting from this tree construction can be
  25. forward-only-iterated toward the root. Extending the tree never
  26. invalidates existing iterators.
  27. */
  28. template <typename T>
  29. class cmLinkedTree
  30. {
  31. typedef typename std::vector<T>::size_type PositionType;
  32. typedef T* PointerType;
  33. typedef T& ReferenceType;
  34. public:
  35. class iterator : public std::iterator<std::forward_iterator_tag, T>
  36. {
  37. friend class cmLinkedTree;
  38. cmLinkedTree* Tree;
  39. // The Position is always 'one past the end'.
  40. PositionType Position;
  41. iterator(cmLinkedTree* tree, PositionType pos)
  42. : Tree(tree)
  43. , Position(pos)
  44. {
  45. }
  46. public:
  47. iterator()
  48. : Tree(CM_NULLPTR)
  49. , Position(0)
  50. {
  51. }
  52. void operator++()
  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. this->Position = this->Tree->UpPositions[this->Position - 1];
  59. }
  60. PointerType operator->() const
  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. PointerType operator->()
  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->GetPointer(this->Position - 1);
  75. }
  76. ReferenceType operator*() const
  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. ReferenceType operator*()
  85. {
  86. assert(this->Tree);
  87. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  88. assert(this->Position <= this->Tree->Data.size());
  89. assert(this->Position > 0);
  90. return this->Tree->GetReference(this->Position - 1);
  91. }
  92. bool operator==(iterator other) const
  93. {
  94. assert(this->Tree);
  95. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  96. assert(this->Tree == other.Tree);
  97. return this->Position == other.Position;
  98. }
  99. bool operator!=(iterator other) const
  100. {
  101. assert(this->Tree);
  102. assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
  103. return !(*this == other);
  104. }
  105. bool IsValid() const
  106. {
  107. if (!this->Tree) {
  108. return false;
  109. }
  110. return this->Position <= this->Tree->Data.size();
  111. }
  112. bool StrictWeakOrdered(iterator other) const
  113. {
  114. assert(this->Tree);
  115. assert(this->Tree == other.Tree);
  116. return this->Position < other.Position;
  117. }
  118. };
  119. iterator Root() const
  120. {
  121. return iterator(const_cast<cmLinkedTree*>(this), 0);
  122. }
  123. iterator Push(iterator it) { return Push_impl(it, T()); }
  124. iterator Push(iterator it, T t) { return Push_impl(it, t); }
  125. bool IsLast(iterator it) { return it.Position == this->Data.size(); }
  126. iterator Pop(iterator it)
  127. {
  128. assert(!this->Data.empty());
  129. assert(this->UpPositions.size() == this->Data.size());
  130. bool const isLast = this->IsLast(it);
  131. ++it;
  132. // If this is the last entry then no other entry can refer
  133. // to it so we can drop its storage.
  134. if (isLast) {
  135. this->Data.pop_back();
  136. this->UpPositions.pop_back();
  137. }
  138. return it;
  139. }
  140. iterator Truncate()
  141. {
  142. assert(!this->UpPositions.empty());
  143. this->UpPositions.erase(this->UpPositions.begin() + 1,
  144. this->UpPositions.end());
  145. assert(!this->Data.empty());
  146. this->Data.erase(this->Data.begin() + 1, this->Data.end());
  147. return iterator(this, 1);
  148. }
  149. void Clear()
  150. {
  151. this->UpPositions.clear();
  152. this->Data.clear();
  153. }
  154. private:
  155. T& GetReference(PositionType pos) { return this->Data[pos]; }
  156. T* GetPointer(PositionType pos) { return &this->Data[pos]; }
  157. iterator Push_impl(iterator it, T t)
  158. {
  159. assert(this->UpPositions.size() == this->Data.size());
  160. assert(it.Position <= this->UpPositions.size());
  161. this->UpPositions.push_back(it.Position);
  162. this->Data.push_back(t);
  163. return iterator(this, this->UpPositions.size());
  164. }
  165. std::vector<T> Data;
  166. std::vector<PositionType> UpPositions;
  167. };
  168. #endif