Helper.cpp
Go to the documentation of this file.
1 #include <swarmio/data/Helper.h>
2 #include <swarmio/Exception.h>
3 #include <iomanip>
4 #include <list>
5 #include <algorithm>
6 
7 using namespace swarmio;
8 using namespace swarmio::data;
9 
10 bool Helper::IsArray(const Variant& value)
11 {
12  switch (value.value_case())
13  {
14  case swarmio::data::Variant::ValueCase::kBoolArray:
15  case swarmio::data::Variant::ValueCase::kIntArray:
16  case swarmio::data::Variant::ValueCase::kUintArray:
17  case swarmio::data::Variant::ValueCase::kDoubleArray:
18  case swarmio::data::Variant::ValueCase::kStringArray:
19  case swarmio::data::Variant::ValueCase::kMapArray:
20  return true;
21  default:
22  return false;
23  }
24 }
25 
26 size_t Helper::GetCount(const Variant& value)
27 {
28  switch (value.value_case())
29  {
30  case swarmio::data::Variant::ValueCase::kBoolArray:
31  return value.bool_array().elements_size();
32 
33  case swarmio::data::Variant::ValueCase::kIntArray:
34  return value.int_array().elements_size();
35 
36  case swarmio::data::Variant::ValueCase::kUintArray:
37  return value.uint_array().elements_size();
38 
39  case swarmio::data::Variant::ValueCase::kDoubleArray:
40  return value.double_array().elements_size();
41 
42  case swarmio::data::Variant::ValueCase::kStringArray:
43  return value.string_array().elements_size();
44 
45  case swarmio::data::Variant::ValueCase::kMapArray:
46  return value.map_array().elements_size();
47 
48  default:
49  return 1;
50  }
51 }
52 
53 data::Variant::ValueCase Helper::GetBaseType(const Variant& value)
54 {
55  switch (value.value_case())
56  {
57  case swarmio::data::Variant::ValueCase::kBoolArray:
58  return swarmio::data::Variant::ValueCase::kBoolValue;
59 
60  case swarmio::data::Variant::ValueCase::kIntArray:
61  return swarmio::data::Variant::ValueCase::kIntValue;
62 
63  case swarmio::data::Variant::ValueCase::kUintArray:
64  return swarmio::data::Variant::ValueCase::kUintValue;
65 
66  case swarmio::data::Variant::ValueCase::kDoubleArray:
67  return swarmio::data::Variant::ValueCase::kDoubleValue;
68 
69  case swarmio::data::Variant::ValueCase::kStringArray:
70  return swarmio::data::Variant::ValueCase::kStringValue;
71 
72  case swarmio::data::Variant::ValueCase::kMapArray:
73  return swarmio::data::Variant::ValueCase::kMapValue;
74 
75  default:
76  return value.value_case();
77  }
78 }
79 
80 discovery::Schema Helper::GetSchemaDescriptor(const Map& value, bool includeArraySizes)
81 {
82  discovery::Schema schema;
83  auto& fields = *schema.mutable_fields();
84  for (const auto& pair : value.pairs())
85  {
86  fields[pair.first] = GetFieldDescriptor(pair.second, includeArraySizes);
87  }
88  return schema;
89 }
90 
91 discovery::Field Helper::GetFieldDescriptor(const Variant& value, bool includeArraySizes)
92 {
93  discovery::Field field;
94  switch (value.value_case())
95  {
96  case Variant::ValueCase::kBoolValue:
97  case Variant::ValueCase::kBoolArray:
98  field.set_type(discovery::Type::BOOL);
99  break;
100 
101  case Variant::ValueCase::kIntValue:
102  case Variant::ValueCase::kIntArray:
103  field.set_type(discovery::Type::INT);
104  break;
105 
106  case Variant::ValueCase::kUintValue:
107  case Variant::ValueCase::kUintArray:
108  field.set_type(discovery::Type::UINT);
109  break;
110 
111  case Variant::ValueCase::kDoubleValue:
112  case Variant::ValueCase::kDoubleArray:
113  field.set_type(discovery::Type::DOUBLE);
114  break;
115 
116  case Variant::ValueCase::kStringValue:
117  case Variant::ValueCase::kStringArray:
118  field.set_type(discovery::Type::STRING);
119  break;
120 
121  case Variant::ValueCase::kMapValue:
122  *field.mutable_schema() = GetSchemaDescriptor(value.map_value(), includeArraySizes);
123  break;
124 
125  case Variant::ValueCase::kMapArray:
126  if (value.map_array().elements_size() > 0)
127  {
128  *field.mutable_schema() = GetSchemaDescriptor(*value.map_array().elements().begin());
129  }
130  else
131  {
132  field.set_type(discovery::Type::UNKNOWN);
133  }
134  break;
135 
136  default:
137  field.set_type(discovery::Type::UNKNOWN);
138  break;
139  }
140  if (IsArray(value))
141  {
142  if (includeArraySizes)
143  {
144  field.set_fixed_size(GetCount(value));
145  }
146  else
147  {
148  field.set_is_variable_size(true);
149  }
150  }
151  return field;
152 }
153 
154 std::string Helper::ToString(const discovery::Schema& value, bool prettyPrint)
155 {
156  std::ostringstream stream;
157  WriteToStream(stream, value, prettyPrint);
158  return stream.str();
159 }
160 
161 std::string Helper::ToString(const Variant& value, bool prettyPrint)
162 {
163  std::ostringstream stream;
164  WriteToStream(stream, value, prettyPrint);
165  return stream.str();
166 }
167 
168 std::string Helper::ToString(const Map& value, bool prettyPrint)
169 {
170  std::ostringstream stream;
171  WriteToStream(stream, value, prettyPrint);
172  return stream.str();
173 }
174 
175 std::string Helper::ToString(const google::protobuf::Map<std::string, swarmio::data::Variant>& value, bool prettyPrint)
176 {
177  std::ostringstream stream;
178  WriteToStream(stream, value, prettyPrint);
179  return stream.str();
180 }
181 
182 void Helper::WriteEscapedAndQuotedStringToStream(std::ostream& stream, const std::string& value)
183 {
184  stream << '"';
185  for (auto c : value)
186  {
187  switch (c)
188  {
189  case '"':
190  stream << "\\\"";
191  break;
192 
193  case '\\':
194  stream << "\\\\";
195  break;
196 
197  case '\b':
198  stream << "\\b";
199  break;
200 
201  case '\f':
202  stream << "\\f";
203  break;
204 
205  case '\n':
206  stream << "\\n";
207  break;
208 
209  case '\r':
210  stream << "\\r";
211  break;
212 
213  case '\t':
214  stream << "\\t";
215  break;
216 
217  default:
218  if ('\x00' <= c && c <= '\x1f')
219  {
220  stream << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)c;
221  }
222  else
223  {
224  stream << c;
225  }
226  break;
227  }
228  }
229  stream << '"';
230 }
231 
232 void Helper::WriteElementSeparatorToStream(std::ostream& stream, bool& first, bool prettyPrint, int indentationLevel)
233 {
234  // Separate elements
235  if (first)
236  {
237  first = false;
238  }
239  else
240  {
241  stream << ",";
242  }
243 
244  // Add indentation
245  if (prettyPrint)
246  {
247  stream << std::endl;
248  for (int i = 0; i <= indentationLevel; ++i)
249  {
250  stream << " ";
251  }
252  }
253 }
254 
255 void Helper::WriteToStream(std::ostream& stream, const Variant& value, bool prettyPrint, int indentationLevel)
256 {
257  if (IsArray(value))
258  {
259  if (GetCount(value) == 0)
260  {
261  stream << "[]";
262  }
263  else
264  {
265  // Open array
266  stream << "[";
267 
268  // Write elements
269  bool first = true;
270  switch (value.value_case())
271  {
272  case Variant::ValueCase::kMapArray:
273  for (const auto& e : value.map_array().elements())
274  {
275  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
276  WriteToStream(stream, e, prettyPrint, indentationLevel + 1);
277  }
278  break;
279 
280  case Variant::ValueCase::kStringArray:
281  for (const auto& e : value.string_array().elements())
282  {
283  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
285  }
286  break;
287 
288  case Variant::ValueCase::kBoolArray:
289  for (auto e : value.bool_array().elements())
290  {
291  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
292  stream << std::boolalpha << e;
293  }
294  break;
295 
296  case Variant::ValueCase::kIntArray:
297  for (auto e : value.int_array().elements())
298  {
299  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
300  stream << e;
301  }
302  break;
303 
304  case Variant::ValueCase::kUintArray:
305  for (auto e : value.uint_array().elements())
306  {
307  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
308  stream << e;
309  }
310  break;
311 
312  case Variant::ValueCase::kDoubleArray:
313  for (auto e : value.double_array().elements())
314  {
315  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
316  stream << e;
317  }
318  break;
319 
320  default:
321  throw Exception("Unknown variant type");
322  }
323 
324  // Close array
325  if (prettyPrint)
326  {
327  stream << std::endl;
328  for (int i = 0; i < indentationLevel; ++i)
329  {
330  stream << " ";
331  }
332  }
333  stream << "]";
334  }
335  }
336  else
337  {
338  switch (value.value_case())
339  {
340  case Variant::ValueCase::kMapValue:
341  WriteToStream(stream, value.map_value(), prettyPrint, indentationLevel);
342  break;
343 
344  case Variant::ValueCase::kStringValue:
345  WriteEscapedAndQuotedStringToStream(stream, value.string_value());
346  break;
347 
348  case Variant::ValueCase::kBoolValue:
349  stream << std::boolalpha << value.bool_value();
350  break;
351 
352  case Variant::ValueCase::kIntValue:
353  stream << value.int_value();
354  break;
355 
356  case Variant::ValueCase::kUintValue:
357  stream << value.uint_value();
358  break;
359 
360  case Variant::ValueCase::kDoubleValue:
361  stream << value.double_value();
362  break;
363 
364  default:
365  throw Exception("Unknown variant type");
366  }
367  }
368 }
369 
370 void Helper::WriteToStream(std::ostream& stream, const Map& value, bool prettyPrint, int indentationLevel)
371 {
372  WriteToStream(stream, value.pairs(), prettyPrint, indentationLevel);
373 }
374 
375 void Helper::WriteToStream(std::ostream& stream, const google::protobuf::Map<std::string, swarmio::data::Variant>& value, bool prettyPrint, int indentationLevel)
376 {
377  // Check for empty map
378  if (value.size() == 0)
379  {
380  stream << "{}";
381  }
382  else
383  {
384  // Open map
385  stream << "{";
386 
387  // Protobuf intentionally randomizes the iteration order
388  // of maps - so the same map would be printed differently
389  // each time this function is called. To work around that,
390  // keys are manually sorted beforehand.
391  std::list<std::string> keys;
392  for (const auto& element : value)
393  {
394  keys.push_back(element.first);
395  }
396  keys.sort();
397 
398  // Add values
399  bool first = true;
400  for (const auto& key : keys)
401  {
402  // Write element separator
403  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
404 
405  // Write key
407 
408  // Write key-value separator
409  stream << ":";
410  if (prettyPrint)
411  {
412  stream << " ";
413  }
414 
415  // Write value
416  WriteToStream(stream, value.at(key), prettyPrint, indentationLevel + 1);
417  }
418 
419  // Close map and return string
420  if (prettyPrint)
421  {
422  stream << std::endl;
423  for (int i = 0; i < indentationLevel; ++i)
424  {
425  stream << " ";
426  }
427  }
428  stream << "}";
429  }
430 }
431 
432 const char* Helper::TypeToString(discovery::Type type)
433 {
434  switch (type)
435  {
437  return "bool";
438 
439  case discovery::Type::INT:
440  return "int";
441 
442  case discovery::Type::UINT:
443  return "uint";
444 
445  case discovery::Type::DOUBLE:
446  return "double";
447 
449  return "string";
450 
451  default:
452  return "unknown";
453  }
454 }
455 
456 void Helper::WriteToStream(std::ostream& stream, const discovery::Schema& value, bool prettyPrint, int indentationLevel)
457 {
458  if (value.fields_size() == 0)
459  {
460  stream << "{}";
461  }
462  else
463  {
464  // Open map
465  stream << "{";
466 
467  // Protobuf intentionally randomizes the iteration order
468  // of maps - so the same map would be printed differently
469  // each time this function is called. To work around that,
470  // keys are manually sorted beforehand.
471  std::list<std::string> keys;
472  for (const auto& element : value.fields())
473  {
474  keys.push_back(element.first);
475  }
476  keys.sort();
477 
478  // Add values
479  bool first = true;
480  for (const auto& key : keys)
481  {
482  // Fetch current element
483  const auto& field = value.fields().at(key);
484 
485  // Write element separator
486  WriteElementSeparatorToStream(stream, first, prettyPrint, indentationLevel);
487 
488  // Write key
489  if (field.multiplicity_case() == discovery::Field::MultiplicityCase::kFixedSize)
490  {
491  WriteEscapedAndQuotedStringToStream(stream, key + "[" + std::to_string(field.fixed_size()) + "]");
492  }
493  else if (field.is_variable_size())
494  {
495  WriteEscapedAndQuotedStringToStream(stream, key + "[]");
496  }
497  else
498  {
500  }
501 
502  // Write key-value separator
503  stream << ":";
504  if (prettyPrint)
505  {
506  stream << " ";
507  }
508 
509  // Write value
510  if (field.descriptor_case() == discovery::Field::DescriptorCase::kSchema)
511  {
512  WriteToStream(stream, field.schema(), prettyPrint, indentationLevel + 1);
513  }
514  else
515  {
516  stream << '"' << TypeToString(field.type()) << '"';
517  }
518  }
519 
520  // Close map and return string
521  if (prettyPrint)
522  {
523  stream << std::endl;
524  for (int i = 0; i < indentationLevel; ++i)
525  {
526  stream << " ";
527  }
528  }
529  stream << "}";
530  }
531 }
532 
533 
534 
static Variant::ValueCase GetBaseType(const Variant &value)
Get the base type of the variant array, or its type if it is not an array.
Definition: Helper.cpp:53
static void WriteToStream(std::ostream &stream, const Variant &value, bool prettyPrint=true, int indentationLevel=0)
Write a string representation of a variant to the stream.
Definition: Helper.cpp:255
Exception class thrown by all library classes.
static void WriteEscapedAndQuotedStringToStream(std::ostream &stream, const std::string &value)
Write an escaped and quoted string to the stream.
Definition: Helper.cpp:182
static std::string ToString(const discovery::Schema &value, bool prettyPrint=true)
Get a string representation of a schema.
Definition: Helper.cpp:154
static void WriteElementSeparatorToStream(std::ostream &stream, bool &first, bool prettyPrint, int indentationLevel)
Write the element separator between two elements of an array.
Definition: Helper.cpp:232
static const char * TypeToString(discovery::Type type)
Look up the human readable name of a type.
Definition: Helper.cpp:432
static size_t GetCount(const Variant &value)
Get the item count of the variant array, or 1 if it is not an array.
Definition: Helper.cpp:26
static bool IsArray(const Variant &value)
Check whether the variant contains an array type.
Definition: Helper.cpp:10
static discovery::Field GetFieldDescriptor(const Variant &value, bool includeArraySizes=false)
Get the schema for an existing map.
Definition: Helper.cpp:91
static discovery::Schema GetSchemaDescriptor(const Map &value, bool includeArraySizes=false)
Get the schema for an existing map.
Definition: Helper.cpp:80


swarmros
Author(s):
autogenerated on Fri Apr 3 2020 03:42:48