bricks: update excluding C++17 features

* spot/bricks/brick-assert,
spot/bricks/brick-bitlevel,
spot/bricks/brick-hashset,
spot/bricks/brick-shmem: Here.
This commit is contained in:
Etienne Renault 2018-11-28 14:12:51 +01:00
parent 9f372d78de
commit fd28cb5e49
4 changed files with 212 additions and 102 deletions

View file

@ -58,21 +58,21 @@
#define ASSERT_EQ_IDX(i, x, y) static_cast< decltype(i, x, y, void(0)) >(0) #define ASSERT_EQ_IDX(i, x, y) static_cast< decltype(i, x, y, void(0)) >(0)
#endif #endif
/* you must #include <brick-string.h> to use ASSERT_UNREACHABLE_F */ /* you must #include <brick-string> to use ASSERT_UNREACHABLE_F */
#define UNREACHABLE_F(...) ::brick::_assert::assert_die_fn( \ #define UNREACHABLE_F(...) ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( brick::string::fmtf(__VA_ARGS__) ) ) ) BRICK_LOCWRAP( BRICK_LOCATION( brick::string::fmtf(__VA_ARGS__) ) ) )
#define UNREACHABLE(x) ::brick::_assert::assert_die_fn( \ #define UNREACHABLE(...) ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( x ) ) ) BRICK_LOCWRAP( BRICK_LOCATION( ::brick::_assert::fmt( __VA_ARGS__ ) ) ) )
#define UNREACHABLE_() ::brick::_assert::assert_die_fn( \ #define UNREACHABLE_() ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( "an unreachable location" ) ) ) BRICK_LOCWRAP( BRICK_LOCATION( "an unreachable location" ) ) )
#define NOT_IMPLEMENTED() ::brick::_assert::assert_die_fn( \ #define NOT_IMPLEMENTED() ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( "a missing implementation" ) ) ) BRICK_LOCWRAP( BRICK_LOCATION( "a missing implementation" ) ) )
#ifdef _MSC_VER #ifdef _MSC_VER
#define DIVINE_UNUSED #define UNUSED
#define noexcept #define noexcept
#else #else
#define DIVINE_UNUSED __attribute__((unused)) #define UNUSED __attribute__((unused))
#endif #endif
#ifndef BRICK_ASSERT_H #ifndef BRICK_ASSERT_H
@ -139,7 +139,7 @@ struct AssertFailed : std::exception
(*this) << ":\n " << expected << " " << l.stmt; (*this) << ":\n " << expected << " " << l.stmt;
} }
const char *what() const noexcept override { return str.c_str(); } const char *what() const noexcept { return str.c_str(); }
}; };
static inline void format( AssertFailed & ) {} static inline void format( AssertFailed & ) {}
@ -196,9 +196,9 @@ inline void assert_die_fn( Location l )
} \ } \
} }
ASSERT_FN(eq, ==, !=) ASSERT_FN(eq, ==, !=);
ASSERT_FN(leq, <=, >) ASSERT_FN(leq, <=, >);
ASSERT_FN(lt, <, >=) ASSERT_FN(lt, <, >=);
template< typename Location, typename X > template< typename Location, typename X >
void assert_pred_fn( Location l, X x, bool p ) void assert_pred_fn( Location l, X x, bool p )
@ -221,6 +221,10 @@ void assert_neq_fn( Location l, X x, Y y )
throw f; throw f;
} }
inline std::string fmt( const char *str ) { return str; }
inline std::string fmt( std::string str ) { return str; }
// another overload of fmt is exported by brick-string and it allows more complex formating
} }
} }

View file

