ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
intra_process_buffer.hpp
1 // Copyright 2019 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__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
16 #define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
17 
18 #include <memory>
19 #include <stdexcept>
20 #include <type_traits>
21 #include <utility>
22 
23 #include "rclcpp/allocator/allocator_common.hpp"
24 #include "rclcpp/allocator/allocator_deleter.hpp"
25 #include "rclcpp/experimental/buffers/buffer_implementation_base.hpp"
26 #include "rclcpp/macros.hpp"
27 
28 namespace rclcpp
29 {
30 namespace experimental
31 {
32 namespace buffers
33 {
34 
36 {
37 public:
38  RCLCPP_SMART_PTR_ALIASES_ONLY(IntraProcessBufferBase)
39 
40  virtual ~IntraProcessBufferBase() {}
41 
42  virtual void clear() = 0;
43 
44  virtual bool has_data() const = 0;
45  virtual bool use_take_shared_method() const = 0;
46 };
47 
48 template<
49  typename MessageT,
50  typename Alloc = std::allocator<void>,
51  typename MessageDeleter = std::default_delete<MessageT>>
53 {
54 public:
55  RCLCPP_SMART_PTR_ALIASES_ONLY(IntraProcessBuffer)
56 
57  virtual ~IntraProcessBuffer() {}
58 
59  using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
60  using MessageSharedPtr = std::shared_ptr<const MessageT>;
61 
62  virtual void add_shared(MessageSharedPtr msg) = 0;
63  virtual void add_unique(MessageUniquePtr msg) = 0;
64 
65  virtual MessageSharedPtr consume_shared() = 0;
66  virtual MessageUniquePtr consume_unique() = 0;
67 };
68 
69 template<
70  typename MessageT,
71  typename Alloc = std::allocator<void>,
72  typename MessageDeleter = std::default_delete<MessageT>,
73  typename BufferT = std::unique_ptr<MessageT>>
74 class TypedIntraProcessBuffer : public IntraProcessBuffer<MessageT, Alloc, MessageDeleter>
75 {
76 public:
77  RCLCPP_SMART_PTR_DEFINITIONS(TypedIntraProcessBuffer)
78 
79  using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
80  using MessageAlloc = typename MessageAllocTraits::allocator_type;
81  using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
82  using MessageSharedPtr = std::shared_ptr<const MessageT>;
83 
84  explicit
86  std::unique_ptr<BufferImplementationBase<BufferT>> buffer_impl,
87  std::shared_ptr<Alloc> allocator = nullptr)
88  {
89  bool valid_type = (std::is_same<BufferT, MessageSharedPtr>::value ||
90  std::is_same<BufferT, MessageUniquePtr>::value);
91  if (!valid_type) {
92  throw std::runtime_error("Creating TypedIntraProcessBuffer with not valid BufferT");
93  }
94 
95  buffer_ = std::move(buffer_impl);
96 
97  if (!allocator) {
98  message_allocator_ = std::make_shared<MessageAlloc>();
99  } else {
100  message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
101  }
102  }
103 
104  virtual ~TypedIntraProcessBuffer() {}
105 
106  void add_shared(MessageSharedPtr msg) override
107  {
108  add_shared_impl<BufferT>(std::move(msg));
109  }
110 
111  void add_unique(MessageUniquePtr msg) override
112  {
113  buffer_->enqueue(std::move(msg));
114  }
115 
116  MessageSharedPtr consume_shared() override
117  {
118  return consume_shared_impl<BufferT>();
119  }
120 
121  MessageUniquePtr consume_unique() override
122  {
123  return consume_unique_impl<BufferT>();
124  }
125 
126  bool has_data() const override
127  {
128  return buffer_->has_data();
129  }
130 
131  void clear() override
132  {
133  buffer_->clear();
134  }
135 
136  bool use_take_shared_method() const override
137  {
138  return std::is_same<BufferT, MessageSharedPtr>::value;
139  }
140 
141 private:
142  std::unique_ptr<BufferImplementationBase<BufferT>> buffer_;
143 
144  std::shared_ptr<MessageAlloc> message_allocator_;
145 
146  // MessageSharedPtr to MessageSharedPtr
147  template<typename DestinationT>
148  typename std::enable_if<
149  std::is_same<DestinationT, MessageSharedPtr>::value
150  >::type
151  add_shared_impl(MessageSharedPtr shared_msg)
152  {
153  buffer_->enqueue(std::move(shared_msg));
154  }
155 
156  // MessageSharedPtr to MessageUniquePtr
157  template<typename DestinationT>
158  typename std::enable_if<
159  std::is_same<DestinationT, MessageUniquePtr>::value
160  >::type
161  add_shared_impl(MessageSharedPtr shared_msg)
162  {
163  // This should not happen: here a copy is unconditionally made, while the intra-process manager
164  // can decide whether a copy is needed depending on the number and the type of buffers
165 
166  MessageUniquePtr unique_msg;
167  MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(shared_msg);
168  auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
169  MessageAllocTraits::construct(*message_allocator_.get(), ptr, *shared_msg);
170  if (deleter) {
171  unique_msg = MessageUniquePtr(ptr, *deleter);
172  } else {
173  unique_msg = MessageUniquePtr(ptr);
174  }
175 
176  buffer_->enqueue(std::move(unique_msg));
177  }
178 
179  // MessageSharedPtr to MessageSharedPtr
180  template<typename OriginT>
181  typename std::enable_if<
182  std::is_same<OriginT, MessageSharedPtr>::value,
183  MessageSharedPtr
184  >::type
185  consume_shared_impl()
186  {
187  return buffer_->dequeue();
188  }
189 
190  // MessageUniquePtr to MessageSharedPtr
191  template<typename OriginT>
192  typename std::enable_if<
193  (std::is_same<OriginT, MessageUniquePtr>::value),
194  MessageSharedPtr
195  >::type
196  consume_shared_impl()
197  {
198  // automatic cast from unique ptr to shared ptr
199  return buffer_->dequeue();
200  }
201 
202  // MessageSharedPtr to MessageUniquePtr
203  template<typename OriginT>
204  typename std::enable_if<
205  (std::is_same<OriginT, MessageSharedPtr>::value),
206  MessageUniquePtr
207  >::type
208  consume_unique_impl()
209  {
210  MessageSharedPtr buffer_msg = buffer_->dequeue();
211 
212  MessageUniquePtr unique_msg;
213  MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(buffer_msg);
214  auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
215  MessageAllocTraits::construct(*message_allocator_.get(), ptr, *buffer_msg);
216  if (deleter) {
217  unique_msg = MessageUniquePtr(ptr, *deleter);
218  } else {
219  unique_msg = MessageUniquePtr(ptr);
220  }
221 
222  return unique_msg;
223  }
224 
225  // MessageUniquePtr to MessageUniquePtr
226  template<typename OriginT>
227  typename std::enable_if<
228  (std::is_same<OriginT, MessageUniquePtr>::value),
229  MessageUniquePtr
230  >::type
231  consume_unique_impl()
232  {
233  return buffer_->dequeue();
234  }
235 };
236 
237 } // namespace buffers
238 } // namespace experimental
239 } // namespace rclcpp
240 
241 
242 #endif // RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.