Files
revng-revng/include/revng/ADT/GenericGraph.h
2026-02-25 14:10:44 +01:00

1635 lines
60 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <type_traits>
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/GraphWriter.h"
#include "revng/ADT/STLExtras.h"
#include "revng/Support/Debug.h"
#include "revng/Support/Error.h"
/// GenericGraph is our implementation of a universal graph architecture.
/// First and foremost, it's tailored for the revng codebase, but maybe you
/// can find it useful as well, that's why it's released under the MIT License.
///
/// To use the Graph, you need to make you choice of the node type. We're
/// currently supporting three architectures:
///
/// - ForwardNode - a trivially-simple single-linked node. It uses the least
/// memory, because each node only stores the list of its successors.
/// This makes backwards iteration impossible without the reference to
/// the whole graph (and really expensive even in those cases).
///
/// - BidirectionalNode - a simple double-linked node. It stores the both
/// lists of its successors and predecessors. Take note, that for the sake
/// of implementation simplicity this node stores COPIES of the labels.
/// It's only suitable to be used with cheap to copy labels which are never
/// mutated. There are plans on making them explicitly immutable (TODO),
/// as such you can consider label mutation a deprecated behavior.
///
/// - MutableEdgeNode - a double-linked node with dynamically allocated
/// labels. It is similar to BidirectionalNode except it stores edge labels
/// on the heap. It's slower and uses more memory but allows for safe label
/// modification as well as controls that nodes and edges are removed
/// safely, with the other "halves" cleaned up as well.
/// Note that it's disallowed to have a mutable edge graph without edge
/// labels. Use `BidirectionalNode` in those cases.
///
/// - The node you're going to write - No-one knows the needs of your
/// project better than you. That's why the best data structure is the one
/// you are going to write. So just inherit one of our nodes, or even copy
/// it and modify it so that it suits your graphs as nicely as possible.
///
/// On the side-note, we're providing a couple of helpful concepts to help
/// differentiate different node types. This is helpful in the projects that
/// use multiple different graph architectures side by side.
template<typename T>
concept SpecializationOfForwardNode = requires { T::is_forward_node; };
template<typename T>
concept StrictSpecializationOfBidirectionalNode = requires {
T::is_bidirectional_node;
typename llvm::Inverse<T *>;
};
template<typename T>
concept StrictSpecializationOfMutableEdgeNode = requires {
T::is_mutable_edge_node;
typename llvm::Inverse<T *>;
};
template<typename T>
concept SpecializationOfGenericGraph = requires {
T::is_generic_graph;
typename T::Node;
};
struct Empty {
bool operator==(const Empty &) const { return true; }
};
template<typename Node, size_t SmallSize = 16, bool HasEntryNode = true>
class GenericGraph;
template<typename T, typename BaseType>
class Parent : public BaseType {
public:
template<typename... ArgTypes>
explicit Parent(ArgTypes &&...Args) :
BaseType(std::forward<ArgTypes>(Args)...), TheParent(nullptr) {}
Parent(const Parent &) = default;
Parent(Parent &&) = default;
private:
T *TheParent = nullptr;
public:
T *getParent() const { return TheParent; }
void setParent(T *Parent) { this->TheParent = Parent; }
};
/// Data structure for edge labels
template<typename Node, typename EdgeLabel>
struct Edge : public EdgeLabel {
Edge(Node *Neighbor) : Neighbor(Neighbor) {}
Edge(Node *Neighbor, EdgeLabel EL) : EdgeLabel(EL), Neighbor(Neighbor) {}
Node *Neighbor = nullptr;
bool operator==(const Edge &Other) const {
return Other.Neighbor == Neighbor and EdgeLabel::operator==(Other);
}
};
//
// Structured binding support for Edge
//
template<size_t I, typename Node, typename EdgeLabel>
auto &get(Edge<Node, EdgeLabel> &E) {
if constexpr (I == 0)
return E.Neighbor;
else
return static_cast<EdgeLabel &>(E);
}
template<size_t I, typename Node, typename EdgeLabel>
auto &get(const Edge<Node, EdgeLabel> &E) {
if constexpr (I == 0)
return E.Neighbor;
else
return static_cast<EdgeLabel &>(E);
}
template<size_t I, typename Node, typename EdgeLabel>
auto &&get(Edge<Node, EdgeLabel> &&E) {
if constexpr (I == 0)
return std::move(E.Neighbor);
else
return std::move(static_cast<EdgeLabel &&>(E));
}
namespace std {
template<typename Node, typename EdgeLabel>
struct std::tuple_size<Edge<Node, EdgeLabel>>
: std::integral_constant<size_t, 2> {};
template<typename Node, typename EdgeLabel>
struct std::tuple_element<0, Edge<Node, EdgeLabel>> {
using type = Node *;
};
template<typename Node, typename EdgeLabel>
struct std::tuple_element<1, Edge<Node, EdgeLabel>> {
using type = EdgeLabel;
};
} // namespace std
namespace revng::detail {
/// We require to operate some decision to select a base type that Forward node
/// will extend. Those decisions are wrapped inside this struct to remove
/// clutter.
///
/// \note At this step Forward edge has not been declared yet, thus we accept a
/// template parameter that has the same signature as ForwardEdge that
/// will be declared later. This allows us to use it as if it was
/// declared, provided that only the real ForwardEdge is used as this
/// argument.
template<typename Node,
typename EdgeLabel,
bool NeedsParent,
size_t SmallSize,
template<typename, typename, bool, size_t, typename, size_t, bool>
class ForwardEdge,
typename FinalType,
size_t ParentSmallSize,
bool ParentHasEntryNode>
struct ForwardNodeBaseTCalc {
static constexpr bool
NoDerivation = std::is_same_v<FinalType, std::false_type>;
using FWNode = ForwardEdge<Node,
EdgeLabel,
NeedsParent,
SmallSize,
FinalType,
ParentSmallSize,
ParentHasEntryNode>;
using DerivedType = std::conditional_t<NoDerivation, FWNode, FinalType>;
using GenericGraph = GenericGraph<DerivedType,
ParentSmallSize,
ParentHasEntryNode>;
using ParentType = Parent<GenericGraph, Node>;
using Result = std::conditional_t<NeedsParent, ParentType, Node>;
};
} // namespace revng::detail
/// Basic nodes type, only forward edges, possibly with parent
template<typename Node,
typename EdgeLabel = Empty,
bool NeedsParent = true,
size_t SmallSize = 2,
typename FinalType = std::false_type,
size_t ParentSmallSize = 16,
bool ParentHasEntryNode = true>
class ForwardNode
: public revng::detail::ForwardNodeBaseTCalc<Node,
EdgeLabel,
NeedsParent,
SmallSize,
ForwardNode,
FinalType,
ParentSmallSize,
ParentHasEntryNode>::Result {
public:
static constexpr bool is_forward_node = true;
static constexpr bool HasParent = NeedsParent;
using TypeCalc = revng::detail::ForwardNodeBaseTCalc<Node,
EdgeLabel,
NeedsParent,
SmallSize,
ForwardNode,
FinalType,
ParentSmallSize,
ParentHasEntryNode>;
using DerivedType = typename TypeCalc::DerivedType;
using Base = typename TypeCalc::Result;
using Edge = Edge<DerivedType, EdgeLabel>;
using NodeData = Node;
public:
template<typename... ArgTypes>
explicit ForwardNode(ArgTypes &&...Args) :
Base(std::forward<ArgTypes>(Args)...) {}
ForwardNode(const ForwardNode &) = default;
ForwardNode(ForwardNode &&) = default;
ForwardNode &operator=(const ForwardNode &) = default;
ForwardNode &operator=(ForwardNode &&) = default;
NodeData &data() { return *this; }
const NodeData &data() const { return *this; }
NodeData copyData() const { return *this; }
NodeData &&moveData() { return std::move(*this); }
public:
static DerivedType *&getNeighbor(Edge &E) { return E.Neighbor; }
static const DerivedType *const &getConstNeighbor(const Edge &E) {
return E.Neighbor;
}
static Edge *getEdgePointer(Edge &E) { return &E; }
static const Edge *getConstEdgePointer(const Edge &E) { return &E; }
private:
using iterator_filter = decltype(&getNeighbor);
using const_iterator_filter = decltype(&getConstNeighbor);
public:
using NeighborContainer = llvm::SmallVector<Edge, SmallSize>;
using child_iterator = llvm::mapped_iterator<Edge *, iterator_filter>;
using const_child_iterator = llvm::mapped_iterator<const Edge *,
const_iterator_filter>;
using edge_iterator = typename NeighborContainer::iterator;
using const_edge_iterator = typename NeighborContainer::const_iterator;
public:
// This stuff is needed by the DominatorTree implementation
void printAsOperand(llvm::raw_ostream &, bool) const { revng_abort(); }
public:
void addSuccessor(DerivedType *NewSuccessor) {
Successors.emplace_back(NewSuccessor);
}
void addSuccessor(DerivedType *NewSuccessor, EdgeLabel EL) {
Successors.emplace_back(NewSuccessor, EL);
}
public:
child_iterator removeSuccessor(child_iterator It) {
auto InternalIt = Successors.erase(It.getCurrent());
return child_iterator(InternalIt, getNeighbor);
}
edge_iterator removeSuccessorEdge(edge_iterator It) {
return Successors.erase(It);
}
void clearSuccessors() { Successors.clear(); }
public:
llvm::iterator_range<const_child_iterator> successors() const {
return toNeighborRange(Successors);
}
llvm::iterator_range<child_iterator> successors() {
return toNeighborRange(Successors);
}
llvm::iterator_range<const_edge_iterator> successor_edges() const {
return llvm::make_range(Successors.begin(), Successors.end());
}
llvm::iterator_range<edge_iterator> successor_edges() {
return llvm::make_range(Successors.begin(), Successors.end());
}
bool hasSuccessors() const { return Successors.size() != 0; }
size_t successorCount() const { return Successors.size(); }
bool hasSuccessor(DerivedType const *S) const {
auto Iterator = llvm::find_if(Successors,
[S](auto &N) { return N.Neighbor == S; });
return Iterator != Successors.end();
}
protected:
static llvm::iterator_range<child_iterator>
toNeighborRange(NeighborContainer &Neighbors) {
auto Range = llvm::make_range(Neighbors.begin(), Neighbors.end());
return llvm::map_range(Range, &getNeighbor);
}
static llvm::iterator_range<const_child_iterator>
toNeighborRange(const NeighborContainer &Neighbors) {
auto Range = llvm::make_range(Neighbors.begin(), Neighbors.end());
return llvm::map_range(Range, &getConstNeighbor);
}
protected:
NeighborContainer Successors;
};
namespace revng::detail {
/// To remove clutter from BidirectionalNode, the computation of some types are
/// done in this class.
///
/// \note At this step BidirectionalEdge has not been declared yet, thus we
/// accept a template parameter that has the same signature as
/// BidirectionalEdge that will be declared later. This allows us to use
/// it as if it was declared, provided that only the real
/// BidirectionalEdge is used as this argument.
template<typename Node,
typename EdgeLabel,
bool NeedsParent,
size_t SmallSize,
template<typename, typename, bool, size_t>
class BidirectionalNode>
struct BidirectionalNodeBaseTCalc {
using BDNode = BidirectionalNode<Node, EdgeLabel, NeedsParent, SmallSize>;
using Result = ForwardNode<Node, EdgeLabel, NeedsParent, SmallSize, BDNode>;
};
} // namespace revng::detail
using revng::detail::BidirectionalNodeBaseTCalc;
/// Same as ForwardNode, but with backward links too
// TODO: Make edge labels immutable
template<typename Node,
typename EdgeLabel = Empty,
bool NeedsParent = true,
size_t SmallSize = 2>
class BidirectionalNode
: public BidirectionalNodeBaseTCalc<Node,
EdgeLabel,
NeedsParent,
SmallSize,
BidirectionalNode>::Result {
public:
static const bool is_bidirectional_node = true;
public:
using NodeData = Node;
using EdgeLabelData = EdgeLabel;
using Base = ForwardNode<Node,
EdgeLabel,
NeedsParent,
SmallSize,
BidirectionalNode>;
using NeighborContainer = typename Base::NeighborContainer;
using child_iterator = typename Base::child_iterator;
using const_child_iterator = typename Base::const_child_iterator;
using edge_iterator = typename Base::edge_iterator;
using const_edge_iterator = typename Base::const_edge_iterator;
public:
template<typename... ArgTypes>
explicit BidirectionalNode(ArgTypes &&...Args) :
Base(std::forward<ArgTypes>(Args)...) {}
BidirectionalNode(const BidirectionalNode &) = default;
BidirectionalNode(BidirectionalNode &&) = default;
NodeData &data() { return *this; }
const NodeData &data() const { return *this; }
NodeData copyData() const { return *this; }
NodeData &&moveData() { return std::move(*this); }
public:
void addSuccessor(BidirectionalNode *NewSuccessor) {
Base::Successors.emplace_back(NewSuccessor);
NewSuccessor->Predecessors.emplace_back(this);
}
void addSuccessor(BidirectionalNode *NewSuccessor, EdgeLabel EL) {
Base::Successors.emplace_back(NewSuccessor, EL);
NewSuccessor->Predecessors.emplace_back(this, EL);
}
void addPredecessor(BidirectionalNode *NewPredecessor) {
Predecessors.emplace_back(NewPredecessor);
NewPredecessor->Successors.emplace_back(this);
}
void addPredecessor(BidirectionalNode *NewPredecessor, EdgeLabel EL) {
Predecessors.emplace_back(NewPredecessor, EL);
NewPredecessor->Successors.emplace_back(this, EL);
}
public:
void removePredecessor(child_iterator It) {
BidirectionalNode *Predecessor = *It;
bool Found = false;
auto PredecessorSuccessors = Predecessor->successor_edges();
for (auto PredecessorIt = PredecessorSuccessors.begin(),
Last = PredecessorSuccessors.end();
PredecessorIt != Last;) {
auto Edge = *PredecessorIt;
Edge.Neighbor = this;
if (Edge == *PredecessorIt) {
Predecessor->Successors.erase(PredecessorIt);
Found = true;
break;
} else {
++PredecessorIt;
}
}
revng_assert(Found);
Predecessors.erase(It.getCurrent());
}
void removePredecessorEdge(edge_iterator It) {
Edge Edge = *It;
bool Found = false;
// Extract predecessor
auto Predecessor = Edge.Neighbor;
// Invert the edge direction
Edge.Neighbor = this;
auto PredecessorSuccessors = Predecessor->successor_edges();
for (auto PredecessorIt = PredecessorSuccessors.begin(),
Last = PredecessorSuccessors.end();
PredecessorIt != Last;) {
if (Edge == *PredecessorIt) {
Predecessor->Successors.erase(PredecessorIt);
Found = true;
break;
} else {
++PredecessorIt;
}
}
revng_assert(Found);
Predecessors.erase(It);
}
void clearPredecessors() {
while (Predecessors.size())
removePredecessorEdge(Predecessors.begin());
}
void removeSuccessor(child_iterator It) {
BidirectionalNode *Successor = *It;
bool Found = false;
auto SuccessorPredecessors = Successor->predecessor_edges();
for (auto SuccessorIt = SuccessorPredecessors.begin(),
Last = SuccessorPredecessors.end();
SuccessorIt != Last;) {
auto Edge = *SuccessorIt;
Edge.Neighbor = this;
if (Edge == *SuccessorIt) {
Successor->Predecessors.erase(SuccessorIt);
Found = true;
break;
} else {
++SuccessorIt;
}
}
revng_assert(Found);
Base::Successors.erase(It.getCurrent());
}
void removeSuccessorEdge(edge_iterator It) {
auto Edge = *It;
bool Found = false;
// Extract successor
auto Successor = Edge.Neighbor;
// Invert edge direction
Edge.Neighbor = this;
auto SuccessorPredecessors = Successor->predecessor_edges();
for (auto SuccessorIt = SuccessorPredecessors.begin(),
Last = SuccessorPredecessors.end();
SuccessorIt != Last;) {
if (Edge == *SuccessorIt) {
Successor->Predecessors.erase(SuccessorIt);
Found = true;
break;
} else {
++SuccessorIt;
}
}
revng_assert(Found);
this->Successors.erase(It);
}
void clearSuccessors() {
while (Base::Successors.size())
removeSuccessorEdge(Base::Successors.begin());
}
public:
llvm::iterator_range<const_child_iterator> predecessors() const {
return this->toNeighborRange(Predecessors);
}
llvm::iterator_range<child_iterator> predecessors() {
return this->toNeighborRange(Predecessors);
}
llvm::iterator_range<const_edge_iterator> predecessor_edges() const {
return llvm::make_range(Predecessors.begin(), Predecessors.end());
}
llvm::iterator_range<edge_iterator> predecessor_edges() {
return llvm::make_range(Predecessors.begin(), Predecessors.end());
}
bool hasPredecessors() const { return Predecessors.size() != 0; }
size_t predecessorCount() const { return Predecessors.size(); }
bool hasPredecessor(BidirectionalNode const *P) const {
auto Iterator = llvm::find_if(Predecessors,
[P](auto &N) { return N.Neighbor == P; });
return Iterator != Predecessors.end();
}
private:
NeighborContainer Predecessors;
};
namespace revng::detail {
/// The parameters deciding specifics of the base type `MutableEdgeNode`
/// extends are non-trivial. That's why those decision were wrapped
/// inside this struct to minimize clutter.
///
/// \note At this step `TheNode` has not been declared yet, thus we accept a
/// template parameter that has the same signature as `TheNode` that
/// will be declared later. This allows us to use it as if it was
/// declared, provided that only the real `TheNode` is used as this
/// argument.
template<typename Node,
typename EdgeLabel,
bool NeedsParent,
size_t SmallSize,
template<typename, typename, bool, size_t, typename, size_t, bool>
class TheNode,
typename FinalType,
size_t ParentSmallSize,
bool ParentHasEntryNode>
struct MutableEdgeNodeBaseTCalc {
static constexpr bool
NoDerivation = std::is_same_v<FinalType, std::false_type>;
using NodeType = TheNode<Node,
EdgeLabel,
NeedsParent,
SmallSize,
FinalType,
ParentSmallSize,
ParentHasEntryNode>;
using DerivedType = std::conditional_t<NoDerivation, NodeType, FinalType>;
using GenericGraph = GenericGraph<DerivedType,
ParentSmallSize,
ParentHasEntryNode>;
using ParentType = Parent<GenericGraph, Node>;
using Result = std::conditional_t<NeedsParent, ParentType, Node>;
};
template<typename NodeType, typename LabelType>
struct OwningEdge {
NodeType *Neighbor = nullptr;
std::unique_ptr<LabelType> Label;
};
template<typename NodeType, typename LabelType>
struct NonOwningEdge {
NodeType *Neighbor = nullptr;
LabelType *Label = nullptr;
};
template<typename NodeType, typename LabelType>
struct EdgeView {
NodeType *Neighbor = nullptr;
LabelType *Label = nullptr;
explicit EdgeView(OwningEdge<NodeType, LabelType> &E) :
Neighbor(E.Neighbor), Label(E.Label.get()) {}
explicit EdgeView(NonOwningEdge<NodeType, LabelType> &E) :
Neighbor(E.Neighbor), Label(E.Label) {}
};
template<typename NodeType, typename LabelType>
struct ConstEdgeView {
NodeType const *Neighbor;
LabelType const *Label;
explicit ConstEdgeView(OwningEdge<NodeType, LabelType> const &E) :
Neighbor(E.Neighbor), Label(E.Label.get()) {}
explicit ConstEdgeView(NonOwningEdge<NodeType, LabelType> const &E) :
Neighbor(E.Neighbor), Label(E.Label) {}
};
} // namespace revng::detail
/// A node type suitable for graphs where the edge labels are not cheap
/// to copy or need to be modified often.
template<typename Node,
typename EdgeLabel,
bool NeedsParent = true,
size_t SmallSize = 2,
typename FinalType = std::false_type,
size_t ParentSmallSize = 16,
bool ParentHasEntryNode = true>
class MutableEdgeNode
: public revng::detail::MutableEdgeNodeBaseTCalc<Node,
EdgeLabel,
NeedsParent,
SmallSize,
MutableEdgeNode,
FinalType,
ParentSmallSize,
ParentHasEntryNode>::Result {
public:
static constexpr bool is_mutable_edge_node = true;
static constexpr bool HasParent = NeedsParent;
using TypeCalc = revng::detail::MutableEdgeNodeBaseTCalc<Node,
EdgeLabel,
NeedsParent,
SmallSize,
MutableEdgeNode,
FinalType,
ParentSmallSize,
ParentHasEntryNode>;
using DerivedType = typename TypeCalc::DerivedType;
using Base = typename TypeCalc::Result;
using NodeData = Node;
using EdgeLabelData = EdgeLabel;
public:
using Edge = EdgeLabel;
using EdgeView = revng::detail::EdgeView<DerivedType, EdgeLabel>;
using ConstEdgeView = revng::detail::ConstEdgeView<DerivedType, EdgeLabel>;
protected:
using OwningEdge = revng::detail::OwningEdge<DerivedType, EdgeLabel>;
using NonOwningEdge = revng::detail::NonOwningEdge<DerivedType, EdgeLabel>;
using EdgeOwnerContainer = llvm::SmallVector<OwningEdge, SmallSize>;
using EdgeViewContainer = llvm::SmallVector<NonOwningEdge, SmallSize>;
public:
template<typename... ArgTypes>
explicit MutableEdgeNode(ArgTypes &&...Args) :
Base(std::forward<ArgTypes>(Args)...) {}
MutableEdgeNode(const MutableEdgeNode &) = default;
MutableEdgeNode(MutableEdgeNode &&) = default;
MutableEdgeNode &operator=(const MutableEdgeNode &) = default;
MutableEdgeNode &operator=(MutableEdgeNode &&) = default;
NodeData &data() { return *this; }
const NodeData &data() const { return *this; }
NodeData copyData() const { return *this; }
NodeData &&moveData() { return std::move(*this); }
public:
// This stuff is needed by the DominatorTree implementation
void printAsOperand(llvm::raw_ostream &, bool) const { revng_abort(); }
public:
EdgeView addSuccessor(MutableEdgeNode *NewSuccessor, EdgeLabel EL = {}) {
auto &&[Owner, View] = constructEdge(this, NewSuccessor, std::move(EL));
auto &Output = Successors.emplace_back(std::move(Owner));
NewSuccessor->Predecessors.emplace_back(std::move(View));
return EdgeView(Output);
}
EdgeView addPredecessor(MutableEdgeNode *NewPredecessor, EdgeLabel EL = {}) {
auto &&[Owner, View] = constructEdge(NewPredecessor, this, std::move(EL));
auto &Output = NewPredecessor->Successors.emplace_back(std::move(Owner));
Predecessors.emplace_back(std::move(View));
return EdgeView(Output);
}
protected:
struct SuccessorFilters {
static EdgeView toView(OwningEdge &E) { return EdgeView(E); }
static ConstEdgeView toConstView(OwningEdge const &E) {
return ConstEdgeView(E);
}
static DerivedType *&toNeighbor(OwningEdge &E) { return E.Neighbor; }
static DerivedType const *const &toConstNeighbor(OwningEdge const &E) {
return E.Neighbor;
}
};
struct PredecessorFilters {
static EdgeView toView(NonOwningEdge &E) { return EdgeView(E); }
static ConstEdgeView toConstView(NonOwningEdge const &E) {
return ConstEdgeView(E);
}
static DerivedType *&toNeighbor(NonOwningEdge &E) { return E.Neighbor; }
static DerivedType const *const &toConstNeighbor(NonOwningEdge const &E) {
return E.Neighbor;
}
};
private:
template<typename IteratorType, typename FunctionType>
using mapped = revng::mapped_iterator<IteratorType, FunctionType>;
using SuccPointer = OwningEdge *;
using CSuccPointer = const OwningEdge *;
using PredPointer = NonOwningEdge *;
using CPredPointer = const NonOwningEdge *;
using RSuccPointer = std::reverse_iterator<OwningEdge *>;
using CRSuccPointer = std::reverse_iterator<const OwningEdge *>;
using RPredPointer = std::reverse_iterator<NonOwningEdge *>;
using CRPredPointer = std::reverse_iterator<const NonOwningEdge *>;
using SuccV = std::decay_t<decltype(SuccessorFilters::toView)>;
using CSuccV = std::decay_t<decltype(SuccessorFilters::toConstView)>;
using SuccN = std::decay_t<decltype(SuccessorFilters::toNeighbor)>;
using CSuccN = std::decay_t<decltype(SuccessorFilters::toConstNeighbor)>;
using PredV = std::decay_t<decltype(PredecessorFilters::toView)>;
using CPredV = std::decay_t<decltype(PredecessorFilters::toConstView)>;
using PredN = std::decay_t<decltype(PredecessorFilters::toNeighbor)>;
using CPredN = std::decay_t<decltype(PredecessorFilters::toConstNeighbor)>;
public:
using SuccessorEdgeIterator = mapped<SuccPointer, SuccV>;
using ConstSuccessorEdgeIterator = mapped<CSuccPointer, CSuccV>;
using SuccessorIterator = mapped<SuccPointer, SuccN>;
using ConstSuccessorIterator = mapped<CSuccPointer, CSuccN>;
using PredecessorEdgeIterator = mapped<PredPointer, PredV>;
using ConstPredecessorEdgeIterator = mapped<CPredPointer, CPredV>;
using PredecessorIterator = mapped<PredPointer, PredN>;
using ConstPredecessorIterator = mapped<CPredPointer, CPredN>;
using ReverseSuccessorEdgeIterator = mapped<RSuccPointer, SuccV>;
using ConstReverseSuccessorEdgeIterator = mapped<CRSuccPointer, CSuccV>;
using ReverseSuccessorIterator = mapped<RSuccPointer, SuccN>;
using ConstReverseSuccessorIterator = mapped<CRSuccPointer, CSuccN>;
using ReversePredecessorEdgeIterator = mapped<RPredPointer, PredV>;
using ConstReversePredecessorEdgeIterator = mapped<CRPredPointer, CPredV>;
using ReversePredecessorIterator = mapped<RPredPointer, PredN>;
using ConstReversePredecessorIterator = mapped<CRPredPointer, CPredN>;
public:
SuccessorEdgeIterator successor_edges_begin() {
return revng::map_iterator(Successors.begin(), SuccessorFilters::toView);
}
ConstSuccessorEdgeIterator successor_edges_begin() const {
return revng::map_iterator(Successors.begin(),
SuccessorFilters::toConstView);
}
ConstSuccessorEdgeIterator successor_edges_cbegin() const {
return revng::map_iterator(Successors.cbegin(),
SuccessorFilters::toConstView);
}
ReverseSuccessorEdgeIterator successor_edges_rbegin() {
return revng::map_iterator(Successors.rbegin(), SuccessorFilters::toView);
}
ConstReverseSuccessorEdgeIterator successor_edges_rbegin() const {
return revng::map_iterator(Successors.rbegin(),
SuccessorFilters::toConstView);
}
ConstReverseSuccessorEdgeIterator successor_edges_crbegin() const {
return revng::map_iterator(Successors.crbegin(),
SuccessorFilters::toConstView);
}
SuccessorEdgeIterator successor_edges_end() {
return revng::map_iterator(Successors.end(), SuccessorFilters::toView);
}
ConstSuccessorEdgeIterator successor_edges_end() const {
return revng::map_iterator(Successors.end(), SuccessorFilters::toConstView);
}
ConstSuccessorEdgeIterator successor_edges_cend() const {
return revng::map_iterator(Successors.cend(),
SuccessorFilters::toConstView);
}
ReverseSuccessorEdgeIterator successor_edges_rend() {
return revng::map_iterator(Successors.rend(), SuccessorFilters::toView);
}
ConstReverseSuccessorEdgeIterator successor_edges_rend() const {
return revng::map_iterator(Successors.rend(),
SuccessorFilters::toConstView);
}
ConstReverseSuccessorEdgeIterator successor_edges_crend() const {
return revng::map_iterator(Successors.crend(),
SuccessorFilters::toConstView);
}
public:
SuccessorIterator successors_begin() {
return revng::map_iterator(Successors.begin(),
SuccessorFilters::toNeighbor);
}
ConstSuccessorIterator successors_begin() const {
return revng::map_iterator(Successors.begin(),
SuccessorFilters::toConstNeighbor);
}
ConstSuccessorIterator successors_cbegin() const {
return revng::map_iterator(Successors.cbegin(),
SuccessorFilters::toConstNeighbor);
}
ReverseSuccessorIterator successors_rbegin() {
return revng::map_iterator(Successors.rbegin(),
SuccessorFilters::toNeighbor);
}
ConstReverseSuccessorIterator successors_rbegin() const {
return revng::map_iterator(Successors.rbegin(),
SuccessorFilters::toConstNeighbor);
}
ConstReverseSuccessorIterator successors_crbegin() const {
return revng::map_iterator(Successors.crbegin(),
SuccessorFilters::toConstNeighbor);
}
SuccessorIterator successors_end() {
return revng::map_iterator(Successors.end(), SuccessorFilters::toNeighbor);
}
ConstSuccessorIterator successors_end() const {
return revng::map_iterator(Successors.end(),
SuccessorFilters::toConstNeighbor);
}
ConstSuccessorIterator successors_cend() const {
return revng::map_iterator(Successors.cend(),
SuccessorFilters::toConstNeighbor);
}
ReverseSuccessorIterator successors_rend() {
return revng::map_iterator(Successors.rend(), SuccessorFilters::toNeighbor);
}
ConstReverseSuccessorIterator successors_rend() const {
return revng::map_iterator(Successors.rend(),
SuccessorFilters::toConstNeighbor);
}
ConstReverseSuccessorIterator successors_crend() const {
return revng::map_iterator(Successors.crend(),
SuccessorFilters::toConstNeighbor);
}
public:
PredecessorEdgeIterator predecessor_edges_begin() {
return revng::map_iterator(Predecessors.begin(),
PredecessorFilters::toView);
}
ConstPredecessorEdgeIterator predecessor_edges_begin() const {
return revng::map_iterator(Predecessors.begin(),
PredecessorFilters::toConstView);
}
ConstPredecessorEdgeIterator predecessor_edges_cbegin() const {
return revng::map_iterator(Predecessors.cbegin(),
PredecessorFilters::toConstView);
}
ReversePredecessorEdgeIterator predecessor_edges_rbegin() {
return revng::map_iterator(Predecessors.rbegin(),
PredecessorFilters::toView);
}
ConstReversePredecessorEdgeIterator predecessor_edges_rbegin() const {
return revng::map_iterator(Predecessors.rbegin(),
PredecessorFilters::toConstView);
}
ConstReversePredecessorEdgeIterator predecessor_edges_crbegin() const {
return revng::map_iterator(Predecessors.crbegin(),
PredecessorFilters::toConstView);
}
PredecessorEdgeIterator predecessor_edges_end() {
return revng::map_iterator(Predecessors.end(), PredecessorFilters::toView);
}
ConstPredecessorEdgeIterator predecessor_edges_end() const {
return revng::map_iterator(Predecessors.end(),
PredecessorFilters::toConstView);
}
ConstPredecessorEdgeIterator predecessor_edges_cend() const {
return revng::map_iterator(Predecessors.cend(),
PredecessorFilters::toConstView);
}
ReversePredecessorEdgeIterator predecessor_edges_rend() {
return revng::map_iterator(Predecessors.rend(), PredecessorFilters::toView);
}
ConstReversePredecessorEdgeIterator predecessor_edges_rend() const {
return revng::map_iterator(Predecessors.rend(),
PredecessorFilters::toConstView);
}
ConstReversePredecessorEdgeIterator predecessor_edges_crend() const {
return revng::map_iterator(Predecessors.crend(),
PredecessorFilters::toConstView);
}
public:
PredecessorIterator predecessors_begin() {
return revng::map_iterator(Predecessors.begin(),
PredecessorFilters::toNeighbor);
}
ConstPredecessorIterator predecessors_begin() const {
return revng::map_iterator(Predecessors.begin(),
PredecessorFilters::toConstNeighbor);
}
ConstPredecessorIterator predecessors_cbegin() const {
return revng::map_iterator(Predecessors.cbegin(),
PredecessorFilters::toConstNeighbor);
}
ReversePredecessorIterator predecessors_rbegin() {
return revng::map_iterator(Predecessors.rbegin(),
PredecessorFilters::toNeighbor);
}
ConstReversePredecessorIterator predecessors_rbegin() const {
return revng::map_iterator(Predecessors.rbegin(),
PredecessorFilters::toConstNeighbor);
}
ConstReversePredecessorIterator predecessors_crbegin() const {
return revng::map_iterator(Predecessors.crbegin(),
PredecessorFilters::toConstNeighbor);
}
PredecessorIterator predecessors_end() {
return revng::map_iterator(Predecessors.end(),
PredecessorFilters::toNeighbor);
}
ConstPredecessorIterator predecessors_end() const {
return revng::map_iterator(Predecessors.end(),
PredecessorFilters::toConstNeighbor);
}
ConstPredecessorIterator predecessors_cend() const {
return revng::map_iterator(Predecessors.cend(),
PredecessorFilters::toConstNeighbor);
}
ReversePredecessorIterator predecessors_rend() {
return revng::map_iterator(Predecessors.rend(),
PredecessorFilters::toNeighbor);
}
ConstReversePredecessorIterator predecessors_rend() const {
return revng::map_iterator(Predecessors.rend(),
PredecessorFilters::toConstNeighbor);
}
ConstReversePredecessorIterator predecessors_crend() const {
return revng::map_iterator(Predecessors.crend(),
PredecessorFilters::toConstNeighbor);
}
public:
llvm::iterator_range<SuccessorEdgeIterator> successor_edges() {
return llvm::make_range(successor_edges_begin(), successor_edges_end());
}
llvm::iterator_range<ConstSuccessorEdgeIterator> successor_edges() const {
return llvm::make_range(successor_edges_begin(), successor_edges_end());
}
llvm::iterator_range<SuccessorIterator> successors() {
return llvm::make_range(successors_begin(), successors_end());
}
llvm::iterator_range<ConstSuccessorIterator> successors() const {
return llvm::make_range(successors_begin(), successors_end());
}
llvm::iterator_range<PredecessorEdgeIterator> predecessor_edges() {
return llvm::make_range(predecessor_edges_begin(), predecessor_edges_end());
}
llvm::iterator_range<ConstPredecessorEdgeIterator> predecessor_edges() const {
return llvm::make_range(predecessor_edges_begin(), predecessor_edges_end());
}
llvm::iterator_range<PredecessorIterator> predecessors() {
return llvm::make_range(predecessors_begin(), predecessors_end());
}
llvm::iterator_range<ConstPredecessorIterator> predecessors() const {
return llvm::make_range(predecessors_begin(), predecessors_end());
}
private:
template<typename IteratorType>
static auto findImpl(DerivedType const *N,
IteratorType FromIterator,
IteratorType ToIterator) {
auto Comparator = [N](auto const &Edge) { return Edge.Neighbor == N; };
return std::find_if(FromIterator, ToIterator, Comparator);
}
template<typename ContainerType>
static auto findImpl(DerivedType const *N, ContainerType &&Where) {
return findImpl(N, Where.begin(), Where.end());
}
static auto findSuccessorHalf(typename EdgeOwnerContainer::iterator Edge,
EdgeViewContainer &Halves) {
auto Comparator = [Edge](auto const &Half) {
return Half.Label == Edge->Label.get();
};
return std::find_if(Halves.begin(), Halves.end(), Comparator);
}
static auto findPredecessorHalf(typename EdgeViewContainer::iterator Edge,
EdgeOwnerContainer &Halves) {
auto Comparator = [Edge](auto const &Half) {
return Half.Label.get() == Edge->Label;
};
return std::find_if(Halves.begin(), Halves.end(), Comparator);
}
public:
SuccessorEdgeIterator findSuccessorEdge(DerivedType const *S) {
return SuccessorEdgeIterator(findImpl(S, Successors),
SuccessorFilters::toView);
}
ConstSuccessorEdgeIterator findSuccessorEdge(DerivedType const *S) const {
return ConstSuccessorEdgeIterator(findImpl(S, Successors),
SuccessorFilters::toConstView);
}
PredecessorEdgeIterator findPredecessorEdge(DerivedType const *P) {
return PredecessorEdgeIterator(findImpl(P, Predecessors),
PredecessorFilters::toView);
}
ConstPredecessorEdgeIterator findPredecessorEdge(DerivedType const *P) const {
return ConstPredecessorEdgeIterator(findImpl(P, Predecessors),
PredecessorFilters::toConstView);
}
SuccessorIterator findSuccessor(DerivedType const *S) {
return SuccessorIterator(findImpl(S, Successors),
SuccessorFilters::toNeighbor);
}
ConstSuccessorIterator findSuccessor(DerivedType const *S) const {
return ConstSuccessorIterator(findImpl(S, Successors),
SuccessorFilters::toConstNeighbor);
}
PredecessorIterator findPredecessor(DerivedType const *P) {
return PredecessorIterator(findImpl(P, Predecessors),
PredecessorFilters::toNeighbor);
}
ConstPredecessorIterator findPredecessor(DerivedType const *P) const {
return ConstPredecessorIterator(findImpl(P, Predecessors),
PredecessorFilters::toConstNeighbor);
}
public:
bool hasSuccessor(DerivedType const *S) const {
return findImpl(S, Successors) != Successors.end();
}
bool hasPredecessor(DerivedType const *P) const {
return findImpl(P, Predecessors) != Predecessors.end();
}
public:
size_t successorCount() const { return Successors.size(); }
size_t predecessorCount() const { return Predecessors.size(); }
bool hasSuccessors() const { return Successors.size() != 0; }
bool hasPredecessors() const { return Predecessors.size() != 0; }
protected:
using InternalOwnerIt = typename EdgeOwnerContainer::const_iterator;
using InternalViewIt = typename EdgeViewContainer::const_iterator;
using InternalOwnerRIt = typename EdgeOwnerContainer::const_reverse_iterator;
using InternalViewRIt = typename EdgeViewContainer::const_reverse_iterator;
protected:
auto removeSuccessorImpl(InternalOwnerIt InputIterator) {
if (Successors.empty())
return Successors.end();
auto Iterator = Successors.begin();
std::advance(Iterator,
std::distance<InternalOwnerIt>(Iterator, InputIterator));
revng_assert(Iterator != Successors.end());
// Maybe we should do some extra checks as to whether `Iterator` is valid.
auto *Successor = Iterator->Neighbor;
revng_assert(!Successor->Predecessors.empty(),
"Half of an edge is missing, graph layout is broken.");
auto PredecessorIt = findSuccessorHalf(Iterator, Successor->Predecessors);
revng_assert(PredecessorIt != Successor->Predecessors.end(),
"Half of an edge is missing, graph layout is broken.");
std::swap(*PredecessorIt, Successor->Predecessors.back());
Successor->Predecessors.pop_back();
auto AssertHelper = findSuccessorHalf(Iterator, Successor->Predecessors);
revng_assert(AssertHelper == Successor->Predecessors.end(),
"More than one half is found for a single edge.");
std::swap(*Iterator, Successors.back());
Successors.pop_back();
return Iterator;
}
auto removePredecessorImpl(InternalViewIt InputIterator) {
if (Predecessors.empty())
return Predecessors.end();
auto Iterator = Predecessors.begin();
std::advance(Iterator,
std::distance<InternalViewIt>(Iterator, InputIterator));
revng_assert(Iterator != Predecessors.end());
// Maybe we should do some extra checks as to whether `Iterator` is valid.
auto *Predecessor = Iterator->Neighbor;
revng_assert(!Predecessor->Successors.empty(),
"Half of an edge is missing, graph layout is broken.");
auto SuccessorIt = findPredecessorHalf(Iterator, Predecessor->Successors);
revng_assert(SuccessorIt != Predecessor->Successors.end(),
"Half of an edge is missing, graph layout is broken.");
std::swap(*SuccessorIt, Predecessor->Successors.back());
Predecessor->Successors.pop_back();
auto AssertHelper = findPredecessorHalf(Iterator, Predecessor->Successors);
revng_assert(AssertHelper == Predecessor->Successors.end(),
"More than one half is found for a single edge.");
std::swap(*Iterator, Predecessors.back());
Predecessors.pop_back();
return Iterator;
}
protected:
auto removeSuccessorImpl(InternalOwnerRIt InputIterator) {
auto Result = removeSuccessorImpl(std::prev(InputIterator.base()));
return std::reverse_iterator(Result);
}
auto removePredecessorImpl(InternalViewRIt InputIterator) {
auto Result = removePredecessorImpl(std::prev(InputIterator.base()));
return std::reverse_iterator(Result);
}
public:
auto removeSuccessor(ConstSuccessorEdgeIterator Iterator) {
auto Result = removeSuccessorImpl(Iterator.getCurrent());
return SuccessorEdgeIterator(Result, SuccessorFilters::toView);
}
auto removeSuccessor(ConstSuccessorIterator Iterator) {
auto Result = removeSuccessorImpl(Iterator.getCurrent());
return SuccessorIterator(Result, SuccessorFilters::toNeighbor);
}
auto removeSuccessor(ConstReverseSuccessorEdgeIterator Iterator) {
auto Result = removeSuccessorImpl(Iterator.getCurrent());
return ReverseSuccessorEdgeIterator(Result, SuccessorFilters::toView);
}
auto removeSuccessor(ConstReverseSuccessorIterator Iterator) {
auto Result = removeSuccessorImpl(Iterator.getCurrent());
return ReverseSuccessorIterator(Result, SuccessorFilters::toNeighbor);
}
auto removePredecessor(ConstPredecessorEdgeIterator Iterator) {
auto Result = removePredecessorImpl(Iterator.getCurrent());
return ReverseSuccessorEdgeIterator(Result, PredecessorFilters::toView);
}
auto removePredecessor(ConstPredecessorIterator Iterator) {
auto Result = removePredecessorImpl(Iterator.getCurrent());
return ReverseSuccessorEdgeIterator(Result, PredecessorFilters::toNeighbor);
}
auto removePredecessor(ConstReversePredecessorEdgeIterator Iterator) {
auto Result = removePredecessorImpl(Iterator.getCurrent());
return ReversePredecessorEdgeIterator(Result, PredecessorFilters::toView);
}
auto removePredecessor(ConstReversePredecessorIterator Iterator) {
auto Result = removePredecessorImpl(Iterator.getCurrent());
return ReversePredecessorIterator(Result, PredecessorFilters::toNeighbor);
}
public:
auto removeSuccessor(SuccessorEdgeIterator Iterator) {
auto Converted = ConstSuccessorEdgeIterator(Iterator.getCurrent(),
SuccessorFilters::toConstView);
return removeSuccessor(Converted);
}
auto removeSuccessor(SuccessorIterator Iterator) {
auto Converted = ConstSuccessorIterator(Iterator.getCurrent(),
SuccessorFilters::toConstNeighbor);
return removeSuccessor(Converted);
}
auto removePredecessor(PredecessorEdgeIterator Iterator) {
auto &F = PredecessorFilters::toConstView;
auto Converted = ConstPredecessorEdgeIterator(Iterator.getCurrent(), F);
return removePredecessor(Converted);
}
auto removePredecessor(PredecessorIterator Iterator) {
auto Conv = ConstPredecessorIterator(Iterator.getCurrent(),
PredecessorFilters::toConstNeighbor);
return removePredecessor(Conv);
}
public:
auto removeSuccessor(ReverseSuccessorEdgeIterator Iterator) {
auto &F = SuccessorFilters::toConstView;
auto Conv = ConstReverseSuccessorEdgeIterator(Iterator.getCurrent(), F);
return removeSuccessor(Conv);
}
auto removeSuccessor(ReverseSuccessorIterator Iterator) {
auto &F = SuccessorFilters::toConstNeighbor;
auto Converted = ConstReverseSuccessorIterator(Iterator.getCurrent(), F);
return removeSuccessor(Converted);
}
auto removePredecessor(ReversePredecessorEdgeIterator Iterator) {
auto &F = PredecessorFilters::toConstView;
auto Conv = ConstReversePredecessorEdgeIterator(Iterator.getCurrent(), F);
return removePredecessor(Conv);
}
auto removePredecessor(ReversePredecessorIterator Iterator) {
auto &F = PredecessorFilters::toConstNeighbor;
auto Converted = ConstReversePredecessorIterator(Iterator.getCurrent(), F);
return removePredecessor(Converted);
}
public:
void removeSuccessors(DerivedType const *S) {
auto Iterator = findImpl(S, Successors);
while (Iterator != Successors.end()) {
Iterator = removeSuccessorImpl(Iterator);
Iterator = findImpl(S, Iterator, Successors.end());
}
}
void removePredecessors(DerivedType const *P) {
auto Iterator = findImpl(P, Predecessors);
while (Iterator != Predecessors.end()) {
Iterator = removePredecessorImpl(Iterator);
Iterator = findImpl(P, Iterator, Predecessors.end());
}
}
public:
void removeSuccessors() {
for (auto It = Successors.begin(); It != Successors.end();)
It = removeSuccessorImpl(It);
revng_assert(Successors.empty());
}
void removePredecessors() {
for (auto It = Predecessors.begin(); It != Predecessors.end();)
It = removePredecessorImpl(It);
revng_assert(Predecessors.empty());
}
public:
MutableEdgeNode &disconnect() {
removeSuccessors();
removePredecessors();
return *this;
}
protected:
std::tuple<OwningEdge, NonOwningEdge>
constructEdge(DerivedType *From, DerivedType *To, EdgeLabel &&EL) {
OwningEdge O{ To, std::make_unique<EdgeLabel>(std::move(EL)) };
NonOwningEdge V{ From, O.Label.get() };
return { std::move(O), std::move(V) };
}
private:
EdgeOwnerContainer Successors;
EdgeViewContainer Predecessors;
};
/// Simple data structure to hold the EntryNode of a GenericGraph
template<typename NodeT>
class EntryNode {
private:
NodeT *EntryNode = nullptr;
public:
NodeT *getEntryNode() const { return EntryNode; }
void setEntryNode(NodeT *EntryNode) { this->EntryNode = EntryNode; }
};
/// Generic graph parametrized in the node type
///
/// This graph owns its nodes (but not the edges).
/// It can optionally have an elected entry point.
template<typename NodeT, size_t SmallSize, bool HasEntryNode>
class GenericGraph
: public std::conditional_t<HasEntryNode, EntryNode<NodeT>, Empty> {
public:
static const bool is_generic_graph = true;
using NodesContainer = llvm::SmallVector<std::unique_ptr<NodeT>, SmallSize>;
using Node = NodeT;
static constexpr bool hasEntryNode = HasEntryNode;
private:
using nodes_iterator_impl = typename NodesContainer::iterator;
using const_nodes_iterator_impl = typename NodesContainer::const_iterator;
public:
GenericGraph() = default;
GenericGraph(const GenericGraph &) = delete;
GenericGraph(GenericGraph &&) = default;
GenericGraph &operator=(const GenericGraph &) = delete;
GenericGraph &operator=(GenericGraph &&) = default;
llvm::Error verify() const debug_function {
llvm::SmallPtrSet<NodeT *, 32> ValidNodes;
// Collect all valid nodes and ensure there are no nullptr
for (const std::unique_ptr<NodeT> &Node : Nodes) {
if (Node.get() == nullptr) {
return revng::createError("Graph contains a nullptr node");
}
ValidNodes.insert(Node.get());
}
// Ensure we only point to valid nodes
for (const std::unique_ptr<NodeT> &Node : Nodes) {
for (NodeT *Successor : Node->successors()) {
if (not ValidNodes.contains(Successor)) {
return revng::createError("A node contains an unknown successor");
}
}
if constexpr (StrictSpecializationOfBidirectionalNode<NodeT>) {
for (NodeT *Predecessor : Node->predecessors()) {
if (not ValidNodes.contains(Predecessor)) {
return revng::createError("A node contains an unknown predecessor");
}
}
}
}
return llvm::Error::success();
}
void dumpGraph() const debug_function { llvm::WriteGraph(this, ""); }
public:
static NodeT *getNode(std::unique_ptr<NodeT> &E) { return E.get(); }
static const NodeT *getConstNode(const std::unique_ptr<NodeT> &E) {
return E.get();
}
// TODO: these iterators will not work with llvm::filter_iterator,
// since the mapped type is not a reference
using nodes_iterator = llvm::mapped_iterator<nodes_iterator_impl,
decltype(&getNode)>;
using const_nodes_iterator = llvm::mapped_iterator<const_nodes_iterator_impl,
decltype(&getConstNode)>;
llvm::iterator_range<nodes_iterator> nodes() {
return llvm::map_range(llvm::make_range(Nodes.begin(), Nodes.end()),
getNode);
}
llvm::iterator_range<const_nodes_iterator> nodes() const {
return llvm::map_range(llvm::make_range(Nodes.begin(), Nodes.end()),
getConstNode);
}
size_t size() const { return Nodes.size(); }
bool empty() const { return Nodes.size() == 0; }
public:
nodes_iterator findNode(Node const *NodePtr) {
auto Comparator = [&NodePtr](auto &N) { return N.get() == NodePtr; };
auto InternalIt = std::find_if(Nodes.begin(), Nodes.end(), Comparator);
return nodes_iterator(InternalIt, getNode);
}
const_nodes_iterator findNode(Node const *NodePtr) const {
auto Comparator = [&NodePtr](auto &N) { return N.get() == NodePtr; };
auto InternalIt = std::find_if(Nodes.begin(), Nodes.end(), Comparator);
return nodes_iterator(InternalIt, getConstNode);
}
public:
bool hasNodes() const { return Nodes.size() != 0; }
bool hasNode(Node const *NodePtr) const {
return findNode(NodePtr) != Nodes.end();
}
public:
NodeT *addNode(std::unique_ptr<NodeT> &&Ptr) {
Nodes.emplace_back(std::move(Ptr));
if constexpr (NodeT::HasParent)
Nodes.back()->setParent(this);
return Nodes.back().get();
}
template<class... ArgTypes>
NodeT *addNode(ArgTypes &&...A) {
Nodes.push_back(std::make_unique<NodeT>(std::forward<ArgTypes>(A)...));
if constexpr (NodeT::HasParent)
Nodes.back()->setParent(this);
return Nodes.back().get();
}
nodes_iterator removeNode(nodes_iterator It) {
if constexpr (StrictSpecializationOfMutableEdgeNode<Node>)
(*It.getCurrent())->disconnect();
auto InternalIt = Nodes.erase(It.getCurrent());
return nodes_iterator(InternalIt, getNode);
}
nodes_iterator removeNode(Node const *NodePtr) {
return removeNode(findNode(NodePtr));
}
public:
nodes_iterator insertNode(nodes_iterator Where,
std::unique_ptr<NodeT> &&Ptr) {
auto InternalIt = Nodes.insert(Where.getCurrent(), std::move(Ptr));
return nodes_iterator(InternalIt, getNode);
}
template<class... ArgTypes>
nodes_iterator insertNode(nodes_iterator Where, ArgTypes &&...A) {
auto Pointer = std::make_unique<NodeT>(std::forward<ArgTypes>(A)...);
auto InternalIt = Nodes.insert(Where.getCurrent(), std::move(Pointer));
return nodes_iterator(InternalIt, getNode);
}
public:
void reserve(size_t Size) { Nodes.reserve(Size); }
void clear() { Nodes.clear(); }
protected:
NodesContainer Nodes;
};
//
// GraphTraits implementation for GenericGraph
//
namespace llvm {
/// Specializes GraphTraits<ForwardNode<...> *>
template<SpecializationOfForwardNode T>
struct GraphTraits<T *> {
public:
using NodeRef = T *;
using ChildIteratorType = std::conditional_t<std::is_const_v<T>,
typename T::const_child_iterator,
typename T::child_iterator>;
using EdgeRef = typename T::Edge &;
template<typename Ty, typename True, typename False>
using if_const_t = std::conditional_t<std::is_const_v<Ty>, True, False>;
using ChildEdgeIteratorType = if_const_t<T,
typename T::const_edge_iterator,
typename T::edge_iterator>;
public:
static ChildIteratorType child_begin(NodeRef N) {
return N->successors().begin();
}
static ChildIteratorType child_end(NodeRef N) {
return N->successors().end();
}
static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
return N->successor_edges().begin();
}
static ChildEdgeIteratorType child_edge_end(NodeRef N) {
return N->successor_edges().end();
}
static NodeRef edge_dest(EdgeRef Edge) { return Edge.Neighbor; }
static NodeRef getEntryNode(NodeRef N) { return N; };
};
/// Specializes GraphTraits<llvm::Inverse<BidirectionalNode<...> *>>
template<StrictSpecializationOfBidirectionalNode T>
struct GraphTraits<llvm::Inverse<T *>> {
public:
using NodeRef = T *;
using ChildIteratorType = std::conditional_t<std::is_const_v<T>,
typename T::const_child_iterator,
typename T::child_iterator>;
using EdgeRef = typename T::Edge &;
template<typename Ty, typename True, typename False>
using if_const_t = std::conditional_t<std::is_const_v<Ty>, True, False>;
using ChildEdgeIteratorType = if_const_t<T,
typename T::const_edge_iterator,
typename T::edge_iterator>;
public:
static ChildIteratorType child_begin(NodeRef N) {
return N->predecessors().begin();
}
static ChildIteratorType child_end(NodeRef N) {
return N->predecessors().end();
}
static ChildEdgeIteratorType child_edge_begin(NodeRef N) {
return N->predecessor_edges().begin();
}
static ChildEdgeIteratorType child_edge_end(NodeRef N) {
return N->predecessor_edges().end();
}
static NodeRef edge_dest(EdgeRef Edge) { return Edge.Neighbor; }
static NodeRef getEntryNode(llvm::Inverse<NodeRef> N) { return N.Graph; };
};
// TODO: implement const version of GraphTraits
/// Specializes GraphTraits<MutableEdgeNode<...> *>
template<StrictSpecializationOfMutableEdgeNode T>
struct GraphTraits<T *> {
public:
using NodeRef = T *;
using EdgeRef = typename T::EdgeView;
private:
using ChildNodeIt = decltype(std::declval<T>().successors().begin());
using ChildEdgeIt = decltype(std::declval<T>().successor_edges().begin());
public:
using ChildIteratorType = ChildNodeIt;
using ChildEdgeIteratorType = ChildEdgeIt;
public:
static auto child_begin(T *N) { return N->successors().begin(); }
static auto child_end(T *N) { return N->successors().end(); }
static auto child_edge_begin(T *N) { return N->successor_edges().begin(); }
static auto child_edge_end(T *N) { return N->successor_edges().end(); }
static T *edge_dest(EdgeRef Edge) { return Edge.Neighbor; }
static T *getEntryNode(T *N) { return N; };
};
// TODO: implement const version of GraphTraits
/// Specializes GraphTraits<llvm::Inverse<MutableEdgeNode<...> *>>
template<StrictSpecializationOfMutableEdgeNode T>
struct GraphTraits<llvm::Inverse<T *>> {
public:
using NodeRef = T *;
using EdgeRef = typename T::EdgeView;
private:
using ChildNodeIt = decltype(std::declval<T>().predecessors().begin());
using ChildEdgeIt = decltype(std::declval<T>().predecessor_edges().begin());
public:
using ChildIteratorType = ChildNodeIt;
using ChildEdgeIteratorType = ChildEdgeIt;
public:
static auto child_begin(T *N) { return N->predecessors().begin(); }
static auto child_end(T *N) { return N->predecessors().end(); }
static auto child_edge_begin(T *N) { return N->predecessor_edges().begin(); }
static auto child_edge_end(T *N) { return N->predecessor_edges().end(); }
static T *edge_dest(EdgeRef Edge) { return &Edge.Neighbor; }
static T *getEntryNode(llvm::Inverse<T *> N) { return N.Graph; };
};
/// Specializes GraphTraits<GenericGraph<...> *>>
template<SpecializationOfGenericGraph T>
struct GraphTraits<T *>
: public GraphTraits<std::conditional_t<std::is_const_v<T>,
const typename T::Node *,
typename T::Node *>> {
using NodeRef = std::conditional_t<std::is_const_v<T>,
const typename T::Node *,
typename T::Node *>;
using nodes_iterator = std::conditional_t<std::is_const_v<T>,
typename T::const_nodes_iterator,
typename T::nodes_iterator>;
static NodeRef getEntryNode(T *G) { return G->getEntryNode(); }
static nodes_iterator nodes_begin(T *G) { return G->nodes().begin(); }
static nodes_iterator nodes_end(T *G) { return G->nodes().end(); }
static size_t size(T *G) { return G->size(); }
};
/// Specializes GraphTraits<llvm::Inverse<GenericGraph<...> *>>>
template<SpecializationOfGenericGraph T>
struct GraphTraits<llvm::Inverse<T *>>
: public GraphTraits<
llvm::Inverse<std::conditional_t<std::is_const_v<T>,
const typename T::Node *,
typename T::Node *>>> {
using NodeRef = std::conditional_t<std::is_const_v<T>,
const typename T::Node *,
typename T::Node *>;
using nodes_iterator = std::conditional_t<std::is_const_v<T>,
typename T::const_nodes_iterator,
typename T::nodes_iterator>;
static NodeRef getEntryNode(llvm::Inverse<T *> Inv) {
// TODO: we might want to consider an option of having optional
// `ExitNode`s as well, for consistency.
return Inv.Graph->getEntryNode();
}
static nodes_iterator nodes_begin(llvm::Inverse<T *> Inv) {
return Inv.Graph->nodes().begin();
}
static nodes_iterator nodes_end(llvm::Inverse<T *> Inv) {
return Inv.Graph->nodes().end();
}
static size_t size(T *G) { return G->size(); }
};
} // namespace llvm