/* * Copyright (c) 2021, the SerenityOS developers. * Copyright (c) 2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include namespace Kernel { template class MutexProtected { AK_MAKE_NONCOPYABLE(MutexProtected); AK_MAKE_NONMOVABLE(MutexProtected); private: template class Locked { AK_MAKE_NONCOPYABLE(Locked); AK_MAKE_NONMOVABLE(Locked); public: Locked(U& value, Mutex& mutex, LockLocation const& location) : m_value(value) , m_locker(mutex, lock_mode, location) { } ALWAYS_INLINE U const* operator->() const { return &m_value; } ALWAYS_INLINE U const& operator*() const { return m_value; } ALWAYS_INLINE U* operator->() requires(!IsConst) { return &m_value; } ALWAYS_INLINE U& operator*() requires(!IsConst) { return m_value; } ALWAYS_INLINE U const& get() const { return &m_value; } ALWAYS_INLINE U& get() requires(!IsConst) { return &m_value; } private: U& m_value; MutexLocker m_locker; }; auto lock_shared(LockLocation const& location) const { return Locked(m_value, m_mutex, location); } auto lock_exclusive(LockLocation const& location) { return Locked(m_value, m_mutex, location); } public: MutexProtected() = default; template decltype(auto) with_shared(Callback callback, LockLocation const& location = LockLocation::current()) const { auto lock = lock_shared(location); return callback(*lock); } template decltype(auto) with_exclusive(Callback callback, LockLocation const& location = LockLocation::current()) { auto lock = lock_exclusive(location); return callback(*lock); } template void for_each_shared(Callback callback, LockLocation const& location = LockLocation::current()) const { with_shared([&](const auto& value) { for (auto& item : value) callback(item); }, location); } template void for_each_exclusive(Callback callback, LockLocation const& location = LockLocation::current()) { with_exclusive([&](auto& value) { for (auto& item : value) callback(item); }, location); } private: T m_value; Mutex mutable m_mutex; }; }