Ariles
writer.cpp
Go to the documentation of this file.
1 /**
2  @file
3  @author Alexander Sherikov
4 
5  @copyright 2018-2020 Alexander Sherikov, Licensed under the Apache License, Version 2.0.
6  (see @ref LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
7 
8  @brief
9 */
10 
12 
13 #include <vector>
14 #include <utility>
15 #include <set>
16 
17 #include <boost/lexical_cast.hpp>
18 
19 
20 
21 namespace ariles2
22 {
23  namespace ns_graphviz
24  {
25  class NodeWrapper : public serialization::Node<std::string>
26  {
27  public:
29 
30  public:
31  std::string actual_id_;
32  std::string label_;
33 
34 
35  public:
36  explicit NodeWrapper(const std::string &node, const Base::Type type = Base::Type::GENERIC)
37  : Base(node, type)
38  {
39  label_ = node;
40  actual_id_ = node;
41  }
42 
43  explicit NodeWrapper(
44  const std::string &node,
45  const std::string &label,
46  const Base::Type type = Base::Type::GENERIC)
47  : Base(node, type)
48  {
49  label_ = label;
50  actual_id_ = node;
51  }
52 
54  const std::string &node,
55  const std::string &label,
56  const std::size_t index,
57  const std::size_t size)
58  : Base(node, index, size)
59  {
60  label_ = label;
61  actual_id_ = node;
62  }
63  };
64  } // namespace ns_graphviz
65 } // namespace ariles2
66 
67 
68 namespace ariles2
69 {
70  namespace ns_graphviz
71  {
72  namespace impl
73  {
75  {
76  public:
77  std::set<std::string> all_ids_;
79 
80  const std::string separator_ = "_";
81 
82 
83  public:
84  template <class... t_Args>
85  explicit Visitor(t_Args &&...args) : FileVisitorImplementation(std::forward<t_Args>(args)...)
86  {
87  }
88 
89 
90  void clear()
91  {
92  all_ids_.clear();
93  node_stack_.clear();
94  }
95 
96 
98  {
100 
101  const std::size_t stack_size = node_stack_.size();
102 
103  CPPUT_ASSERT(0 < stack_size, "Internal error: stack must contain at least 2 entries.");
104 
105  // node
106  back().actual_id_ = node_options.id_;
107 
108  if (all_ids_.insert(back().actual_id_).second)
109  {
110  *output_stream_ << node_options.id_;
111  *output_stream_ << "[";
112  if (not node_options.label_.empty())
113  {
114  *output_stream_ << "label=\"" << node_options.label_ << "\"";
115  }
116  if (not node_options.options_.empty())
117  {
118  *output_stream_ << "," << node_options.options_;
119  }
120  *output_stream_ << "];\n";
121  }
122 
123  // connection
124  if (stack_size > 1)
125  {
126  *output_stream_ //
127  << node_stack_[stack_size - 2].actual_id_ //
128  << "->" //
129  << back().actual_id_ << ";\n";
130  }
131  }
132  };
133  } // namespace impl
134  } // namespace ns_graphviz
135 } // namespace ariles2
136 
137 
138 namespace ariles2
139 {
140  namespace ns_graphviz
141  {
142  Visitor::Visitor(const std::string &file_name)
143  {
144  makeImplPtr(file_name);
145  }
146 
147 
148  Visitor::Visitor(std::ostream &output_stream)
149  {
150  makeImplPtr(output_stream);
151  }
152 
153 
155  {
156  impl_->output_stream_->flush();
157  }
158 
159 
160  void Visitor::startRoot(const std::string &name, const Parameters &parameters)
161  {
163  impl_->clear();
164  impl_->parameters_ = &parameters;
165  if (name.empty())
166  {
167  impl_->emplace("ariles");
168  }
169  else
170  {
171  impl_->emplace(name);
172  }
173  *impl_->output_stream_ //
174  << "digraph graph_" << impl_->back().node_ //
175  << " {\n" //
176  << parameters.graph_options_; //
177  }
178 
179 
180  void Visitor::endRoot(const std::string & /*name*/)
181  {
183  *impl_->output_stream_ << "}\n";
184  }
185 
186  std::string Visitor::getDefaultNodeId() const
187  {
188  if (impl_->back().isArray())
189  {
190  return (impl_->back().node_ + "_" + boost::lexical_cast<std::string>(impl_->back().index_));
191  }
192  return (impl_->back().node_);
193  }
194 
195  std::string Visitor::getDefaultNodeLabel() const
196  {
197  if (impl_->back().isArray())
198  {
199  return (impl_->back().label_ + "_" + boost::lexical_cast<std::string>(impl_->back().index_));
200  }
201  return (impl_->back().label_);
202  }
203 
204  void Visitor::startMap(const Parameters &parameters, const Parameters::NodeOptions &node_options)
205  {
207  if (not impl_->parameters_->override_parameters_)
208  {
209  impl_->parameters_ = &parameters;
210  }
211  impl_->writeNodeAndConnection(node_options);
212  }
213 
214  void Visitor::startMap(const Parameters &parameters, const std::size_t /*num_entries*/)
215  {
217  if (not impl_->parameters_->override_parameters_)
218  {
219  impl_->parameters_ = &parameters;
220  }
221  impl_->writeNodeAndConnection(
222  impl_->parameters_->getDefaultNodeOptions(getDefaultNodeId(), getDefaultNodeLabel()));
223  }
224 
225  void Visitor::startMapEntry(const std::string &name)
226  {
228  if (impl_->back().isArray())
229  {
230  impl_->emplace(
231  impl_->concatWithNode(
232  impl_->separator_,
233  boost::lexical_cast<std::string>(impl_->back().index_),
234  impl_->separator_,
235  name),
236  name);
237  }
238  else
239  {
240  impl_->emplace(impl_->concatWithNode(impl_->separator_, name), name);
241  }
242  }
243 
245  {
247  impl_->pop();
248  }
249 
250 
251  void Visitor::startArray(const std::size_t size, const bool compact)
252  {
254  CPPUT_ASSERT(not impl_->empty(), "Internal error: empty stack.");
255 
256  if (size > 0 || not compact)
257  {
258  impl_->writeNodeAndConnection(
259  impl_->parameters_->getDefaultNodeOptions(getDefaultNodeId(), getDefaultNodeLabel()));
260  }
261 
262  if (impl_->back().isArray())
263  {
264  const std::string index = boost::lexical_cast<std::string>(impl_->back().index_);
265  impl_->emplace(
266  impl_->concatWithNode(impl_->separator_, index),
267  cpput::concat::simple(impl_->back().label_, impl_->separator_, index),
268  0,
269  size);
270  }
271  else
272  {
273  impl_->emplace(impl_->back().node_, impl_->back().label_, 0, size);
274  }
275  }
276 
278  {
279  impl_->shiftArray();
280  }
281 
283  {
285  impl_->pop();
286  }
287 
288 
289 #define ARILES2_BASIC_TYPE(type) \
290  void Visitor::writeElement(const type &, const Parameters &) \
291  { \
292  impl_->writeNodeAndConnection( \
293  impl_->parameters_->getDefaultNodeOptions(getDefaultNodeId(), getDefaultNodeLabel())); \
294  }
295 
298 
299 #undef ARILES2_BASIC_TYPE
300  } // namespace ns_graphviz
301 } // namespace ariles2
NodeWrapper(const std::string &node, const std::string &label, const std::size_t index, const std::size_t size)
Definition: writer.cpp:53
NodeWrapper(const std::string &node, const std::string &label, const Base::Type type=Base::Type::GENERIC)
Definition: writer.cpp:43
NodeWrapper(const std::string &node, const Base::Type type=Base::Type::GENERIC)
Definition: writer.cpp:36
std::string getDefaultNodeId() const
Definition: writer.cpp:186
std::string getDefaultNodeLabel() const
Definition: writer.cpp:195
void startRoot(const std::string &name, const Parameters &)
Definition: writer.cpp:160
void startMap(const Parameters &, const Parameters::NodeOptions &)
Definition: writer.cpp:204
void startMapEntry(const std::string &map_name)
Starts a nested map in the configuration file.
Definition: writer.cpp:225
void flush()
Flush the configuration to the output.
Definition: writer.cpp:154
void startArray(const std::size_t size, const bool compact=false)
Definition: writer.cpp:251
void endRoot(const std::string &name)
Definition: writer.cpp:180
std::set< std::string > all_ids_
Definition: writer.cpp:77
const Parameters * parameters_
Definition: writer.cpp:78
const std::string separator_
Definition: writer.cpp:80
void writeNodeAndConnection(const Parameters::NodeOptions &node_options)
Definition: writer.cpp:97
std::ostream * output_stream_
output stream
Definition: write.h:380
FileVisitorImplementation(const std::string &file_name)
Definition: write.h:384
#define CPPUT_ASSERT(condition,...)
Definition: exception.h:32
#define ARILES2_COMPLEX_NUMBER_TYPES_LIST
Definition: helpers.h:68
#define ARILES2_BASIC_TYPES_LIST
Definition: helpers.h:72
#define CPPUT_MACRO_SUBSTITUTE(macro)
Definition: misc.h:21
Definition: basic.h:17
std::string simple(t_String &&...strings)
Definition: concat.h:38
#define CPPUT_TRACE_FUNCTION
Definition: trace.h:126