#pragma once // Copyright (c) 2018-2019 David Burkett // Distributed under the MIT software license, see the accompanying // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include template class Reader { template class InnerReader { public: InnerReader(std::shared_ptr pObject, std::shared_ptr pMutex, const bool lock, const bool unlock) : m_pObject(pObject), m_pMutex(pMutex), m_unlock(unlock) { if (lock) { m_pMutex->lock_shared(); } } ~InnerReader() { if (m_unlock) { m_pMutex->unlock_shared(); } } std::shared_ptr m_pObject; std::shared_ptr m_pMutex; bool m_unlock; }; public: static Reader Create(std::shared_ptr pObject, std::shared_ptr pMutex, const bool lock, const bool unlock) { return Reader(std::shared_ptr>(new InnerReader(pObject, pMutex, lock, unlock))); } Reader() = default; virtual ~Reader() = default; const T* operator->() const { return m_pReader->m_pObject.get(); } const T& operator*() const { return *m_pReader->m_pObject; } std::shared_ptr GetShared() const { return m_pReader->m_pObject; } bool IsNull() const { return m_pReader->m_pObject == nullptr; } private: Reader(std::shared_ptr> pReader) : m_pReader(pReader) { } std::shared_ptr> m_pReader; }; class MutexUnlocker { public: MutexUnlocker(std::shared_ptr pMutex) : m_pMutex(pMutex) { } ~MutexUnlocker() { m_pMutex->unlock(); } private: std::shared_ptr m_pMutex; }; template class Writer : virtual public Reader { template class InnerWriter { public: InnerWriter(std::shared_ptr pObject, std::shared_ptr pMutex, const bool lock) : m_pObject(pObject), m_pMutex(pMutex) { if (lock) { m_pMutex->lock(); } } virtual ~InnerWriter() { // Using MutexUnlocker in case exception is thrown. MutexUnlocker unlocker(m_pMutex); } std::shared_ptr m_pObject; std::shared_ptr m_pMutex; }; public: static Writer Create(std::shared_ptr pObject, std::shared_ptr pMutex, const bool lock) { return Writer(std::shared_ptr>(new InnerWriter(pObject, pMutex, lock))); } Writer() = default; virtual ~Writer() = default; T* operator->() { return m_pWriter->m_pObject.get(); } const T* operator->() const { return m_pWriter->m_pObject.get(); } T& operator*() { return *m_pWriter->m_pObject; } const T& operator*() const { return *m_pWriter->m_pObject; } std::shared_ptr GetShared() { return m_pWriter->m_pObject; } std::shared_ptr GetShared() const { return m_pWriter->m_pObject; } bool IsNull() const { return m_pWriter == nullptr; } void Clear() { m_pWriter = nullptr; } private: Writer(std::shared_ptr> pWriter) : Reader(Reader::Create(pWriter->m_pObject, pWriter->m_pMutex, false, false)), m_pWriter(pWriter) { } std::shared_ptr> m_pWriter; }; template class Locked { friend class MultiLocker; public: Locked(std::shared_ptr pObject) : m_pObject(pObject), m_pMutex(std::make_shared()) { } virtual ~Locked() = default; Reader Read() const { return Reader::Create(m_pObject, m_pMutex, true, true); } Reader Read(std::adopt_lock_t) const { return Reader::Create(m_pObject, m_pMutex, false, true); } Writer Write() { return Writer::Create(m_pObject, m_pMutex, true); } Writer Write(std::adopt_lock_t) { return Writer::Create(m_pObject, m_pMutex, false); } private: std::shared_ptr m_pObject; std::shared_ptr m_pMutex; };