2016-09-27 19:01:08 +00:00
|
|
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
2015-05-22 22:04:09 +00:00
|
|
|
#ifndef cmLinkedTree_h
|
|
|
|
#define cmLinkedTree_h
|
|
|
|
|
2017-08-25 18:39:02 +00:00
|
|
|
#include "cmConfigure.h" // IWYU pragma: keep
|
2016-09-01 18:05:48 +00:00
|
|
|
|
2019-09-06 20:58:06 +00:00
|
|
|
#include <cassert>
|
2016-11-05 20:40:14 +00:00
|
|
|
#include <vector>
|
2015-05-22 22:04:09 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
@brief A adaptor for traversing a tree structure in a vector
|
|
|
|
|
|
|
|
This class is not intended to be wholly generic like a standard library
|
|
|
|
container adaptor. Mostly it exists to facilitate code sharing for the
|
|
|
|
needs of the cmState. For example, the Truncate() method is a specific
|
|
|
|
requirement of the cmState.
|
|
|
|
|
2015-11-25 15:23:05 +00:00
|
|
|
An empty cmLinkedTree provides a Root() method, and an Push() method,
|
2015-05-22 22:04:09 +00:00
|
|
|
each of which return iterators. A Tree can be built up by extending
|
|
|
|
from the root, and then extending from any other iterator.
|
|
|
|
|
|
|
|
An iterator resulting from this tree construction can be
|
|
|
|
forward-only-iterated toward the root. Extending the tree never
|
|
|
|
invalidates existing iterators.
|
|
|
|
*/
|
2016-05-16 14:34:04 +00:00
|
|
|
template <typename T>
|
2015-05-22 22:04:09 +00:00
|
|
|
class cmLinkedTree
|
|
|
|
{
|
2019-08-23 21:25:56 +00:00
|
|
|
using PositionType = typename std::vector<T>::size_type;
|
|
|
|
using PointerType = T*;
|
|
|
|
using ReferenceType = T&;
|
2016-05-16 14:34:04 +00:00
|
|
|
|
2015-05-22 22:04:09 +00:00
|
|
|
public:
|
2018-12-30 20:55:14 +00:00
|
|
|
class iterator
|
2015-05-22 22:04:09 +00:00
|
|
|
{
|
|
|
|
friend class cmLinkedTree;
|
|
|
|
cmLinkedTree* Tree;
|
|
|
|
|
|
|
|
// The Position is always 'one past the end'.
|
|
|
|
PositionType Position;
|
|
|
|
|
|
|
|
iterator(cmLinkedTree* tree, PositionType pos)
|
2016-05-16 14:34:04 +00:00
|
|
|
: Tree(tree)
|
|
|
|
, Position(pos)
|
2015-05-22 22:04:09 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
iterator()
|
2017-08-22 21:42:36 +00:00
|
|
|
: Tree(nullptr)
|
2016-05-16 14:34:04 +00:00
|
|
|
, Position(0)
|
2015-05-22 22:04:09 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator++()
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Position <= this->Tree->Data.size());
|
|
|
|
assert(this->Position > 0);
|
|
|
|
this->Position = this->Tree->UpPositions[this->Position - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
PointerType operator->() const
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Position <= this->Tree->Data.size());
|
|
|
|
assert(this->Position > 0);
|
|
|
|
return this->Tree->GetPointer(this->Position - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
PointerType operator->()
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Position <= this->Tree->Data.size());
|
|
|
|
assert(this->Position > 0);
|
|
|
|
return this->Tree->GetPointer(this->Position - 1);
|
|
|
|
}
|
|
|
|
|
2015-06-08 18:09:55 +00:00
|
|
|
ReferenceType operator*() const
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Position <= this->Tree->Data.size());
|
|
|
|
assert(this->Position > 0);
|
|
|
|
return this->Tree->GetReference(this->Position - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReferenceType operator*()
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Position <= this->Tree->Data.size());
|
|
|
|
assert(this->Position > 0);
|
|
|
|
return this->Tree->GetReference(this->Position - 1);
|
|
|
|
}
|
|
|
|
|
2015-05-22 22:04:09 +00:00
|
|
|
bool operator==(iterator other) const
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
assert(this->Tree == other.Tree);
|
|
|
|
return this->Position == other.Position;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(iterator other) const
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree->UpPositions.size() == this->Tree->Data.size());
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsValid() const
|
|
|
|
{
|
2016-05-16 14:34:04 +00:00
|
|
|
if (!this->Tree) {
|
2015-05-22 22:04:09 +00:00
|
|
|
return false;
|
2016-05-16 14:34:04 +00:00
|
|
|
}
|
2015-05-22 22:04:09 +00:00
|
|
|
return this->Position <= this->Tree->Data.size();
|
|
|
|
}
|
2015-08-02 08:07:30 +00:00
|
|
|
|
|
|
|
bool StrictWeakOrdered(iterator other) const
|
|
|
|
{
|
|
|
|
assert(this->Tree);
|
|
|
|
assert(this->Tree == other.Tree);
|
|
|
|
return this->Position < other.Position;
|
|
|
|
}
|
2015-05-22 22:04:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
iterator Root() const
|
|
|
|
{
|
|
|
|
return iterator(const_cast<cmLinkedTree*>(this), 0);
|
|
|
|
}
|
|
|
|
|
2016-05-16 14:34:04 +00:00
|
|
|
iterator Push(iterator it) { return Push_impl(it, T()); }
|
2015-05-22 22:04:09 +00:00
|
|
|
|
2017-10-04 17:34:36 +00:00
|
|
|
iterator Push(iterator it, T t) { return Push_impl(it, std::move(t)); }
|
2015-05-22 22:04:09 +00:00
|
|
|
|
2016-05-16 14:34:04 +00:00
|
|
|
bool IsLast(iterator it) { return it.Position == this->Data.size(); }
|
2015-11-24 19:42:20 +00:00
|
|
|
|
|
|
|
iterator Pop(iterator it)
|
2016-05-16 14:34:04 +00:00
|
|
|
{
|
2015-11-24 19:42:20 +00:00
|
|
|
assert(!this->Data.empty());
|
|
|
|
assert(this->UpPositions.size() == this->Data.size());
|
|
|
|
bool const isLast = this->IsLast(it);
|
|
|
|
++it;
|
|
|
|
// If this is the last entry then no other entry can refer
|
|
|
|
// to it so we can drop its storage.
|
2016-05-16 14:34:04 +00:00
|
|
|
if (isLast) {
|
2015-11-24 19:42:20 +00:00
|
|
|
this->Data.pop_back();
|
|
|
|
this->UpPositions.pop_back();
|
|
|
|
}
|
2016-05-16 14:34:04 +00:00
|
|
|
return it;
|
|
|
|
}
|
2015-11-24 19:42:20 +00:00
|
|
|
|
2015-05-22 22:04:09 +00:00
|
|
|
iterator Truncate()
|
|
|
|
{
|
2016-09-15 21:59:29 +00:00
|
|
|
assert(!this->UpPositions.empty());
|
2015-05-22 22:04:09 +00:00
|
|
|
this->UpPositions.erase(this->UpPositions.begin() + 1,
|
|
|
|
this->UpPositions.end());
|
2016-09-15 21:59:29 +00:00
|
|
|
assert(!this->Data.empty());
|
2015-05-22 22:04:09 +00:00
|
|
|
this->Data.erase(this->Data.begin() + 1, this->Data.end());
|
|
|
|
return iterator(this, 1);
|
|
|
|
}
|
|
|
|
|
2015-06-13 23:38:57 +00:00
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
this->UpPositions.clear();
|
|
|
|
this->Data.clear();
|
|
|
|
}
|
|
|
|
|
2015-05-22 22:04:09 +00:00
|
|
|
private:
|
2016-05-16 14:34:04 +00:00
|
|
|
T& GetReference(PositionType pos) { return this->Data[pos]; }
|
2015-05-22 22:04:09 +00:00
|
|
|
|
2016-05-16 14:34:04 +00:00
|
|
|
T* GetPointer(PositionType pos) { return &this->Data[pos]; }
|
2015-05-22 22:04:09 +00:00
|
|
|
|
2017-10-04 17:34:36 +00:00
|
|
|
iterator Push_impl(iterator it, T&& t)
|
2015-05-22 22:04:09 +00:00
|
|
|
{
|
|
|
|
assert(this->UpPositions.size() == this->Data.size());
|
|
|
|
assert(it.Position <= this->UpPositions.size());
|
|
|
|
this->UpPositions.push_back(it.Position);
|
2017-10-04 17:34:36 +00:00
|
|
|
this->Data.push_back(std::move(t));
|
2015-05-22 22:04:09 +00:00
|
|
|
return iterator(this, this->UpPositions.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<T> Data;
|
|
|
|
std::vector<PositionType> UpPositions;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|