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


ros_type_introspection
Author(s): Davide Faconti
autogenerated on Sun Sep 6 2020 03:19:54