• A once_flag which is failable

    From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Sat Oct 25 11:52:56 2025
    From Newsgroup: comp.lang.c++

    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;
    }
    --- Synchronet 3.21a-Linux NewsLink 1.2