-
Notifications
You must be signed in to change notification settings - Fork 34
/
safe_object.hpp
129 lines (110 loc) · 2.96 KB
/
safe_object.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <shared_mutex>
#include <type_traits>
#define SAFE_UNIQUE_CAPTURE(x, ...) \
x ^= __VA_ARGS__(typename std::remove_cvref_t<decltype(x)>::Type & x)
#define SAFE_SHARED_CAPTURE(x, ...) \
x |= __VA_ARGS__(const typename std::remove_cvref_t<decltype(x)>::Type &x)
#define SAFE_UNIQUE(x) SAFE_UNIQUE_CAPTURE(x, [&])
#define SAFE_SHARED(x) SAFE_SHARED_CAPTURE(x, [&])
// clang-format off
/**
* Protected object wrapper. Allow read-write access.
* @tparam T object type
* Example:
* @code
* SafeObject<std::string> obj("1");
* bool const is_one_att1 =
* obj.sharedAccess([](auto const &str) {
* return str == "1";
* });
* obj.exclusiveAccess([](auto &str) {
* str = "2";
* });
* bool const is_one_att2 =
* obj.sharedAccess([](auto const &str) {
* return str == "1";
* });
*
* std::cout <<
* "Attempt 1: " << is_one_att1 << std::endl <<
* "Attempt 2: " << is_one_att2;
* @endcode
*/
// clang-format on
template <typename T, typename M = std::shared_mutex>
struct SafeObject {
using Type = T;
template <typename... Args>
SafeObject(Args &&...args) : t_(std::forward<Args>(args)...) {}
template <typename F>
inline auto exclusiveAccess(F &&f) {
std::unique_lock lock(cs_);
return std::forward<F>(f)(t_);
}
template <typename F>
inline auto sharedAccess(F &&f) const {
std::shared_lock lock(cs_);
return std::forward<F>(f)(t_);
}
auto operator^=(auto &&f) {
return exclusiveAccess(std::forward<decltype(f)>(f));
}
auto operator|=(auto &&f) const {
return sharedAccess(std::forward<decltype(f)>(f));
}
T &unsafeGet() {
return t_;
}
const T &unsafeGet() const {
return t_;
}
private:
T t_;
mutable M cs_;
};
template <typename T, typename M = std::shared_mutex>
SafeObject(T &&) -> SafeObject<T, M>;
class WaitForSingleObject final {
std::condition_variable wait_cv_;
std::mutex wait_m_;
bool flag_ = true;
public:
WaitForSingleObject(const WaitForSingleObject &) = delete;
WaitForSingleObject &operator=(const WaitForSingleObject &) = delete;
WaitForSingleObject(WaitForSingleObject &&) = delete;
WaitForSingleObject &operator=(WaitForSingleObject &&) = delete;
WaitForSingleObject() = default;
~WaitForSingleObject() = default;
bool wait(std::chrono::microseconds wait_timeout) {
std::unique_lock<std::mutex> _lock(wait_m_);
return wait_cv_.wait_for(_lock, wait_timeout, [&]() {
auto prev = !flag_;
flag_ = true;
return prev;
});
}
void wait() {
std::unique_lock<std::mutex> _lock(wait_m_);
wait_cv_.wait(_lock, [&]() {
auto prev = !flag_;
flag_ = true;
return prev;
});
}
void set() {
{
std::unique_lock<std::mutex> _lock(wait_m_);
flag_ = false;
}
wait_cv_.notify_one();
}
};