mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
180 lines
5.5 KiB
C++
180 lines
5.5 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <compare>
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "revng/GraphLayout/SugiyamaStyle/Compute.h"
|
|
|
|
using RankingStrategy = yield::layout::sugiyama::RankingStrategy;
|
|
using Configuration = yield::layout::sugiyama::Configuration;
|
|
|
|
using Point = yield::layout::Point;
|
|
using Size = yield::layout::Size;
|
|
|
|
using Index = size_t;
|
|
using Rank = size_t;
|
|
using RankDelta = std::ptrdiff_t;
|
|
|
|
using InternalGraph = yield::layout::sugiyama::InternalGraph;
|
|
using InternalNode = InternalGraph::Node;
|
|
using InternalEdge = InternalNode::Edge;
|
|
|
|
/// A wrapper around an `InternalNode` pointer used for comparison overloading.
|
|
class NodeView {
|
|
public:
|
|
NodeView(InternalNode *Pointer = nullptr) : Pointer(Pointer) {}
|
|
|
|
operator InternalNode *() const {
|
|
revng_assert(Pointer != nullptr);
|
|
return Pointer;
|
|
}
|
|
InternalNode &operator*() const {
|
|
revng_assert(Pointer != nullptr);
|
|
return *Pointer;
|
|
}
|
|
InternalNode *operator->() const {
|
|
revng_assert(Pointer != nullptr);
|
|
return Pointer;
|
|
}
|
|
|
|
auto operator<=>(const NodeView &Another) const {
|
|
revng_assert(Pointer != nullptr);
|
|
revng_assert(Another.Pointer != nullptr);
|
|
return Pointer->index() <=> Another.Pointer->index();
|
|
}
|
|
|
|
private:
|
|
InternalNode *Pointer = nullptr;
|
|
};
|
|
|
|
namespace std {
|
|
template<>
|
|
struct hash<::NodeView> {
|
|
auto operator()(const ::NodeView &View) const {
|
|
return std::hash<InternalNode *>()(&*View);
|
|
}
|
|
};
|
|
} // namespace std
|
|
|
|
/// A view onto an edge as a extension of a known node.
|
|
/// This is useful as a `second` value for a map where the `first` one
|
|
/// is the `From` node.
|
|
struct EdgeDestinationView {
|
|
NodeView To;
|
|
size_t EdgeIndex;
|
|
|
|
EdgeDestinationView(NodeView To, const InternalEdge &Label) :
|
|
To(To), EdgeIndex(Label.index()) {}
|
|
|
|
auto operator<=>(const EdgeDestinationView &) const = default;
|
|
};
|
|
|
|
/// A generic view onto an edge. It's the same as the `EdgeDestinationView`
|
|
/// but stores the views onto both of the nodes.
|
|
struct EdgeView : EdgeDestinationView {
|
|
public:
|
|
NodeView From;
|
|
|
|
EdgeView(NodeView From, NodeView To, const InternalEdge &Label) :
|
|
EdgeDestinationView(To, Label), From(From) {}
|
|
|
|
auto operator<=>(const EdgeView &) const = default;
|
|
|
|
InternalEdge &label() {
|
|
auto Lambda = [this](auto Edge) {
|
|
return Edge.Neighbor == To && Edge.Label->index() == EdgeIndex;
|
|
};
|
|
revng_assert(llvm::count_if(From->successor_edges(), Lambda) == 1);
|
|
|
|
auto Iterator = llvm::find_if(From->successor_edges(), Lambda);
|
|
revng_assert(Iterator != From->successor_edges().end());
|
|
revng_assert(Iterator->Label != nullptr);
|
|
return *Iterator->Label;
|
|
}
|
|
|
|
const InternalEdge &label() const {
|
|
auto Lambda = [this](auto Edge) {
|
|
return Edge.Neighbor == To && Edge.Label->index() == EdgeIndex;
|
|
};
|
|
revng_assert(llvm::count_if(From->successor_edges(), Lambda) == 1);
|
|
|
|
auto Iterator = llvm::find_if(From->successor_edges(), Lambda);
|
|
revng_assert(Iterator != From->successor_edges().end());
|
|
revng_assert(Iterator->Label != nullptr);
|
|
return *Iterator->Label;
|
|
}
|
|
};
|
|
|
|
/// An internal data structure used to pass node ranks around.
|
|
using RankContainer = std::unordered_map<NodeView, Rank>;
|
|
|
|
/// An internal data structure used to pass around information about
|
|
/// the layers specific nodes belong to.
|
|
using LayerContainer = std::vector<std::vector<NodeView>>;
|
|
|
|
/// An internal data structure used to pass around information about the way
|
|
/// graph is split onto segments.
|
|
using SegmentContainer = std::unordered_map<NodeView, NodeView>;
|
|
|
|
/// It's used to describe the position of a single node within the layered grid.
|
|
struct LogicalPosition {
|
|
Rank Layer; /// Rank of the layer the node is in.
|
|
Rank Index; /// An index within the layer
|
|
};
|
|
|
|
/// It's used to describe the complete layout by storing the exact
|
|
/// position of each node relative to all the others.
|
|
using LayoutContainer = std::unordered_map<NodeView, LogicalPosition>;
|
|
|
|
/// An internal data structure used to pass around information about the lanes
|
|
/// used to route edges.
|
|
struct LaneContainer {
|
|
/// Stores edges that require a horizontal section grouped by layer.
|
|
std::vector<std::map<EdgeView, Rank>> Horizontal;
|
|
|
|
/// Stores edges entering a node groped by the node they enter.
|
|
std::unordered_map<NodeView, std::map<EdgeDestinationView, Rank>> Entries;
|
|
|
|
/// Stores edges leaving a node grouped by the node they leave.
|
|
std::unordered_map<NodeView, std::map<EdgeDestinationView, Rank>> Exits;
|
|
};
|
|
|
|
/// An internal data structure used to represent a corner. It stores three
|
|
/// points: center of the corner and two ends.
|
|
struct Corner {
|
|
Point Start, Center, End;
|
|
};
|
|
|
|
/// An internal data structure used to represent a pair of nodes.
|
|
struct NodePair {
|
|
NodeView From, To;
|
|
|
|
auto operator<=>(const NodePair &) const = default;
|
|
};
|
|
|
|
/// An internal data structure used to pass around information about the routed
|
|
/// corners.
|
|
using CornerContainer = std::map<NodePair, Corner>;
|
|
|
|
/// An internal data structure used to represent all the necessary information
|
|
/// for an edge to be routed. This data is usable even after the internal graph
|
|
/// was destroyed.
|
|
struct RoutableEdge {
|
|
InternalEdge *Label = nullptr;
|
|
Point FromCenter, ToCenter;
|
|
Size FromSize, ToSize;
|
|
Rank LaneIndex, ExitCount, EntryCount;
|
|
float CenteredExitIndex, CenteredEntryIndex;
|
|
std::optional<Corner> Prerouted;
|
|
};
|
|
|
|
/// An internal data structure used to pass around an ordered list of routed
|
|
/// edges.
|
|
using OrderedEdgeContainer = std::vector<RoutableEdge>;
|