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> 48 std::function<void(const ROSMessage*, StringTreeNode*, MessageTreeNode*)> recursiveTreeCreator;
52 const size_t NUM_FIELDS = msg_definition->
fields().size();
54 string_node->children().reserve(NUM_FIELDS);
55 msg_node->children().reserve(NUM_FIELDS);
59 if (field.isConstant() ==
false)
62 string_node->addChild(field.name());
63 StringTreeNode* new_string_node = &(string_node->children().back());
66 new_string_node->
children().reserve(1);
67 new_string_node = new_string_node->
addChild(
"#");
72 if (field.type().isBuiltin() ==
false)
75 if (next_msg ==
nullptr)
77 throw std::runtime_error(
"This type was not registered ");
79 msg_node->addChild(next_msg);
81 recursiveTreeCreator(next_msg, new_string_node, new_msg_node);
94 inline bool operator==(
const std::string& a,
const boost::string_ref& b)
96 return (a.size() == b.size() && std::strncmp(a.data(), b.data(), a.size()) == 0);
102 if (tail->
value() == pattern[index])
117 if (index == pattern.size())
125 for (
auto& child : tail->
children())
137 for (
const auto& rule : given_rules)
139 if (rule_set.find(rule) == rule_set.end())
141 rule_set.insert(rule);
160 const std::unordered_set<SubstitutionRule>& rule_set = rule_it.second;
164 const std::string& msg_identifier = msg_it.first;
169 std::vector<RulesCache>& cache_vector =
_rule_caches[msg_identifier];
170 for (
const auto& rule : rule_set)
176 std::find(cache_vector.begin(), cache_vector.end(), cache) == cache_vector.end())
178 cache_vector.push_back(std::move(cache));
187 const std::string& definition)
195 static const boost::regex msg_separation_regex(
"^\\s*=+\\n+");
197 std::vector<std::string> split;
198 std::vector<const ROSType*> all_types;
200 boost::split_regex(split, definition, msg_separation_regex);
205 for (
size_t i = 0;
i < split.size(); ++
i)
213 info.
type_list.push_back(std::move(msg));
214 all_types.push_back(&(info.
type_list.back().type()));
235 return &(
it->second);
244 if (msg.
type() == type)
257 if (msg_info ==
nullptr)
259 throw std::runtime_error(
"extractField: msg_identifier not registered. Use registerMessageDefinition");
267 std::function<void(const MessageTreeNode*)> recursiveImpl;
268 size_t buffer_offset = 0;
271 const ROSMessage* msg_definition = msg_node->value();
274 const bool matching = (msg_type == monitored_type);
276 uint8_t* prev_buffer_ptr = buffer.
data() + buffer_offset;
277 size_t prev_offset = buffer_offset;
283 if (field.isConstant())
288 int32_t array_size = field.arraySize();
289 if (array_size == -1)
298 for (
int i = 0;
i < array_size;
i++)
307 for (
int i = 0;
i < array_size;
i++)
309 recursiveImpl(msg_node->child(index_m));
317 callback(monitored_type, view);
325 template <
typename Container>
328 if (container.size() <= new_size)
330 const size_t increased_size = std::max(
size_t(32), container.size() * 2);
331 container.resize(increased_size);
336 FlatMessage* flat_container,
const uint32_t max_array_size)
const 338 bool entire_message_parse =
true;
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;
346 if (msg_info ==
nullptr)
348 throw std::runtime_error(
"deserializeIntoFlatContainer: msg_identifier not registerd. Use " 349 "registerMessageDefinition");
351 size_t buffer_offset = 0;
353 std::function<void(const MessageTreeNode*, StringTreeLeaf, bool)> deserializeImpl;
362 bool DO_STORE =
store;
363 if (field.isConstant())
370 auto new_tree_leaf = tree_leaf;
371 new_tree_leaf.node_ptr = tree_leaf.node_ptr->child(index_s);
373 int32_t array_size = field.arraySize();
374 if (array_size == -1)
380 new_tree_leaf.index_array.push_back(0);
381 new_tree_leaf.node_ptr = new_tree_leaf.node_ptr->child(0);
384 bool IS_BLOB =
false;
387 if (array_size > static_cast<int32_t>(max_array_size) && field_type.
typeID() !=
OTHER)
399 entire_message_parse =
false;
407 if (buffer_offset + array_size > static_cast<std::size_t>(buffer.
size()))
409 throw std::runtime_error(
"Buffer overrun in deserializeIntoFlatContainer (blob)");
413 flat_container->
blob[blob_index].first = new_tree_leaf;
414 auto& blob = flat_container->
blob[blob_index].second;
423 std::memcpy(
storage.data(), &buffer[buffer_offset], array_size);
424 blob_storage_index++;
433 buffer_offset += array_size;
437 bool DO_STORE_ARRAY = DO_STORE;
438 for (
int i = 0;
i < array_size;
i++)
440 if (DO_STORE_ARRAY &&
i >= static_cast<int32_t>(max_array_size))
442 DO_STORE_ARRAY =
false;
445 if (field.isArray() && DO_STORE_ARRAY)
447 new_tree_leaf.index_array.
back() =
i;
454 uint32_t string_size = 0;
457 if (buffer_offset + string_size > static_cast<std::size_t>(buffer.
size()))
459 throw std::runtime_error(
"Buffer overrun in RosIntrospection::ReadFromBuffer");
464 if (string_size == 0)
467 flat_container->
name[name_index].second.clear();
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);
474 flat_container->
name[name_index].first = new_tree_leaf;
477 buffer_offset += string_size;
486 flat_container->
value[value_index] = std::make_pair(new_tree_leaf, std::move(var));
493 deserializeImpl(msg_node->
child(index_m), new_tree_leaf, DO_STORE_ARRAY);
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);
519 if (buffer.
size() - buffer_offset > 1)
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());
527 throw std::runtime_error(msg_buff);
529 return entire_message_parse;
534 return s.size() == 1 && s[0] ==
'#';
539 return s.size() == 1 && s[0] ==
'@';
552 if (node_ptr != pattern_head)
563 node_ptr = node_ptr->
parent();
568 template <
typename VectorType>
569 inline void JoinStrings(
const VectorType& vect,
const char separator, std::string& destination)
572 for (
const auto& v : vect)
578 destination.resize(count + vect.size() - 1);
580 char*
buffer = &destination[0];
583 for (
size_t c = 0; c < vect.size() - 1; c++)
585 const size_t S = vect[c].size();
586 std::memcpy(&buffer[buff_pos], vect[c].
data(), S);
588 buffer[buff_pos++] = separator;
590 std::memcpy(&buffer[buff_pos], vect.back().data(), vect.back().size());
604 const size_t num_values = container.
value.size();
605 const size_t num_names = container.
name.size();
607 renamed_value->resize( num_values + num_names );
615 for (
size_t i = 0;
i < num_values;
i++)
624 const std::vector<RulesCache>& rules_cache = rule_found->second;
632 if (!pattern_head || !alias_head)
635 for (
size_t n = 0; n < num_names; n++)
641 for (
size_t value_index = 0; value_index < num_values; value_index++)
646 const auto& value_leaf = container.
value[value_index];
652 if (pattern_array_pos >= 0)
654 boost::string_ref new_name;
656 for (
size_t n = 0; n < num_names; n++)
658 const auto&
it = container.
name[n];
665 new_name =
it.second;
672 if (!new_name.empty())
674 boost::container::static_vector<boost::string_ref, 12> concatenated_name;
680 while (node_ptr != pattern_head)
682 const boost::string_ref& str_val = node_ptr->
value();
694 concatenated_name.push_back(str_val);
696 node_ptr = node_ptr->
parent();
705 concatenated_name.push_back(new_name);
710 concatenated_name.push_back(str_val);
714 for (
size_t p = 0; p < rule->
pattern().size() && node_ptr; p++)
716 node_ptr = node_ptr->
parent();
721 boost::string_ref str_val = node_ptr->
value();
733 concatenated_name.push_back(str_val);
735 node_ptr = node_ptr->
parent();
739 auto& renamed_pair = (*renamed_value)[value_index];
743 concatenated_name.pop_back();
746 std::reverse(concatenated_name.begin(), concatenated_name.end());
747 JoinStrings(concatenated_name,
'/', renamed_pair.first);
748 renamed_pair.second = value_leaf.second;
758 for (
size_t value_index = 0; value_index < container.
value.size(); value_index++)
762 const std::pair<StringTreeLeaf, Variant>& value_leaf = container.
value[value_index];
764 std::string& destination = (*renamed_value)[value_index].first;
766 (*renamed_value)[value_index].second = value_leaf.second;
770 for (
size_t str_index = 0; str_index < container.
name.size(); str_index++)
772 const std::pair<StringTreeLeaf, Variant>& str_leaf = container.
name[str_index];
774 size_t index = num_values + str_index;
775 std::string& destination = (*renamed_value)[ index ].first;
777 (*renamed_value)[index].second = str_leaf.second;
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.
std::vector< int > _alias_array_pos
Variant ReadFromBufferToVariant(const Span< uint8_t > &buffer, size_t &offset)
std::vector< ROSMessage > type_list
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.
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
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.
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
const SubstitutionRule * rule
boost::container::static_vector< uint16_t, 8 > index_array
MaxArrayPolicy _discard_large_array
constexpr auto count() -> size_t
void mutateType(const ROSType &new_type)
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 ...
const ChildrenVector & children() const
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
std::vector< int8_t > _substituted
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 StringTreeNode * pattern_head
const std::vector< boost::string_ref > & pattern() const
const std::vector< boost::string_ref > & substitution() const
const TreeNode * parent() const
const StringTreeNode * alias_head
std::vector< std::pair< std::string, Variant > > RenamedValues
TreeNode * addChild(const T &child)
void createTrees(ROSMessageInfo &info, const std::string &type_name) const
BuiltinType typeID() const
If type is builtin, returns the id. BuiltinType::OTHER otherwise.
bool isSubstitutionPlaceholder(const boost::string_ref &s)
span_constexpr size_type size() const span_noexcept
const ROSType & type() const
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...
void updateMissingPkgNames(const std::vector< const ROSType *> &all_types)
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
const TreeNode * child(size_t index) const
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)