This commit is contained in:
Alessandro Di Federico
2021-02-08 18:42:42 +01:00
parent 0261181cd1
commit e0c4cd843e
3 changed files with 169 additions and 57 deletions
+2
View File
@@ -264,6 +264,8 @@ public:
static const bool is_bidirectional_node = true;
public:
using NodeData = Node;
using EdgeLabelData = EdgeLabel;
using Base = ForwardNode<Node,
EdgeLabel,
HasParent,
+107 -55
View File
@@ -7,86 +7,138 @@
#include "llvm/ADT/GraphTraits.h"
#include "revng/ADT/GenericGraph.h"
#include "revng/ADT/KeyedObjectTraits.h"
#include "revng/ADT/SortedVector.h"
#include "revng/Model/TupleTree.h"
template<typename NodeType>
template<typename NodeType, typename EdgeLabel>
struct SerializableEdge {
using KKeyType = decltype(
KeyedObjectTraits<NodeType>::key(*((NodeType *) NULL)));
SerializableEdge(KKeyType Neighbor) : Neighbor(Neighbor) {}
SerializableEdge(KKeyType Neighbor, const EdgeLabel &Label) :
Neighbor(Neighbor), Label(Label) {}
KKeyType Neighbor;
EdgeLabel Label;
bool operator==(const SerializableEdge &Other) const = default;
bool operator<(const SerializableEdge &Other) const = default;
};
template<typename NodeType, typename EdgeLabel>
struct llvm::yaml::MappingTraits<SerializableEdge<NodeType, EdgeLabel>>
: public TupleLikeMappingTraits<SerializableEdge<NodeType, EdgeLabel>> {};
template<typename NodeType, typename EdgeLabel>
struct SerializableNode {
using BDir = BidirectionalNode<NodeType>;
using KKeyType = decltype(KeyedObjectTraits<BDir>::key(*((BDir *) NULL)));
NodeType N;
SortedVector<KKeyType> Successors;
using KKeyType = decltype(
KeyedObjectTraits<NodeType>::key(*((NodeType *) NULL)));
NodeType Node;
SortedVector<SerializableEdge<NodeType, EdgeLabel>> Successors;
bool operator!=(const SerializableNode<NodeType> &O) const {
return N != O.N;
bool operator==(const SerializableNode &O) const = default;
};
template<typename NodeType, typename EdgeLabel>
struct llvm::yaml::MappingTraits<SerializableNode<NodeType, EdgeLabel>>
: public TupleLikeMappingTraits<SerializableNode<NodeType, EdgeLabel>> {};
template<typename NodeType, typename EdgeLabel>
struct KeyedObjectTraits<SerializableNode<NodeType, EdgeLabel>> {
using KKeyType = decltype(
KeyedObjectTraits<NodeType>::key(*((NodeType *) NULL)));
static KKeyType key(const SerializableNode<NodeType, EdgeLabel> &Node) {
return KeyedObjectTraits<NodeType>::key(NodeType(Node.Node));
}
static SerializableNode<NodeType, EdgeLabel> fromKey(const KKeyType &Key) {
return SerializableNode<NodeType, EdgeLabel>({ Key, {} });
}
};
template<typename NodeType>
struct KeyedObjectTraits<SerializableNode<NodeType>> {
using BDir = BidirectionalNode<NodeType>;
using KKeyType = decltype(KeyedObjectTraits<BDir>::key(*((BDir *) NULL)));
template<typename NodeType, typename EdgeLabel>
struct KeyedObjectTraits<SerializableEdge<NodeType, EdgeLabel>> {
using KKeyType = decltype(
KeyedObjectTraits<NodeType>::key(*((NodeType *) NULL)));
static KKeyType key(const SerializableNode<NodeType> &FD) {
return KeyedObjectTraits<BDir>::key(BDir(FD.N));
static KKeyType key(const SerializableEdge<NodeType, EdgeLabel> &Node) {
return KeyedObjectTraits<NodeType>::key(NodeType(Node.Neighbor));
}
static SerializableNode<NodeType> fromKey(KKeyType Key) {
return SerializableNode<NodeType>({ Key, {} });
static SerializableEdge<NodeType, EdgeLabel> fromKey(const KKeyType &Key) {
return SerializableEdge<NodeType, EdgeLabel>({ Key, {} });
}
};
template<typename NodeType>
template<typename NodeType, typename EdgeLabel>
struct SerializableGraph {
using BDir = BidirectionalNode<NodeType>;
using SNode = SerializableNode<NodeType>;
using KKeyType = decltype(KeyedObjectTraits<BDir>::key(*((BDir *) NULL)));
using KKeyType = decltype(
KeyedObjectTraits<NodeType>::key(*((NodeType *) NULL)));
SortedVector<SNode> Nodes;
SortedVector<SerializableNode<NodeType, EdgeLabel>> Nodes;
KKeyType EntryNode;
bool operator!=(const SerializableGraph<NodeType> &O) const {
return Nodes != O.Nodes;
}
bool operator==(const SerializableGraph &O) const = default;
static SerializableGraph toSerializable(const GenericGraph<BDir> &G) {
SerializableGraph Out;
{
auto Inserter = Out.Nodes.batch_insert();
for (const auto &N : G.nodes())
Inserter.insert(SNode{ getKey(*N), {} });
}
template<typename GenericGraphNodeType>
GenericGraph<GenericGraphNodeType> toGenericGraph() const {
GenericGraph<GenericGraphNodeType> Ret;
for (const auto &N : G.nodes()) {
auto Inserter = Out.Nodes.at(getKey(*N)).Successors.batch_insert();
for (const auto &J : N->successors())
Inserter.insert(getKey(*J));
}
if constexpr (GenericGraph<BDir>::hasEntryNode) {
if (G.getEntryNode() != nullptr)
Out.EntryNode = getKey(*G.getEntryNode());
}
return Out;
};
GenericGraph<BDir> fromSerializable() const {
GenericGraph<BDir> Ret;
std::map<KKeyType, BDir *> Map;
std::map<KKeyType, GenericGraphNodeType *> Map;
for (const auto &N : Nodes)
Map[getKey(N.N)] = Ret.addNode(N.N);
Map[KeyedObjectTraits<NodeType>::key(N.Node)] = Ret.addNode(N.Node);
for (const auto &N : Nodes)
for (const auto &S : N.Successors)
Map[getKey(N.N)]->addSuccessor(Map[S]);
Map[KeyedObjectTraits<NodeType>::key(N.Node)]->addSuccessor(Map[S.Neighbor], S.Label);
if constexpr (GenericGraph<BDir>::hasEntryNode) {
if constexpr (GenericGraph<NodeType>::hasEntryNode) {
Ret.setEntryNode(Map[EntryNode]);
}
return Ret;
}
private:
static KKeyType getKey(const NodeType &N) {
return KeyedObjectTraits<BDir>::key(BDir(N));
}
};
template<typename NodeType, typename EdgeLabel>
struct llvm::yaml::MappingTraits<SerializableGraph<NodeType, EdgeLabel>>
: public TupleLikeMappingTraits<SerializableGraph<NodeType, EdgeLabel>> {};
template<typename G>
SerializableGraph<typename G::Node::NodeData, typename G::Node::EdgeLabelData>
toSerializable(const G &Graph) {
using Node = typename G::Node::NodeData;
using EdgeLabelData = typename G::Node::EdgeLabelData;
SerializableGraph<Node, EdgeLabelData> Result;
{
auto Inserter = Result.Nodes.batch_insert();
for (const auto &N : Graph.nodes())
Inserter.insert({ KeyedObjectTraits<Node>::key(*N), {} });
}
for (const auto &N : Graph.nodes()) {
auto Inserter = Result.Nodes.at(KeyedObjectTraits<Node>::key(*N))
.Successors.batch_insert();
for (const auto &J : N->successor_edges())
Inserter.insert({ KeyedObjectTraits<Node>::key(*J.Neighbor), J });
}
if constexpr (GenericGraph<Node>::hasEntryNode) {
if (Graph.getEntryNode() != nullptr)
Result.EntryNode = KeyedObjectTraits<Node>::key(*Graph.getEntryNode());
}
return Result;
}
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { using type = U; };
#define TYPE(A) argument_type<void(A)>::type
#define SERIALIZABLEGRAPH_INTROSPECTION(A, B) \
INTROSPECTION(TYPE((SerializableGraph<A, B>)), Nodes, EntryNode); \
INTROSPECTION(TYPE((SerializableNode<A, B>)), Node, Successors); \
INTROSPECTION(TYPE((SerializableEdge<A, B>)), Neighbor, Label)
+60 -2
View File
@@ -19,6 +19,7 @@ bool init_unit_test();
#include "revng/ADT/FilteredGraphTraits.h"
#include "revng/ADT/GenericGraph.h"
#include "revng/ADT/SerializableGraph.h"
using namespace llvm;
@@ -112,18 +113,48 @@ BOOST_AUTO_TEST_CASE(TestCompile) {
}
}
//
// Define TestEdgeLabel
//
struct TestEdgeLabel {
bool operator==(const TestEdgeLabel &) const = default;
unsigned Weight;
};
INTROSPECTION(TestEdgeLabel, Weight);
template<>
struct llvm::yaml::MappingTraits<TestEdgeLabel>
: public TupleLikeMappingTraits<TestEdgeLabel> {};
//
// Define TestNodeData
//
struct TestNodeData {
TestNodeData(unsigned Rank) : Rank(Rank) {}
bool operator==(const TestNodeData &) const = default;
unsigned Rank;
};
INTROSPECTION(TestNodeData, Rank);
template<>
struct llvm::yaml::MappingTraits<TestNodeData>
: public TupleLikeMappingTraits<TestNodeData> {};
template<>
struct KeyedObjectTraits<TestNodeData> {
static unsigned key(const TestNodeData &Node) { return Node.Rank; }
static TestNodeData fromKey(const unsigned &Key) { return { Key }; }
};
using TestNode = BidirectionalNode<TestNodeData, TestEdgeLabel>;
using TestGraph = GenericGraph<TestNode>;
SERIALIZABLEGRAPH_INTROSPECTION(TestNodeData, TestEdgeLabel);
static bool
shouldKeepNodePair(TestNode *const &Source, TestNode *const &Destination) {
return Source->Rank + Destination->Rank <= 2;
@@ -148,7 +179,7 @@ static DiamondGraph createGraph() {
// Create nodes
DG.Root = Graph.addNode(0);
DG.Then = Graph.addNode(1);
DG.Else = Graph.addNode(1);
DG.Else = Graph.addNode(3);
DG.Final = Graph.addNode(2);
// Set entry node
@@ -228,7 +259,7 @@ BOOST_AUTO_TEST_CASE(TestFilterGraphTraits) {
FGT>;
auto Begin = fdf_iterator::begin(Root);
auto End = fdf_iterator::end(Root);
revng_check(3 == std::distance(Begin, End));
revng_check(2 == std::distance(Begin, End));
}
{
@@ -248,3 +279,30 @@ BOOST_AUTO_TEST_CASE(TestWriteGraph) {
llvm::raw_null_ostream NullOutput;
llvm::WriteGraph(NullOutput, &DG.Graph, "lol");
}
BOOST_AUTO_TEST_CASE(TestSerializableGraph) {
DiamondGraph DG = createGraph();
auto Serializable = toSerializable(DG.Graph);
auto Reserializable = toSerializable(Serializable.toGenericGraph<TestNode>());
revng_check(Reserializable == Serializable);
}
BOOST_AUTO_TEST_CASE(TestSerializeGraph) {
DiamondGraph DG = createGraph();
auto Serializable = toSerializable(DG.Graph);
std::string Buffer;
{
llvm::raw_string_ostream Stream(Buffer);
yaml::Output YAMLOutput(Stream);
YAMLOutput << Serializable;
}
dbg << Buffer << "\n";
decltype(Serializable) Deserialized;
llvm::yaml::Input YAMLInput(Buffer);
YAMLInput >> Deserialized;
revng_check(Deserialized == Serializable);
}