1+ #pragma  once
2+ 
3+ #include  " interval_types.hpp" 
4+ 
5+ #include  < iostream> 
6+ #include  < string> 
7+ #include  < optional> 
8+ #include  < vector> 
9+ #include  < utility> 
10+ 
11+ namespace  lib_interval_tree 
12+ {
13+  struct  dot_graph_draw_settings 
14+  {
15+  bool  digraph = true ;
16+  std::string name = " G"  ;
17+  std::vector<std::string> extra_node_attributes = {};
18+  std::vector<std::string> extra_statements = {};
19+  bool  space_after_comma = false ;
20+  std::optional<char > left_brace = std::nullopt ;
21+  std::optional<char > right_brace = std::nullopt ;
22+  std::vector<std::string> edge_attributes = {};
23+  std::string indent = " \t "  ;
24+  };
25+ 
26+  namespace  detail 
27+  {
28+  template  <typename  TreeT>
29+  class  graph_painter 
30+  {
31+  public: 
32+  graph_painter (std::ostream& stream, TreeT const & tree, dot_graph_draw_settings settings)
33+  : stream_{stream}
34+  , tree_{tree}
35+  , settings_{std::move (settings)}
36+  , node_id_{" a"  }
37+  , left_brace_{}
38+  , right_brace_{}
39+  {
40+  using  ival_type = typename  TreeT::interval_type;
41+ 
42+  const  auto  determine_brace = []() {
43+  if  (std::is_same_v<typename  ival_type::interval_kind, closed>)
44+  return  " []"  ;
45+  else  if  (std::is_same_v<typename  ival_type::interval_kind, left_open>)
46+  return  " (]"  ;
47+  else  if  (std::is_same_v<typename  ival_type::interval_kind, right_open>)
48+  return  " [)"  ;
49+  else  if  (std::is_same_v<typename  ival_type::interval_kind, open>)
50+  return  " ()"  ;
51+  else  if  (std::is_same_v<typename  ival_type::interval_kind, closed_adjacent>)
52+  return  " []"  ;
53+  else 
54+  return  " []"  ;
55+  };
56+ 
57+  if  (settings_.left_brace )
58+  left_brace_ = *settings_.left_brace ;
59+  else 
60+  left_brace_ = determine_brace ()[0 ];
61+ 
62+  if  (settings_.right_brace )
63+  right_brace_ = *settings_.right_brace ;
64+  else 
65+  right_brace_ = determine_brace ()[1 ];
66+  }
67+ 
68+  void  make_header ()
69+  {
70+  stream_ << (settings_.digraph  ? " digraph"   : " graph"  ) << "  "   << settings_.name  << "  {\n "  ;
71+  for  (auto  const & statement : settings_.extra_statements )
72+  {
73+  stream_ << settings_.indent  << statement << " ;\n "  ;
74+  }
75+  }
76+ 
77+  template  <typename  T>
78+  void  make_label (T const & ival)
79+  {
80+ #if  __cplusplus >= 201703L
81+  if  constexpr  (std::is_same_v<typename  T::interval_kind, dynamic>)
82+  {
83+  stream_ << (ival.left_border () == interval_border::open ? ' ('   : ' ['  ) << ival.low ()
84+  << (settings_.space_after_comma  ? " , "   : " ,"  ) << ival.high ()
85+  << (ival.right_border () == interval_border::open ? ' )'   : ' ]'  );
86+  }
87+  else 
88+  {
89+  stream_ << left_brace_ << ival.low () << (settings_.space_after_comma  ? " , "   : " ,"  ) << ival.high ()
90+  << right_brace_;
91+  }
92+ #else 
93+  stream_ << left_brace_ << ival.low () << (settings_.space_after_comma  ? " , "   : " ,"  ) << ival.high ()
94+  << right_brace_;
95+ #endif 
96+  }
97+ 
98+  template  <typename  interval_type>
99+  void  specify_node (interval_type const & ival)
100+  {
101+  stream_ << settings_.indent  << node_id_ << "  [label=\" "  ;
102+  increment_node_id ();
103+  make_label (ival);
104+  stream_ << " \" "  ;
105+  if  (!settings_.extra_node_attributes .empty ())
106+  {
107+  for  (auto  const & attr : settings_.extra_node_attributes )
108+  {
109+  stream_ << " , "   << attr;
110+  }
111+  }
112+  stream_ << " ];\n "  ;
113+  }
114+ 
115+  template  <typename  iterator_type>
116+  void  specify_all_nodes (iterator_type const & node)
117+  {
118+  specify_node (*node);
119+  if  (node.left () != tree_.end ())
120+  specify_all_nodes (node.left ());
121+  if  (node.right () != tree_.end ())
122+  specify_all_nodes (node.right ());
123+  }
124+ 
125+  void  specify_edge (std::string const & from, std::string const & to)
126+  {
127+  stream_ << settings_.indent  << from << (settings_.digraph  ? "  -> "   : "  -- "  ) << to;
128+  if  (!settings_.edge_attributes .empty ())
129+  {
130+  stream_ << "  ["  ;
131+  for  (auto  iter = settings_.edge_attributes .begin (); iter != settings_.edge_attributes .end (); ++iter)
132+  {
133+  stream_ << *iter;
134+  if  (iter + 1  != settings_.edge_attributes .end ())
135+  stream_ << " , "  ;
136+  }
137+  stream_ << " ]"  ;
138+  }
139+  stream_ << " ;\n "  ;
140+  }
141+ 
142+  template  <typename  iterator_type>
143+  void  specify_all_edges (iterator_type const & node)
144+  {
145+  auto  previous_id = node_id_;
146+  if  (node.left () != tree_.end ())
147+  {
148+  increment_node_id ();
149+  specify_edge (previous_id, node_id_);
150+  specify_all_edges (node.left ());
151+  }
152+  if  (node.right () != tree_.end ())
153+  {
154+  increment_node_id ();
155+  specify_edge (previous_id, node_id_);
156+  specify_all_edges (node.right ());
157+  }
158+  }
159+ 
160+  void  close ()
161+  {
162+  stream_ << " }"  ;
163+  }
164+ 
165+  void  reset_node_id ()
166+  {
167+  node_id_ = " a"  ;
168+  }
169+ 
170+  private: 
171+  void  increment_node_id ()
172+  {
173+  const  auto  character = node_id_.begin ();
174+  for  (auto  iter = character; iter != node_id_.end (); ++iter)
175+  {
176+  if  (*iter == ' z'  )
177+  {
178+  *iter = ' a'  ;
179+  if  (iter + 1  == node_id_.end ())
180+  {
181+  node_id_ += ' a'  ;
182+  break ;
183+  }
184+  }
185+  else 
186+  {
187+  ++*iter;
188+  break ;
189+  }
190+  }
191+  }
192+ 
193+  private: 
194+  std::ostream& stream_;
195+  TreeT const & tree_;
196+  dot_graph_draw_settings settings_;
197+  std::string node_id_;
198+  char  left_brace_;
199+  char  right_brace_;
200+  };
201+  }
202+ 
203+  template  <typename  TreeT>
204+  void  draw_dot_graph (std::ostream& stream, TreeT const & tree, dot_graph_draw_settings const & settings = {})
205+  {
206+  detail::graph_painter painter{stream, tree, settings};
207+  painter.make_header ();
208+  if  (tree.empty ())
209+  {
210+  painter.close ();
211+  return ;
212+  }
213+  painter.specify_all_nodes (tree.root ());
214+  painter.reset_node_id ();
215+  painter.specify_all_edges (tree.root ());
216+  painter.close ();
217+  }
218+ }
0 commit comments