304 lines
6.2 KiB
C++
304 lines
6.2 KiB
C++
|
|
/*
|
|||
|
|
|
|||
|
|
* ResourceKeeper.hpp
|
|||
|
|
*
|
|||
|
|
* Created on: 29 <EFBFBD><EFBFBD><EFBFBD>. 2018 <EFBFBD>.
|
|||
|
|
* Author: titov
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#ifndef SOURCE_COMMON_RESOURCEKEEPER_HPP_
|
|||
|
|
#define SOURCE_COMMON_RESOURCEKEEPER_HPP_
|
|||
|
|
|
|||
|
|
#include <atomic>
|
|||
|
|
#include <cstddef>
|
|||
|
|
|
|||
|
|
//!<21><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
/*!<21><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
*/
|
|||
|
|
template<typename T>
|
|||
|
|
class ResourceKeeper {
|
|||
|
|
protected:
|
|||
|
|
T & resource; //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
std::atomic_flag & usable; //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
ResourceKeeper( T & resource, std::atomic_flag & flag );
|
|||
|
|
|
|||
|
|
virtual T * grab(); //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
const T & show(); //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
virtual void release( T * & ) noexcept; //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
|
|||
|
|
bool is_owned( T * p ) const noexcept;
|
|||
|
|
|
|||
|
|
virtual ~ResourceKeeper() = default;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline ResourceKeeper<T>::ResourceKeeper( T & r, std::atomic_flag & flag ) : resource(r), usable(flag) {
|
|||
|
|
usable.clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline T * ResourceKeeper<T>::grab() {
|
|||
|
|
|
|||
|
|
T * result = nullptr;
|
|||
|
|
|
|||
|
|
//todo: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> cpu.
|
|||
|
|
|
|||
|
|
if( !usable.test_and_set() )
|
|||
|
|
result = &resource;
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline const T & ResourceKeeper<T>::show() {
|
|||
|
|
|
|||
|
|
return resource;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline void ResourceKeeper<T>::release( T * & arg ) noexcept {
|
|||
|
|
|
|||
|
|
if( arg == &resource ) {
|
|||
|
|
arg = nullptr;
|
|||
|
|
usable.clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
class Local {
|
|||
|
|
private:
|
|||
|
|
T * resource; //!<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|||
|
|
ResourceKeeper<T> * keeper;
|
|||
|
|
|
|||
|
|
Local( const Local &) = delete;
|
|||
|
|
Local & operator=( const Local & ) = delete;
|
|||
|
|
public:
|
|||
|
|
Local( T * res, ResourceKeeper<T> & keep );
|
|||
|
|
Local( ResourceKeeper<T> * );
|
|||
|
|
~Local() noexcept;
|
|||
|
|
|
|||
|
|
T * operator->();
|
|||
|
|
explicit operator bool() {
|
|||
|
|
return resource;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void release( T * & );
|
|||
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> release
|
|||
|
|
void reset(T * &);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline Local<T>::Local( T * res, ResourceKeeper<T> & keep ) :
|
|||
|
|
resource(res), keeper(&keep) {}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline Local<T>::~Local() noexcept {
|
|||
|
|
|
|||
|
|
if( resource and keeper )
|
|||
|
|
keeper->release( resource );
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline Local<T>::Local( ResourceKeeper<T> * keep ) :
|
|||
|
|
keeper(keep), resource(keep ? keep->grab() : nullptr) {}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline T * Local<T>::operator ->() {
|
|||
|
|
|
|||
|
|
return resource;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline T * grab( ResourceKeeper<T> * rk ) {
|
|||
|
|
|
|||
|
|
return rk ? rk->grab() : nullptr;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline const T * show( ResourceKeeper<T> * rk ) {
|
|||
|
|
|
|||
|
|
return rk ? &rk->show() : nullptr;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline bool grab( T * & res, ResourceKeeper<T> * rk ) {
|
|||
|
|
T * new_ptr = ( rk ? rk->grab() : nullptr );
|
|||
|
|
res = res ? res : new_ptr;
|
|||
|
|
return res;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline bool show( const T * & res, ResourceKeeper<T> * rk ) {
|
|||
|
|
const T * new_ptr = ( rk ? &rk->show() : nullptr );
|
|||
|
|
res = res ? res : new_ptr;
|
|||
|
|
return res;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline void release( ResourceKeeper<T> * rk, T * k ) {
|
|||
|
|
|
|||
|
|
if( rk and k ) rk->release( k );
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline void Local<T>::release( T * & new_owner ) {
|
|||
|
|
|
|||
|
|
T * temp = resource;
|
|||
|
|
resource = nullptr;
|
|||
|
|
new_owner = temp;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline void Local<T>::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<typename T>
|
|||
|
|
class Locable : public LocableInterface {
|
|||
|
|
public:
|
|||
|
|
Locable( ResourceKeeper<T> & 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<T> & keeper;
|
|||
|
|
|
|||
|
|
Locable( const Locable &) = delete;
|
|||
|
|
Locable & operator=( const Locable & ) = delete;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline Locable<T>::Locable( ResourceKeeper<T> & keeper ) : keeper(keeper), resource(nullptr) {}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline Locable<T>::~Locable() noexcept {
|
|||
|
|
keeper.release( resource );
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline T * Locable<T>::operator->() const {
|
|||
|
|
return resource;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline const T & Locable<T>::show() const {
|
|||
|
|
|
|||
|
|
return keeper.show();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline bool Locable<T>::try_lock() {
|
|||
|
|
|
|||
|
|
resource = keeper.grab();
|
|||
|
|
|
|||
|
|
return resource;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline T * Locable<T>::pointer() const {
|
|||
|
|
|
|||
|
|
return resource;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline void Locable<T>::unlock() noexcept {
|
|||
|
|
|
|||
|
|
keeper.release( resource );
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename ... Args>
|
|||
|
|
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<typename ... Args>
|
|||
|
|
inline ScopeLock<Args...>::ScopeLock( Args & ... args ) : is_locked( true ), frozen( false ), counter( 0 ) {
|
|||
|
|
int temp[] = { add(args)... };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename ... Args>
|
|||
|
|
inline ScopeLock<Args...>::operator bool() {
|
|||
|
|
|
|||
|
|
return is_locked;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename ... Args>
|
|||
|
|
inline ScopeLock<Args...>::~ScopeLock() noexcept {
|
|||
|
|
if( not is_locked or not frozen ) {
|
|||
|
|
for( std::size_t i = 0; i < counter; i++ )
|
|||
|
|
locable[i]->unlock();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename ... Args>
|
|||
|
|
inline int ScopeLock<Args...>::add( LocableInterface & lc ) {
|
|||
|
|
|
|||
|
|
if( is_locked and ( is_locked = lc.try_lock() ) )
|
|||
|
|
locable[counter++] = &lc;
|
|||
|
|
|
|||
|
|
return is_locked;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename ... Args>
|
|||
|
|
inline void ScopeLock<Args...>::freeze() {
|
|||
|
|
frozen = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
inline bool ResourceKeeper<T>::is_owned( T * pointer ) const noexcept {
|
|||
|
|
|
|||
|
|
return pointer == &resource;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif /* SOURCE_COMMON_RESOURCEKEEPER_HPP_ */
|