shape_shifter.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 // SPDX-FileCopyrightText: Czech Technical University in Prague
3 
10 // HACK begin we need to access many private fields of topic_tools::ShapeShifter
11 #include <sstream>
12 #define private public
13 #include <topic_tools/shape_shifter.h>
14 #undef private
15 // HACK end
16 
17 
18 #include <algorithm>
19 #include <utility>
20 
21 #include <boost/shared_ptr.hpp>
22 
23 #include <ros/common.h>
24 #include <ros/serialization.h>
25 #include <std_msgs/Header.h>
26 
29 
31 
32 namespace cras
33 {
34 
35 #if ROS_VERSION_MINIMUM(1, 15, 0)
36 
38 {
39  return msg.msgBuf.data();
40 }
41 
42 const uint8_t* getBuffer(const topic_tools::ShapeShifter& msg)
43 {
44  return msg.msgBuf.data();
45 }
46 
47 void resizeBuffer(topic_tools::ShapeShifter& msg, size_t newLength)
48 {
49  if (newLength == msg.size())
50  return;
51  // resize() makes sure that if the buffer was reallocated, the start of the old buffer will get copied to the new one
52  msg.msgBuf.resize(newLength);
53 }
54 
56 {
57  out = in;
58 }
59 
60 #else
61 
63 {
64  return msg.msgBuf;
65 }
66 
67 const uint8_t* getBuffer(const topic_tools::ShapeShifter& msg)
68 {
69  return msg.msgBuf;
70 }
71 
72 void resizeBuffer(topic_tools::ShapeShifter& msg, size_t newLength)
73 {
74  if (newLength == msg.size())
75  return;
76  if (newLength < msg.size())
77  {
78  msg.msgBufUsed = newLength;
79  }
80  else
81  {
82  auto oldBuf = msg.msgBuf;
83  const auto oldLength = msg.msgBufUsed;
84  msg.msgBuf = new uint8_t[newLength];
85  msg.msgBufAlloc = newLength;
86  msg.msgBufUsed = newLength;
87  // Not exactly needed, but to keep compatibility with the Noetic version
88  std::memcpy(msg.msgBuf, oldBuf, oldLength);
89  delete[] oldBuf;
90  }
91 }
92 
94 {
95  out = in;
96  out.msgBuf = new uint8_t[in.msgBufUsed];
97  out.msgBufAlloc = in.msgBufUsed;
98  std::memcpy(out.msgBuf, in.msgBuf, in.msgBufUsed);
99 }
100 
101 #endif
102 
104 {
105  return msg.size();
106 }
107 
109 {
110  // This is a bit simplified but there is no really good way to detect it (cannot use rosmsg_cpp as the embedded
111  // Python cannot be run in multiple nodelets; cannot use ros_msg_parser as it has not yet been released).
112  // TODO: Consider using ros_msg_parser when it is released
113  return cras::contains(msg.getMessageDefinition(), "Header header");
114 }
115 
116 cras::optional<std_msgs::Header> getHeader(const topic_tools::ShapeShifter& msg)
117 {
118  try
119  {
120  auto p = boost::make_shared<std_msgs::Header>();
121 
122  ros::serialization::IStream s(const_cast<uint8_t*>(cras::getBuffer(msg)), cras::getBufferLength(msg));
124 
125  return *p;
126  }
127  catch (...)
128  {
129  return cras::nullopt;
130  }
131 }
132 
133 bool setHeader(topic_tools::ShapeShifter& msg, std_msgs::Header& header)
134 {
135  const auto oldHeader = cras::getHeader(msg);
136  if (!oldHeader.has_value())
137  return false;
138 
139  const auto oldHeaderLength = ros::serialization::serializationLength(oldHeader.value());
140  const auto newHeaderLength = ros::serialization::serializationLength(header);
141  const auto oldLength = msg.size();
142  const auto newLength = oldLength + newHeaderLength - oldHeaderLength;
143 
144  if (oldHeaderLength == newHeaderLength)
145  {
146  // New message is same length as the old one - we just overwrite the header
147  try
148  {
150  ros::serialization::serialize(ostream, header);
151  return true;
152  }
153  catch (...)
154  {
155  return false;
156  }
157  }
158  else if (newHeaderLength < oldHeaderLength)
159  {
160  // New message is shorter - we just move the data part to the left
161  cras::resizeBuffer(msg, newLength); // The buffer remains the same.
162  auto buffer = cras::getBuffer(msg);
163  try
164  {
165  ros::serialization::OStream ostream(buffer, newLength);
166  ros::serialization::serialize(ostream, header);
167  std::memmove(buffer + newHeaderLength, buffer + oldHeaderLength, oldLength - oldHeaderLength);
168  return true;
169  }
170  catch (...)
171  {
172  return false;
173  }
174  }
175  else
176  {
177  // New message is longer - we need to reallocate the buffer, move its data to the right and then write new header
178  cras::resizeBuffer(msg, newLength); // buffer contents are copied to the reallocated one
179  auto buffer = cras::getBuffer(msg);
180  std::memmove(buffer + newHeaderLength, buffer + oldHeaderLength, oldLength - oldHeaderLength);
181  try
182  {
183  ros::serialization::OStream ostream(buffer, newLength);
184  ros::serialization::serialize(ostream, header);
185  return true;
186  }
187  catch (...)
188  {
189  return false;
190  }
191  }
192 }
193 
194 #if ROS_VERSION_MINIMUM(1, 15, 0)
195 #else
196 
197 ShapeShifter::ShapeShifter() = default;
198 ShapeShifter::~ShapeShifter() = default;
199 
201  ShapeShifter(reinterpret_cast<const ShapeShifter&>(other))
202 {
203 }
204 
206  ShapeShifter(reinterpret_cast<ShapeShifter &&>(other))
207 {
208 }
209 
211 {
212  return operator=(reinterpret_cast<const ShapeShifter&>(other));
213 }
214 
216 {
217  return operator=(reinterpret_cast<ShapeShifter &&>(other));
218 }
219 
221 {
222  this->md5 = other.md5;
223  this->datatype = other.datatype;
224  this->msg_def = other.msg_def;
225  this->latching = other.latching;
226  this->typed = other.typed;
227  this->msgBufUsed = this->msgBufAlloc = other.msgBufUsed;
228  if (other.msgBuf != nullptr && other.msgBufUsed > 0)
229  {
230  this->msgBuf = new uint8_t[other.msgBufUsed];
231  memcpy(this->msgBuf, other.msgBuf, other.msgBufUsed);
232  }
233 }
234 
236 {
237  this->md5 = other.md5;
238  this->datatype = other.datatype;
239  this->msg_def = other.msg_def;
240  this->latching = other.latching;
241  this->typed = other.typed;
242  this->msgBufUsed = this->msgBufAlloc = other.msgBufUsed;
243  if (other.msgBuf != nullptr && other.msgBufUsed > 0)
244  {
245  this->msgBuf = std::exchange(other.msgBuf, nullptr);
246  other.msgBufAlloc = 0;
247  other.msgBufUsed = 0;
248  }
249 }
250 
252 {
253  if (this == &other)
254  return *this;
255 
256  this->md5 = other.md5;
257  this->datatype = other.datatype;
258  this->msg_def = other.msg_def;
259  this->latching = other.latching;
260  this->typed = other.typed;
261  this->msgBufUsed = other.msgBufUsed;
262  if (other.msgBuf != nullptr && other.msgBufUsed > 0)
263  {
264  if (this->msgBufAlloc < other.msgBufUsed)
265  {
266  delete[] this->msgBuf;
267  this->msgBuf = new uint8_t[other.msgBufUsed];
268  this->msgBufAlloc = other.msgBufUsed;
269  }
270  memcpy(this->msgBuf, other.msgBuf, other.msgBufUsed);
271  }
272  else if (this->msgBuf != nullptr)
273  {
274  delete[] this->msgBuf;
275  this->msgBuf = nullptr;
276  this->msgBufAlloc = 0;
277  }
278  return *this;
279 }
280 
282 {
283  if (this == &other)
284  return *this;
285 
286  this->md5 = other.md5;
287  this->datatype = other.datatype;
288  this->msg_def = other.msg_def;
289  this->latching = other.latching;
290  this->typed = other.typed;
291  std::swap(this->msgBufUsed, other.msgBufUsed);
292  std::swap(this->msgBufAlloc, other.msgBufAlloc);
293  std::swap(this->msgBuf, other.msgBuf);
294  return *this;
295 }
296 
297 #endif
298 
299 }
msg
void copyShapeShifter(const ::topic_tools::ShapeShifter &in, ::topic_tools::ShapeShifter &out)
Copy in ShapeShifter to out.
uint8_t * getBuffer(::topic_tools::ShapeShifter &msg)
Get the internal buffer with serialized message data.
ShapeShifter & operator=(const ::topic_tools::ShapeShifter &other)
~ShapeShifter() override
::cras::optional<::std_msgs::Header > getHeader(const ::topic_tools::ShapeShifter &msg)
Get the header field of the given message, if it has any.
XmlRpcServer s
uint32_t size() const
void serialize(Stream &stream, const T &t)
Tools for more convenient working with ShapeShifter objects.
std::string const & getMessageDefinition() const
bool setHeader(::topic_tools::ShapeShifter &msg, ::std_msgs::Header &header)
Change the header field of the given message, if it has any.
size_t getBufferLength(const ::topic_tools::ShapeShifter &msg)
Get the length of the internal buffer with serialized message data.
void resizeBuffer(::topic_tools::ShapeShifter &msg, size_t newLength)
Resize the internal buffer of the message.
uint32_t serializationLength(const T &t)
ShapeShifter class with fixed behavior on copy/move on Melodic. Use this class everywhere possible to...
bool contains(const ::std::string &str, char c)
bool hasHeader(const ::topic_tools::ShapeShifter &msg)
Tell whether the given message has header field.
void deserialize(Stream &stream, T &t)


cras_topic_tools
Author(s): Martin Pecka
autogenerated on Sat Jun 17 2023 02:33:13