Switch to one participant per context model (#145)
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
5616437a4d
commit
8a1d3fc092
7 changed files with 1355 additions and 1599 deletions
|
@ -28,6 +28,7 @@ endif()
|
|||
find_package(ament_cmake_ros REQUIRED)
|
||||
|
||||
find_package(rcutils REQUIRED)
|
||||
find_package(rcpputils REQUIRED)
|
||||
|
||||
#find_package(cyclonedds_cmake_module REQUIRED)
|
||||
find_package(CycloneDDS QUIET CONFIG)
|
||||
|
@ -38,13 +39,16 @@ if(NOT CycloneDDS_FOUND)
|
|||
endif()
|
||||
|
||||
find_package(rmw REQUIRED)
|
||||
find_package(rmw_dds_common REQUIRED)
|
||||
find_package(rosidl_runtime_c REQUIRED)
|
||||
find_package(rosidl_typesupport_introspection_c REQUIRED)
|
||||
find_package(rosidl_typesupport_introspection_cpp REQUIRED)
|
||||
|
||||
ament_export_dependencies(rcutils)
|
||||
ament_export_dependencies(rcpputils)
|
||||
ament_export_dependencies(rmw)
|
||||
ament_export_dependencies(rosidl_runtime_c)
|
||||
ament_export_dependencies(rmw_dds_common)
|
||||
ament_export_dependencies(rosidl_typesupport_introspection_c)
|
||||
ament_export_dependencies(rosidl_typesupport_introspection_cpp)
|
||||
|
||||
|
@ -52,9 +56,9 @@ add_library(rmw_cyclonedds_cpp
|
|||
src/rmw_node.cpp
|
||||
src/serdata.cpp
|
||||
src/serdes.cpp
|
||||
src/graphrhc.cpp
|
||||
src/u16string.cpp
|
||||
src/exception.cpp
|
||||
src/demangle.cpp
|
||||
src/deserialization_exception.cpp
|
||||
src/Serialization.cpp
|
||||
src/TypeSupport2.cpp)
|
||||
|
@ -64,13 +68,17 @@ target_include_directories(rmw_cyclonedds_cpp PUBLIC
|
|||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
target_link_libraries(rmw_cyclonedds_cpp CycloneDDS::ddsc)
|
||||
target_link_libraries(rmw_cyclonedds_cpp
|
||||
CycloneDDS::ddsc
|
||||
)
|
||||
|
||||
ament_target_dependencies(rmw_cyclonedds_cpp
|
||||
"rcutils"
|
||||
"rcpputils"
|
||||
"rosidl_typesupport_introspection_c"
|
||||
"rosidl_typesupport_introspection_cpp"
|
||||
"rmw"
|
||||
"rmw_dds_common"
|
||||
"rosidl_runtime_c"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2019 ADLINK Technology
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
||||
#define RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
||||
|
||||
#include "dds/dds.h"
|
||||
|
||||
/* Introduction of custom RHC coincides with promoting the library instance & domains to entities,
|
||||
and so with the introduction of DDS_CYCLONEDDS_HANDLE. */
|
||||
#ifdef DDS_CYCLONEDDS_HANDLE
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
|
||||
struct dds_rhc * graphrhc_new();
|
||||
#endif // DDS_CYCLONEDDS_HANDLE
|
||||
|
||||
#endif // RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
<depend>cyclonedds</depend>
|
||||
<depend>rcutils</depend>
|
||||
<depend>rcpputils</depend>
|
||||
<depend>rmw</depend>
|
||||
<depend>rmw_dds_common</depend>
|
||||
<depend>rosidl_runtime_c</depend>
|
||||
<depend>rosidl_typesupport_introspection_c</depend>
|
||||
<depend>rosidl_typesupport_introspection_cpp</depend>
|
||||
|
|
197
rmw_cyclonedds_cpp/src/demangle.cpp
Normal file
197
rmw_cyclonedds_cpp/src/demangle.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
// Copyright 2016-2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcpputils/find_and_replace.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
#include "rcutils/types.h"
|
||||
#include "namespace_prefix.hpp"
|
||||
#include "demangle.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
const char * const ros_topic_prefix = "rt";
|
||||
const char * const ros_service_requester_prefix = "rq";
|
||||
const char * const ros_service_response_prefix = "rr";
|
||||
|
||||
const std::vector<std::string> _ros_prefixes =
|
||||
{ROS_TOPIC_PREFIX, ROS_SERVICE_REQUESTER_PREFIX, ROS_SERVICE_RESPONSE_PREFIX};
|
||||
} // extern "C"
|
||||
|
||||
/// Returns `name` stripped of `prefix`.
|
||||
std::string
|
||||
_resolve_prefix(const std::string & name, const std::string & prefix)
|
||||
{
|
||||
if (name.rfind(prefix, 0) == 0 && name.at(prefix.length()) == '/') {
|
||||
return name.substr(prefix.length());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// Strip the ROS specific prefix if it exists from the topic name.
|
||||
std::string
|
||||
_strip_ros_prefix_if_exists(const std::string & topic_name)
|
||||
{
|
||||
for (const auto & prefix : _ros_prefixes) {
|
||||
if (topic_name.rfind(prefix, 0) == 0 && topic_name.at(prefix.length()) == '/') {
|
||||
return topic_name.substr(prefix.length());
|
||||
}
|
||||
}
|
||||
return topic_name;
|
||||
}
|
||||
|
||||
/// Return the demangle ROS topic or the original if not a ROS topic.
|
||||
std::string
|
||||
_demangle_if_ros_topic(const std::string & topic_name)
|
||||
{
|
||||
return _strip_ros_prefix_if_exists(topic_name);
|
||||
}
|
||||
|
||||
/// Return the demangled ROS type or the original if not a ROS type.
|
||||
std::string
|
||||
_demangle_if_ros_type(const std::string & dds_type_string)
|
||||
{
|
||||
if (dds_type_string[dds_type_string.size() - 1] != '_') {
|
||||
// not a ROS type
|
||||
return dds_type_string;
|
||||
}
|
||||
|
||||
std::string substring = "dds_::";
|
||||
size_t substring_position = dds_type_string.find(substring);
|
||||
if (substring_position == std::string::npos) {
|
||||
// not a ROS type
|
||||
return dds_type_string;
|
||||
}
|
||||
|
||||
std::string type_namespace = dds_type_string.substr(0, substring_position);
|
||||
type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
|
||||
size_t start = substring_position + substring.size();
|
||||
std::string type_name = dds_type_string.substr(start, dds_type_string.length() - 1 - start);
|
||||
return type_namespace + type_name;
|
||||
}
|
||||
|
||||
/// Return the topic name for a given topic if it is part of one, else "".
|
||||
std::string
|
||||
_demangle_ros_topic_from_topic(const std::string & topic_name)
|
||||
{
|
||||
return _resolve_prefix(topic_name, ros_topic_prefix);
|
||||
}
|
||||
|
||||
/// Return the service name for a given topic if it is part of one, else "".
|
||||
std::string
|
||||
_demangle_service_from_topic(
|
||||
const std::string & prefix, const std::string & topic_name, std::string suffix)
|
||||
{
|
||||
std::string service_name = _resolve_prefix(topic_name, prefix);
|
||||
if ("" == service_name) {
|
||||
return "";
|
||||
}
|
||||
|
||||
size_t suffix_position = service_name.rfind(suffix);
|
||||
if (suffix_position != std::string::npos) {
|
||||
if (service_name.length() - suffix_position - suffix.length() != 0) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rmw_fastrtps_shared_cpp",
|
||||
"service topic has service prefix and a suffix, but not at the end"
|
||||
", report this: '%s'", topic_name.c_str());
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rmw_fastrtps_shared_cpp",
|
||||
"service topic has prefix but no suffix"
|
||||
", report this: '%s'", topic_name.c_str());
|
||||
return "";
|
||||
}
|
||||
return service_name.substr(0, suffix_position);
|
||||
}
|
||||
|
||||
std::string
|
||||
_demangle_service_from_topic(const std::string & topic_name)
|
||||
{
|
||||
const std::string demangled_topic = _demangle_service_reply_from_topic(topic_name);
|
||||
if ("" != demangled_topic) {
|
||||
return demangled_topic;
|
||||
}
|
||||
return _demangle_service_request_from_topic(topic_name);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
_demangle_service_request_from_topic(const std::string & topic_name)
|
||||
{
|
||||
return _demangle_service_from_topic(ros_service_requester_prefix, topic_name, "Request");
|
||||
}
|
||||
|
||||
std::string
|
||||
_demangle_service_reply_from_topic(const std::string & topic_name)
|
||||
{
|
||||
return _demangle_service_from_topic(ros_service_response_prefix, topic_name, "Reply");
|
||||
}
|
||||
|
||||
/// Return the demangled service type if it is a ROS srv type, else "".
|
||||
std::string
|
||||
_demangle_service_type_only(const std::string & dds_type_name)
|
||||
{
|
||||
std::string ns_substring = "dds_::";
|
||||
size_t ns_substring_position = dds_type_name.find(ns_substring);
|
||||
if (std::string::npos == ns_substring_position) {
|
||||
// not a ROS service type
|
||||
return "";
|
||||
}
|
||||
auto suffixes = {
|
||||
std::string("_Response_"),
|
||||
std::string("_Request_"),
|
||||
};
|
||||
std::string found_suffix = "";
|
||||
size_t suffix_position = 0;
|
||||
for (auto suffix : suffixes) {
|
||||
suffix_position = dds_type_name.rfind(suffix);
|
||||
if (suffix_position != std::string::npos) {
|
||||
if (dds_type_name.length() - suffix_position - suffix.length() != 0) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rmw_fastrtps_shared_cpp",
|
||||
"service type contains 'dds_::' and a suffix, but not at the end"
|
||||
", report this: '%s'", dds_type_name.c_str());
|
||||
continue;
|
||||
}
|
||||
found_suffix = suffix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (std::string::npos == suffix_position) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rmw_fastrtps_shared_cpp",
|
||||
"service type contains 'dds_::' but does not have a suffix"
|
||||
", report this: '%s'", dds_type_name.c_str());
|
||||
return "";
|
||||
}
|
||||
// everything checks out, reformat it from '[type_namespace::]dds_::<type><suffix>'
|
||||
// to '[type_namespace/]<type>'
|
||||
std::string type_namespace = dds_type_name.substr(0, ns_substring_position);
|
||||
type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
|
||||
size_t start = ns_substring_position + ns_substring.length();
|
||||
std::string type_name = dds_type_name.substr(start, suffix_position - start);
|
||||
return type_namespace + type_name;
|
||||
}
|
||||
|
||||
std::string
|
||||
_identity_demangle(const std::string & name)
|
||||
{
|
||||
return name;
|
||||
}
|
57
rmw_cyclonedds_cpp/src/demangle.hpp
Normal file
57
rmw_cyclonedds_cpp/src/demangle.hpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
// Copyright 2016-2018 Proyectos y Sistemas de Mantenimiento SL (eProsima).
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef DEMANGLE_HPP_
|
||||
#define DEMANGLE_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
/// Return the demangle ROS topic or the original if not a ROS topic.
|
||||
std::string
|
||||
_demangle_if_ros_topic(const std::string & topic_name);
|
||||
|
||||
/// Return the demangled ROS type or the original if not a ROS type.
|
||||
std::string
|
||||
_demangle_if_ros_type(const std::string & dds_type_string);
|
||||
|
||||
/// Return the topic name for a given topic if it is part of one, else "".
|
||||
std::string
|
||||
_demangle_ros_topic_from_topic(const std::string & topic_name);
|
||||
|
||||
/// Return the service name for a given topic if it is part of a service, else "".
|
||||
std::string
|
||||
_demangle_service_from_topic(const std::string & topic_name);
|
||||
|
||||
/// Return the service name for a given topic if it is part of a service request, else "".
|
||||
std::string
|
||||
_demangle_service_request_from_topic(const std::string & topic_name);
|
||||
|
||||
/// Return the service name for a given topic if it is part of a service reply, else "".
|
||||
std::string
|
||||
_demangle_service_reply_from_topic(const std::string & topic_name);
|
||||
|
||||
/// Return the demangled service type if it is a ROS srv type, else "".
|
||||
std::string
|
||||
_demangle_service_type_only(const std::string & dds_type_name);
|
||||
|
||||
/// Used when ros names are not mangled.
|
||||
std::string
|
||||
_identity_demangle(const std::string & name);
|
||||
|
||||
|
||||
using DemangleFunction = std::string (*)(const std::string &);
|
||||
using MangleFunction = DemangleFunction;
|
||||
|
||||
#endif // DEMANGLE_HPP_
|
|
@ -1,184 +0,0 @@
|
|||
// Copyright 2019 ADLINK Technology
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
||||
#define RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
||||
|
||||
#include "dds/dds.h"
|
||||
|
||||
/* Introduction of custom RHC coincides with promoting the library instance & domains to entities,
|
||||
and so with the introduction of DDS_CYCLONEDDS_HANDLE. */
|
||||
#ifdef DDS_CYCLONEDDS_HANDLE
|
||||
|
||||
#include "dds/ddsc/dds_rhc.h"
|
||||
|
||||
struct graphrhc : dds_rhc
|
||||
{
|
||||
struct dds_reader * reader;
|
||||
};
|
||||
|
||||
static dds_return_t graphrhc_associate(
|
||||
struct dds_rhc * rhc_cmn, struct dds_reader * reader,
|
||||
const struct ddsi_sertopic * topic,
|
||||
struct ddsi_tkmap * tkmap)
|
||||
{
|
||||
// C++ doesn't grok the fake inheritance in C, so static_cast won't work
|
||||
struct graphrhc * rhc = reinterpret_cast<struct graphrhc *>(rhc_cmn);
|
||||
rhc->reader = reader;
|
||||
static_cast<void>(topic);
|
||||
static_cast<void>(tkmap);
|
||||
return DDS_RETCODE_OK;
|
||||
}
|
||||
|
||||
static void graphrhc_free(struct ddsi_rhc * rhc_cmn)
|
||||
{
|
||||
// C++ doesn't grok the fake inheritance in C, so static_cast won't work
|
||||
struct graphrhc * rhc = reinterpret_cast<struct graphrhc *>(rhc_cmn);
|
||||
delete rhc;
|
||||
}
|
||||
|
||||
static bool graphrhc_store(
|
||||
struct ddsi_rhc * __restrict rhc_cmn,
|
||||
const struct ddsi_writer_info * __restrict wrinfo,
|
||||
struct ddsi_serdata * __restrict sample,
|
||||
struct ddsi_tkmap_instance * __restrict tk)
|
||||
{
|
||||
// C++ doesn't grok the fake inheritance in C, so static_cast won't work
|
||||
struct graphrhc * rhc = reinterpret_cast<struct graphrhc *>(rhc_cmn);
|
||||
dds_reader_data_available_cb(rhc->reader);
|
||||
static_cast<void>(wrinfo);
|
||||
static_cast<void>(sample);
|
||||
static_cast<void>(tk);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void graphrhc_unregister_wr(
|
||||
struct ddsi_rhc * __restrict rhc_cmn,
|
||||
const struct ddsi_writer_info * __restrict wrinfo)
|
||||
{
|
||||
// C++ doesn't grok the fake inheritance in C, so static_cast won't work
|
||||
struct graphrhc * rhc = reinterpret_cast<struct graphrhc *>(rhc_cmn);
|
||||
dds_reader_data_available_cb(rhc->reader);
|
||||
static_cast<void>(wrinfo);
|
||||
}
|
||||
|
||||
static void graphrhc_relinquish_ownership(
|
||||
struct ddsi_rhc * __restrict rhc_cmn,
|
||||
const uint64_t wr_iid)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(wr_iid);
|
||||
}
|
||||
|
||||
static void graphrhc_set_qos(struct ddsi_rhc * rhc_cmn, const struct dds_qos * qos)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(qos);
|
||||
}
|
||||
|
||||
static int graphrhc_read(
|
||||
struct dds_rhc * rhc_cmn, bool lock, void ** values,
|
||||
dds_sample_info_t * info_seq, uint32_t max_samples, uint32_t mask,
|
||||
dds_instance_handle_t handle, struct dds_readcond * cond)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(lock);
|
||||
static_cast<void>(values);
|
||||
static_cast<void>(info_seq);
|
||||
static_cast<void>(max_samples);
|
||||
static_cast<void>(mask);
|
||||
static_cast<void>(handle);
|
||||
static_cast<void>(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int graphrhc_take(
|
||||
struct dds_rhc * rhc_cmn, bool lock, void ** values,
|
||||
dds_sample_info_t * info_seq, uint32_t max_samples, uint32_t mask,
|
||||
dds_instance_handle_t handle, struct dds_readcond * cond)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(lock);
|
||||
static_cast<void>(values);
|
||||
static_cast<void>(info_seq);
|
||||
static_cast<void>(max_samples);
|
||||
static_cast<void>(mask);
|
||||
static_cast<void>(handle);
|
||||
static_cast<void>(cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int graphrhc_takecdr(
|
||||
struct dds_rhc * rhc_cmn, bool lock, struct ddsi_serdata ** values,
|
||||
dds_sample_info_t * info_seq, uint32_t max_samples,
|
||||
uint32_t sample_states, uint32_t view_states, uint32_t instance_states,
|
||||
dds_instance_handle_t handle)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(lock);
|
||||
static_cast<void>(values);
|
||||
static_cast<void>(info_seq);
|
||||
static_cast<void>(max_samples);
|
||||
static_cast<void>(sample_states);
|
||||
static_cast<void>(view_states);
|
||||
static_cast<void>(instance_states);
|
||||
static_cast<void>(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool graphrhc_add_readcondition(struct dds_rhc * rhc_cmn, struct dds_readcond * cond)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(cond);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void graphrhc_remove_readcondition(struct dds_rhc * rhc_cmn, struct dds_readcond * cond)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
static_cast<void>(cond);
|
||||
}
|
||||
|
||||
static uint32_t graphrhc_lock_samples(struct dds_rhc * rhc_cmn)
|
||||
{
|
||||
static_cast<void>(rhc_cmn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dds_rhc_ops graphrhc_ops = {
|
||||
{
|
||||
graphrhc_store,
|
||||
graphrhc_unregister_wr,
|
||||
graphrhc_relinquish_ownership,
|
||||
graphrhc_set_qos,
|
||||
graphrhc_free
|
||||
},
|
||||
graphrhc_read,
|
||||
graphrhc_take,
|
||||
graphrhc_takecdr,
|
||||
graphrhc_add_readcondition,
|
||||
graphrhc_remove_readcondition,
|
||||
graphrhc_lock_samples,
|
||||
graphrhc_associate
|
||||
};
|
||||
|
||||
struct dds_rhc * graphrhc_new()
|
||||
{
|
||||
auto rhc = new graphrhc;
|
||||
rhc->common.ops = &graphrhc_ops;
|
||||
return static_cast<struct dds_rhc *>(rhc);
|
||||
}
|
||||
|
||||
#endif // DDS_CYCLONEDDS_HANDLE
|
||||
|
||||
#endif // RMW_CYCLONEDDS_CPP__GRAPHRHC_HPP_
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue