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:
parent
9f372d78de
commit
fd28cb5e49
4 changed files with 212 additions and 102 deletions
|
|
@ -58,21 +58,21 @@
|
|||
#define ASSERT_EQ_IDX(i, x, y) static_cast< decltype(i, x, y, void(0)) >(0)
|
||||
#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( \
|
||||
BRICK_LOCWRAP( BRICK_LOCATION( brick::string::fmtf(__VA_ARGS__) ) ) )
|
||||
#define UNREACHABLE(x) ::brick::_assert::assert_die_fn( \
|
||||
BRICK_LOCWRAP( BRICK_LOCATION( x ) ) )
|
||||
#define UNREACHABLE(...) ::brick::_assert::assert_die_fn( \
|
||||
BRICK_LOCWRAP( BRICK_LOCATION( ::brick::_assert::fmt( __VA_ARGS__ ) ) ) )
|
||||
#define UNREACHABLE_() ::brick::_assert::assert_die_fn( \
|
||||
BRICK_LOCWRAP( BRICK_LOCATION( "an unreachable location" ) ) )
|
||||
#define NOT_IMPLEMENTED() ::brick::_assert::assert_die_fn( \
|
||||
BRICK_LOCWRAP( BRICK_LOCATION( "a missing implementation" ) ) )
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define DIVINE_UNUSED
|
||||
#define UNUSED
|
||||
#define noexcept
|
||||
#else
|
||||
#define DIVINE_UNUSED __attribute__((unused))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#ifndef BRICK_ASSERT_H
|
||||
|
|
@ -139,7 +139,7 @@ struct AssertFailed : std::exception
|
|||
(*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 & ) {}
|
||||
|
|
@ -196,9 +196,9 @@ inline void assert_die_fn( Location l )
|
|||
} \
|
||||
}
|
||||
|
||||
ASSERT_FN(eq, ==, !=)
|
||||
ASSERT_FN(leq, <=, >)
|
||||
ASSERT_FN(lt, <, >=)
|
||||
ASSERT_FN(eq, ==, !=);
|
||||
ASSERT_FN(leq, <=, >);
|
||||
ASSERT_FN(lt, <, >=);
|
||||
|
||||
template< typename Location, typename X >
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <limits>
|
||||
|
||||
#ifdef __linux
|
||||
#include <asm/byteorder.h>
|
||||
#include <sys/types.h>
|
||||
#include <byteswap.h>
|
||||
#elif !defined LITTLE_ENDIAN // if defined _WIN32
|
||||
#define BYTE_ORDER 1234
|
||||
|
|
@ -55,6 +55,28 @@ constexpr inline T1 downalign( T1 v, T2 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 {
|
||||
|
||||
template< typename T >
|
||||
|
|
@ -89,10 +111,7 @@ struct bvpair
|
|||
constexpr bvpair( L l, H h = 0 ) : low( l ), high( h ) {}
|
||||
constexpr bvpair() = default;
|
||||
explicit constexpr operator bool() const { return low || high; }
|
||||
#if ((__GNUC__ >= 4 && __GNUC_MINOR__ > 9) || (__clang_major__ == 3 && __clang_minor__ >= 6))
|
||||
constexpr
|
||||
#endif
|
||||
bvpair operator<<( int s ) const
|
||||
constexpr bvpair operator<<( int s ) const
|
||||
{
|
||||
int rem = 8 * sizeof( low ) - s;
|
||||
int unshift = std::max( rem, 0 );
|
||||
|
|
@ -100,10 +119,7 @@ struct bvpair
|
|||
H carry = ( low & ~ones< L >( unshift ) ) >> unshift;
|
||||
return bvpair( low << s, ( high << s ) | ( carry << shift ) );
|
||||
}
|
||||
#if ((__GNUC__ >= 4 && __GNUC_MINOR__ > 9) || (__clang_major__ == 3 && __clang_minor__ >= 6))
|
||||
constexpr
|
||||
#endif
|
||||
bvpair operator>>( int s ) const
|
||||
constexpr bvpair operator>>( int s ) const
|
||||
{
|
||||
int rem = 8 * sizeof( low ) - s;
|
||||
int unshift = std::max( rem, 0 );
|
||||
|
|
@ -133,22 +149,45 @@ template< int i > using bitvec = typename _bitvec< i >::T;
|
|||
|
||||
namespace {
|
||||
|
||||
uint32_t mixdown( uint64_t i ) /* due to Thomas Wang */
|
||||
template< typename T >
|
||||
union Cast
|
||||
{
|
||||
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;
|
||||
bitvec< sizeof( T ) * 8 > r;
|
||||
T c;
|
||||
Cast( T c ) : c( c ) {}
|
||||
Cast( bitvec< sizeof( T ) * 8 > r ) : r( r ) {}
|
||||
};
|
||||
|
||||
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; \
|
||||
}
|
||||
|
||||
OP(+=)
|
||||
OP(-=)
|
||||
OP(*=)
|
||||
OP(/=)
|
||||
OP(%=)
|
||||
OP(|=)
|
||||
OP(&=)
|
||||
OP(+=);
|
||||
OP(-=);
|
||||
OP(*=);
|
||||
OP(/=);
|
||||
OP(%=);
|
||||
OP(|=);
|
||||
OP(&=);
|
||||
#undef OP
|
||||
};
|
||||
};
|
||||
|
|
@ -654,7 +693,8 @@ struct BitTupleTest {
|
|||
ASSERT( !get< 0 >( bt ).word() );
|
||||
}
|
||||
|
||||
TEST(assign) {
|
||||
TEST(assign) /* TODO fails in DIVINE */
|
||||
{
|
||||
bitlevel::BitTuple<
|
||||
BitField< bool, 1 >,
|
||||
BitField< int, 6 >,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ using hash::hash128_t;
|
|||
|
||||
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 );
|
||||
}
|
||||
|
|
@ -153,7 +153,8 @@ struct FastAtomicCell : CellBase< T, Hasher >
|
|||
return true;
|
||||
}
|
||||
|
||||
bool tryStore( T v, hash32_t hash ) {
|
||||
bool tryStore( T v, hash32_t hash )
|
||||
{
|
||||
hash |= 0x1;
|
||||
hash32_t chl = 0;
|
||||
if ( _hashlock.compare_exchange_strong( chl, (hash << 2) | 1 ) ) {
|
||||
|
|
@ -164,6 +165,8 @@ struct FastAtomicCell : CellBase< T, Hasher >
|
|||
return false;
|
||||
}
|
||||
|
||||
void store( T v, hash32_t hash ) { tryStore( v, hash ); }
|
||||
|
||||
template< typename Value >
|
||||
bool is( const Value &v, hash64_t hash, Hasher &h ) {
|
||||
hash |= 0x1;
|
||||
|
|
@ -209,9 +212,9 @@ struct AtomicCell : CellBase< T, Hasher >
|
|||
{
|
||||
std::atomic< Tagged< T > > value;
|
||||
|
||||
static_assert( sizeof( std::atomic< Tagged< T > > ) == sizeof( Tagged< T > ),
|
||||
"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( sizeof( std::atomic< Tagged< T > > ) == sizeof( Tagged< T > ),
|
||||
// "std::atomic< Tagged< T > > must be lock-free" );
|
||||
// static_assert( Tagged< T >::tag_bits > 0, "T has at least a one-bit tagspace" );
|
||||
|
||||
bool empty() { return !value.load().t; }
|
||||
bool invalid() {
|
||||
|
|
@ -226,20 +229,19 @@ struct AtomicCell : CellBase< T, Hasher >
|
|||
return AtomicCell( value.exchange( v ) );
|
||||
}
|
||||
|
||||
Tagged< T > &deatomize() {
|
||||
value.load(); // fence
|
||||
return *reinterpret_cast< Tagged< T > * >( &value );
|
||||
}
|
||||
|
||||
T &fetch() { return deatomize().t; }
|
||||
T fetch() { return value.load().t; }
|
||||
T copy() { Tagged< T > v = value; v.tag( 0 ); return v.t; }
|
||||
bool wait() { return !invalid(); }
|
||||
|
||||
void store( T bn, hash64_t hash ) {
|
||||
return tryStore( bn, hash );
|
||||
void store( T bn, hash64_t 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 > next( b );
|
||||
next.tag( highbits( hash, Tagged< T >::tag_bits ) | 1 );
|
||||
|
|
@ -299,13 +301,25 @@ struct HashSetBase
|
|||
|
||||
Hasher hasher;
|
||||
|
||||
struct iterator {
|
||||
struct proxy
|
||||
{
|
||||
value_type v;
|
||||
value_type *operator->() { return &v; }
|
||||
};
|
||||
|
||||
struct iterator
|
||||
{
|
||||
Cell *_cell;
|
||||
value_type _value;
|
||||
bool _new;
|
||||
iterator( Cell *c = nullptr, bool n = false ) : _cell( c ), _new( n ) {}
|
||||
value_type *operator->() { return &(_cell->fetch()); }
|
||||
value_type &operator*() { return _cell->fetch(); }
|
||||
|
||||
iterator( Cell *c = nullptr, bool n = false )
|
||||
: _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(); }
|
||||
void update( value_type v ) { _cell->store( v ); }
|
||||
bool valid() { return _cell; }
|
||||
bool isnew() { return _new; }
|
||||
};
|
||||
|
|
@ -355,13 +369,16 @@ struct _HashSet : HashSetBase< Cell >
|
|||
size_t _maxsize;
|
||||
bool _growing;
|
||||
|
||||
size_t size() const { return _table.size(); }
|
||||
size_t capacity() const { return _table.size(); }
|
||||
bool empty() const { return !_used; }
|
||||
|
||||
int count( const value_type &i ) { return find( i ).valid(); }
|
||||
hash64_t hash( const value_type &i ) { return hash128( i ).first; }
|
||||
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 >
|
||||
iterator find( const T &i ) {
|
||||
|
|
@ -387,27 +404,35 @@ struct _HashSet : HashSetBase< Cell >
|
|||
return this->end();
|
||||
}
|
||||
|
||||
iterator insertHinted( const value_type &i, hash64_t h ) {
|
||||
return insertHinted( i, h, _table, _used );
|
||||
iterator insertHinted( const value_type &i, hash64_t h, bool replace = false )
|
||||
{
|
||||
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();
|
||||
|
||||
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 );
|
||||
|
||||
if ( table[ idx ].empty() ) {
|
||||
if ( table[ idx ].empty() )
|
||||
{
|
||||
++ used;
|
||||
table[ idx ].store( item, h );
|
||||
return iterator( &table[ idx ], true );
|
||||
}
|
||||
|
||||
if ( table[ idx ].is( item, h, this->hasher ) )
|
||||
{
|
||||
if ( replace )
|
||||
table[ idx ].store( item, h );
|
||||
return iterator( &table[ idx ], false );
|
||||
}
|
||||
}
|
||||
|
||||
grow();
|
||||
|
|
@ -416,7 +441,7 @@ struct _HashSet : HashSetBase< Cell >
|
|||
}
|
||||
|
||||
void grow() {
|
||||
if ( 2 * size() >= _maxsize )
|
||||
if ( 2 * capacity() >= _maxsize )
|
||||
UNREACHABLE( "ran out of space in the hash table" );
|
||||
|
||||
if( _growing )
|
||||
|
|
@ -428,7 +453,7 @@ struct _HashSet : HashSetBase< Cell >
|
|||
|
||||
Table table;
|
||||
|
||||
table.resize( 2 * size(), Cell() );
|
||||
table.resize( 2 * capacity(), Cell() );
|
||||
_bits |= (_bits << 1); // unmask more
|
||||
|
||||
for ( auto cell : _table ) {
|
||||
|
|
@ -444,7 +469,7 @@ struct _HashSet : HashSetBase< Cell >
|
|||
_growing = false;
|
||||
}
|
||||
|
||||
void setSize( size_t s )
|
||||
void reserve( size_t s )
|
||||
{
|
||||
_bits = 0;
|
||||
while ((s = s >> 1))
|
||||
|
|
@ -454,7 +479,7 @@ struct _HashSet : HashSetBase< Cell >
|
|||
|
||||
void clear() {
|
||||
_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 ]; }
|
||||
|
|
@ -467,7 +492,7 @@ struct _HashSet : HashSetBase< Cell >
|
|||
_HashSet( Hasher h, int initial )
|
||||
: Base( h ), _used( 0 ), _maxsize( -1 ), _growing( false )
|
||||
{
|
||||
setSize( initial );
|
||||
reserve( initial );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -595,28 +620,29 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
|
|||
return s * 2;
|
||||
}
|
||||
|
||||
size_t size() { return current().size(); }
|
||||
size_t capacity() { return current().size(); }
|
||||
Row ¤t() { return _s->table[ _s->currentRow ]; }
|
||||
Row ¤t( unsigned index ) { return _s->table[ index ]; }
|
||||
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 >
|
||||
iterator find( const T &x ) {
|
||||
iterator find( const T &x )
|
||||
{
|
||||
return findHinted( x, hasher.hash( x ).first );
|
||||
}
|
||||
|
||||
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 ) {
|
||||
Row &row = current( _l.currentRow );
|
||||
Insert ir = insertCell< false >( row, x, h );
|
||||
Insert ir = insertCell< false >( row, x, h, replace );
|
||||
switch ( ir.r ) {
|
||||
case Resolution::Success:
|
||||
increaseUsage();
|
||||
|
|
@ -689,7 +715,7 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
|
|||
}
|
||||
|
||||
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 ) {
|
||||
// read usage first to guarantee usage <= size
|
||||
|
|
@ -709,14 +735,20 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
|
|||
{
|
||||
Cell &cell = row[ Base::index( h, i, mask ) ];
|
||||
|
||||
if ( cell.empty() ) {
|
||||
if ( cell.empty() )
|
||||
{
|
||||
if ( cell.tryStore( x, h ) )
|
||||
return Insert( Resolution::Success, &cell );
|
||||
if ( !force && changed( _l.currentRow ) )
|
||||
return Insert( Resolution::Growing );
|
||||
}
|
||||
|
||||
if ( cell.is( x, h, hasher ) )
|
||||
{
|
||||
if ( replace )
|
||||
cell.store( x, h );
|
||||
return Insert( Resolution::Found, &cell );
|
||||
}
|
||||
|
||||
if ( !force && changed( _l.currentRow ) )
|
||||
return Insert( Resolution::Growing );
|
||||
|
|
@ -932,7 +964,7 @@ struct Sequential
|
|||
ASSERT( set.count( 1 ) );
|
||||
|
||||
unsigned count = 0;
|
||||
for ( unsigned i = 0; i != set.size(); ++i )
|
||||
for ( unsigned i = 0; i != set.capacity(); ++i )
|
||||
if ( set.valueAt( i ) )
|
||||
++count;
|
||||
|
||||
|
|
@ -1024,7 +1056,7 @@ struct Parallel
|
|||
static HS< int > _multi( std::size_t count, int from, int to )
|
||||
{
|
||||
shmem::ThreadSet< Insert > arr;
|
||||
arr.resize( count, Insert() );
|
||||
arr.resize( count );
|
||||
arr[ 0 ].set.initialSize( isize );
|
||||
|
||||
for ( std::size_t i = 0; i < count; ++i )
|
||||
|
|
@ -1049,7 +1081,7 @@ struct Parallel
|
|||
|
||||
int count = 0;
|
||||
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 ( s.find( set.valueAt( i ) ) == s.end() )
|
||||
s.insert( set.valueAt( i ) );
|
||||
|
|
@ -1395,7 +1427,7 @@ struct RandomInsert {
|
|||
: insert( true ), max( max )
|
||||
{
|
||||
if ( bg->reserve() > 0 )
|
||||
t.setSize( bg->items() * bg->reserve() );
|
||||
t.reserve( bg->items() * bg->reserve() );
|
||||
}
|
||||
|
||||
template< typename BG >
|
||||
|
|
@ -1478,7 +1510,7 @@ struct wrap_set {
|
|||
C< T > *t;
|
||||
struct ThreadData {};
|
||||
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 ); }
|
||||
int count( T i ) { return t->count( i ); }
|
||||
HashTable() : t( new C< T > ) {}
|
||||
|
|
|
|||
|
|
@ -42,10 +42,10 @@
|
|||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <future>
|
||||
|
||||
#include <unistd.h> // alarm
|
||||
#include <vector>
|
||||
|
|
@ -54,18 +54,21 @@
|
|||
#define BRICK_SHMEM_H
|
||||
|
||||
#ifndef BRICKS_CACHELINE
|
||||
#if (__GNUC__ >= 7) // Please new Versions of GCC
|
||||
#define BRICKS_CACHELINE 16
|
||||
#else
|
||||
#define BRICKS_CACHELINE 64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace brick {
|
||||
namespace shmem {
|
||||
|
||||
struct ThreadBase
|
||||
{
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual ~ThreadBase() {}
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct Thread : T
|
||||
struct Thread : T, ThreadBase
|
||||
{
|
||||
std::unique_ptr< std::thread > _thread;
|
||||
bool _start_on_move; // :-(
|
||||
|
|
@ -89,9 +92,9 @@ struct Thread : T
|
|||
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()
|
||||
|
|
@ -117,13 +120,6 @@ struct Thread : T
|
|||
_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 >
|
||||
|
|
@ -178,13 +174,13 @@ struct AsyncLoop : Thread< LoopWrapper< T > >
|
|||
stop(); /* call the correct stop(), with interrupt() */
|
||||
}
|
||||
|
||||
void start() noexcept override
|
||||
void start()
|
||||
{
|
||||
this->_interrupted.store( false, std::memory_order_relaxed );
|
||||
Super::start();
|
||||
}
|
||||
|
||||
void stop() override
|
||||
void stop()
|
||||
{
|
||||
this->interrupt();
|
||||
Super::stop();
|
||||
|
|
@ -192,19 +188,22 @@ struct AsyncLoop : Thread< LoopWrapper< T > >
|
|||
};
|
||||
|
||||
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;
|
||||
return std::move( al );
|
||||
}
|
||||
|
||||
template< typename L >
|
||||
auto thread( L &&l ) -> Thread< LambdaWrapper< L > >
|
||||
auto thread( L &&l )
|
||||
{
|
||||
Thread< LambdaWrapper< L > > thr( std::forward< L >( l ) );
|
||||
thr._start_on_move = true;
|
||||
return thr;
|
||||
return std::move( thr );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
|
|
@ -213,7 +212,7 @@ struct ThreadSet : std::vector< Thread< T > >
|
|||
template< typename... 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(); }
|
||||
};
|
||||
|
||||
|
|
@ -638,6 +637,41 @@ struct Chunked
|
|||
template< typename 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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue