[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