File indexing completed on 2024-05-19 04:25:05

0001 /*
0002  *  SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISADAPTEDLOCK_H
0008 #define KISADAPTEDLOCK_H
0009 
0010 #include <mutex>
0011 
0012 /**
0013  * A wrapper class that adapts std::unique_lock to any kind
0014  * of locking that might be necessary to a particular class.
0015  *
0016  * Just define an Adapter class that implements `lock()`,
0017  * `unlock()` and (optionally) `try_lock()` interface and
0018  * pass it to `KisAdaptedLock`. The resulting class will
0019  * behave as normal `std::unique_lock` and lock/unlock the
0020  * object as you intructed it.
0021  *
0022  * See examples in `KisCursorOverrideLockAdapter` and
0023  * `KisLockFrameGenerationLock`
0024  */
0025 template <typename Adapter>
0026 class KisAdaptedLock
0027     : protected Adapter,
0028       public std::unique_lock<Adapter>
0029 {
0030 public:
0031     template<typename Object>
0032     KisAdaptedLock(Object object)
0033         : Adapter(object)
0034         , std::unique_lock<Adapter>(
0035               static_cast<Adapter&>(*this))
0036     {}
0037 
0038     template<typename Object>
0039     KisAdaptedLock(Object object, std::try_to_lock_t t)
0040         : Adapter(object)
0041         , std::unique_lock<Adapter>(static_cast<Adapter&>(*this), t)
0042     {}
0043 
0044     template<typename Object>
0045     KisAdaptedLock(Object object, std::defer_lock_t t)
0046         : Adapter(object)
0047         , std::unique_lock<Adapter>(static_cast<Adapter&>(*this), t)
0048     {}
0049 
0050     template<typename Object>
0051     KisAdaptedLock(Object object, std::adopt_lock_t t)
0052         : Adapter(object)
0053         , std::unique_lock<Adapter>(static_cast<Adapter&>(*this), t)
0054     {}
0055 
0056     KisAdaptedLock(KisAdaptedLock &&rhs)
0057         : Adapter(static_cast<Adapter&>(rhs))
0058         , std::unique_lock<Adapter>(
0059               static_cast<Adapter&>(*this), std::adopt_lock)
0060     {
0061         rhs.release();
0062     }
0063 
0064     KisAdaptedLock& operator=(KisAdaptedLock &&rhs)
0065     {
0066         static_cast<Adapter&>(*this) = rhs;
0067         static_cast<std::unique_lock<Adapter>&>(*this) =
0068             std::unique_lock<Adapter>(static_cast<Adapter&>(*this),
0069                                       std::adopt_lock);
0070         rhs.release();
0071         return *this;
0072     }
0073 
0074     using std::unique_lock<Adapter>::try_lock;
0075     using std::unique_lock<Adapter>::lock;
0076     using std::unique_lock<Adapter>::unlock;
0077 };
0078 
0079 /**
0080  * A macro to make sure that the resulting lock is
0081  * a 'class' and can be forward-declared instead of
0082  * the entire include pulling
0083  */
0084 #define KIS_DECLARE_ADAPTED_LOCK(Name, Adapter) \
0085 class Name : public KisAdaptedLock<Adapter>     \
0086 {                                               \
0087     public:                                     \
0088     using BaseClass = KisAdaptedLock<Adapter>;  \
0089     using BaseClass::BaseClass;                 \
0090 };
0091 
0092 #endif // KISADAPTEDLOCK_H