6 #ifndef SWIFT_MISC_LOCKFREE_H
7 #define SWIFT_MISC_LOCKFREE_H
11 #include <type_traits>
36 const T &
get()
const {
return *m_ptr; }
39 operator const T &()
const {
return *m_ptr; }
49 friend class LockFree<std::remove_const_t<T>>;
52 std::shared_ptr<const T> m_ptr;
65 T &
get() {
return *m_ptr; }
68 operator T &() {
return *m_ptr; }
81 *m_ptr = std::move(other);
93 : m_old(std::move(other.m_old)), m_now(std::move(other.m_now)), m_ptr(std::move(other.m_ptr))
99 std::tie(m_old, m_now, m_ptr) =
100 std::forward_as_tuple(std::move(other.m_old), std::move(other.m_now), std::move(other.m_ptr));
107 if (m_ptr.use_count() == 0) {
return; }
108 bool success = std::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr));
109 Q_ASSERT_X(success, Q_FUNC_INFO,
"UniqueWriter detected simultaneous writes");
117 : m_old(ptr), m_now(now), m_ptr(std::make_shared<T>(*m_old))
119 std::shared_ptr<const T> m_old;
120 std::shared_ptr<const T> *m_now;
121 std::shared_ptr<T> m_ptr;
127 template <
typename T>
134 T &
get() {
return *m_ptr; }
137 operator T &() {
return *m_ptr; }
150 *m_ptr = std::move(other);
164 Q_ASSERT_X(m_ptr.use_count() > 0, Q_FUNC_INFO,
"SharedWriter tried to commit changes twice");
165 if (std::atomic_compare_exchange_strong(m_now, &m_old, std::shared_ptr<const T>(m_ptr)))
171 m_old = std::atomic_load(m_now);
172 m_ptr = std::make_shared<T>(*m_old);
179 Q_ASSERT_X(m_ptr.use_count() == 0, Q_FUNC_INFO,
"SharedWriter destroyed without committing changes");
190 : m_old(std::move(other.m_old)), m_now(std::move(other.m_now)), m_ptr(std::move(other.m_ptr))
196 std::tie(m_old, m_now, m_ptr) =
197 std::forward_as_tuple(std::move(other.m_old), std::move(other.m_now), std::move(other.m_ptr));
205 : m_old(ptr), m_now(now), m_ptr(std::make_shared<T>(*m_old))
207 std::shared_ptr<const T> m_old;
208 std::shared_ptr<const T> *m_now;
209 std::shared_ptr<T> m_ptr;
217 template <
typename T>
225 LockFree(
const T &other) : m_ptr(std::make_shared<const T>(other)) {}
228 LockFree(T &&other) noexcept(std::is_nothrow_move_assignable_v<T>)
229 : m_ptr(std::make_shared<const T>(std::move(other)))
250 template <
typename F>
253 return std::forward<F>(inspector)(
read().get());
257 template <
typename F>
265 template <
typename F>
270 std::forward<F>(mutator)(writer.get());
276 std::shared_ptr<const T> m_ptr = std::make_shared<const T>();
282 template <
template <
typename>
class T,
typename... Ts>
293 template <
typename F>
296 return call(std::forward<F>(
function), std::make_index_sequence<
sizeof...(Ts)>());
300 template <
typename F,
size_t... Is>
301 auto call(F &&
function, std::index_sequence<Is...>)
303 return std::forward<F>(
function)(std::get<Is>(m_tup).get()...);
306 const std::tuple<T<Ts>...> m_tup;
312 template <
typename... Ts>
315 return { std::forward_as_tuple(vs.
read()...) };
321 template <
typename... Ts>
324 return { std::forward_as_tuple(vs.
uniqueWrite()...) };
331 template <
typename T>
334 return reader->begin();
337 template <
typename T>
340 return reader->end();
343 template <
typename T>
346 return writer->begin();
349 template <
typename T>
352 return writer->end();
355 template <
typename T>
358 return writer->begin();
361 template <
typename T>
364 return writer->end();
374 template <
typename T>
377 template <
typename T>
380 template <
typename T>
383 template <
typename T>
386 template <
typename T>
389 template <
typename T>
Lock-free wrapper for synchronizing multi-threaded access to an object.
LockFree & operator=(const LockFree &)=delete
LockFree cannot be copied or moved.
LockFreeUniqueWriter< T > uniqueWrite()
Return an object which can write a new value, as long as there are no other writes.
LockFree()=default
Default constructor. Object will contain a default-constructed T.
LockFree & operator=(LockFree &&)=delete
LockFree cannot be copied or moved.
void sharedWrite(F &&mutator)
Pass a modifiable reference to the functor mutator. Safe if there are multiple writers....
auto read(F &&inspector)
Pass the current value to the functor inspector, and return whatever inspector returns.
LockFree(LockFree &&)=delete
LockFree cannot be copied or moved.
LockFree(const T &other)
Construct by copying from a T.
LockFreeReader< const T > read() const
Return an object which can read the current value.
LockFree(const LockFree &)=delete
LockFree cannot be copied or moved.
LockFree(T &&other) noexcept(std::is_nothrow_move_assignable_v< T >)
Construct by moving from a T.
LockFreeSharedWriter< T > sharedWrite()
Return an object which can write a new value, even if there are other writes.
void uniqueWrite(F &&mutator)
Pass a modifiable reference to the functor mutator. Unsafe if there are multiple writers.
Compose multiple LockFreeReader or LockFreeUniqueWriter instances.
auto operator()(F &&function) &&
Function call operator.
LockFreeMulti(std::tuple< T< Ts > &&... > &&tup)
Construct from a forwarded tuple. Prefer to construct via swift::misc::multiRead or swift::misc::mult...
Return value of LockFree::read().
const T & operator*() const
Return the value that was present when the reader was created.
LockFreeReader(const LockFreeReader &)=default
Copy constructor.
LockFreeReader & operator=(const LockFreeReader &)=default
Copy assignment operator.
const T * operator->() const
Return the value that was present when the reader was created.
const T & get() const
Return the value that was present when the reader was created.
Return value of LockFree::sharedWrite().
LockFreeSharedWriter & operator=(LockFreeSharedWriter &&other) noexcept
Move assignment operator.
LockFreeSharedWriter & operator=(T &&other) noexcept(std::is_nothrow_move_assignable_v< T >)
Replace the stored value by moving from a T. The change is applied by evaluating in a bool context.
LockFreeSharedWriter(const LockFreeSharedWriter &)=delete
LockFreeSharedWriter cannot be copied.
T & operator*()
The value can be modified through the returned reference. The modification is applied by evaluating i...
T * operator->()
The value can be modified through the returned reference. The modification is applied by evaluating i...
LockFreeSharedWriter(LockFreeSharedWriter &&other) noexcept
Move constructor.
LockFreeSharedWriter & operator=(const LockFreeSharedWriter &)=delete
LockFreeSharedWriter cannot be copied.
bool operator!()
Try to overwrite the original object with the new one stored in the writer, and return false on succe...
LockFreeSharedWriter & operator=(const T &other)
Replace the stored value by copying from a T. The change is applied by evaluating in a bool context.
T & get()
The value can be modified through the returned reference. The modification is applied by evaluating i...
~LockFreeSharedWriter()
Destructor. The writer's changes must be committed before this is called.
Return value of LockFree::uniqueWrite().
T * operator->()
The value can be modified through the returned reference. The modification is applied in the destruct...
LockFreeUniqueWriter & operator=(const LockFreeUniqueWriter &)=delete
LockFreeUniqueWriter cannot be copied.
LockFreeUniqueWriter(LockFreeUniqueWriter &&other) noexcept
Move constructor.
LockFreeUniqueWriter & operator=(const T &other)
Replace the stored value by copying from a T. The change is applied in the destructor.
~LockFreeUniqueWriter()
Destructor. The original object will be overwritten by the new one stored in the writer.
LockFreeUniqueWriter & operator=(T &&other) noexcept(std::is_nothrow_move_assignable_v< T >)
Replace the stored value by moving from a T. The change is applied in the destructor.
T & get()
The value can be modified through the returned reference. The modification is applied in the destruct...
LockFreeUniqueWriter(const LockFreeUniqueWriter &)=delete
LockFreeUniqueWriter cannot be copied.
LockFreeUniqueWriter & operator=(LockFreeUniqueWriter &&other) noexcept
Move assignment operator.
T & operator*()
The value can be modified through the returned reference. The modification is applied in the destruct...
Free functions in swift::misc.
T::const_iterator begin(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
LockFreeMulti< LockFreeReader, const Ts... > multiRead(const LockFree< Ts > &...vs)
Return a callable object for reading from multiple LockFree instances simultaneously.
T::const_iterator end(const LockFreeReader< T > &reader)
Non-member begin() and end() for so LockFree containers can be used in ranged for loops.
LockFreeMulti< LockFreeUniqueWriter, Ts... > multiUniqueWrite(LockFree< Ts > &...vs)
Return a callable object for writing to multiple LockFree instances simultaneously.