#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/ADT/GraphTraits.h" #include "revng/ADT/GenericGraph.h" #include "revng/ADT/KeyedObjectTraits.h" #include "revng/ADT/SortedVector.h" #include "revng/TupleTree/TupleTree.h" // // SerializableEdge // template class SerializableEdge { private: using KOC = KeyedObjectTraits; public: using NodeKey = decltype(KOC::key(std::declval())); public: SerializableEdge(NodeKey Neighbor) : Neighbor(Neighbor) {} SerializableEdge(NodeKey Neighbor, const EdgeLabel &Label) : Neighbor(Neighbor), Label(Label) {} public: bool operator==(const SerializableEdge &Other) const = default; bool operator<(const SerializableEdge &Other) const = default; public: NodeKey Neighbor; EdgeLabel Label; }; template class KeyedObjectTraits> { private: using KOC = KeyedObjectTraits; public: using NodeKey = decltype(KOC::key(std::declval())); public: static NodeKey key(const SerializableEdge &Node) { return KOC::key(NodeType(Node.Neighbor)); } static SerializableEdge fromKey(const NodeKey &Key) { return SerializableEdge({ Key, {} }); } }; template struct llvm::yaml::MappingTraits> : public TupleLikeMappingTraits> {}; // // SerializableNode // template class SerializableNode { private: using KOC = KeyedObjectTraits; public: using NodeKey = decltype(KOC::key(std::declval())); public: bool operator==(const SerializableNode &O) const = default; public: NodeType Node; SortedVector> Successors; }; template class KeyedObjectTraits> { private: using KOC = KeyedObjectTraits; public: using NodeKey = decltype(KOC::key(std::declval())); public: static NodeKey key(const SerializableNode &Node) { return KOC::key(NodeType(Node.Node)); } static SerializableNode fromKey(const NodeKey &Key) { return SerializableNode({ Key, {} }); } }; template struct llvm::yaml::MappingTraits> : public TupleLikeMappingTraits> {}; // // SerializableGraph // template class SerializableGraph { private: using KOC = KeyedObjectTraits; public: using NodeKey = decltype(KOC::key(std::declval())); public: bool operator==(const SerializableGraph &O) const = default; public: template GenericGraph toGenericGraph() const { GenericGraph Ret; std::map Map; for (const auto &N : Nodes) Map[KOC::key(N.Node)] = Ret.addNode(N.Node); for (const auto &N : Nodes) for (const auto &S : N.Successors) Map[KOC::key(N.Node)]->addSuccessor(Map[S.Neighbor], S.Label); if constexpr (GenericGraph::hasEntryNode) { Ret.setEntryNode(Map[EntryNode]); } return Ret; } public: SortedVector> Nodes; NodeKey EntryNode; }; template struct llvm::yaml::MappingTraits> : public TupleLikeMappingTraits> {}; template SerializableGraph toSerializable(const G &Graph) { using Node = typename G::Node::NodeData; using EdgeLabelData = typename G::Node::EdgeLabelData; using KOC = KeyedObjectTraits; SerializableGraph Result; { auto Inserter = Result.Nodes.batch_insert(); for (const auto &N : Graph.nodes()) Inserter.insert({ KOC::key(*N), {} }); } for (const auto &N : Graph.nodes()) { auto Inserter = Result.Nodes.at(KOC::key(*N)).Successors.batch_insert(); for (const auto &J : N->successor_edges()) Inserter.insert({ KOC::key(*J.Neighbor), J }); } if constexpr (GenericGraph::hasEntryNode) { if (Graph.getEntryNode() != nullptr) Result.EntryNode = KOC::key(*Graph.getEntryNode()); } return Result; } // // Make `struct Empty` serialiazible // template<> struct std::tuple_size : std::integral_constant {}; template<> struct llvm::yaml::MappingTraits : public TupleLikeMappingTraits { }; // // Expose macros to make SerializableGraph actually serializable // template struct argument_type; template struct argument_type { using type = U; }; #define TYPE(A) argument_type::type #define SERIALIZABLEGRAPH_INTROSPECTION(A, B) \ INTROSPECTION(TYPE((SerializableGraph) ), Nodes, EntryNode); \ INTROSPECTION(TYPE((SerializableNode) ), Node, Successors); \ INTROSPECTION(TYPE((SerializableEdge) ), Neighbor, Label)