• A once_flag which is failable

    From Bonita Montero@3:633/10 to All on Sat Oct 25 11:52:56 2025
    I was annoyed that the initialition-lambda of once_flag can be
    bypassed only if you throw an exception. So I wrote xonce_flag
    that optionally accepts a bool from the initialization-lambda
    and when it is false the initialization stops.
    "defer" is similary to experimental::scope_exit.

    #pragma once
    #include <atomic>
    #include "defer.h"

    struct xonce_flag
    {
    xonce_flag() = default;
    xonce_flag( xonce_flag const & );
    private:
    template<typename Fn>
    friend bool xcall_once( xonce_flag &onceFlag, Fn fn );
    std::atomic<int8_t> m_flag = 0;
    };

    xonce_flag::xonce_flag( xonce_flag const &other ) :
    m_flag( other.m_flag.load( std::memory_order_relaxed ) )
    {
    }

    template<typename Fn>
    bool xcall_once( xonce_flag &once, Fn fn )
    {
    using namespace std;
    auto load = [&] { return once.m_flag.load( memory_order_acquire ); };
    for( int8_t flag = load(); flag <= 0; ) [[likely]]
    {
    if( flag < 0 )
    {
    once.m_flag.wait( flag, memory_order_relaxed );
    flag = load();
    continue;
    }
    if( !once.m_flag.compare_exchange_strong( flag, -1, memory_order_acquire, memory_order_relaxed ) )
    continue;
    defer finally( [&]
    {
    once.m_flag.store( 0, memory_order_relaxed );
    once.m_flag.notify_all();
    } );
    if constexpr( !requires { { fn() } -> convertible_to<bool>; } )
    fn();
    else
    if( !fn() )
    return false;
    finally.disable();
    once.m_flag.store( 1, memory_order_release );
    once.m_flag.notify_all();
    return true;
    }
    return true;
    }

    --- PyGate Linux v1.5
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)