33#ifndef REALTIME_TOOLS__REALTIME_THREAD_SAFE_BOX_HPP_
34#define REALTIME_TOOLS__REALTIME_THREAD_SAFE_BOX_HPP_
37#include <initializer_list>
42#include "rcpputils/pointer_traits.hpp"
44#include "realtime_tools/mutex.hpp"
45#define DEFAULT_MUTEX realtime_tools::prio_inherit_mutex
46#define RECURSIVE_MUTEX realtime_tools::prio_inherit_recursive_mutex
48#define DEFAULT_MUTEX std::mutex
49#define RECURSIVE_MUTEX std::recursive_mutex
56constexpr auto is_ptr_or_smart_ptr = rcpputils::is_pointer<T>::value;
66template <
class T,
typename mutex_type = DEFAULT_MUTEX>
69 static_assert(std::is_copy_constructible_v<T>,
"Passed type must be copy constructible");
72 using mutex_t = mutex_type;
82 std::unique_lock<mutex_t> lock(o.lock_);
93 std::unique_lock<mutex_t> lock_other(o.lock_);
94 std::unique_lock<mutex_t> lock_self(lock_);
104 std::unique_lock<mutex_t> lock(o.lock_);
106 value_ = std::move(o.value_);
110 template <
typename U = T>
112 const std::initializer_list<U> & init,
113 std::enable_if_t<std::is_constructible_v<U, std::initializer_list<U>>>)
123 std::unique_lock<mutex_t> lock_other(o.lock_);
124 std::unique_lock<mutex_t> lock_self(lock_);
126 value_ = std::move(o.value_);
136 template <
typename U = T>
137 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
bool>
try_set(
const T & value)
139 std::unique_lock<mutex_t> guard(lock_, std::defer_lock);
140 if (!guard.try_lock()) {
152 bool try_set(
const std::function<
void(T &)> & func)
154 std::unique_lock<mutex_t> guard(lock_, std::defer_lock);
155 if (!guard.try_lock()) {
167 template <
typename U = T>
168 [[nodiscard]]
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, std::optional<U>>
try_get()
const
170 std::unique_lock<mutex_t> guard(lock_, std::defer_lock);
171 if (!guard.try_lock()) {
182 bool try_get(
const std::function<
void(
const T &)> & func)
184 std::unique_lock<mutex_t> guard(lock_, std::defer_lock);
185 if (!guard.try_lock()) {
198 template <
typename U = T>
199 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
void>
set(
const T & value)
201 std::lock_guard<mutex_t> guard(lock_);
215 typename = std::enable_if_t<std::is_invocable_v<F, T &> && !std::is_invocable_v<F, T>>>
218 std::lock_guard<mutex_t> guard(lock_);
219 std::forward<F>(func)(value_);
226 template <
typename U = T,
typename = std::enable_if_t<is_ptr_or_smart_ptr<U>>>
229 std::lock_guard<mutex_t> guard(lock_);
238 void set(
const std::function<
void(T &)> & func)
240 std::lock_guard<mutex_t> guard(lock_);
242 if constexpr (is_ptr_or_smart_ptr<T>) {
255 template <
typename U = T>
256 [[nodiscard]]
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, U>
get()
const
258 std::lock_guard<mutex_t> guard(lock_);
266 template <
typename U = T>
267 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
void>
get(T & in)
const
269 std::lock_guard<mutex_t> guard(lock_);
279 void get(
const std::function<
void(
const T &)> & func)
281 std::lock_guard<mutex_t> guard(lock_);
289 template <
typename U = T>
290 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
void>
operator=(
const T & value)
299 template <
typename U = T,
typename =
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>>>
300 [[nodiscard]]
operator T()
const
310 template <
typename U = T,
typename =
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>>>
311 [[nodiscard]]
operator std::optional<T>()
const
320 [[nodiscard]]
const mutex_t & get_mutex()
const {
return lock_; }
321 [[nodiscard]] mutex_t & get_mutex() {
return lock_; }
331 mutable mutex_t lock_;
337using RealtimeThreadSafeBoxRecursive = RealtimeThreadSafeBox<T, RECURSIVE_MUTEX>;