@ -28,7 +28,7 @@
#include <limits> #include <limits>
#ifdef __linux #ifdef __linux
#include <asm/byteorder.h> #include <sys/types.h>
#include <byteswap.h> #include <byteswap.h>
#elif !defined LITTLE_ENDIAN // if defined _WIN32 #elif !defined LITTLE_ENDIAN // if defined _WIN32
#define BYTE_ORDER 1234 #define BYTE_ORDER 1234
@ -55,6 +55,28 @@ constexpr inline T1 downalign( T1 v, T2 a ) {
return v - (v % T1(a)); return v - (v % T1(a));
} }
template< typename F, typename T >
void maybe_bitcast( F f, T &t )
{
ASSERT( sizeof( T ) == sizeof( F ) );
memcpy( &t, &f, sizeof( T ) );
}
template< typename F, typename T >
void bitcast( F f, T &t )
{
//static_assert( sizeof( F ) == sizeof( T ) );
maybe_bitcast( f, t );
}
template< typename T, typename F >
T bitcast( F f )
{
T t;
bitcast( f, t );
return t;
}
namespace compiletime { namespace compiletime {
template< typename T > template< typename T >
@ -89,10 +111,7 @@ struct bvpair
constexpr bvpair( L l, H h = 0 ) : low( l ), high( h ) {} constexpr bvpair( L l, H h = 0 ) : low( l ), high( h ) {}
constexpr bvpair() = default; constexpr bvpair() = default;
explicit constexpr operator bool() const { return low || high; } explicit constexpr operator bool() const { return low || high; }
#if ((__GNUC__ >= 4 && __GNUC_MINOR__ > 9) || (__clang_major__ == 3 && __clang_minor__ >= 6)) constexpr bvpair operator<<( int s ) const
constexpr
#endif
bvpair operator<<( int s ) const
{ {
int rem = 8 * sizeof( low ) - s; int rem = 8 * sizeof( low ) - s;
int unshift = std::max( rem, 0 ); int unshift = std::max( rem, 0 );
@ -100,10 +119,7 @@ struct bvpair
H carry = ( low & ~ones< L >( unshift ) ) >> unshift; H carry = ( low & ~ones< L >( unshift ) ) >> unshift;
return bvpair( low << s, ( high << s ) | ( carry << shift ) ); return bvpair( low << s, ( high << s ) | ( carry << shift ) );
} }
#if ((__GNUC__ >= 4 && __GNUC_MINOR__ > 9) || (__clang_major__ == 3 && __clang_minor__ >= 6)) constexpr bvpair operator>>( int s ) const
constexpr
#endif
bvpair operator>>( int s ) const
{ {
int rem = 8 * sizeof( low ) - s; int rem = 8 * sizeof( low ) - s;
int unshift = std::max( rem, 0 ); int unshift = std::max( rem, 0 );
@ -133,22 +149,45 @@ template< int i > using bitvec = typename _bitvec< i >::T;
namespace { namespace {
uint32_t mixdown( uint64_t i ) /* due to Thomas Wang */ template< typename T >
union Cast
{ {
i = (~i) + (i << 18); bitvec< sizeof( T ) * 8 > r;
i = i ^ (i >> 31); T c;
i = i * 21; Cast( T c ) : c( c ) {}
i = i ^ (i >> 11); Cast( bitvec< sizeof( T ) * 8 > r ) : r( r ) {}
i = i + (i << 6); };
i = i ^ (i >> 22);
return i; template< typename T >
bitvec< sizeof( T ) * 8 > raw( T t )
{
Cast< T > c( t );
return c.r;
} }
__attribute__((unused)) uint32_t mixdown( uint32_t a, uint32_t b ) template< typename T >
T unraw( bitvec< sizeof( T ) * 8 > r )
{ {
return mixdown( ( uint64_t( a ) << 32 ) | uint64_t( b ) ); Cast< T > c( r );
return c.c;
} }
// uint32_t mixdown( uint64_t i ) /* due to Thomas Wang */
// {
// i = (~i) + (i << 18);
// i = i ^ (i >> 31);
// i = i * 21;
// i = i ^ (i >> 11);
// i = i + (i << 6);
// i = i ^ (i >> 22);
// return i;
// }
// uint32_t mixdown( uint32_t a, uint32_t b )
// {
// return mixdown( ( uint64_t( a ) << 32 ) | uint64_t( b ) );
// }
} }
/* /*
@ -367,13 +406,13 @@ struct BitField
return *this; \ return *this; \
} }
OP(+=) OP(+=);
OP(-=) OP(-=);
OP(*=) OP(*=);
OP(/=) OP(/=);
OP(%=) OP(%=);
OP(|=) OP(|=);
OP(&=) OP(&=);
#undef OP #undef OP
}; };
}; };
@ -654,7 +693,8 @@ struct BitTupleTest {
ASSERT( !get< 0 >( bt ).word() ); ASSERT( !get< 0 >( bt ).word() );
} }
TEST(assign) { TEST(assign) /* TODO fails in DIVINE */
{
bitlevel::BitTuple< bitlevel::BitTuple<
BitField< bool, 1 >, BitField< bool, 1 >,
BitField< int, 6 >, BitField< int, 6 >,

View file

@ -43,7 +43,7 @@ using hash::hash128_t;
struct DefaultHasher struct DefaultHasher
{ {
auto hash( int64_t v ) const -> std::pair<int64_t, int64_t> auto hash( int64_t v ) const
{ {
return std::make_pair( v, ~v ); return std::make_pair( v, ~v );
} }
@ -153,7 +153,8 @@ struct FastAtomicCell : CellBase< T, Hasher >
return true; return true;
} }
bool tryStore( T v, hash32_t hash ) { bool tryStore( T v, hash32_t hash )
{
hash |= 0x1; hash |= 0x1;
hash32_t chl = 0; hash32_t chl = 0;
if ( _hashlock.compare_exchange_strong( chl, (hash << 2) | 1 ) ) { if ( _hashlock.compare_exchange_strong( chl, (hash << 2) | 1 ) ) {
@ -164,6 +165,8 @@ struct FastAtomicCell : CellBase< T, Hasher >
return false; return false;
} }
void store( T v, hash32_t hash ) { tryStore( v, hash ); }
template< typename Value > template< typename Value >
bool is( const Value &v, hash64_t hash, Hasher &h ) { bool is( const Value &v, hash64_t hash, Hasher &h ) {
hash |= 0x1; hash |= 0x1;
@ -209,9 +212,9 @@ struct AtomicCell : CellBase< T, Hasher >
{ {
std::atomic< Tagged< T > > value; std::atomic< Tagged< T > > value;
static_assert( sizeof( std::atomic< Tagged< T > > ) == sizeof( Tagged< T > ), // static_assert( sizeof( std::atomic< Tagged< T > > ) == sizeof( Tagged< T > ),
"std::atomic< Tagged< T > > must be lock-free" ); // "std::atomic< Tagged< T > > must be lock-free" );
static_assert( Tagged< T >::tag_bits > 0, "T has at least a one-bit tagspace" ); // static_assert( Tagged< T >::tag_bits > 0, "T has at least a one-bit tagspace" );
bool empty() { return !value.load().t; } bool empty() { return !value.load().t; }
bool invalid() { bool invalid() {
@ -226,20 +229,19 @@ struct AtomicCell : CellBase< T, Hasher >
return AtomicCell( value.exchange( v ) ); return AtomicCell( value.exchange( v ) );
} }
Tagged< T > &deatomize() { T fetch() { return value.load().t; }
value.load(); // fence
return *reinterpret_cast< Tagged< T > * >( &value );
}
T &fetch() { return deatomize().t; }
T copy() { Tagged< T > v = value; v.tag( 0 ); return v.t; } T copy() { Tagged< T > v = value; v.tag( 0 ); return v.t; }
bool wait() { return !invalid(); } bool wait() { return !invalid(); }
void store( T bn, hash64_t hash ) { void store( T bn, hash64_t hash )
return tryStore( bn, hash ); {
Tagged< T > next( bn );
next.tag( highbits( hash, Tagged< T >::tag_bits ) | 1 );
value.store( next );
} }
bool tryStore( T b, hash64_t hash ) { bool tryStore( T b, hash64_t hash )
{
Tagged< T > zero; Tagged< T > zero;
Tagged< T > next( b ); Tagged< T > next( b );
next.tag( highbits( hash, Tagged< T >::tag_bits ) | 1 ); next.tag( highbits( hash, Tagged< T >::tag_bits ) | 1 );
@ -299,13 +301,25 @@ struct HashSetBase
Hasher hasher; Hasher hasher;
struct iterator { struct proxy
{
value_type v;
value_type *operator->() { return &v; }
};
struct iterator
{
Cell *_cell; Cell *_cell;
value_type _value;
bool _new; bool _new;
iterator( Cell *c = nullptr, bool n = false ) : _cell( c ), _new( n ) {}
value_type *operator->() { return &(_cell->fetch()); } iterator( Cell *c = nullptr, bool n = false )
value_type &operator*() { return _cell->fetch(); } : _cell( c ), _value( c ? c->fetch() : value_type() ), _new( n )
{}
proxy operator->() { return proxy( _value ); }
value_type operator*() { return _value; }
value_type copy() { return _cell->copy(); } value_type copy() { return _cell->copy(); }
void update( value_type v ) { _cell->store( v ); }
bool valid() { return _cell; } bool valid() { return _cell; }
bool isnew() { return _new; } bool isnew() { return _new; }
}; };
@ -355,13 +369,16 @@ struct _HashSet : HashSetBase< Cell >
size_t _maxsize; size_t _maxsize;
bool _growing; bool _growing;
size_t size() const { return _table.size(); } size_t capacity() const { return _table.size(); }
bool empty() const { return !_used; } bool empty() const { return !_used; }
int count( const value_type &i ) { return find( i ).valid(); } int count( const value_type &i ) { return find( i ).valid(); }
hash64_t hash( const value_type &i ) { return hash128( i ).first; } hash64_t hash( const value_type &i ) { return hash128( i ).first; }
hash128_t hash128( const value_type &i ) { return this->hasher.hash( i ); } hash128_t hash128( const value_type &i ) { return this->hasher.hash( i ); }
iterator insert( value_type i ) { return insertHinted( i, hash( i ) ); } iterator insert( value_type i, bool replace = false )
{
return insertHinted( i, hash( i ), replace );
}
template< typename T > template< typename T >
iterator find( const T &i ) { iterator find( const T &i ) {
@ -387,28 +404,36 @@ struct _HashSet : HashSetBase< Cell >
return this->end(); return this->end();
} }
iterator insertHinted( const value_type &i, hash64_t h ) { iterator insertHinted( const value_type &i, hash64_t h, bool replace = false )
return insertHinted( i, h, _table, _used ); {
return insertHinted( i, h, _table, _used, replace );
} }
iterator insertHinted( const value_type &item, hash64_t h, Table &table, int &used ) iterator insertHinted( const value_type &item, hash64_t h, Table &table, int &used,
bool replace = false )
{ {
if ( !_growing && size_t( _used ) > (size() / 100) * 75 ) if ( !_growing && size_t( _used ) > ( capacity() / 100 ) * 75 )
grow(); grow();
size_t idx; size_t idx;
for ( size_t i = 0; i < this->maxcollisions; ++i ) { for ( size_t i = 0; i < this->maxcollisions; ++i )
{
idx = this->index( h, i, _bits ); idx = this->index( h, i, _bits );
if ( table[ idx ].empty() ) { if ( table[ idx ].empty() )
{
++ used; ++ used;
table[ idx ].store( item, h ); table[ idx ].store( item, h );
return iterator( &table[ idx ], true ); return iterator( &table[ idx ], true );
} }
if ( table[ idx ].is( item, h, this->hasher ) ) if ( table[ idx ].is( item, h, this->hasher ) )
{
if ( replace )
table[ idx ].store( item, h );
return iterator( &table[ idx ], false ); return iterator( &table[ idx ], false );
} }
}
grow(); grow();
@ -416,7 +441,7 @@ struct _HashSet : HashSetBase< Cell >
} }
void grow() { void grow() {
if ( 2 * size() >= _maxsize ) if ( 2 * capacity() >= _maxsize )
UNREACHABLE( "ran out of space in the hash table" ); UNREACHABLE( "ran out of space in the hash table" );
if( _growing ) if( _growing )
@ -428,7 +453,7 @@ struct _HashSet : HashSetBase< Cell >
Table table; Table table;
table.resize( 2 * size(), Cell() ); table.resize( 2 * capacity(), Cell() );
_bits |= (_bits << 1); // unmask more _bits |= (_bits << 1); // unmask more
for ( auto cell : _table ) { for ( auto cell : _table ) {
@ -444,7 +469,7 @@ struct _HashSet : HashSetBase< Cell >
_growing = false; _growing = false;
} }
void setSize( size_t s ) void reserve( size_t s )
{ {
_bits = 0; _bits = 0;
while ((s = s >> 1)) while ((s = s >> 1))
@ -454,7 +479,7 @@ struct _HashSet : HashSetBase< Cell >
void clear() { void clear() {
_used = 0; _used = 0;
std::fill( _table.begin(), _table.end(), value_type() ); std::fill( _table.begin(), _table.end(), Cell() );
} }
Cell &cellAt( size_t idx ) { return _table[ idx ]; } Cell &cellAt( size_t idx ) { return _table[ idx ]; }
@ -467,7 +492,7 @@ struct _HashSet : HashSetBase< Cell >
_HashSet( Hasher h, int initial ) _HashSet( Hasher h, int initial )
: Base( h ), _used( 0 ), _maxsize( -1 ), _growing( false ) : Base( h ), _used( 0 ), _maxsize( -1 ), _growing( false )
{ {
setSize( initial ); reserve( initial );
} }
}; };
@ -595,28 +620,29 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
return s * 2; return s * 2;
} }
size_t size() { return current().size(); } size_t capacity() { return current().size(); }
Row &current() { return _s->table[ _s->currentRow ]; } Row &current() { return _s->table[ _s->currentRow ]; }
Row &current( unsigned index ) { return _s->table[ index ]; } Row &current( unsigned index ) { return _s->table[ index ]; }
bool changed( unsigned row ) { return row < _s->currentRow || _s->growing; } bool changed( unsigned row ) { return row < _s->currentRow || _s->growing; }
iterator insert( value_type x ) iterator insert( value_type x, bool replace = false )
{ {
return insertHinted( x, hasher.hash( x ).first ); return insertHinted( x, hasher.hash( x ).first, replace );
} }
template< typename T > template< typename T >
iterator find( const T &x ) { iterator find( const T &x )
{
return findHinted( x, hasher.hash( x ).first ); return findHinted( x, hasher.hash( x ).first );
} }
int count( value_type x ) { return find( x ).valid() ? 1 : 0; } int count( value_type x ) { return find( x ).valid() ? 1 : 0; }
iterator insertHinted( value_type x, hash64_t h ) iterator insertHinted( value_type x, hash64_t h, bool replace = false )
{ {
while ( true ) { while ( true ) {
Row &row = current( _l.currentRow ); Row &row = current( _l.currentRow );
Insert ir = insertCell< false >( row, x, h ); Insert ir = insertCell< false >( row, x, h, replace );
switch ( ir.r ) { switch ( ir.r ) {
case Resolution::Success: case Resolution::Success:
increaseUsage(); increaseUsage();
@ -689,7 +715,7 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
} }
template< bool force > template< bool force >
Insert insertCell( Row &row, value_type x, hash64_t h ) Insert insertCell( Row &row, value_type x, hash64_t h, bool replace = false )
{ {
if ( !force ) { if ( !force ) {
// read usage first to guarantee usage <= size // read usage first to guarantee usage <= size
@ -709,14 +735,20 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
{ {
Cell &cell = row[ Base::index( h, i, mask ) ]; Cell &cell = row[ Base::index( h, i, mask ) ];
if ( cell.empty() ) { if ( cell.empty() )
{
if ( cell.tryStore( x, h ) ) if ( cell.tryStore( x, h ) )
return Insert( Resolution::Success, &cell ); return Insert( Resolution::Success, &cell );
if ( !force && changed( _l.currentRow ) ) if ( !force && changed( _l.currentRow ) )
return Insert( Resolution::Growing ); return Insert( Resolution::Growing );
} }
if ( cell.is( x, h, hasher ) ) if ( cell.is( x, h, hasher ) )
{
if ( replace )
cell.store( x, h );
return Insert( Resolution::Found, &cell ); return Insert( Resolution::Found, &cell );
}
if ( !force && changed( _l.currentRow ) ) if ( !force && changed( _l.currentRow ) )
return Insert( Resolution::Growing ); return Insert( Resolution::Growing );
@ -932,7 +964,7 @@ struct Sequential
ASSERT( set.count( 1 ) ); ASSERT( set.count( 1 ) );
unsigned count = 0; unsigned count = 0;
for ( unsigned i = 0; i != set.size(); ++i ) for ( unsigned i = 0; i != set.capacity(); ++i )
if ( set.valueAt( i ) ) if ( set.valueAt( i ) )
++count; ++count;
@ -1024,7 +1056,7 @@ struct Parallel
static HS< int > _multi( std::size_t count, int from, int to ) static HS< int > _multi( std::size_t count, int from, int to )
{ {
shmem::ThreadSet< Insert > arr; shmem::ThreadSet< Insert > arr;
arr.resize( count, Insert() ); arr.resize( count );
arr[ 0 ].set.initialSize( isize ); arr[ 0 ].set.initialSize( isize );
for ( std::size_t i = 0; i < count; ++i ) for ( std::size_t i = 0; i < count; ++i )
@ -1049,7 +1081,7 @@ struct Parallel
int count = 0; int count = 0;
std::set< int > s; std::set< int > s;
for ( size_t i = 0; i != set.size(); ++i ) { for ( size_t i = 0; i != set.capacity(); ++i ) {
if ( set.valueAt( i ) ) { if ( set.valueAt( i ) ) {
if ( s.find( set.valueAt( i ) ) == s.end() ) if ( s.find( set.valueAt( i ) ) == s.end() )
s.insert( set.valueAt( i ) ); s.insert( set.valueAt( i ) );
@ -1395,7 +1427,7 @@ struct RandomInsert {
: insert( true ), max( max ) : insert( true ), max( max )
{ {
if ( bg->reserve() > 0 ) if ( bg->reserve() > 0 )
t.setSize( bg->items() * bg->reserve() ); t.reserve( bg->items() * bg->reserve() );
} }
template< typename BG > template< typename BG >
@ -1478,7 +1510,7 @@ struct wrap_set {
C< T > *t; C< T > *t;
struct ThreadData {}; struct ThreadData {};
HashTable< T > withTD( ThreadData & ) { return *this; } HashTable< T > withTD( ThreadData & ) { return *this; }
void setSize( int s ) { t->rehash( s ); } void reserve( int s ) { t->rehash( s ); }
void insert( T i ) { t->insert( i ); } void insert( T i ) { t->insert( i ); }
int count( T i ) { return t->count( i ); } int count( T i ) { return t->count( i ); }
HashTable() : t( new C< T > ) {} HashTable() : t( new C< T > ) {}

View file

@ -42,10 +42,10 @@
#include <iostream> #include <iostream>
#include <typeinfo> #include <typeinfo>
#include <mutex>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <future>
#include <unistd.h> // alarm #include <unistd.h> // alarm
#include <vector> #include <vector>
@ -54,18 +54,21 @@
#define BRICK_SHMEM_H #define BRICK_SHMEM_H
#ifndef BRICKS_CACHELINE #ifndef BRICKS_CACHELINE
#if (__GNUC__ >= 7) // Please new Versions of GCC
#define BRICKS_CACHELINE 16
#else
#define BRICKS_CACHELINE 64 #define BRICKS_CACHELINE 64
#endif #endif
#endif
namespace brick { namespace brick {
namespace shmem { namespace shmem {
struct ThreadBase
{
virtual void start() = 0;
virtual void stop() = 0;
virtual ~ThreadBase() {}
};
template< typename T > template< typename T >
struct Thread : T struct Thread : T, ThreadBase
{ {
std::unique_ptr< std::thread > _thread; std::unique_ptr< std::thread > _thread;
bool _start_on_move; // :-( bool _start_on_move; // :-(
@ -89,9 +92,9 @@ struct Thread : T
start(); start();
} }
virtual void start() noexcept virtual void start()
{ {
_thread.reset( new std::thread( [this]() noexcept { this->main(); } ) ); _thread.reset( new std::thread( [this]() { this->main(); } ) );
} }
virtual void stop() virtual void stop()
@ -117,13 +120,6 @@ struct Thread : T
_thread.reset(); _thread.reset();
} }
} }
const Thread& operator=(const Thread& other)
{
std::cerr << "FIXME Added by us (Spot) to avoid compilation warnings\n";
std::cerr << " Should not pass here.\n";
return other;
}
}; };
template< typename T > template< typename T >
@ -178,13 +174,13 @@ struct AsyncLoop : Thread< LoopWrapper< T > >
stop(); /* call the correct stop(), with interrupt() */ stop(); /* call the correct stop(), with interrupt() */
} }
void start() noexcept override void start()
{ {
this->_interrupted.store( false, std::memory_order_relaxed ); this->_interrupted.store( false, std::memory_order_relaxed );
Super::start(); Super::start();
} }
void stop() override void stop()
{ {
this->interrupt(); this->interrupt();
Super::stop(); Super::stop();
@ -192,19 +188,22 @@ struct AsyncLoop : Thread< LoopWrapper< T > >
}; };
template< typename L > template< typename L >
auto async_loop( L &&l ) -> AsyncLoop< LambdaWrapper< L > >&& using AsyncLambdaLoop = AsyncLoop< LambdaWrapper< L > >;
template< typename L >
auto async_loop( L &&l )
{ {
AsyncLoop< LambdaWrapper< L > > al( std::forward< L >( l ) ); AsyncLambdaLoop< L > al( std::forward< L >( l ) );
al._start_on_move = true; al._start_on_move = true;
return std::move( al ); return std::move( al );
} }
template< typename L > template< typename L >
auto thread( L &&l ) -> Thread< LambdaWrapper< L > > auto thread( L &&l )
{ {
Thread< LambdaWrapper< L > > thr( std::forward< L >( l ) ); Thread< LambdaWrapper< L > > thr( std::forward< L >( l ) );
thr._start_on_move = true; thr._start_on_move = true;
return thr; return std::move( thr );
} }
template< typename T > template< typename T >
@ -213,7 +212,7 @@ struct ThreadSet : std::vector< Thread< T > >
template< typename... Args > template< typename... Args >
ThreadSet( Args&&... args ) : std::vector< Thread< T > >( std::forward< Args >( args )... ) {} ThreadSet( Args&&... args ) : std::vector< Thread< T > >( std::forward< Args >( args )... ) {}
void start() noexcept { for ( auto &t : *this ) t.start(); } void start() { for ( auto &t : *this ) t.start(); }
void join() { for ( auto &t : *this ) t.join(); } void join() { for ( auto &t : *this ) t.join(); }
}; };
@ -638,6 +637,41 @@ struct Chunked
template< typename T > template< typename T >
using SharedQueue = Chunked< LockedQueue, T >; using SharedQueue = Chunked< LockedQueue, T >;
namespace
{
using steady_time = std::chrono::time_point< std::chrono::steady_clock >;
// steady_time later( int ms )
// {
// return std::chrono::steady_clock::now() + std::chrono::milliseconds( ms );
// }
template< typename I, typename F >
std::future_status wait( I b, I e, F cleanup,
steady_time until /*= 0 later( 500 )*/ ) try
{
int total = 0, ready = 0;
for ( auto i = b; i != e; ++i )
{
if ( !i->valid() ) continue;
++ total;
if ( i->wait_until( until ) == std::future_status::ready )
{
++ ready;
i->get(); /* throw any exceptions */
}
}
if ( total == ready )
{
cleanup();
return std::future_status::ready;
}
return std::future_status::timeout;
} catch ( ... ) { cleanup(); throw; };
}
} }
namespace t_shmem { namespace t_shmem {