ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
duration.cpp
1 // Copyright 2017 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 #include <cmath>
16 #include <cstdlib>
17 #include <limits>
18 #include <utility>
19 
20 #include "rclcpp/clock.hpp"
21 #include "rclcpp/time.hpp"
22 
23 #include "builtin_interfaces/msg/duration.hpp"
24 
25 #include "rcl/time.h"
26 
27 #include "rclcpp/exceptions.hpp"
28 
29 #include "rcutils/logging_macros.h"
30 
31 namespace rclcpp
32 {
33 
34 Duration::Duration(int32_t seconds, uint32_t nanoseconds)
35 {
36  rcl_duration_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(seconds));
37  rcl_duration_.nanoseconds += nanoseconds;
38 }
39 
40 Duration::Duration(std::chrono::nanoseconds nanoseconds)
41 {
42  rcl_duration_.nanoseconds = nanoseconds.count();
43 }
44 
45 Duration::Duration(const Duration & rhs) = default;
46 
47 Duration::Duration(
48  const builtin_interfaces::msg::Duration & duration_msg)
49 {
50  rcl_duration_.nanoseconds =
51  RCL_S_TO_NS(static_cast<rcl_duration_value_t>(duration_msg.sec));
52  rcl_duration_.nanoseconds += static_cast<rcl_duration_value_t>(duration_msg.nanosec);
53 }
54 
55 Duration::Duration(const rcl_duration_t & duration)
56 : rcl_duration_(duration)
57 {
58  // noop
59 }
60 
61 Duration::operator builtin_interfaces::msg::Duration() const
62 {
63  builtin_interfaces::msg::Duration msg_duration;
64  constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
65  constexpr int32_t max_s = std::numeric_limits<int32_t>::max();
66  constexpr int32_t min_s = std::numeric_limits<int32_t>::min();
67  constexpr uint32_t max_ns = std::numeric_limits<uint32_t>::max();
68  const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
69  if (result.rem >= 0) {
70  // saturate if we will overflow
71  if (result.quot > max_s) {
72  msg_duration.sec = max_s;
73  msg_duration.nanosec = max_ns;
74  } else {
75  msg_duration.sec = static_cast<int32_t>(result.quot);
76  msg_duration.nanosec = static_cast<uint32_t>(result.rem);
77  }
78  } else {
79  if (result.quot <= min_s) {
80  msg_duration.sec = min_s;
81  msg_duration.nanosec = 0u;
82  } else {
83  msg_duration.sec = static_cast<int32_t>(result.quot - 1);
84  msg_duration.nanosec = static_cast<uint32_t>(kDivisor + result.rem);
85  }
86  }
87  return msg_duration;
88 }
89 
90 Duration &
91 Duration::operator=(const Duration & rhs) = default;
92 
93 Duration &
94 Duration::operator=(const builtin_interfaces::msg::Duration & duration_msg)
95 {
96  *this = Duration(duration_msg);
97  return *this;
98 }
99 
100 bool
101 Duration::operator==(const rclcpp::Duration & rhs) const
102 {
103  return rcl_duration_.nanoseconds == rhs.rcl_duration_.nanoseconds;
104 }
105 
106 bool
107 Duration::operator!=(const rclcpp::Duration & rhs) const
108 {
109  return rcl_duration_.nanoseconds != rhs.rcl_duration_.nanoseconds;
110 }
111 
112 bool
113 Duration::operator<(const rclcpp::Duration & rhs) const
114 {
115  return rcl_duration_.nanoseconds < rhs.rcl_duration_.nanoseconds;
116 }
117 
118 bool
119 Duration::operator<=(const rclcpp::Duration & rhs) const
120 {
121  return rcl_duration_.nanoseconds <= rhs.rcl_duration_.nanoseconds;
122 }
123 
124 bool
125 Duration::operator>=(const rclcpp::Duration & rhs) const
126 {
127  return rcl_duration_.nanoseconds >= rhs.rcl_duration_.nanoseconds;
128 }
129 
130 bool
131 Duration::operator>(const rclcpp::Duration & rhs) const
132 {
133  return rcl_duration_.nanoseconds > rhs.rcl_duration_.nanoseconds;
134 }
135 
136 void
137 bounds_check_duration_sum(int64_t lhsns, int64_t rhsns, uint64_t max)
138 {
139  auto abs_lhs = static_cast<uint64_t>(std::abs(lhsns));
140  auto abs_rhs = static_cast<uint64_t>(std::abs(rhsns));
141 
142  if (lhsns > 0 && rhsns > 0) {
143  if (abs_lhs + abs_rhs > max) {
144  throw std::overflow_error("addition leads to int64_t overflow");
145  }
146  } else if (lhsns < 0 && rhsns < 0) {
147  if (abs_lhs + abs_rhs > max) {
148  throw std::underflow_error("addition leads to int64_t underflow");
149  }
150  }
151 }
152 
153 Duration
154 Duration::operator+(const rclcpp::Duration & rhs) const
155 {
156  bounds_check_duration_sum(
157  this->rcl_duration_.nanoseconds,
158  rhs.rcl_duration_.nanoseconds,
159  std::numeric_limits<rcl_duration_value_t>::max());
161  rcl_duration_.nanoseconds + rhs.rcl_duration_.nanoseconds);
162 }
163 
164 void
165 bounds_check_duration_difference(int64_t lhsns, int64_t rhsns, uint64_t max)
166 {
167  auto abs_lhs = static_cast<uint64_t>(std::abs(lhsns));
168  auto abs_rhs = static_cast<uint64_t>(std::abs(rhsns));
169 
170  if (lhsns > 0 && rhsns < 0) {
171  if (abs_lhs + abs_rhs > max) {
172  throw std::overflow_error("duration subtraction leads to int64_t overflow");
173  }
174  } else if (lhsns < 0 && rhsns > 0) {
175  if (abs_lhs + abs_rhs > max) {
176  throw std::underflow_error("duration subtraction leads to int64_t underflow");
177  }
178  }
179 }
180 
181 Duration
182 Duration::operator-(const rclcpp::Duration & rhs) const
183 {
184  bounds_check_duration_difference(
185  this->rcl_duration_.nanoseconds,
186  rhs.rcl_duration_.nanoseconds,
187  std::numeric_limits<rcl_duration_value_t>::max());
188 
190  rcl_duration_.nanoseconds - rhs.rcl_duration_.nanoseconds);
191 }
192 
193 void
194 bounds_check_duration_scale(int64_t dns, double scale, uint64_t max)
195 {
196  auto abs_dns = static_cast<uint64_t>(std::abs(dns));
197  auto abs_scale = std::abs(scale);
198  if (abs_scale > 1.0 && abs_dns >
199  static_cast<uint64_t>(static_cast<long double>(max) / static_cast<long double>(abs_scale)))
200  {
201  if ((dns > 0 && scale > 0) || (dns < 0 && scale < 0)) {
202  throw std::overflow_error("duration scaling leads to int64_t overflow");
203  } else {
204  throw std::underflow_error("duration scaling leads to int64_t underflow");
205  }
206  }
207 }
208 
209 Duration
210 Duration::operator*(double scale) const
211 {
212  if (!std::isfinite(scale)) {
213  throw std::runtime_error("abnormal scale in rclcpp::Duration");
214  }
215  bounds_check_duration_scale(
216  this->rcl_duration_.nanoseconds,
217  scale,
218  std::numeric_limits<rcl_duration_value_t>::max());
219  long double scale_ld = static_cast<long double>(scale);
221  static_cast<rcl_duration_value_t>(
222  static_cast<long double>(rcl_duration_.nanoseconds) * scale_ld));
223 }
224 
227 {
228  return rcl_duration_.nanoseconds;
229 }
230 
231 Duration
233 {
234  return Duration(std::numeric_limits<int32_t>::max(), 999999999);
235 }
236 
237 double
239 {
240  return std::chrono::duration<double>(std::chrono::nanoseconds(rcl_duration_.nanoseconds)).count();
241 }
242 
243 rmw_time_t
245 {
246  if (rcl_duration_.nanoseconds < 0) {
247  throw std::runtime_error("rmw_time_t cannot be negative");
248  }
249 
250  // Purposefully avoid creating from builtin_interfaces::msg::Duration
251  // to avoid possible overflow converting from int64_t to int32_t, then back to uint64_t
252  rmw_time_t result;
253  constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
254  const auto div_result = std::div(rcl_duration_.nanoseconds, kDivisor);
255  result.sec = static_cast<uint64_t>(div_result.quot);
256  result.nsec = static_cast<uint64_t>(div_result.rem);
257 
258  return result;
259 }
260 
261 Duration
262 Duration::from_rmw_time(rmw_time_t duration)
263 {
264  Duration ret;
265  constexpr rcl_duration_value_t limit_ns = std::numeric_limits<rcl_duration_value_t>::max();
266  constexpr rcl_duration_value_t limit_sec = RCL_NS_TO_S(limit_ns);
267  if (duration.sec > limit_sec || duration.nsec > limit_ns) {
268  // saturate if will overflow
269  ret.rcl_duration_.nanoseconds = limit_ns;
270  return ret;
271  }
272  uint64_t total_ns = RCL_S_TO_NS(duration.sec) + duration.nsec;
273  if (total_ns > limit_ns) {
274  // saturate if will overflow
275  ret.rcl_duration_.nanoseconds = limit_ns;
276  return ret;
277  }
278  ret.rcl_duration_.nanoseconds = static_cast<rcl_duration_value_t>(total_ns);
279  return ret;
280 }
281 
282 Duration
283 Duration::from_seconds(double seconds)
284 {
285  Duration ret;
286  ret.rcl_duration_.nanoseconds = static_cast<int64_t>(RCL_S_TO_NS(seconds));
287  return ret;
288 }
289 
290 Duration
292 {
293  Duration ret;
294  ret.rcl_duration_.nanoseconds = nanoseconds;
295  return ret;
296 }
297 
298 } // namespace rclcpp
rcl_duration_value_t nanoseconds() const
Get duration in nanosecods.
Definition: duration.cpp:226
double seconds() const
Get duration in seconds.
Definition: duration.cpp:238
static Duration from_nanoseconds(rcl_duration_value_t nanoseconds)
Create a duration object from an integer number representing nanoseconds.
Definition: duration.cpp:291
static Duration max()
Get the maximum representable value.
Definition: duration.cpp:232
rmw_time_t to_rmw_time() const
Convert Duration into rmw_time_t.
Definition: duration.cpp:244
static Duration from_seconds(double seconds)
Create a duration object from a floating point number representing seconds.
Definition: duration.cpp:283
Duration(int32_t seconds, uint32_t nanoseconds)
Duration constructor.
Definition: duration.cpp:34
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
A duration of time, measured in nanoseconds and its source.
Definition: time.h:75
rcl_duration_value_t nanoseconds
Duration in nanoseconds and its source.
Definition: time.h:77
#define RCL_NS_TO_S
Convenience macro to convert nanoseconds to seconds.
Definition: time.h:39
rcutils_duration_value_t rcl_duration_value_t
A duration of time, measured in nanoseconds.
Definition: time.h:48
#define RCL_S_TO_NS
Convenience macro to convert seconds to nanoseconds.
Definition: time.h:32