/******************************************************************************/ /* THREADING - INLINE CODE ****************************************************/ /******************************************************************************/ #ifndef _H_LW_LIB_INLINE_THREADING #define _H_LW_LIB_INLINE_THREADING #include namespace lw { /*= T_ReadWriteMutex =========================================================*/ inline T_ReadWriteMutex::T_ReadWriteMutex( ) : state_( 0 ) { } inline T_ReadWriteMutex::~T_ReadWriteMutex( ) { assert( state_ == 0 ); } /*----------------------------------------------------------------------------*/ inline void T_ReadWriteMutex::lock( ) { T_ExclusiveLock lock( mutex_ ); writerBlock_.wait( lock , [this]( ) { return ( state_ & C_WLOCKED_ ) == 0; } ); state_ |= C_WLOCKED_; readerBlock_.wait( lock , [this]( ) { return ( state_ & C_READERS_ ) == 0; } ); } inline bool T_ReadWriteMutex::try_lock( ) { T_ExclusiveLock lock( mutex_ , std::try_to_lock ); if ( lock.owns_lock( ) && state_ == 0 ) { state_ = C_WLOCKED_; return true; } return false; } inline void T_ReadWriteMutex::unlock( ) { T_ScopeLock lock( mutex_ ); assert( ( state_ & C_WLOCKED_ ) != 0 ); state_ = 0; writerBlock_.notify_all( ); } /*----------------------------------------------------------------------------*/ inline void T_ReadWriteMutex::lock_shared( ) { T_ExclusiveLock lock( mutex_ ); writerBlock_.wait( lock , [this]( ) { return state_ < C_READERS_; } ); state_ ++; } inline bool T_ReadWriteMutex::try_lock_shared( ) { T_ExclusiveLock lock( mutex_ , std::try_to_lock ); if ( !lock.owns_lock( ) && state_ < C_READERS_ ) { state_ ++; return true; } return false; } inline void T_ReadWriteMutex::unlock_shared( ) { T_ScopeLock lock( mutex_ ); assert( ( state_ & C_READERS_ ) != 0 ); auto previous( state_ -- ); if ( previous == ( C_WLOCKED_ & 1 ) ) { readerBlock_.notify_one( ); } else if ( previous == C_READERS_ ) { writerBlock_.notify_one( ); } } /*----------------------------------------------------------------------------*/ inline void T_ReadWriteMutex::upgradeLock( ) { T_ExclusiveLock lock( mutex_ ); assert( ( state_ & C_READERS_ ) != 0 ); state_ --; writerBlock_.wait( lock , [this]( ) { return ( state_ & C_WLOCKED_ ) == 0; } ); state_ |= C_WLOCKED_; readerBlock_.wait( lock , [this]( ) { return ( state_ & C_READERS_ ) == 0; } ); } /*= T_ReadLock ===============================================================*/ inline T_ReadLock::T_ReadLock( ) noexcept : std::shared_lock< T_ReadWriteMutex >( ) { } inline T_ReadLock::T_ReadLock( T_ReadLock&& other ) : std::shared_lock< T_ReadWriteMutex >( std::move( other ) ) { } inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m ) : std::shared_lock< T_ReadWriteMutex >( m ) { } inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::defer_lock_t t ) : std::shared_lock< T_ReadWriteMutex >( m , t ) { } inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::try_to_lock_t t ) : std::shared_lock< T_ReadWriteMutex >( m , t ) { } inline T_ReadLock::T_ReadLock( T_ReadWriteMutex& m , std::adopt_lock_t t ) : std::shared_lock< T_ReadWriteMutex >( m , t ) { } /*----------------------------------------------------------------------------*/ inline T_WriteLock T_ReadLock::upgrade( ) { assert( owns_lock( ) ); RP_ReadWriteMutex mutex( release( ) ); mutex->upgradeLock( ); return T_WriteLock( *mutex , std::adopt_lock ); } /*= T_RingBuffer =============================================================*/ template< typename T > inline T_RingBuffer< T >::T_RingBuffer( uint32_t expand ) : expand_( expand ) , data_( nullptr ) , allocated_( 0 ) , used_( 0 ) , readPos_( 0 ) { assert( expand ); } template< typename T > inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T > const& other ) : expand_( other.expand_ ) , allocated_( other.allocated_ ) , used_( other.used_ ) , readPos_( 0 ) { if ( allocated_ ) { data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) ); for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) { const auto sidx( ( i + other.readPos_ ) % allocated_ ); new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] ); } } else { data_ = nullptr; } } template< typename T > inline T_RingBuffer< T >::T_RingBuffer( T_RingBuffer< T >&& other ) noexcept : T_RingBuffer( other.growth( ) ) { swap( *this , other ); } /*----------------------------------------------------------------------------*/ template< typename T > inline T_RingBuffer< T >::~T_RingBuffer( ) { free( ); } /*----------------------------------------------------------------------------*/ template< typename T > inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T > const& other ) { free( ); expand_ = other.expand_; allocated_ = other.allocated_; used_ = other.used_; readPos_ = 0; if ( allocated_ ) { data_ = reinterpret_cast< T* >( ::operator new( sizeof( T ) * allocated_ ) ); for ( uint32_t i = 0 ; i < other.used_ ; i ++ ) { const auto sidx( ( i + other.readPos_ ) % allocated_ ); new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( other.data_[ sidx ] ); } } return *this; } template< typename T > inline T_RingBuffer< T >& T_RingBuffer< T >::operator =( T_RingBuffer< T >&& other ) noexcept { free( ); expand_ = other.expand_; swap( *this , other ); return *this; } /*----------------------------------------------------------------------------*/ template< typename T > inline void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept { using std::swap; swap( lhs.expand_ , rhs.expand_ ); swap( lhs.data_ , rhs.data_ ); swap( lhs.allocated_ , rhs.allocated_ ); swap( lhs.used_ , rhs.used_ ); swap( lhs.readPos_ , rhs.readPos_ ); } /*----------------------------------------------------------------------------*/ template< typename T > inline void T_RingBuffer< T >::free( ) { for ( uint32_t i = 0 ; i < used_ ; i ++ ) { const auto idx( ( readPos_ + i ) % allocated_ ); data_[ idx ].~T( ); } ::operator delete( (void*) data_ ); data_ = nullptr; allocated_ = 0; used_ = 0; readPos_ = 0; } /*----------------------------------------------------------------------------*/ template< typename T > inline uint32_t T_RingBuffer< T >::size( ) const { return used_; } template< typename T > inline uint32_t T_RingBuffer< T >::capacity( ) const { return allocated_; } template< typename T > inline uint32_t T_RingBuffer< T >::growth( ) const { return expand_; } /*----------------------------------------------------------------------------*/ template< typename T > inline bool T_RingBuffer< T >::readNext( T& output ) { if ( used_ == 0 ) { return false; } output = std::move( data_[ readPos_ ] ); data_[ readPos_ ].~T( ); readPos_ = ( readPos_ + 1 ) % allocated_; used_ --; return true; } template< typename T > inline bool T_RingBuffer< T >::readAll( T_Array< T >& output ) { if ( used_ == 0 ) { return false; } for ( uint32_t i = 0 ; i < used_ ; i ++ ) { output.add( std::move( data_[ ( readPos_ + i ) % allocated_ ] ) ); } for ( uint32_t i = 0 ; i < used_ ; i ++ ) { data_[ ( readPos_ + i ) % allocated_ ].~T( ); } used_ = 0; return true; } /*----------------------------------------------------------------------------*/ template< typename T > inline void T_RingBuffer< T >::put( T const& input ) { if ( used_ == allocated_ ) { expand( ); } const auto idx( ( readPos_ + used_ ) % allocated_ ); new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( input ); used_ ++; } template< typename T > inline void T_RingBuffer< T >::put( T&& input ) { if ( used_ == allocated_ ) { expand( ); } const auto idx( ( readPos_ + used_ ) % allocated_ ); new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::move( input ) ); used_ ++; } template< typename T > template< typename... ArgTypes > inline void T_RingBuffer< T >::putNew( ArgTypes&&... arguments ) { if ( used_ == allocated_ ) { expand( ); } const auto idx( ( readPos_ + used_ ) % allocated_ ); new ( reinterpret_cast< char* >( &data_[ idx ] ) ) T( std::forward< ArgTypes >( arguments ) ... ); used_ ++; } /*----------------------------------------------------------------------------*/ template< typename T > inline void T_RingBuffer< T >::expand( ) { const auto nsz( allocated_ + expand_ ); T* nData( reinterpret_cast< T* >( ::operator new( sizeof( T ) * nsz ) ) ); for ( uint32_t i = 0 ; i < used_ ; i ++ ) { const auto idx( ( readPos_ + i ) % allocated_ ); new( reinterpret_cast< char* >( &nData[ i ] ) ) T( std::move( data_[ idx ] ) ); data_[ idx ].~T( ); } using std::swap; swap( data_ , nData ); allocated_ = nsz; readPos_ = 0; ::operator delete( (void*) nData ); } } #endif // _H_LW_LIB_INLINE_THREADING