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_);
212 typename = std::enable_if_t<std::is_invocable_v<F, T &> && !std::is_invocable_v<F, T>>>
215 std::lock_guard<mutex_t> guard(lock_);
216 std::forward<F>(func)(value_);
223 template <
typename U = T,
typename = std::enable_if_t<is_ptr_or_smart_ptr<U>>>
226 std::lock_guard<mutex_t> guard(lock_);
234 template <
typename U = T>
235 [[nodiscard]]
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>, U>
get()
const
237 std::lock_guard<mutex_t> guard(lock_);
245 template <
typename U = T>
246 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
void>
get(T & in)
const
248 std::lock_guard<mutex_t> guard(lock_);
258 void get(
const std::function<
void(
const T &)> & func)
260 std::lock_guard<mutex_t> guard(lock_);
268 template <
typename U = T>
269 typename std::enable_if_t<!is_ptr_or_smart_ptr<U>,
void>
operator=(
const T & value)
278 template <
typename U = T,
typename =
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>>>
279 [[nodiscard]]
operator T()
const
289 template <
typename U = T,
typename =
typename std::enable_if_t<!is_ptr_or_smart_ptr<U>>>
290 [[nodiscard]]
operator std::optional<T>()
const
299 [[nodiscard]]
const mutex_t & get_mutex()
const {
return lock_; }
300 [[nodiscard]] mutex_t & get_mutex() {
return lock_; }
310 mutable mutex_t lock_;
316using RealtimeThreadSafeBoxRecursive = RealtimeThreadSafeBox<T, RECURSIVE_MUTEX>;