[Bf-blender-cvs] [0fea5c5d59e] functions: dot file export
Jacques Lucke
noreply at git.blender.org
Sun Nov 24 14:59:14 CET 2019
Commit: 0fea5c5d59e10d542cbfcbed7b3ec5aeb9bbd4ff
Author: Jacques Lucke
Date: Sun Nov 24 12:55:58 2019 +0100
Branches: functions
https://developer.blender.org/rB0fea5c5d59e10d542cbfcbed7b3ec5aeb9bbd4ff
dot file export
===================================================================
A source/blender/blenlib/BLI_dot_export.h
M source/blender/blenlib/BLI_string_map.h
M source/blender/blenlib/CMakeLists.txt
A source/blender/blenlib/intern/dot_export.cc
===================================================================
diff --git a/source/blender/blenlib/BLI_dot_export.h b/source/blender/blenlib/BLI_dot_export.h
new file mode 100644
index 00000000000..973962f44c3
--- /dev/null
+++ b/source/blender/blenlib/BLI_dot_export.h
@@ -0,0 +1,174 @@
+#ifndef __BLI_DOT_EXPORT_H__
+#define __BLI_DOT_EXPORT_H__
+
+#include "BLI_vector.h"
+#include "BLI_optional.h"
+#include "BLI_string_map.h"
+#include "BLI_map.h"
+#include "BLI_utility_mixins.h"
+
+#include <sstream>
+
+namespace BLI {
+namespace DotExport {
+
+class Graph;
+class DirectedGraph;
+class UndirectedGraph;
+class Node;
+class NodePort;
+class DirectedEdge;
+class UndirectedEdge;
+class Cluster;
+class AttributeList;
+
+class AttributeList {
+ private:
+ Map<std::string, std::string> m_attributes;
+
+ public:
+ void export__as_bracket_list(std::stringstream &ss) const;
+
+ void set(StringRef key, StringRef value)
+ {
+ m_attributes.add_override(key, value);
+ }
+};
+
+class Graph {
+ private:
+ Vector<std::unique_ptr<Node>> m_nodes;
+ Vector<std::unique_ptr<Cluster>> m_clusters;
+
+ friend Cluster;
+
+ public:
+ Node &new_node(StringRef label);
+ Cluster &new_cluster();
+
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+};
+
+class UndirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<UndirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ UndirectedEdge &new_edge(NodePort a, NodePort b);
+};
+
+class DirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<DirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ DirectedEdge &new_edge(NodePort from, NodePort to);
+};
+
+class Cluster {
+ private:
+ AttributeList m_attributes;
+ Graph *m_graph;
+ Cluster *m_parent;
+ Vector<std::unique_ptr<Cluster>> m_clusters;
+ Vector<std::unique_ptr<Node>> m_nodes;
+
+ public:
+ Cluster(Graph &graph, Cluster *parent) : m_graph(&graph), m_parent(parent)
+ {
+ }
+
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+
+ Cluster &new_cluster();
+
+ Node &new_node(StringRef label);
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+};
+
+class NodePort {
+ private:
+ Node *m_node;
+ Optional<std::string> m_port_name;
+
+ public:
+ NodePort(Node &node, Optional<std::string> port_name = {})
+ : m_node(&node), m_port_name(std::move(port_name))
+ {
+ }
+
+ void to_dot_string(std::stringstream &ss) const;
+};
+
+class Edge : BLI::NonCopyable, BLI::NonMovable {
+ protected:
+ AttributeList m_attributes;
+ NodePort m_a;
+ NodePort m_b;
+
+ public:
+ Edge(NodePort a, NodePort b) : m_a(std::move(a)), m_b(std::move(b))
+ {
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+};
+
+class DirectedEdge : public Edge {
+ public:
+ DirectedEdge(NodePort from, NodePort to) : Edge(std::move(from), std::move(to))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+class UndirectedEdge : public Edge {
+ public:
+ UndirectedEdge(NodePort a, NodePort b) : Edge(std::move(a), std::move(b))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+class Node {
+ private:
+ AttributeList m_attributes;
+
+ public:
+ const AttributeList &attributes() const
+ {
+ return m_attributes;
+ }
+
+ AttributeList &attributes()
+ {
+ return m_attributes;
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void export__as_id(std::stringstream &ss) const;
+
+ void export__as_declaration(std::stringstream &ss) const;
+};
+
+} // namespace DotExport
+} // namespace BLI
+
+#endif /* __BLI_DOT_EXPORT_H__ */
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.h
index 8d146771123..458a48cad5e 100644
--- a/source/blender/blenlib/BLI_string_map.h
+++ b/source/blender/blenlib/BLI_string_map.h
@@ -345,6 +345,19 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
}
}
+ template<typename FuncT> void foreach_key_value_pair(const FuncT &func) const
+ {
+ for (const Item &item : m_array) {
+ for (uint offset = 0; offset < 4; offset++) {
+ if (item.is_set(offset)) {
+ StringRefNull key = item.get_key(offset, m_chars);
+ const T &value = *item.value(offset);
+ func(key, value);
+ }
+ }
+ }
+ }
+
private:
uint32_t compute_string_hash(StringRef key) const
{
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index f6b658befff..b10f513c471 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -255,6 +255,8 @@ set(SRC
PIL_time.h
PIL_time_utildefines.h
+ BLI_dot_export.h
+ intern/dot_export.cc
BLI_chained_strings.h
BLI_lazy_init.h
BLI_lazy_init_cxx.h
diff --git a/source/blender/blenlib/intern/dot_export.cc b/source/blender/blenlib/intern/dot_export.cc
new file mode 100644
index 00000000000..5f7907c85b1
--- /dev/null
+++ b/source/blender/blenlib/intern/dot_export.cc
@@ -0,0 +1,154 @@
+#include "BLI_dot_export.h"
+
+namespace BLI {
+namespace DotExport {
+
+std::string DirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "digraph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (auto &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+std::string UndirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "graph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (auto &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ for (auto &node : m_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (auto &cluster : m_clusters) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+}
+
+void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ ss << "subgraph cluster_" << (void *)this << " {\n";
+
+ ss << "graph ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n\n";
+
+ for (auto &node : m_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (auto &cluster : m_clusters) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+
+ ss << "}\n";
+}
+
+void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -> ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -- ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void AttributeList::export__as_bracket_list(std::stringstream &ss) const
+{
+ ss << "[";
+ for (auto item : m_attributes.items()) {
+ ss << item.key << "=\"" << item.value << "\", ";
+ }
+ ss << "]";
+}
+
+Node &Graph::new_node(StringRef label)
+{
+ Node *node = new Node();
+ m_nodes.append(std::unique_ptr<Node>(node));
+ node->set_attribute("label", label);
+ return *node;
+}
+
+Cluster &Graph::new_cluster()
+{
+ Cluster *cluster = new Cluster(*this, nullptr);
+ m_clusters.append(std::unique_ptr<Cluster>(cluster));
+ return *cluster;
+}
+
+Node &Cluster::new_node(StringRef label)
+{
+ Node *node = new Node();
+ m_nodes.append(std::unique_ptr<Node>(node));
+ node->set_attribute("label", label);
+ return *node;
+}
+
+UndirectedEdge &UndirectedGraph::new_edge(NodePort a, NodePort b)
+{
+ UndirectedEdge *edge = new UndirectedEdge(a, b);
+ m_edges.append(std::unique_ptr<UndirectedEdge>(edge));
+ return *edge;
+}
+
+DirectedEdge &DirectedGraph::new_edge(NodePort from, NodePort to)
+{
+ DirectedEdge *edge = new DirectedEdge(from, to);
+ m_edges.append(std::unique_ptr<DirectedEdge>(edge));
+ return *edge;
+}
+
+void Node::export__as_id(std::stringstream &ss) const
+{
+ ss << '"' << (const void *)this << '"';
+}
+
+void Node::export__as_declaration(std::stringstream &ss) const
+{
+ this->export__as_id(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n";
+}
+
+void NodePort::to_dot_string(std::stringstream &ss) const
+{
+ m_node->export__as_id(ss);
+ if (m_port_name.has_value()) {
+ ss << ":" << m_port_name.value();
+ }
+}
+
+} // namespace DotExport
+} // namespace BLI
More information about the Bf-blender-cvs
mailing list