//
// Created by 张雪明 <zhangxueming@uniontech.com> on 2023/1/9.
//

#ifndef UOS_RECOVERY_UR_READ_WRITE_LOCK_H
#define UOS_RECOVERY_UR_READ_WRITE_LOCK_H

#include <mutex>
#include <condition_variable>
#include <functional>

// Uos Recovery Read Write Lock
class URRWLock {
public:
    URRWLock();
    ~URRWLock();

    void readLock();
    void writeLock();
    void unReadLock();
    void unWriteLock();

private:
    bool isReadCond() const;
    bool isWriteCond() const;

private:
    mutable std::mutex m_mutex;
    std::condition_variable m_readCond;
    std::condition_variable m_writeCond;
    volatile size_t m_readNum = 0;
    bool m_isWrite = false;
};

template <typename T>
class URReadLockGuard {
public:
    explicit URReadLockGuard(T &lock) : m_rLock(lock), m_locked(false)
    {
        m_rLock.readLock();
        m_locked = true;
    }

    ~URReadLockGuard()
    {
        if (m_locked) {
            m_rLock.unReadLock();
        }
    }

private:
    URReadLockGuard() = delete;
    URReadLockGuard(const URReadLockGuard &) = delete;
    URReadLockGuard& operator=(const URReadLockGuard &) = delete;
private:
    T &m_rLock;
    mutable bool m_locked;
};

template <typename T>
class URWriteLockGuard {
public:
    explicit URWriteLockGuard(T &lock) : m_wLock(lock), m_locked(false)
    {
        m_wLock.writeLock();
        m_locked = true;
    }

    ~URWriteLockGuard()
    {
        if (m_locked) {
            m_wLock.unWriteLock();
        }
    }

private:
    URWriteLockGuard() = delete;
    URWriteLockGuard(const URWriteLockGuard &) = delete;
    URWriteLockGuard& operator=(const URWriteLockGuard &) = delete;
private:
    T &m_wLock;
    mutable bool m_locked;
};

#endif
