@@ -243,6 +243,61 @@ class Handle
243243 // END
244244 }
245245
246+ /* *
247+ * @brief Get the value of the handle.
248+ * @tparam T The type of the value to be retrieved.
249+ * @param value The variable to store the retrieved value.
250+ * @param wait_for_lock If true, the method will wait for the lock to be available, else it will
251+ * try to get the lock without blocking.
252+ * @return true if the value is retrieved successfully, false otherwise.
253+ *
254+ * @note The method is thread-safe.
255+ * @note This method is real-time safe or non-blocking, only if wait_for_lock is set to false.
256+ * @note Ideal for the data types that are large in size to avoid copy during return.
257+ */
258+ template <
259+ typename T, typename = std::enable_if_t <
260+ !std::is_same_v<std::decay_t <T>, std::shared_lock<std::shared_mutex>>>>
261+ [[nodiscard]] bool get_value (T & value, bool wait_for_lock) const
262+ {
263+ if (wait_for_lock)
264+ {
265+ std::shared_lock<std::shared_mutex> lock (handle_mutex_);
266+ return get_value (lock, value);
267+ }
268+ else
269+ {
270+ std::shared_lock<std::shared_mutex> lock (handle_mutex_, std::try_to_lock);
271+ return get_value (lock, value);
272+ }
273+ }
274+
275+ /* *
276+ * @brief Set the value of the handle.
277+ * @tparam T The type of the value to be set.
278+ * @param value The value to be set.
279+ * @param wait_for_lock If true, the method will wait for the lock to be available, else it will
280+ * try to get the lock without blocking.
281+ * @return true if the value is set successfully, false otherwise.
282+ *
283+ * @note The method is thread-safe.
284+ * @note This method is real-time safe or non-blocking, only if wait_for_lock is set to false.
285+ */
286+ template <typename T>
287+ [[nodiscard]] bool set_value (const T & value, bool wait_for_lock)
288+ {
289+ if (wait_for_lock)
290+ {
291+ std::unique_lock<std::shared_mutex> lock (handle_mutex_);
292+ return set_value (lock, value);
293+ }
294+ else
295+ {
296+ std::unique_lock<std::shared_mutex> lock (handle_mutex_, std::try_to_lock);
297+ return set_value (lock, value);
298+ }
299+ }
300+
246301 /* *
247302 * @brief Set the value of the handle.
248303 * @tparam T The type of the value to be set.
@@ -315,6 +370,68 @@ class Handle
315370 return (value_ptr_ != nullptr ) || !std::holds_alternative<std::monostate>(value_);
316371 }
317372
373+ protected:
374+ /* *
375+ * @brief Get the value of the handle.
376+ * @tparam T The type of the value to be retrieved.
377+ * @param lock The lock to access the value.
378+ * @param value The variable to store the retrieved value.
379+ * @return true if the value is retrieved successfully, false otherwise.
380+ * @note The method is thread-safe and non-blocking.
381+ * @note Ideal for the data types that are large in size to avoid copy during return.
382+ */
383+ template <typename T>
384+ [[nodiscard]] bool get_value (std::shared_lock<std::shared_mutex> & lock, T & value) const
385+ {
386+ if (!lock.owns_lock ())
387+ {
388+ return false ;
389+ }
390+ // BEGIN (Handle export change): for backward compatibility
391+ // TODO(saikishor) get value_ if old functionality is removed
392+ if constexpr (std::is_same_v<T, double >)
393+ {
394+ switch (data_type_)
395+ {
396+ case HandleDataType::DOUBLE:
397+ THROW_ON_NULLPTR (value_ptr_);
398+ value = *value_ptr_;
399+ return true ;
400+ case HandleDataType::BOOL:
401+ // TODO(christophfroehlich): replace with RCLCPP_WARN_ONCE once
402+ // https://github.com/ros2/rclcpp/issues/2587
403+ // is fixed
404+ if (!notified_)
405+ {
406+ RCLCPP_WARN (
407+ rclcpp::get_logger (get_name ()),
408+ " Casting bool to double for interface: %s. Better use get_optional<bool>()." ,
409+ get_name ().c_str ());
410+ notified_ = true ;
411+ }
412+ value = static_cast <double >(std::get<bool >(value_));
413+ return true ;
414+ default :
415+ throw std::runtime_error (
416+ fmt::format (
417+ FMT_COMPILE (" Data type: '{}' cannot be casted to double for interface: {}" ),
418+ data_type_.to_string (), get_name ()));
419+ }
420+ }
421+ try
422+ {
423+ value = std::get<T>(value_);
424+ return true ;
425+ }
426+ catch (const std::bad_variant_access & err)
427+ {
428+ throw std::runtime_error (
429+ fmt::format (
430+ FMT_COMPILE (" Invalid data type: '{}' access for interface: {} expected: '{}'" ),
431+ get_type_name<T>(), get_name (), data_type_.to_string ()));
432+ }
433+ }
434+
318435private:
319436 void copy (const Handle & other) noexcept
320437 {
0 commit comments