Skip to content

[22894] Apply demangling to ROS 2 topics in IDL view #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Find more about us at [eProsima’s webpage](https://eprosima.com/).

## Documentation

You can access the documentation online, which is hosted on [Read the Docs](https://eprosima-dds-router.readthedocs.io).
You can access the documentation online, which is hosted on [Read the Docs](https://fast-dds-statistics-backend.readthedocs.io).

* [Introduction](https://fast-dds-statistics-backend.readthedocs.io/en/latest/)
* [Installation Manual](https://fast-dds-statistics-backend.readthedocs.io/en/latest/rst/installation/linux_installation.html)
Expand Down
1 change: 1 addition & 0 deletions docs/rst/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Colcon
datareader
datasharing
datawriter
demangled
Deserialize
destructor
eprosima
Expand Down
22 changes: 21 additions & 1 deletion include/fastdds_statistics_backend/StatisticsBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class StatisticsBackend
EntityId entity_id);

/**
* @brief Get the IDL representation of a data type in string format for a given topic entity
* @brief Get the IDL representation of a data type in string format for a given topic entity.
*
* @param entity_id The entity for which the data type IDL is retrieved.
* @return String object describing the entity's data type IDL.
Expand All @@ -284,6 +284,26 @@ class StatisticsBackend
static std::string get_type_idl(
EntityId entity_id);

/**
* @brief Get the demangled type name in string format for a given topic entity, if it exists, for display purposes.
*
* @param entity_id The entity for which the data type IDL is retrieved.
* @return String object describing the entity's data type IDL.
*/
FASTDDS_STATISTICS_BACKEND_DllAPI
static std::string get_ros2_type_name(
EntityId entity_id);

/**
* @brief Get the ROS 2 IDL representation of a data type in string format for a given topic entity, if it exists.
*
* @param entity_id The entity for which the data type IDL is retrieved.
* @return String object describing the entity's data type IDL.
*/
FASTDDS_STATISTICS_BACKEND_DllAPI
static std::string get_ros2_type_idl(
EntityId entity_id);

/**
* @brief Returns the id of the topic associated to an endpoint.
*
Expand Down
24 changes: 24 additions & 0 deletions src/cpp/StatisticsBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,30 @@ std::string StatisticsBackend::get_type_idl(
return StatisticsBackendData::get_instance()->database_->get_type_idl(topic_info[DATA_TYPE_TAG]);
}

std::string StatisticsBackend::get_ros2_type_name(
EntityId entity_id)
{
// Check if the entity is a topic
if (EntityKind::TOPIC != get_type(entity_id))
{
throw BadParameter("EntityId received does not match with a valid topic entity");
}
Info topic_info = StatisticsBackend::get_info(entity_id);
return StatisticsBackendData::get_instance()->database_->get_ros2_type_name(topic_info[DATA_TYPE_TAG]);
}

std::string StatisticsBackend::get_ros2_type_idl(
EntityId entity_id)
{
// Check if the entity is a topic
if (EntityKind::TOPIC != get_type(entity_id))
{
throw BadParameter("EntityId received does not match with a valid topic entity");
}
Info topic_info = StatisticsBackend::get_info(entity_id);
return StatisticsBackendData::get_instance()->database_->get_ros2_type_idl(topic_info[DATA_TYPE_TAG]);
}

EntityId StatisticsBackend::get_endpoint_topic_id(
EntityId endpoint_id)
{
Expand Down
150 changes: 147 additions & 3 deletions src/cpp/database/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,24 +283,119 @@ EntityId Database::insert_new_topic(
bool Database::is_type_in_database(
const std::string& type_name)
{
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
return (type_idls_.find(type_name) != type_idls_.end());
}

void Database::insert_new_type_idl(
const std::string& type_name,
const std::string& type_idl)
{
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
// Check that type name is not empty
if (type_name.empty())
{
throw BadParameter("Type name cannot be empty");
EPROSIMA_LOG_ERROR(BACKEND_DATABASE, "Type name cannot be empty");
return;
}

// Check that type name is not already registered and we're trying to delete the type IDL
if (is_type_in_database(type_name) && type_idl.empty())
{
return;
}
type_idls_[type_name] = type_idl;

if (type_idl.find("module dds_\n") != std::string::npos
|| type_idl.find("::dds_::") != std::string::npos
|| type_name.find("dds_") != std::string::npos)
{
//Perform the demangling operations

std::string type_name_demangled = type_name;
std::string type_idl_demangled = type_idl;

//Step 1: delete the module dds_

while (type_idl_demangled.find("module dds_\n") != std::string::npos)
{
//First: delete the module dds_ identification, and the open brace
size_t pos_start = type_idl_demangled.find("module dds_\n");
size_t pos_open_brace = type_idl_demangled.find("{", pos_start);
type_idl_demangled.erase(pos_start, pos_open_brace - pos_start + 2);

//Second: find next line, and delete dangling whitespace
size_t pos_line = type_idl_demangled.find_first_not_of(" ", pos_start);
type_idl_demangled.erase(pos_start, pos_line - pos_start);

//Third: unindent all the content
pos_start = type_idl_demangled.find(" ", pos_start);
while (type_idl_demangled[type_idl_demangled.find_first_not_of(" ", pos_start)] != '}')
{
type_idl_demangled.erase(pos_start, 4);
size_t pos_new_line = type_idl_demangled.find_first_not_of(' ', pos_start);
pos_start = type_idl_demangled.find(" ", pos_new_line);
}

//Fourth: delete the closing brace and whitespace
size_t pos_end = type_idl_demangled.find("};", pos_start);
type_idl_demangled.erase(pos_start - 1, pos_end - pos_start + 3);
}

//Step 2: delete the ::dds_:: namespace

while (type_name_demangled.find("::dds_::") != std::string::npos)
{
size_t pos = type_name_demangled.find("::dds_::");
type_name_demangled.erase(pos, 6);
}

while (type_idl_demangled.find("::dds_::") != std::string::npos)
{
size_t pos = type_idl_demangled.find("::dds_::");
type_idl_demangled.erase(pos, 6);
}

//Step 3: delete the underscores

while (type_name_demangled.back() == '_')
{
type_name_demangled.pop_back();
}

while (type_idl_demangled.find("__") != std::string::npos)
{
size_t pos = type_idl_demangled.find("__");
type_idl_demangled.erase(pos, 2);
}

while (type_idl_demangled.find("_ ") != std::string::npos)
{
size_t pos = type_idl_demangled.find("_ ");
type_idl_demangled.erase(pos, 1);
}

while (type_idl_demangled.find("_\n") != std::string::npos)
{
size_t pos = type_idl_demangled.find("_\n");
type_idl_demangled.erase(pos, 1);
}

while (type_idl_demangled.find("_>") != std::string::npos)
{
size_t pos = type_idl_demangled.find("_>");
type_idl_demangled.erase(pos, 1);
}

//Register the now demangled idl, the original as backup, and their relation
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
type_idls_[type_name] = type_idl_demangled;
type_ros2_unmodified_idl_[type_name] = type_idl;
type_ros2_modified_name_[type_name] = type_name_demangled;
}
else
{
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
type_idls_[type_name] = type_idl;
}
}

EntityId Database::insert_new_endpoint(
Expand Down Expand Up @@ -2486,6 +2581,55 @@ std::string Database::get_type_idl_nts(
throw BadParameter("Type " + type_name + " not found in the database");
}

std::string Database::get_ros2_type_name(
const std::string& type_name) const
{
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
return get_ros2_type_name_nts(type_name);
}

std::string Database::get_ros2_type_name_nts(
const std::string& type_name) const
{
auto it = type_ros2_modified_name_.find(type_name);
if (it != type_ros2_modified_name_.end())
{
// The type was demangled
return it->second;
}
else
{
auto it_non_ros2 = type_idls_.find(type_name);
if (it_non_ros2 != type_idls_.end())
{
return type_name;
}
throw BadParameter("Type " + type_name + " not found in the database");
}
}

std::string Database::get_ros2_type_idl(
const std::string& type_name) const
{
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
return get_ros2_type_idl_nts(type_name);
}

std::string Database::get_ros2_type_idl_nts(
const std::string& type_name) const
{
auto it = type_ros2_unmodified_idl_.find(type_name);
if (it != type_ros2_unmodified_idl_.end())
{
// The type was demangled
return it->second;
}
else
{
return get_type_idl_nts(type_name);
}
}

void Database::erase(
EntityId& domain_id)
{
Expand Down
58 changes: 56 additions & 2 deletions src/cpp/database/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,10 @@ class Database
const std::string& type_name);

/**
* @brief Insert a new type IDL into the database or update it.
* @brief Insert a new type IDL into the database or update it, and perform ROS 2 demangling if needed.
* If demangled, insert the demangled type IDL and separately, the original one as *topic_name*_backup_.
* @param topic_type The type of the topic.
* @param topic_idl The IDL representation of the type
* @param topic_idl The IDL representation of the type.
*/
void insert_new_type_idl(
const std::string& topic_type,
Expand Down Expand Up @@ -472,6 +473,26 @@ class Database
std::string get_type_idl(
const std::string& type_name) const;

/**
* @brief Get the demangled type name of a given type, if it exists, for display purposes.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The name type in std::string format.
*/
std::string get_ros2_type_name(
const std::string& type_name) const;

/**
* @brief Get the original ROS 2 type IDL of a given type name, if it exists.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The original ROS 2 IDL representation of the type in std::string format.
*/
std::string get_ros2_type_idl(
const std::string& type_name) const;

/**
* @brief Get the entity of a given EntityKind that matches with the requested GUID.
*
Expand Down Expand Up @@ -1225,6 +1246,26 @@ class Database
std::string get_type_idl_nts(
const std::string& type_name) const;

/**
* @brief Get the demangled type name of a given type, if it exists, for display purposes. This method is not thread safe.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The name type in std::string format.
*/
std::string get_ros2_type_name_nts(
const std::string& type_name) const;

/**
* @brief Get the original ROS 2 type IDL of a given type name, if it exists. This method is not thread safe.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The original ROS 2 IDL representation of the type in std::string format.
*/
std::string get_ros2_type_idl_nts(
const std::string& type_name) const;

/**
* @brief Get the entity of a given EntityKind that matches with the requested GUID. This method is not thread safe.
*
Expand Down Expand Up @@ -1512,6 +1553,19 @@ class Database
*/
std::map<std::string, std::string> type_idls_;

/**
* Collection of type names relating the original name and the ROS 2 demangled name.
* Only those types that have been modified are stored.
*/
std::map<std::string, std::string> type_ros2_modified_name_;

/**
* Collection of type idls relating the original idl and the original name.
* Note that demangling is done by default, so the demangled IDL is stored in the main map.
* Only those types that have been modified are stored.
*/
std::map<std::string, std::string> type_ros2_unmodified_idl_;

//! Graph map describing per domain complete topology of the entities.
std::map<EntityId, Graph> domain_view_graph;

Expand Down
Loading