diff --git a/modules/Thread/SharedLocker.mpp b/modules/Thread/SharedLocker.mpp index 7e183b79..94b23560 100644 --- a/modules/Thread/SharedLocker.mpp +++ b/modules/Thread/SharedLocker.mpp @@ -65,6 +65,23 @@ export namespace CppUtils::Thread m_value{std::forward(args)...} {} + SharedLocker(const SharedLocker&) = delete; + auto operator=(const SharedLocker&) -> SharedLocker& = delete; + + inline SharedLocker(SharedLocker&& other) noexcept(std::is_nothrow_move_constructible_v): + m_value{std::move(other.uniqueAccess().value())} + {} + + inline auto operator=(SharedLocker&& other) noexcept(std::is_nothrow_move_assignable_v) -> SharedLocker& + { + if (this != std::addressof(other)) + { + auto guard = std::scoped_lock{m_mutex, other.m_mutex}; + m_value = std::move(other.m_value); + } + return *this; + } + [[nodiscard]] inline auto uniqueAccess() -> UniqueAccessor { return Accessor{m_mutex, m_value}; diff --git a/tests/Thread/SharedLocker.mpp b/tests/Thread/SharedLocker.mpp index e11a2681..ed86a914 100644 --- a/tests/Thread/SharedLocker.mpp +++ b/tests/Thread/SharedLocker.mpp @@ -64,5 +64,25 @@ namespace CppUtils::UnitTest::Thread::SharedLocker suite.expectEqual(std::get<1>(accessor.values), "Bar"); } }); + + suite.addTest("Move constructor", [&] { + auto source = CppUtils::Thread::SharedLocker>{std::make_unique(42)}; + auto destination = CppUtils::Thread::SharedLocker>{std::move(source)}; + + suite.expect(source.uniqueAccess().value() == nullptr); + suite.expect(destination.sharedAccess().value() != nullptr); + suite.expectEqual(*destination.sharedAccess().value(), 42); + }); + + suite.addTest("Move assignment", [&] { + auto source = CppUtils::Thread::SharedLocker>{std::make_unique(100)}; + auto destination = CppUtils::Thread::SharedLocker>{std::make_unique(200)}; + + destination = std::move(source); + + suite.expect(source.uniqueAccess().value() == nullptr); + suite.expect(destination.sharedAccess().value() != nullptr); + suite.expectEqual(*destination.sharedAccess().value(), 100); + }); }}; }