cmake/Source/cmLinkedTree.h

190 lines
5.1 KiB
C
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2021-09-14 00:13:48 +02:00
#pragma once
2015-11-17 17:22:37 +01:00
2018-01-26 17:06:56 +01:00
#include "cmConfigure.h" // IWYU pragma: keep
2016-10-30 18:24:19 +01:00
2020-02-01 23:06:01 +01:00
#include <cassert>
2017-04-14 19:02:05 +02:00
#include <vector>
2015-11-17 17:22:37 +01: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-12-03 18:43:53 +01:00
An empty cmLinkedTree provides a Root() method, and an Push() method,
2015-11-17 17:22:37 +01: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-07-09 11:21:54 +02:00
template <typename T>
2015-11-17 17:22:37 +01:00
class cmLinkedTree
{
2020-02-01 23:06:01 +01:00
using PositionType = typename std::vector<T>::size_type;
using PointerType = T*;
using ReferenceType = T&;
2016-07-09 11:21:54 +02:00
2015-11-17 17:22:37 +01:00
public:
2019-11-11 23:01:05 +01:00
class iterator
2015-11-17 17:22:37 +01:00
{
friend class cmLinkedTree;
cmLinkedTree* Tree;
// The Position is always 'one past the end'.
PositionType Position;
iterator(cmLinkedTree* tree, PositionType pos)
2016-07-09 11:21:54 +02:00
: Tree(tree)
, Position(pos)
2015-11-17 17:22:37 +01:00
{
}
public:
iterator()
2018-01-26 17:06:56 +01:00
: Tree(nullptr)
2016-07-09 11:21:54 +02:00
, Position(0)
2015-11-17 17:22:37 +01: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);
}
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);
}
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-07-09 11:21:54 +02:00
if (!this->Tree) {
2015-11-17 17:22:37 +01:00
return false;
2016-07-09 11:21:54 +02:00
}
2015-11-17 17:22:37 +01:00
return this->Position <= this->Tree->Data.size();
}
bool StrictWeakOrdered(iterator other) const
{
assert(this->Tree);
assert(this->Tree == other.Tree);
return this->Position < other.Position;
}
};
iterator Root() const
{
return iterator(const_cast<cmLinkedTree*>(this), 0);
}
2021-09-14 00:13:48 +02:00
iterator Push(iterator it) { return this->Push_impl(it, T()); }
2015-11-17 17:22:37 +01:00
2021-09-14 00:13:48 +02:00
iterator Push(iterator it, T t) { return this->Push_impl(it, std::move(t)); }
2015-11-17 17:22:37 +01:00
2016-07-09 11:21:54 +02:00
bool IsLast(iterator it) { return it.Position == this->Data.size(); }
2015-12-03 18:43:53 +01:00
iterator Pop(iterator it)
2016-07-09 11:21:54 +02:00
{
2015-12-03 18:43:53 +01: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-07-09 11:21:54 +02:00
if (isLast) {
2015-12-03 18:43:53 +01:00
this->Data.pop_back();
this->UpPositions.pop_back();
}
2016-07-09 11:21:54 +02:00
return it;
}
2015-12-03 18:43:53 +01:00
2015-11-17 17:22:37 +01:00
iterator Truncate()
{
2016-10-30 18:24:19 +01:00
assert(!this->UpPositions.empty());
2015-11-17 17:22:37 +01:00
this->UpPositions.erase(this->UpPositions.begin() + 1,
this->UpPositions.end());
2016-10-30 18:24:19 +01:00
assert(!this->Data.empty());
2015-11-17 17:22:37 +01:00
this->Data.erase(this->Data.begin() + 1, this->Data.end());
return iterator(this, 1);
}
void Clear()
{
this->UpPositions.clear();
this->Data.clear();
}
private:
2016-07-09 11:21:54 +02:00
T& GetReference(PositionType pos) { return this->Data[pos]; }
2015-11-17 17:22:37 +01:00
2016-07-09 11:21:54 +02:00
T* GetPointer(PositionType pos) { return &this->Data[pos]; }
2015-11-17 17:22:37 +01:00
2018-04-23 21:13:27 +02:00
iterator Push_impl(iterator it, T&& t)
2015-11-17 17:22:37 +01:00
{
assert(this->UpPositions.size() == this->Data.size());
assert(it.Position <= this->UpPositions.size());
this->UpPositions.push_back(it.Position);
2018-04-23 21:13:27 +02:00
this->Data.push_back(std::move(t));
2015-11-17 17:22:37 +01:00
return iterator(this, this->UpPositions.size());
}
std::vector<T> Data;
std::vector<PositionType> UpPositions;
};