From
Bonita Montero@Bonita.Montero@gmail.com to
comp.lang.c++ on Mon Mar 2 08:25:53 2026
From Newsgroup: comp.lang.c++
My own std::barrier-variant. Slightly simpler than the original.
And the completion function can return a value.
struct xarrival_token
{
xarrival_token() noexcept = default;
xarrival_token( const xarrival_token &tk ) noexcept = default;
xarrival_token &operator =( const xarrival_token &tk ) noexcept = default;
private:
template<std::invocable Complete>
friend struct xbarrier;
int m_id = -1;
};
template<std::invocable Complete>
struct xbarrier
{
static constexpr bool WithReturn = !std::same_as<std::invoke_result_t<Complete>, void>;
using arrive_result = std::conditional_t<WithReturn, std::optional<std::invoke_result_t<Complete>>, void>;
xbarrier( unsigned initial, Complete &&complete );
xbarrier( const xbarrier & ) = delete;
xbarrier &operator =( const xbarrier & ) = delete;
arrive_result arrive( xarrival_token &tk, bool drop = false );
private:
std::mutex m_mtx;
xcondition_variable m_cv;
unsigned m_initial, m_ctr;
bool m_genFlip;
NO_UNIQUE_ADDRESS Complete m_complete;
};
template<std::invocable Complete>
xbarrier<Complete>::xbarrier( unsigned initial, Complete &&complete ) :
m_initial( initial ),
m_ctr( initial ),
m_complete( std::forward<Complete>( complete ) )
{
if constexpr( requires { (bool)m_complete; } )
assert((bool)m_complete);
}
template<std::invocable Complete>
auto xbarrier<Complete>::arrive( xarrival_token &tk, bool drop ) -> arrive_result
{
using namespace std;
unique_lock lock( m_mtx );
assert(m_ctr <= m_initial);
if( !m_initial )
return (arrive_result)nullopt;
m_initial -= drop;
unsigned newId = --m_ctr;
if( bool gen = m_genFlip; m_ctr )
m_cv.wait( lock, [&] { return m_genFlip != gen; } );
else
{
m_ctr = m_initial;
m_genFlip = !gen;
m_cv.notify_all();
}
if( tk.m_id < 0 )
tk.m_id = newId;
if( !tk.m_id )
return m_complete();
return (arrive_result)nullopt;
}
--- Synchronet 3.21d-Linux NewsLink 1.2