rclcpp  master
C++ ROS Client Library API
any_subscription_callback.hpp
Go to the documentation of this file.
1 // Copyright 2014 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__ANY_SUBSCRIPTION_CALLBACK_HPP_
16 #define RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
17 
18 #include <functional>
19 #include <memory>
20 #include <stdexcept>
21 #include <type_traits>
22 #include <utility>
23 #include <variant> // NOLINT[build/include_order]
24 
25 #include "tracetools/tracetools.h"
26 #include "tracetools/utils.hpp"
27 
31 #include "rclcpp/message_info.hpp"
32 
33 template<class>
34 inline constexpr bool always_false_v = false;
35 
36 namespace rclcpp
37 {
38 
39 namespace detail
40 {
41 
42 template<typename MessageT, typename AllocatorT>
44 {
46  using MessageAlloc = typename MessageAllocTraits::allocator_type;
48 };
49 
50 template<typename MessageT, typename AllocatorT>
52 {
54 
55  using ConstRefCallback =
56  std::function<void (const MessageT &)>;
58  std::function<void (const MessageT &, const rclcpp::MessageInfo &)>;
59 
60  using UniquePtrCallback =
64 
69 
74 
75  // Deprecated signatures:
76  using SharedPtrCallback =
80 
81  using variant_type = std::variant<
92  >;
93 };
94 
95 } // namespace detail
96 
97 template<
98  typename MessageT,
99  typename AllocatorT = std::allocator<void>
100 >
102 {
103 private:
106 
107  using MessageAllocTraits = typename MessageDeleterHelper::MessageAllocTraits;
108  using MessageAlloc = typename MessageDeleterHelper::MessageAlloc;
109  using MessageDeleter = typename MessageDeleterHelper::MessageDeleter;
110 
111  // See AnySubscriptionCallbackHelper for the types of these.
112  using ConstRefCallback = typename HelperT::ConstRefCallback;
113  using ConstRefWithInfoCallback = typename HelperT::ConstRefWithInfoCallback;
114 
115  using UniquePtrCallback = typename HelperT::UniquePtrCallback;
116  using UniquePtrWithInfoCallback = typename HelperT::UniquePtrWithInfoCallback;
117 
118  using SharedConstPtrCallback = typename HelperT::SharedConstPtrCallback;
119  using SharedConstPtrWithInfoCallback = typename HelperT::SharedConstPtrWithInfoCallback;
120 
121  using ConstRefSharedConstPtrCallback =
122  typename HelperT::ConstRefSharedConstPtrCallback;
123  using ConstRefSharedConstPtrWithInfoCallback =
124  typename HelperT::ConstRefSharedConstPtrWithInfoCallback;
125 
126  using SharedPtrCallback = typename HelperT::SharedPtrCallback;
127  using SharedPtrWithInfoCallback = typename HelperT::SharedPtrWithInfoCallback;
128 
129 public:
130  explicit
131  AnySubscriptionCallback(const AllocatorT & allocator = AllocatorT()) // NOLINT[runtime/explicit]
132  {
133  message_allocator_ = allocator;
134  allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
135  }
136 
137  [[deprecated("use AnySubscriptionCallback(const AllocatorT & allocator) instead")]]
138  explicit
139  AnySubscriptionCallback(std::shared_ptr<AllocatorT> allocator) // NOLINT[runtime/explicit]
140  {
141  if (allocator == nullptr) {
142  throw std::runtime_error("invalid allocator");
143  }
144  message_allocator_ = *allocator;
145  allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
146  }
147 
149 
151 
156  template<typename CallbackT>
158  set(CallbackT callback)
159  {
160  // Use the SubscriptionCallbackTypeHelper to determine the actual type of
161  // the CallbackT, in terms of std::function<...>, which does not happen
162  // automatically with lambda functions in cases where the arguments can be
163  // converted to one another, e.g. shared_ptr and unique_ptr.
165 
166  // Determine if the given CallbackT is a deprecated signature or not.
167  constexpr auto is_deprecated =
169  typename scbth::callback_type,
171  >::value
172  ||
174  typename scbth::callback_type,
176  >::value;
177 
178  // Use the discovered type to force the type of callback when assigning
179  // into the variant.
180  if constexpr (is_deprecated) {
181  // If deprecated, call sub-routine that is deprecated.
182  set_deprecated(static_cast<typename scbth::callback_type>(callback));
183  } else {
184  // Otherwise just assign it.
185  callback_variant_ = static_cast<typename scbth::callback_type>(callback);
186  }
187 
188  // Return copy of self for easier testing, normally will be compiled out.
189  return *this;
190  }
191 
193  // TODO(wjwwood): enable this deprecation after Galactic
194  // [[deprecated(
195  // "use 'void (std::shared_ptr<const MessageT>)' instead"
196  // )]]
197  void
199  // set(CallbackT callback)
200  {
201  callback_variant_ = callback;
202  }
203 
205  // TODO(wjwwood): enable this deprecation after Galactic
206  // [[deprecated(
207  // "use 'void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
208  // )]]
209  void
212  {
213  callback_variant_ = callback;
214  }
215 
218  {
219  auto ptr = MessageAllocTraits::allocate(message_allocator_, 1);
220  MessageAllocTraits::construct(message_allocator_, ptr, *message);
221  return std::unique_ptr<MessageT, MessageDeleter>(ptr, message_deleter_);
222  }
223 
224  void
227  const rclcpp::MessageInfo & message_info)
228  {
229  TRACEPOINT(callback_start, static_cast<const void *>(this), false);
230  // Check if the variant is "unset", throw if it is.
231  if (callback_variant_.index() == 0) {
232  if (std::get<0>(callback_variant_) == nullptr) {
233  // This can happen if it is default initialized, or if it is assigned nullptr.
234  throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
235  }
236  }
237  // Dispatch.
238  std::visit(
239  [&message, &message_info, this](auto && callback) {
240  using T = std::decay_t<decltype(callback)>;
241 
242  if constexpr (std::is_same_v<T, ConstRefCallback>) {
243  callback(*message);
244  } else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
245  callback(*message, message_info);
246  } else if constexpr (std::is_same_v<T, UniquePtrCallback>) {
248  } else if constexpr (std::is_same_v<T, UniquePtrWithInfoCallback>) {
249  callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
250  } else if constexpr ( // NOLINT[readability/braces]
251  std::is_same_v<T, SharedConstPtrCallback>||
252  std::is_same_v<T, ConstRefSharedConstPtrCallback>||
253  std::is_same_v<T, SharedPtrCallback>)
254  {
255  callback(message);
256  } else if constexpr ( // NOLINT[readability/braces]
257  std::is_same_v<T, SharedConstPtrWithInfoCallback>||
258  std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
259  std::is_same_v<T, SharedPtrWithInfoCallback>)
260  {
261  callback(message, message_info);
262  } else {
263  static_assert(always_false_v<T>, "unhandled callback type");
264  }
265  }, callback_variant_);
266  TRACEPOINT(callback_end, static_cast<const void *>(this));
267  }
268 
269  void
272  const rclcpp::MessageInfo & message_info)
273  {
274  TRACEPOINT(callback_start, static_cast<const void *>(this), true);
275  // Check if the variant is "unset", throw if it is.
276  if (callback_variant_.index() == 0) {
277  if (std::get<0>(callback_variant_) == nullptr) {
278  // This can happen if it is default initialized, or if it is assigned nullptr.
279  throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
280  }
281  }
282  // Dispatch.
283  std::visit(
284  [&message, &message_info, this](auto && callback) {
285  using T = std::decay_t<decltype(callback)>;
286 
287  if constexpr (std::is_same_v<T, ConstRefCallback>) {
288  callback(*message);
289  } else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
290  callback(*message, message_info);
291  } else if constexpr ( // NOLINT[readability/braces]
292  std::is_same_v<T, UniquePtrCallback>||
293  std::is_same_v<T, SharedPtrCallback>)
294  {
296  } else if constexpr ( // NOLINT[readability/braces]
297  std::is_same_v<T, UniquePtrWithInfoCallback>||
298  std::is_same_v<T, SharedPtrWithInfoCallback>)
299  {
300  callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
301  } else if constexpr ( // NOLINT[readability/braces]
302  std::is_same_v<T, SharedConstPtrCallback>||
303  std::is_same_v<T, ConstRefSharedConstPtrCallback>)
304  {
305  callback(message);
306  } else if constexpr ( // NOLINT[readability/braces]
307  std::is_same_v<T, SharedConstPtrWithInfoCallback>||
308  std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>)
309  {
310  callback(message, message_info);
311  } else {
312  static_assert(always_false_v<T>, "unhandled callback type");
313  }
314  }, callback_variant_);
315  TRACEPOINT(callback_end, static_cast<const void *>(this));
316  }
317 
318  void
321  const rclcpp::MessageInfo & message_info)
322  {
323  TRACEPOINT(callback_start, static_cast<const void *>(this), true);
324  // Check if the variant is "unset", throw if it is.
325  if (callback_variant_.index() == 0) {
326  if (std::get<0>(callback_variant_) == nullptr) {
327  // This can happen if it is default initialized, or if it is assigned nullptr.
328  throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
329  }
330  }
331  // Dispatch.
332  std::visit(
333  [&message, &message_info](auto && callback) {
334  using T = std::decay_t<decltype(callback)>;
335 
336  if constexpr (std::is_same_v<T, ConstRefCallback>) {
337  callback(*message);
338  } else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
339  callback(*message, message_info);
340  } else if constexpr ( // NOLINT[readability/braces]
341  std::is_same_v<T, UniquePtrCallback>||
342  std::is_same_v<T, SharedConstPtrCallback>||
343  std::is_same_v<T, ConstRefSharedConstPtrCallback>||
344  std::is_same_v<T, SharedPtrCallback>)
345  {
346  callback(std::move(message));
347  } else if constexpr ( // NOLINT[readability/braces]
348  std::is_same_v<T, UniquePtrWithInfoCallback>||
349  std::is_same_v<T, SharedConstPtrWithInfoCallback>||
350  std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
351  std::is_same_v<T, SharedPtrWithInfoCallback>)
352  {
353  callback(std::move(message), message_info);
354  } else {
355  static_assert(always_false_v<T>, "unhandled callback type");
356  }
357  }, callback_variant_);
358  TRACEPOINT(callback_end, static_cast<const void *>(this));
359  }
360 
361  constexpr
362  bool
364  {
365  return
366  std::holds_alternative<SharedConstPtrCallback>(callback_variant_) ||
367  std::holds_alternative<SharedConstPtrWithInfoCallback>(callback_variant_) ||
368  std::holds_alternative<ConstRefSharedConstPtrCallback>(callback_variant_) ||
369  std::holds_alternative<ConstRefSharedConstPtrWithInfoCallback>(callback_variant_);
370  }
371 
372  void
374  {
375 #ifndef TRACETOOLS_DISABLED
376  std::visit(
377  [this](auto && callback) {
378  TRACEPOINT(
379  rclcpp_callback_register,
380  static_cast<const void *>(this),
381  tracetools::get_symbol(callback));
382  }, callback_variant_);
383 #endif // TRACETOOLS_DISABLED
384  }
385 
386  typename HelperT::variant_type &
388  {
389  return callback_variant_;
390  }
391 
392  const typename HelperT::variant_type &
393  get_variant() const
394  {
395  return callback_variant_;
396  }
397 
398 private:
399  // TODO(wjwwood): switch to inheriting from std::variant (i.e. HelperT::variant_type) once
400  // inheriting from std::variant is realistic (maybe C++23?), see:
401  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2162r0.html
402  // For now, compose the variant into this class as a private attribute.
403  typename HelperT::variant_type callback_variant_;
404 
405  MessageAlloc message_allocator_;
406  MessageDeleter message_deleter_;
407 };
408 
409 } // namespace rclcpp
410 
411 #endif // RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
rclcpp::detail::AnySubscriptionCallbackHelper::UniquePtrWithInfoCallback
std::function< void(std::unique_ptr< MessageT, MessageDeleter >, const rclcpp::MessageInfo &)> UniquePtrWithInfoCallback
Definition: any_subscription_callback.hpp:63
std::shared_ptr
message_info.hpp
rclcpp::detail::AnySubscriptionCallbackHelper::SharedPtrCallback
std::function< void(std::shared_ptr< MessageT >)> SharedPtrCallback
Definition: any_subscription_callback.hpp:77
std::move
T move(T... args)
rclcpp::detail::AnySubscriptionCallbackHelper
Definition: any_subscription_callback.hpp:51
rclcpp::detail::MessageDeleterHelper::MessageDeleter
allocator::Deleter< MessageAlloc, MessageT > MessageDeleter
Definition: any_subscription_callback.hpp:47
subscription_callback_type_helper.hpp
rclcpp::detail::MessageDeleterHelper::MessageAlloc
typename MessageAllocTraits::allocator_type MessageAlloc
Definition: any_subscription_callback.hpp:46
rclcpp::detail::AnySubscriptionCallbackHelper::ConstRefWithInfoCallback
std::function< void(const MessageT &, const rclcpp::MessageInfo &)> ConstRefWithInfoCallback
Definition: any_subscription_callback.hpp:58
rclcpp::AnySubscriptionCallback::get_variant
const HelperT::variant_type & get_variant() const
Definition: any_subscription_callback.hpp:393
rclcpp::detail::AnySubscriptionCallbackHelper::MessageDeleter
typename MessageDeleterHelper< MessageT, AllocatorT >::MessageDeleter MessageDeleter
Definition: any_subscription_callback.hpp:53
std::function
rclcpp::AnySubscriptionCallback::set_deprecated
void set_deprecated(std::function< void(std::shared_ptr< MessageT >, const rclcpp::MessageInfo &)> callback)
Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
Definition: any_subscription_callback.hpp:210
rclcpp::AnySubscriptionCallback::use_take_shared_method
constexpr bool use_take_shared_method() const
Definition: any_subscription_callback.hpp:363
rclcpp::AnySubscriptionCallback::register_callback_for_tracing
void register_callback_for_tracing()
Definition: any_subscription_callback.hpp:373
rclcpp
This header provides the get_node_base_interface() template function.
Definition: allocator_common.hpp:24
always_false_v
constexpr bool always_false_v
Definition: any_subscription_callback.hpp:34
rclcpp::AnySubscriptionCallback::set
AnySubscriptionCallback< MessageT, AllocatorT > set(CallbackT callback)
Generic function for setting the callback.
Definition: any_subscription_callback.hpp:158
rclcpp::detail::MessageDeleterHelper
Definition: any_subscription_callback.hpp:43
rclcpp::detail::AnySubscriptionCallbackHelper::ConstRefSharedConstPtrWithInfoCallback
std::function< void(const std::shared_ptr< const MessageT > &, const rclcpp::MessageInfo &)> ConstRefSharedConstPtrWithInfoCallback
Definition: any_subscription_callback.hpp:73
rclcpp::allocator::set_allocator_for_deleter
void set_allocator_for_deleter(D *deleter, Alloc *alloc)
Definition: allocator_deleter.hpp:72
allocator_common.hpp
rclcpp::AnySubscriptionCallback::dispatch_intra_process
void dispatch_intra_process(std::unique_ptr< MessageT, MessageDeleter > message, const rclcpp::MessageInfo &message_info)
Definition: any_subscription_callback.hpp:319
rclcpp::detail::AnySubscriptionCallbackHelper::SharedConstPtrWithInfoCallback
std::function< void(std::shared_ptr< const MessageT >, const rclcpp::MessageInfo &)> SharedConstPtrWithInfoCallback
Definition: any_subscription_callback.hpp:68
rclcpp::allocator::AllocRebind
typename std::allocator_traits< Alloc >::template rebind_traits< T > AllocRebind
Definition: allocator_common.hpp:30
rclcpp::detail::AnySubscriptionCallbackHelper::SharedConstPtrCallback
std::function< void(std::shared_ptr< const MessageT >)> SharedConstPtrCallback
Definition: any_subscription_callback.hpp:66
rclcpp::AnySubscriptionCallback::dispatch_intra_process
void dispatch_intra_process(std::shared_ptr< const MessageT > message, const rclcpp::MessageInfo &message_info)
Definition: any_subscription_callback.hpp:270
rclcpp::detail::SubscriptionCallbackTypeHelper
Template metaprogramming helper used to resolve the callback argument into a std::function.
Definition: subscription_callback_type_helper.hpp:63
rclcpp::detail::AnySubscriptionCallbackHelper::variant_type
std::variant< ConstRefCallback, ConstRefWithInfoCallback, UniquePtrCallback, UniquePtrWithInfoCallback, SharedConstPtrCallback, SharedConstPtrWithInfoCallback, ConstRefSharedConstPtrCallback, ConstRefSharedConstPtrWithInfoCallback, SharedPtrCallback, SharedPtrWithInfoCallback > variant_type
Definition: any_subscription_callback.hpp:92
rclcpp::AnySubscriptionCallback
Definition: any_subscription_callback.hpp:101
std::runtime_error
rclcpp::AnySubscriptionCallback::set_deprecated
void set_deprecated(std::function< void(std::shared_ptr< MessageT >)> callback)
Function for shared_ptr to non-const MessageT, which is deprecated.
Definition: any_subscription_callback.hpp:198
rclcpp::detail::AnySubscriptionCallbackHelper::ConstRefCallback
std::function< void(const MessageT &)> ConstRefCallback
Definition: any_subscription_callback.hpp:56
rclcpp::AnySubscriptionCallback::AnySubscriptionCallback
AnySubscriptionCallback(const AllocatorT &allocator=AllocatorT())
Definition: any_subscription_callback.hpp:131
rclcpp::function_traits::same_arguments
Definition: function_traits.hpp:159
function_traits.hpp
rclcpp::detail::MessageDeleterHelper::MessageAllocTraits
allocator::AllocRebind< MessageT, AllocatorT > MessageAllocTraits
Definition: any_subscription_callback.hpp:45
rclcpp::MessageInfo
Additional meta data about messages taken from subscriptions.
Definition: message_info.hpp:26
rclcpp::AnySubscriptionCallback::get_variant
HelperT::variant_type & get_variant()
Definition: any_subscription_callback.hpp:387
rclcpp::allocator::Deleter
typename std::conditional< std::is_same< typename std::allocator_traits< Alloc >::template rebind_alloc< T >, typename std::allocator< void >::template rebind< T >::other >::value, std::default_delete< T >, AllocatorDeleter< Alloc > >::type Deleter
Definition: allocator_deleter.hpp:101
rclcpp::detail::AnySubscriptionCallbackHelper::ConstRefSharedConstPtrCallback
std::function< void(const std::shared_ptr< const MessageT > &)> ConstRefSharedConstPtrCallback
Definition: any_subscription_callback.hpp:71
rclcpp::AnySubscriptionCallback::AnySubscriptionCallback
AnySubscriptionCallback(std::shared_ptr< AllocatorT > allocator)
Definition: any_subscription_callback.hpp:139
rclcpp::AnySubscriptionCallback::create_unique_ptr_from_shared_ptr_message
std::unique_ptr< MessageT, MessageDeleter > create_unique_ptr_from_shared_ptr_message(const std::shared_ptr< const MessageT > &message)
Definition: any_subscription_callback.hpp:217
std::allocator
rclcpp::detail::AnySubscriptionCallbackHelper::UniquePtrCallback
std::function< void(std::unique_ptr< MessageT, MessageDeleter >)> UniquePtrCallback
Definition: any_subscription_callback.hpp:61
std::unique_ptr
rclcpp::AnySubscriptionCallback::dispatch
void dispatch(std::shared_ptr< MessageT > message, const rclcpp::MessageInfo &message_info)
Definition: any_subscription_callback.hpp:225