ros_introspection.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright 2016-2017 Davide Faconti
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  * *******************************************************************/
34 
35 #include <boost/algorithm/string.hpp>
36 #include <boost/utility/string_ref.hpp>
37 #include <boost/lexical_cast.hpp>
38 #include <boost/regex.hpp>
39 #include <boost/algorithm/string/regex.hpp>
40 #include <functional>
43 
44 namespace RosIntrospection
45 {
46 void Parser::createTrees(ROSMessageInfo& info, const std::string& type_name) const
47 {
48  std::function<void(const ROSMessage*, StringTreeNode*, MessageTreeNode*)> recursiveTreeCreator;
49 
50  recursiveTreeCreator = [&](const ROSMessage* msg_definition, StringTreeNode* string_node, MessageTreeNode* msg_node) {
51  // note: should use reserve here, NOT resize
52  const size_t NUM_FIELDS = msg_definition->fields().size();
53 
54  string_node->children().reserve(NUM_FIELDS);
55  msg_node->children().reserve(NUM_FIELDS);
56 
57  for (const ROSField& field : msg_definition->fields())
58  {
59  if (field.isConstant() == false)
60  {
61  // Let's add first a child to string_node
62  string_node->addChild(field.name());
63  StringTreeNode* new_string_node = &(string_node->children().back());
64  if (field.isArray())
65  {
66  new_string_node->children().reserve(1);
67  new_string_node = new_string_node->addChild("#");
68  }
69 
70  const ROSMessage* next_msg = nullptr;
71  // builtin types will not trigger a recursion
72  if (field.type().isBuiltin() == false)
73  {
74  next_msg = getMessageByType(field.type(), info);
75  if (next_msg == nullptr)
76  {
77  throw std::runtime_error("This type was not registered ");
78  }
79  msg_node->addChild(next_msg);
80  MessageTreeNode* new_msg_node = &(msg_node->children().back());
81  recursiveTreeCreator(next_msg, new_string_node, new_msg_node);
82  }
83  } // end of field.isConstant()
84  } // end of for fields
85  }; // end of lambda
86 
87  info.string_tree.root()->setValue(type_name);
88  info.message_tree.root()->setValue(&info.type_list.front());
89  // TODO info.type_tree.root()->value() =
90  // start recursion
91  recursiveTreeCreator(&info.type_list.front(), info.string_tree.root(), info.message_tree.root());
92 }
93 
94 inline bool operator==(const std::string& a, const boost::string_ref& b)
95 {
96  return (a.size() == b.size() && std::strncmp(a.data(), b.data(), a.size()) == 0);
97 }
98 
99 inline bool FindPattern(const std::vector<boost::string_ref>& pattern, size_t index, const StringTreeNode* tail,
100  const StringTreeNode** head)
101 {
102  if (tail->value() == pattern[index])
103  {
104  index++;
105  }
106  else
107  { // mismatch
108  if (index > 0)
109  {
110  // reset counter;
111  FindPattern(pattern, 0, tail, head);
112  return false;
113  }
114  index = 0;
115  }
116 
117  if (index == pattern.size())
118  {
119  *head = (tail);
120  return true;
121  }
122 
123  bool found = false;
124 
125  for (auto& child : tail->children())
126  {
127  found = FindPattern(pattern, index, &child, head);
128  if (found)
129  break;
130  }
131  return found;
132 }
133 
134 void Parser::registerRenamingRules(const ROSType& type, const std::vector<SubstitutionRule>& given_rules)
135 {
136  std::unordered_set<SubstitutionRule>& rule_set = _registered_rules[type];
137  for (const auto& rule : given_rules)
138  {
139  if (rule_set.find(rule) == rule_set.end())
140  {
141  rule_set.insert(rule);
142  _rule_cache_dirty = true;
143  }
144  }
145 }
146 
148 {
149  if (_rule_cache_dirty == false)
150  {
151  return;
152  }
153  else
154  {
155  _rule_cache_dirty = false;
156  }
157  for (const auto& rule_it : _registered_rules)
158  {
159  const ROSType& type = rule_it.first;
160  const std::unordered_set<SubstitutionRule>& rule_set = rule_it.second;
161 
162  for (const auto& msg_it : _registered_messages)
163  {
164  const std::string& msg_identifier = msg_it.first;
165  const ROSMessageInfo& msg_info = msg_it.second;
166 
167  if (getMessageByType(type, msg_info))
168  {
169  std::vector<RulesCache>& cache_vector = _rule_caches[msg_identifier];
170  for (const auto& rule : rule_set)
171  {
172  RulesCache cache(rule);
173  FindPattern(cache.rule->pattern(), 0, msg_info.string_tree.croot(), &cache.pattern_head);
174  FindPattern(cache.rule->alias(), 0, msg_info.string_tree.croot(), &cache.alias_head);
175  if (cache.pattern_head && cache.alias_head &&
176  std::find(cache_vector.begin(), cache_vector.end(), cache) == cache_vector.end())
177  {
178  cache_vector.push_back(std::move(cache));
179  }
180  }
181  }
182  }
183  }
184 }
185 
186 void Parser::registerMessageDefinition(const std::string& msg_definition, const ROSType& main_type,
187  const std::string& definition)
188 {
189  if (_registered_messages.count(msg_definition) > 0)
190  {
191  return; // already registered
192  }
193  _rule_cache_dirty = true;
194 
195  static const boost::regex msg_separation_regex("^\\s*=+\\n+");
196 
197  std::vector<std::string> split;
198  std::vector<const ROSType*> all_types;
199 
200  boost::split_regex(split, definition, msg_separation_regex);
201 
202  ROSMessageInfo info;
203  info.type_list.reserve(split.size());
204 
205  for (size_t i = 0; i < split.size(); ++i)
206  {
207  ROSMessage msg(split[i]);
208  if (i == 0)
209  {
210  msg.mutateType(main_type);
211  }
212 
213  info.type_list.push_back(std::move(msg));
214  all_types.push_back(&(info.type_list.back().type()));
215  }
216 
217  for (ROSMessage& msg : info.type_list)
218  {
219  msg.updateMissingPkgNames(all_types);
220  }
221  //------------------------------
222 
223  createTrees(info, msg_definition);
224 
225  // std::cout << info.string_tree << std::endl;
226  // std::cout << info.message_tree << std::endl;
227  _registered_messages.insert(std::make_pair(msg_definition, std::move(info)));
228 }
229 
230 const ROSMessageInfo* Parser::getMessageInfo(const std::string& msg_identifier) const
231 {
232  auto it = _registered_messages.find(msg_identifier);
233  if (it != _registered_messages.end())
234  {
235  return &(it->second);
236  }
237  return nullptr;
238 }
239 
241 {
242  for (const ROSMessage& msg : info.type_list) // find in the list
243  {
244  if (msg.type() == type)
245  {
246  return &msg;
247  }
248  }
249  return nullptr;
250 }
251 
252 void Parser::applyVisitorToBuffer(const std::string& msg_identifier, const ROSType& monitored_type,
254 {
255  const ROSMessageInfo* msg_info = getMessageInfo(msg_identifier);
256 
257  if (msg_info == nullptr)
258  {
259  throw std::runtime_error("extractField: msg_identifier not registered. Use registerMessageDefinition");
260  }
261  if (getMessageByType(monitored_type, *msg_info) == nullptr)
262  {
263  // you will not find it. Skip it;
264  return;
265  }
266 
267  std::function<void(const MessageTreeNode*)> recursiveImpl;
268  size_t buffer_offset = 0;
269 
270  recursiveImpl = [&](const MessageTreeNode* msg_node) {
271  const ROSMessage* msg_definition = msg_node->value();
272  const ROSType& msg_type = msg_definition->type();
273 
274  const bool matching = (msg_type == monitored_type);
275 
276  uint8_t* prev_buffer_ptr = buffer.data() + buffer_offset;
277  size_t prev_offset = buffer_offset;
278 
279  size_t index_m = 0;
280 
281  for (const ROSField& field : msg_definition->fields())
282  {
283  if (field.isConstant())
284  continue;
285 
286  const ROSType& field_type = field.type();
287 
288  int32_t array_size = field.arraySize();
289  if (array_size == -1)
290  {
291  ReadFromBuffer(buffer, buffer_offset, array_size);
292  }
293 
294  //------------------------------------
295 
296  if (field_type.isBuiltin())
297  {
298  for (int i = 0; i < array_size; i++)
299  {
300  // Skip
301  ReadFromBufferToVariant(field_type.typeID(), buffer, buffer_offset);
302  }
303  }
304  else
305  {
306  // field_type.typeID() == OTHER
307  for (int i = 0; i < array_size; i++)
308  {
309  recursiveImpl(msg_node->child(index_m));
310  }
311  index_m++;
312  }
313  } // end for fields
314  if (matching)
315  {
316  Span<uint8_t> view(prev_buffer_ptr, buffer_offset - prev_offset);
317  callback(monitored_type, view);
318  }
319  }; // end lambda
320 
321  // start recursion
322  recursiveImpl(msg_info->message_tree.croot());
323 }
324 
325 template <typename Container>
326 inline void ExpandVectorIfNecessary(Container& container, size_t new_size)
327 {
328  if (container.size() <= new_size)
329  {
330  const size_t increased_size = std::max(size_t(32), container.size() * 2);
331  container.resize(increased_size);
332  }
333 }
334 
335 bool Parser::deserializeIntoFlatContainer(const std::string& msg_identifier, Span<uint8_t> buffer,
336  FlatMessage* flat_container, const uint32_t max_array_size) const
337 {
338  bool entire_message_parse = true;
339  const ROSMessageInfo* msg_info = getMessageInfo(msg_identifier);
340 
341  size_t value_index = 0;
342  size_t name_index = 0;
343  size_t blob_index = 0;
344  size_t blob_storage_index = 0;
345 
346  if (msg_info == nullptr)
347  {
348  throw std::runtime_error("deserializeIntoFlatContainer: msg_identifier not registerd. Use "
349  "registerMessageDefinition");
350  }
351  size_t buffer_offset = 0;
352 
353  std::function<void(const MessageTreeNode*, StringTreeLeaf, bool)> deserializeImpl;
354 
355  deserializeImpl = [&](const MessageTreeNode* msg_node, const StringTreeLeaf& tree_leaf, bool store) {
356  const ROSMessage* msg_definition = msg_node->value();
357  size_t index_s = 0;
358  size_t index_m = 0;
359 
360  for (const ROSField& field : msg_definition->fields())
361  {
362  bool DO_STORE = store;
363  if (field.isConstant())
364  {
365  continue;
366  }
367 
368  const ROSType& field_type = field.type();
369 
370  auto new_tree_leaf = tree_leaf;
371  new_tree_leaf.node_ptr = tree_leaf.node_ptr->child(index_s);
372 
373  int32_t array_size = field.arraySize();
374  if (array_size == -1)
375  {
376  ReadFromBuffer(buffer, buffer_offset, array_size);
377  }
378  if (field.isArray())
379  {
380  new_tree_leaf.index_array.push_back(0);
381  new_tree_leaf.node_ptr = new_tree_leaf.node_ptr->child(0);
382  }
383 
384  bool IS_BLOB = false;
385 
386  // Stop storing it if is NOT a blob and a very large array.
387  if (array_size > static_cast<int32_t>(max_array_size) && field_type.typeID() != OTHER)
388  {
389  if (builtinSize(field_type.typeID()) == 1)
390  {
391  IS_BLOB = true;
392  }
393  else
394  {
396  {
397  DO_STORE = false;
398  }
399  entire_message_parse = false;
400  }
401  }
402 
403  if (IS_BLOB) // special case. This is a "blob", typically an image, a map, pointcloud, etc.
404  {
405  ExpandVectorIfNecessary(flat_container->blob, blob_index);
406 
407  if (buffer_offset + array_size > static_cast<std::size_t>(buffer.size()))
408  {
409  throw std::runtime_error("Buffer overrun in deserializeIntoFlatContainer (blob)");
410  }
411  if (DO_STORE)
412  {
413  flat_container->blob[blob_index].first = new_tree_leaf;
414  auto& blob = flat_container->blob[blob_index].second;
415  blob_index++;
416 
418  {
419  ExpandVectorIfNecessary(flat_container->blob_storage, blob_storage_index);
420 
421  auto& storage = flat_container->blob_storage[blob_storage_index];
422  storage.resize(array_size);
423  std::memcpy(storage.data(), &buffer[buffer_offset], array_size);
424  blob_storage_index++;
425 
426  blob = Span<uint8_t>(storage.data(), storage.size());
427  }
428  else
429  {
430  blob = Span<uint8_t>(&buffer[buffer_offset], array_size);
431  }
432  }
433  buffer_offset += array_size;
434  }
435  else // NOT a BLOB
436  {
437  bool DO_STORE_ARRAY = DO_STORE;
438  for (int i = 0; i < array_size; i++)
439  {
440  if (DO_STORE_ARRAY && i >= static_cast<int32_t>(max_array_size))
441  {
442  DO_STORE_ARRAY = false;
443  }
444 
445  if (field.isArray() && DO_STORE_ARRAY)
446  {
447  new_tree_leaf.index_array.back() = i;
448  }
449 
450  if (field_type.typeID() == STRING)
451  {
452  ExpandVectorIfNecessary(flat_container->name, name_index);
453 
454  uint32_t string_size = 0;
455  ReadFromBuffer(buffer, buffer_offset, string_size);
456 
457  if (buffer_offset + string_size > static_cast<std::size_t>(buffer.size()))
458  {
459  throw std::runtime_error("Buffer overrun in RosIntrospection::ReadFromBuffer");
460  }
461 
462  if (DO_STORE_ARRAY)
463  {
464  if (string_size == 0)
465  {
466  // corner case, when there is an empty string at the end of the message
467  flat_container->name[name_index].second.clear();
468  }
469  else
470  {
471  const char* buffer_ptr = reinterpret_cast<const char*>(buffer.data() + buffer_offset);
472  flat_container->name[name_index].second.assign(buffer_ptr, string_size);
473  }
474  flat_container->name[name_index].first = new_tree_leaf;
475  name_index++;
476  }
477  buffer_offset += string_size;
478  }
479  else if (field_type.isBuiltin())
480  {
481  ExpandVectorIfNecessary(flat_container->value, value_index);
482 
483  Variant var = ReadFromBufferToVariant(field_type.typeID(), buffer, buffer_offset);
484  if (DO_STORE_ARRAY)
485  {
486  flat_container->value[value_index] = std::make_pair(new_tree_leaf, std::move(var));
487  value_index++;
488  }
489  }
490  else
491  { // field_type.typeID() == OTHER
492 
493  deserializeImpl(msg_node->child(index_m), new_tree_leaf, DO_STORE_ARRAY);
494  }
495  } // end for array_size
496  }
497 
498  if (field_type.typeID() == OTHER)
499  {
500  index_m++;
501  }
502  index_s++;
503  } // end for fields
504  }; // end of lambda
505 
506  flat_container->tree = &msg_info->string_tree;
507 
508  StringTreeLeaf rootnode;
509  rootnode.node_ptr = msg_info->string_tree.croot();
510 
511  deserializeImpl(msg_info->message_tree.croot(), rootnode, true);
512 
513  flat_container->name.resize(name_index);
514  flat_container->value.resize(value_index);
515  flat_container->blob.resize(blob_index);
516  flat_container->blob_storage.resize(blob_storage_index);
517 
518  // WORKAROUNG: messages created with ROS serial might have 1 extra byte :(
519  if (buffer.size() - buffer_offset > 1)
520  {
521  char msg_buff[1000];
522  sprintf(msg_buff,
523  "buildRosFlatType: There was an error parsing the buffer.\n"
524  "Size %d != %d, while parsing [%s]",
525  (int)buffer_offset, (int)buffer.size(), msg_identifier.c_str());
526 
527  throw std::runtime_error(msg_buff);
528  }
529  return entire_message_parse;
530 }
531 
532 inline bool isNumberPlaceholder(const boost::string_ref& s)
533 {
534  return s.size() == 1 && s[0] == '#';
535 }
536 
537 inline bool isSubstitutionPlaceholder(const boost::string_ref& s)
538 {
539  return s.size() == 1 && s[0] == '@';
540 }
541 
542 // given a leaf of the tree, that can have multiple index_array,
543 // find the only index which corresponds to the # in the pattern
544 inline int PatternMatchAndIndexPosition(const StringTreeLeaf& leaf, const StringTreeNode* pattern_head)
545 {
546  const StringTreeNode* node_ptr = leaf.node_ptr;
547 
548  int pos = leaf.index_array.size() - 1;
549 
550  while (node_ptr)
551  {
552  if (node_ptr != pattern_head)
553  {
554  if (isNumberPlaceholder(node_ptr->value()))
555  {
556  pos--;
557  }
558  }
559  else
560  {
561  return pos;
562  }
563  node_ptr = node_ptr->parent();
564  } // end while
565  return -1;
566 }
567 
568 template <typename VectorType>
569 inline void JoinStrings(const VectorType& vect, const char separator, std::string& destination)
570 {
571  size_t count = 0;
572  for (const auto& v : vect)
573  count += v.size();
574 
575  // the following approach seems to be faster
576  // https://github.com/facontidavide/InterestingBenchmarks/blob/master/StringAppend_vs_Memcpy.md
577 
578  destination.resize(count + vect.size() - 1);
579 
580  char* buffer = &destination[0];
581  size_t buff_pos = 0;
582 
583  for (size_t c = 0; c < vect.size() - 1; c++)
584  {
585  const size_t S = vect[c].size();
586  std::memcpy(&buffer[buff_pos], vect[c].data(), S);
587  buff_pos += S;
588  buffer[buff_pos++] = separator;
589  }
590  std::memcpy(&buffer[buff_pos], vect.back().data(), vect.back().size());
591 }
592 
593 void Parser::applyNameTransform(const std::string& msg_identifier,
594  const FlatMessage& container,
595  RenamedValues* renamed_value,
596  bool skip_topicname)
597 {
598  if (_rule_cache_dirty)
599  {
600  updateRuleCache();
601  }
602  auto rule_found = _rule_caches.find(msg_identifier);
603 
604  const size_t num_values = container.value.size();
605  const size_t num_names = container.name.size();
606 
607  renamed_value->resize( num_values + num_names );
608  // DO NOT clear() renamed_value
609 
610  _alias_array_pos.resize(num_names);
611  _formatted_string.reserve(num_values);
612  _formatted_string.clear();
613 
614  _substituted.resize(num_values);
615  for (size_t i = 0; i < num_values; i++)
616  {
617  _substituted[i] = false;
618  }
619 
620  // size_t renamed_index = 0;
621 
622  if (rule_found != _rule_caches.end())
623  {
624  const std::vector<RulesCache>& rules_cache = rule_found->second;
625 
626  for (const RulesCache& cache : rules_cache)
627  {
628  const SubstitutionRule* rule = cache.rule;
629  const StringTreeNode* pattern_head = cache.pattern_head;
630  const StringTreeNode* alias_head = cache.alias_head;
631 
632  if (!pattern_head || !alias_head)
633  continue;
634 
635  for (size_t n = 0; n < num_names; n++)
636  {
637  const StringTreeLeaf& name_leaf = container.name[n].first;
638  _alias_array_pos[n] = PatternMatchAndIndexPosition(name_leaf, alias_head);
639  }
640 
641  for (size_t value_index = 0; value_index < num_values; value_index++)
642  {
643  if (_substituted[value_index])
644  continue;
645 
646  const auto& value_leaf = container.value[value_index];
647 
648  const StringTreeLeaf& leaf = value_leaf.first;
649 
650  int pattern_array_pos = PatternMatchAndIndexPosition(leaf, pattern_head);
651 
652  if (pattern_array_pos >= 0) // -1 if pattern doesn't match
653  {
654  boost::string_ref new_name;
655 
656  for (size_t n = 0; n < num_names; n++)
657  {
658  const auto& it = container.name[n];
659  const StringTreeLeaf& alias_leaf = it.first;
660 
661  if (_alias_array_pos[n] >= 0) // -1 if pattern doesn't match
662  {
663  if (alias_leaf.index_array[_alias_array_pos[n]] == leaf.index_array[pattern_array_pos])
664  {
665  new_name = it.second;
666  break;
667  }
668  }
669  }
670 
671  //--------------------------
672  if (!new_name.empty())
673  {
674  boost::container::static_vector<boost::string_ref, 12> concatenated_name;
675 
676  const StringTreeNode* node_ptr = leaf.node_ptr;
677 
678  int position = leaf.index_array.size() - 1;
679 
680  while (node_ptr != pattern_head)
681  {
682  const boost::string_ref& str_val = node_ptr->value();
683 
684  if (isNumberPlaceholder(str_val))
685  {
686  char buffer[16];
687  const int number = leaf.index_array[position--];
688  int str_size = print_number(buffer, number);
689  _formatted_string.push_back(std::string(buffer, str_size));
690  concatenated_name.push_back(_formatted_string.back());
691  }
692  else
693  {
694  concatenated_name.push_back(str_val);
695  }
696  node_ptr = node_ptr->parent();
697  }
698 
699  for (int s = rule->substitution().size() - 1; s >= 0; s--)
700  {
701  const boost::string_ref& str_val = rule->substitution()[s];
702 
703  if (isSubstitutionPlaceholder(str_val))
704  {
705  concatenated_name.push_back(new_name);
706  position--;
707  }
708  else
709  {
710  concatenated_name.push_back(str_val);
711  }
712  }
713 
714  for (size_t p = 0; p < rule->pattern().size() && node_ptr; p++)
715  {
716  node_ptr = node_ptr->parent();
717  }
718 
719  while (node_ptr)
720  {
721  boost::string_ref str_val = node_ptr->value();
722 
723  if (isNumberPlaceholder(str_val))
724  {
725  char buffer[16];
726  const int number = leaf.index_array[position--];
727  int str_size = print_number(buffer, number);
728  _formatted_string.push_back(std::string(buffer, str_size));
729  concatenated_name.push_back(_formatted_string.back());
730  }
731  else
732  {
733  concatenated_name.push_back(str_val);
734  }
735  node_ptr = node_ptr->parent();
736  }
737 
738  //------------------------
739  auto& renamed_pair = (*renamed_value)[value_index];
740 
741  if (skip_topicname)
742  {
743  concatenated_name.pop_back();
744  }
745 
746  std::reverse(concatenated_name.begin(), concatenated_name.end());
747  JoinStrings(concatenated_name, '/', renamed_pair.first);
748  renamed_pair.second = value_leaf.second;
749 
750  _substituted[value_index] = true;
751 
752  } // end if( new_name )
753  } // end if( PatternMatching )
754  } // end for values
755  } // end for rules
756  } // end rule found
757 
758  for (size_t value_index = 0; value_index < container.value.size(); value_index++)
759  {
760  if (!_substituted[value_index])
761  {
762  const std::pair<StringTreeLeaf, Variant>& value_leaf = container.value[value_index];
763 
764  std::string& destination = (*renamed_value)[value_index].first;
765  CreateStringFromTreeLeaf(value_leaf.first, skip_topicname, destination);
766  (*renamed_value)[value_index].second = value_leaf.second;
767  }
768  }
769 
770  for (size_t str_index = 0; str_index < container.name.size(); str_index++)
771  {
772  const std::pair<StringTreeLeaf, Variant>& str_leaf = container.name[str_index];
773 
774  size_t index = num_values + str_index;
775  std::string& destination = (*renamed_value)[ index ].first;
776  CreateStringFromTreeLeaf(str_leaf.first, skip_topicname, destination);
777  (*renamed_value)[index].second = str_leaf.second;
778  }
779 
780 }
781 
782 } // namespace RosIntrospection
int print_number(char *buffer, uint16_t value)
The StringTreeLeaf is, as the name suggests, a leaf (terminal node) of a StringTree. It provides the pointer to the node and a list of numbers that represent the index that corresponds to the placeholder "#".
const TreeNode< T > * croot() const
Constant pointer to the root of the tree.
const std::vector< boost::string_ref > & alias() const
std::vector< std::string > _formatted_string
std::vector< std::pair< StringTreeLeaf, std::string > > name
bool FindPattern(const std::vector< boost::string_ref > &pattern, size_t index, const StringTreeNode *tail, const StringTreeNode **head)
const StringTree * tree
Tree that the StringTreeLeaf(s) refer to.
TreeNode< T > * root()
Mutable pointer to the root of the tree.
type
std::vector< int > _alias_array_pos
Variant ReadFromBufferToVariant(const Span< uint8_t > &buffer, size_t &offset)
XmlRpcServer s
std::vector< ROSMessage > type_list
Definition: ros_message.hpp:84
Element of the tree. it has a single parent and N >= 0 children.
bool operator==(const std::string &a, const boost::string_ref &b)
const std::vector< ROSField > & fields() const
Vector of fields.
Definition: ros_message.hpp:60
std::unordered_map< std::string, std::vector< RulesCache > > _rule_caches
int PatternMatchAndIndexPosition(const StringTreeLeaf &leaf, const StringTreeNode *pattern_head)
auto sprintf(const S &fmt, const T &... args) -> std::basic_string< Char >
std::vector< std::vector< uint8_t > > blob_storage
#define S(x)
void JoinStrings(const VectorType &vect, const char separator, std::string &destination)
void CreateStringFromTreeLeaf(const StringTreeLeaf &leaf, bool skip_root, std::string &out)
bool isBuiltin() const
True if the type is ROS builtin.
Definition: ros_type.hpp:127
std::unordered_map< ROSType, std::unordered_set< SubstitutionRule > > _registered_rules
int builtinSize(const BuiltinType c)
std::unordered_map< std::string, ROSMessageInfo > _registered_messages
void ExpandVectorIfNecessary(Container &container, size_t new_size)
span_constexpr pointer data() const span_noexcept
auto var(V &&v)
boost::container::static_vector< uint16_t, 8 > index_array
constexpr auto count() -> size_t
void mutateType(const ROSType &new_type)
Definition: ros_message.hpp:64
std::vector< std::pair< StringTreeLeaf, Variant > > value
void applyVisitorToBuffer(const std::string &msg_identifier, const ROSType &monitored_type, Span< uint8_t > &buffer, VisitingCallback callback) const
applyVisitorToBuffer is used to pass a callback that is invoked every time a chunk of memory storing ...
void applyNameTransform(const std::string &msg_identifier, const FlatMessage &container, RenamedValues *renamed_value, bool dont_add_topicname=false)
applyNameTransform is used to create a vector of type RenamedValues from the vector FlatMessage::valu...
span_constexpr_exp reference back() const span_noexcept
iterator it
std::vector< int8_t > _substituted
std::size_t index
const ROSMessage * getMessageByType(const ROSType &type, const ROSMessageInfo &info) const
getMessageByType provides a pointer to a ROSMessage stored in ROSMessageInfo.
const StringTreeNode * node_ptr
const std::vector< boost::string_ref > & pattern() const
size_t & i
const std::vector< boost::string_ref > & substitution() const
def msg_type(f)
def field_type(f)
std::vector< std::pair< std::string, Variant > > RenamedValues
void createTrees(ROSMessageInfo &info, const std::string &type_name) const
BuiltinType typeID() const
If type is builtin, returns the id. BuiltinType::OTHER otherwise.
Definition: ros_type.hpp:137
bool isSubstitutionPlaceholder(const boost::string_ref &s)
span_constexpr size_type size() const span_noexcept
const ROSType & type() const
Definition: ros_message.hpp:62
std::vector< std::pair< StringTreeLeaf, Span< uint8_t > > > blob
const ROSMessageInfo * getMessageInfo(const std::string &msg_identifier) const
getMessageInfo provides some metadata amout a registered ROSMessage.
A ROSMessage will contain one or more ROSField(s). Each field is little more than a name / type pair...
Definition: ros_field.hpp:52
void updateMissingPkgNames(const std::vector< const ROSType *> &all_types)
Definition: ros_message.cpp:77
void registerRenamingRules(const ROSType &type, const std::vector< SubstitutionRule > &rules)
registerRenamingRules is used to register the renaming rules. You MUST use registerMessageDefinition ...
bool isNumberPlaceholder(const boost::string_ref &s)
std::function< void(const ROSType &, Span< uint8_t > &)> VisitingCallback
void registerMessageDefinition(const std::string &message_identifier, const ROSType &main_type, const std::string &definition)
A single message definition will (most probably) generate myltiple ROSMessage(s). In fact the "child"...
bool deserializeIntoFlatContainer(const std::string &msg_identifier, Span< uint8_t > buffer, FlatMessage *flat_container_output, const uint32_t max_array_size) const
deserializeIntoFlatContainer takes a raw buffer of memory and extract information from it...
void ReadFromBuffer(const Span< uint8_t > &buffer, size_t &offset, T &destination)
msg


plotjuggler_ros
Author(s): Davide Faconti
autogenerated on Fri Jun 23 2023 02:28:03