/* * ResourceKeeper.hpp * * Created on: 29 ���. 2018 �. * Author: titov */ #ifndef SOURCE_COMMON_RESOURCEKEEPER_HPP_ #define SOURCE_COMMON_RESOURCEKEEPER_HPP_ #include #include //!Êëàññ çàùèòû ðåñóðñîâ îò ìíîæåñòâåííîãî èñïîëüçîâàíèÿ. /*!Êëàññ îáåñïå÷èâàåò âîçìîæíîñòü çàõâàòèòü ðåñóðñ äëÿ óíèêàëüíîãî èñïîëüçîâàíèÿ. * Õðàíèò íå âëàäåþùóþ ññûëêó íà ðåñóðñ, è ïðèçíàê èñïîëüçîâàíèÿ. */ template class ResourceKeeper { protected: T & resource; //!<Çàùèùàåìûé ðåñóðñ. std::atomic_flag & usable; //!<Ïðèçíàê èñïîëüçîâàíèÿ. public: ResourceKeeper( T & resource, std::atomic_flag & flag ); virtual T * grab(); //!<Ôóíêöèÿ çàõâàòà ðåñóðñà äëÿ óíèêàëüíîãî èñïîëüçîâàíèÿ. const T & show(); //!<Ôóíêöèÿ ïîëó÷åíèÿ äîñòóïà ê äàííûì ðåñóðñà. virtual void release( T * & ) noexcept; //!<Ôóíêöèÿ îñâîáîæäåíèÿ ðåñóðñà. bool is_owned( T * p ) const noexcept; virtual ~ResourceKeeper() = default; }; template inline ResourceKeeper::ResourceKeeper( T & r, std::atomic_flag & flag ) : resource(r), usable(flag) { usable.clear(); } template inline T * ResourceKeeper::grab() { T * result = nullptr; //todo: Ðåøèòü ïðîáëåììó ìíîæåñòâåííîãî ãðàáà ñ ðàçíûõ cpu. if( !usable.test_and_set() ) result = &resource; return result; } template inline const T & ResourceKeeper::show() { return resource; } template inline void ResourceKeeper::release( T * & arg ) noexcept { if( arg == &resource ) { arg = nullptr; usable.clear(); } } template class Local { private: T * resource; //!<Çàùèùàåìûé ðåñóðñ. ResourceKeeper * keeper; Local( const Local &) = delete; Local & operator=( const Local & ) = delete; public: Local( T * res, ResourceKeeper & keep ); Local( ResourceKeeper * ); ~Local() noexcept; T * operator->(); explicit operator bool() { return resource; } void release( T * & ); //Çàìåíà õðàíèìîãî ðåñóðñà. Äëÿ ïðåäûäóùåãî áóäåò âûçâàí ìåòîä release void reset(T * &); }; template inline Local::Local( T * res, ResourceKeeper & keep ) : resource(res), keeper(&keep) {} template inline Local::~Local() noexcept { if( resource and keeper ) keeper->release( resource ); } template inline Local::Local( ResourceKeeper * keep ) : keeper(keep), resource(keep ? keep->grab() : nullptr) {} template inline T * Local::operator ->() { return resource; } template inline T * grab( ResourceKeeper * rk ) { return rk ? rk->grab() : nullptr; } template inline const T * show( ResourceKeeper * rk ) { return rk ? &rk->show() : nullptr; } template inline bool grab( T * & res, ResourceKeeper * rk ) { T * new_ptr = ( rk ? rk->grab() : nullptr ); res = res ? res : new_ptr; return res; } template inline bool show( const T * & res, ResourceKeeper * rk ) { const T * new_ptr = ( rk ? &rk->show() : nullptr ); res = res ? res : new_ptr; return res; } template inline void release( ResourceKeeper * rk, T * k ) { if( rk and k ) rk->release( k ); } template inline void Local::release( T * & new_owner ) { T * temp = resource; resource = nullptr; new_owner = temp; } template inline void Local::reset( T * & new_resource ) { if( resource and keeper ) keeper->release( resource ); resource = new_resource; } struct LocableInterface { virtual bool try_lock() = 0; virtual void unlock() = 0; virtual ~LocableInterface() = default; }; template class Locable : public LocableInterface { public: Locable( ResourceKeeper & keeper ); ~Locable() noexcept; T * operator->() const; T * pointer() const; const T & show() const; explicit operator bool() const { return resource; } bool try_lock(); void unlock() noexcept; private: T * resource; ResourceKeeper & keeper; Locable( const Locable &) = delete; Locable & operator=( const Locable & ) = delete; }; template inline Locable::Locable( ResourceKeeper & keeper ) : keeper(keeper), resource(nullptr) {} template inline Locable::~Locable() noexcept { keeper.release( resource ); } template inline T * Locable::operator->() const { return resource; } template inline const T & Locable::show() const { return keeper.show(); } template inline bool Locable::try_lock() { resource = keeper.grab(); return resource; } template inline T * Locable::pointer() const { return resource; } template inline void Locable::unlock() noexcept { keeper.release( resource ); } template struct ScopeLock { ScopeLock( Args & ... args ); explicit operator bool(); void freeze(); ~ScopeLock() noexcept; private: bool is_locked; bool frozen; std::size_t counter; LocableInterface * locable[ sizeof...(Args) ]; int add( LocableInterface & ); }; template inline ScopeLock::ScopeLock( Args & ... args ) : is_locked( true ), frozen( false ), counter( 0 ) { int temp[] = { add(args)... }; } template inline ScopeLock::operator bool() { return is_locked; } template inline ScopeLock::~ScopeLock() noexcept { if( not is_locked or not frozen ) { for( std::size_t i = 0; i < counter; i++ ) locable[i]->unlock(); } } template inline int ScopeLock::add( LocableInterface & lc ) { if( is_locked and ( is_locked = lc.try_lock() ) ) locable[counter++] = &lc; return is_locked; } template inline void ScopeLock::freeze() { frozen = true; } template inline bool ResourceKeeper::is_owned( T * pointer ) const noexcept { return pointer == &resource; } #endif /* SOURCE_COMMON_RESOURCEKEEPER_HPP_ */