ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
loaned_message.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__LOANED_MESSAGE_HPP_
16 #define RCLCPP__LOANED_MESSAGE_HPP_
17 
18 #include <memory>
19 #include <utility>
20 
21 #include "rclcpp/allocator/allocator_common.hpp"
22 #include "rclcpp/logging.hpp"
23 #include "rclcpp/publisher_base.hpp"
24 
25 #include "rcl/allocator.h"
26 #include "rcl/publisher.h"
27 
28 namespace rclcpp
29 {
30 
31 template<typename MessageT, typename AllocatorT = std::allocator<void>>
33 {
34 public:
35  using MessageAllocatorTraits = rclcpp::allocator::AllocRebind<MessageT, AllocatorT>;
36  using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
37 
39 
59  const rclcpp::PublisherBase & pub,
60  MessageAllocator allocator)
61  : pub_(pub),
62  message_(nullptr),
63  message_allocator_(std::move(allocator))
64  {
65  if (pub_.can_loan_messages()) {
66  void * message_ptr = nullptr;
67  auto ret = rcl_borrow_loaned_message(
68  pub_.get_publisher_handle().get(),
69  rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
70  &message_ptr);
71  if (RCL_RET_OK != ret) {
72  rclcpp::exceptions::throw_from_rcl_error(ret);
73  }
74  message_ = static_cast<MessageT *>(message_ptr);
75  } else {
76  RCLCPP_INFO_ONCE(
77  rclcpp::get_logger("rclcpp"),
78  "Currently used middleware can't loan messages. Local allocator will be used.");
79  message_ = message_allocator_.allocate(1);
80  new (message_) MessageT();
81  }
82  }
83 
86  : pub_(std::move(other.pub_)),
87  message_(std::move(other.message_)),
88  message_allocator_(std::move(other.message_allocator_))
89  {
90  other.message_ = nullptr;
91  }
92 
94 
105  virtual ~LoanedMessage()
106  {
107  auto error_logger = rclcpp::get_logger("LoanedMessage");
108 
109  if (message_ == nullptr) {
110  return;
111  }
112 
113  if (pub_.can_loan_messages()) {
114  // return allocated memory to the middleware
115  auto ret =
117  if (ret != RCL_RET_OK) {
118  RCLCPP_ERROR(
119  error_logger, "rcl_deallocate_loaned_message failed: %s", rcl_get_error_string().str);
120  rcl_reset_error();
121  }
122  } else {
123  // call destructor before deallocating
124  message_->~MessageT();
125  message_allocator_.deallocate(message_, 1);
126  }
127  message_ = nullptr;
128  }
129 
131 
138  bool is_valid() const
139  {
140  return message_ != nullptr;
141  }
142 
144 
151  MessageT & get() const
152  {
153  return *message_;
154  }
155 
157 
167  std::unique_ptr<MessageT, std::function<void(MessageT *)>>
169  {
170  auto msg = message_;
171  message_ = nullptr;
172 
173  if (pub_.can_loan_messages()) {
174  return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(msg, [](MessageT *) {});
175  }
176 
177  return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(
178  msg,
179  [allocator = message_allocator_](MessageT * msg_ptr) mutable {
180  // call destructor before deallocating
181  msg_ptr->~MessageT();
182  allocator.deallocate(msg_ptr, 1);
183  });
184  }
185 
186 protected:
187  const rclcpp::PublisherBase & pub_;
188 
189  MessageT * message_;
190 
191  MessageAllocator message_allocator_;
192 
194  LoanedMessage(const LoanedMessage<MessageT> & other) = delete;
195 };
196 
197 } // namespace rclcpp
198 
199 #endif // RCLCPP__LOANED_MESSAGE_HPP_
std::unique_ptr< MessageT, std::function< void(MessageT *)> > release()
Release ownership of the ROS message instance.
LoanedMessage(const LoanedMessage< MessageT > &other)=delete
Deleted copy constructor to preserve memory integrity.
LoanedMessage(const rclcpp::PublisherBase &pub, MessageAllocator allocator)
Constructor of the LoanedMessage class.
MessageT & get() const
Access the ROS message instance.
LoanedMessage(LoanedMessage< MessageT > &&other)
Move semantic for RVO.
virtual ~LoanedMessage()
Destructor of the LoanedMessage class.
bool is_valid() const
Validate if the message was correctly allocated.
RCLCPP_PUBLIC std::shared_ptr< rcl_publisher_t > get_publisher_handle()
Get the rcl publisher handle.
RCLCPP_PUBLIC bool can_loan_messages() const
Check if publisher instance can loan messages.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:34
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_borrow_loaned_message(const rcl_publisher_t *publisher, const rosidl_message_type_support_t *type_support, void **ros_message)
Borrow a loaned message.
Definition: publisher.c:245
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_return_loaned_message_from_publisher(const rcl_publisher_t *publisher, void *loaned_message)
Return a loaned message previously borrowed from a publisher.
Definition: publisher.c:258
#define RCL_RET_OK
Success return code.
Definition: types.h:27