ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
subscription_intra_process_buffer.hpp
1 // Copyright 2021 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
16 #define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
17 
18 #include <memory>
19 #include <string>
20 #include <stdexcept>
21 #include <utility>
22 
23 #include "rcl/error_handling.h"
24 #include "rcl/guard_condition.h"
25 #include "rcl/wait.h"
26 
27 #include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
28 #include "rclcpp/experimental/create_intra_process_buffer.hpp"
29 #include "rclcpp/experimental/subscription_intra_process_base.hpp"
30 #include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
31 #include "rclcpp/qos.hpp"
32 #include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
33 
34 #include "tracetools/tracetools.h"
35 
36 namespace rclcpp
37 {
38 namespace experimental
39 {
40 
41 template<
42  typename SubscribedType,
43  typename Alloc = std::allocator<SubscribedType>,
44  typename Deleter = std::default_delete<SubscribedType>,
47  typename ROSMessageType = SubscribedType
48 >
50  typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
51  allocator::Deleter<typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
52  ROSMessageType>>
53 {
54 public:
55  RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
56 
57  using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, Alloc>;
58  using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
59  using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
60 
61  using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
62  using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
63  using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
64 
65  using ConstMessageSharedPtr = std::shared_ptr<const ROSMessageType>;
66  using MessageUniquePtr = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
67 
68  using ConstDataSharedPtr = std::shared_ptr<const SubscribedType>;
69  using SubscribedTypeUniquePtr = std::unique_ptr<SubscribedType, SubscribedTypeDeleter>;
70 
71  using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
72  SubscribedType,
73  Alloc,
74  SubscribedTypeDeleter
75  >::UniquePtr;
76 
78  std::shared_ptr<Alloc> allocator,
79  rclcpp::Context::SharedPtr context,
80  const std::string & topic_name,
81  const rclcpp::QoS & qos_profile,
83  : SubscriptionROSMsgIntraProcessBuffer<ROSMessageType, ROSMessageTypeAllocator,
84  ROSMessageTypeDeleter>(
85  context, topic_name, qos_profile),
86  subscribed_type_allocator_(*allocator)
87  {
88  allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
89 
90  // Create the intra-process buffer.
91  buffer_ = rclcpp::experimental::create_intra_process_buffer<SubscribedType, Alloc,
92  SubscribedTypeDeleter>(
93  buffer_type,
94  qos_profile,
95  std::make_shared<Alloc>(subscribed_type_allocator_));
96  TRACETOOLS_TRACEPOINT(
97  rclcpp_ipb_to_subscription,
98  static_cast<const void *>(buffer_.get()),
99  static_cast<const void *>(this));
100  }
101 
102  void
103  add_to_wait_set(rcl_wait_set_t & wait_set) override
104  {
105  if (this->buffer_->has_data()) {
106  this->trigger_guard_condition();
107  }
108  detail::add_guard_condition_to_rcl_wait_set(wait_set, this->gc_);
109  }
110 
111  bool
112  is_ready([[maybe_unused]] const rcl_wait_set_t & wait_set) override
113  {
114  return buffer_->has_data();
115  }
116 
117  SubscribedTypeUniquePtr
118  convert_ros_message_to_subscribed_type_unique_ptr(const ROSMessageType & msg)
119  {
120  if constexpr (!std::is_same<SubscribedType, ROSMessageType>::value) {
121  auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
122  SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr);
124  return SubscribedTypeUniquePtr(ptr, subscribed_type_deleter_);
125  } else {
126  throw std::runtime_error(
127  "convert_ros_message_to_subscribed_type_unique_ptr "
128  "unexpectedly called without TypeAdapter");
129  }
130  }
131 
132  void
133  provide_intra_process_message(ConstMessageSharedPtr message) override
134  {
135  if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
136  buffer_->add_shared(std::move(message));
137  trigger_guard_condition();
138  } else {
139  buffer_->add_shared(convert_ros_message_to_subscribed_type_unique_ptr(*message));
140  trigger_guard_condition();
141  }
142  this->invoke_on_new_message();
143  }
144 
145  void
146  provide_intra_process_message(MessageUniquePtr message) override
147  {
148  if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
149  buffer_->add_unique(std::move(message));
150  trigger_guard_condition();
151  } else {
152  buffer_->add_unique(convert_ros_message_to_subscribed_type_unique_ptr(*message));
153  trigger_guard_condition();
154  }
155  this->invoke_on_new_message();
156  }
157 
158  void
159  provide_intra_process_data(ConstDataSharedPtr message)
160  {
161  buffer_->add_shared(std::move(message));
162  trigger_guard_condition();
163  this->invoke_on_new_message();
164  }
165 
166  void
167  provide_intra_process_data(SubscribedTypeUniquePtr message)
168  {
169  buffer_->add_unique(std::move(message));
170  trigger_guard_condition();
171  this->invoke_on_new_message();
172  }
173 
174  bool
175  use_take_shared_method() const override
176  {
177  return buffer_->use_take_shared_method();
178  }
179 
180  size_t available_capacity() const override
181  {
182  return buffer_->available_capacity();
183  }
184 
185 protected:
186  void
187  trigger_guard_condition() override
188  {
189  this->gc_.trigger();
190  }
191 
192  BufferUniquePtr buffer_;
193  SubscribedTypeAllocator subscribed_type_allocator_;
194  SubscribedTypeDeleter subscribed_type_deleter_;
195 };
196 
197 } // namespace experimental
198 } // namespace rclcpp
199 
200 #endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
RCLCPP_PUBLIC void trigger()
Signal that the condition has been met, notifying both the wait set and listeners,...
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
void add_to_wait_set(rcl_wait_set_t &wait_set) override
Add the Waitable to a wait set.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
Template structure used to adapt custom, user-defined types to ROS types.