Skip to content

Commit dca54e1

Browse files
committed
(core) add read / write / access overload which take a closure for locked
1 parent 03ad3af commit dca54e1

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

modules/stormkit/core/parallelism/locked.cppm

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ export namespace stormkit { inline namespace core {
5959
using MutexType = Mutex;
6060

6161
private:
62+
template<LockAccessMode Mode>
63+
using AccessClosureInvokeParameter = meta::If<Mode == LockAccessMode::READ_ONLY, ConstReferenceType, ReferenceType>;
64+
6265
template<template<class> class Lock, LockAccessMode Mode>
6366
class Access;
6467

@@ -85,12 +88,30 @@ export namespace stormkit { inline namespace core {
8588
template<LockAccessMode Mode, template<class> class Lock, typename... LockArgs, class Self>
8689
auto access(this Self& self, LockArgs&&... lock_args) noexcept -> Access<Lock, Mode>;
8790

91+
template<LockAccessMode Mode,
92+
std::invocable<AccessClosureInvokeParameter<Mode>> Closure,
93+
template<class> class Lock,
94+
typename... LockArgs,
95+
class Self>
96+
auto access(this Self& self, Closure&& closure, LockArgs&&... lock_args) noexcept
97+
-> std::invoke_result_t<Closure, AccessClosureInvokeParameter<Mode>>;
98+
8899
template<template<class> class Lock = details::DefaultReadOnlyLock, typename... LockArgs>
89100
auto read(LockArgs&&... lock_args) const noexcept -> ReadAccess<Lock>;
90101

102+
template<std::invocable<ConstReferenceType> Closure,
103+
template<class> class Lock = details::DefaultReadOnlyLock,
104+
typename... LockArgs>
105+
auto read(Closure&& closure, LockArgs&&... lock_args) const noexcept -> std::invoke_result_t<Closure, ConstReferenceType>;
106+
91107
template<template<class> class Lock = details::DefaultReadWriteLock, typename... LockArgs>
92108
auto write(LockArgs&&... lock_args) noexcept -> WriteAccess<Lock>;
93109

110+
template<std::invocable<ReferenceType> Closure,
111+
template<class> class Lock = details::DefaultReadWriteLock,
112+
typename... LockArgs>
113+
auto write(Closure&& closure, LockArgs&&... lock_args) noexcept -> std::invoke_result_t<Closure, ReferenceType>;
114+
94115
template<template<class> class Lock = details::DefaultReadOnlyLock, typename... LockArgs>
95116
auto copy(LockArgs&&... lock_args) const noexcept -> ValueType;
96117

@@ -210,6 +231,24 @@ namespace stormkit { inline namespace core {
210231
return AccessType { std::forward<Self&>(self), std::forward<LockArgs>(lock_args)... };
211232
}
212233

234+
////////////////////////////////////////
235+
////////////////////////////////////////
236+
template<meta::IsNotRawIndirection T, class Mutex>
237+
template<LockAccessMode Mode,
238+
std::invocable<typename Locked<T, Mutex>::template AccessClosureInvokeParameter<Mode>> Closure,
239+
template<class> class Lock,
240+
typename... LockArgs,
241+
class Self>
242+
STORMKIT_FORCE_INLINE
243+
auto Locked<T, Mutex>::access(this Self& self, Closure&& closure, LockArgs&&... lock_args) noexcept
244+
-> std::invoke_result_t<Closure, AccessClosureInvokeParameter<Mode>> {
245+
static_assert(not(Mode == LockAccessMode::READ_ONLY and not std::is_const_v<meta::RemoveIndirectionsType<Self>>),
246+
"can't get read access on const Locked<T>");
247+
using AccessType = Access<Lock, Mode>;
248+
auto access_ = AccessType { std::forward<Self&>(self), std::forward<LockArgs>(lock_args)... };
249+
return std::invoke(std::forward<Closure>(closure), *access_);
250+
}
251+
213252
////////////////////////////////////////
214253
////////////////////////////////////////
215254
template<meta::IsNotRawIndirection T, class Mutex>
@@ -219,6 +258,19 @@ namespace stormkit { inline namespace core {
219258
return access<LockAccessMode::READ_ONLY, Lock>(std::forward<LockArgs>(lock_args)...);
220259
}
221260

261+
////////////////////////////////////////
262+
////////////////////////////////////////
263+
template<meta::IsNotRawIndirection T, class Mutex>
264+
template<std::invocable<typename Locked<T, Mutex>::ConstReferenceType> Closure,
265+
template<class> class Lock,
266+
typename... LockArgs>
267+
STORMKIT_FORCE_INLINE
268+
auto Locked<T, Mutex>::read(Closure&& closure, LockArgs&&... lock_args) const noexcept
269+
-> std::invoke_result_t<Closure, ConstReferenceType> {
270+
return access<LockAccessMode::READ_ONLY, Closure, Lock>(std::forward<Closure>(closure),
271+
std::forward<LockArgs>(lock_args)...);
272+
}
273+
222274
////////////////////////////////////////
223275
////////////////////////////////////////
224276
template<meta::IsNotRawIndirection T, class Mutex>
@@ -228,6 +280,17 @@ namespace stormkit { inline namespace core {
228280
return access<LockAccessMode::READ_WRITE, Lock>(std::forward<LockArgs>(lock_args)...);
229281
}
230282

283+
////////////////////////////////////////
284+
////////////////////////////////////////
285+
template<meta::IsNotRawIndirection T, class Mutex>
286+
template<std::invocable<typename Locked<T, Mutex>::ReferenceType> Closure, template<class> class Lock, typename... LockArgs>
287+
STORMKIT_FORCE_INLINE
288+
auto Locked<T, Mutex>::write(Closure&& closure, LockArgs&&... lock_args) noexcept
289+
-> std::invoke_result_t<Closure, ReferenceType> {
290+
return access<LockAccessMode::READ_WRITE, Closure, Lock>(std::forward<Closure>(closure),
291+
std::forward<LockArgs>(lock_args)...);
292+
}
293+
231294
////////////////////////////////////////
232295
////////////////////////////////////////
233296
template<meta::IsNotRawIndirection T, class Mutex>

tests/core/parallelism/locked.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,24 @@ namespace {
3232
future_1.wait();
3333
future_2.wait();
3434

35+
EXPECTS(locked_int.unsafe() == (ITERATIONS * 2));
36+
} },
37+
{ "Locked.write_closure",
38+
[] static noexcept {
39+
static constexpr auto ITERATIONS = 1'000'000;
40+
auto locked_int = Locked { 0 };
41+
const auto func = [&locked_int] noexcept {
42+
for (auto foo = 0; foo != ITERATIONS; ++foo) {
43+
locked_int.write([](auto& value) static noexcept { value += 1; });
44+
}
45+
};
46+
47+
auto future_1 = std::async(std::launch::async, func);
48+
auto future_2 = std::async(std::launch::async, func);
49+
50+
future_1.wait();
51+
future_2.wait();
52+
3553
EXPECTS(locked_int.unsafe() == (ITERATIONS * 2));
3654
} },
3755
{ "Locked.move",

0 commit comments

Comments
 (0)