Async-Trampoline

 view release on metacpan or  search on metacpan

src/Async.h  view on Meta::CPAN

#pragma once
#include "Destructible.h"
#include "NoexceptSwap.h"

#include <cassert>
#include <functional>
#include <vector>
#include <utility>

#ifndef ASYNC_TRAMPOLINE_DEBUG
#define ASYNC_TRAMPOLINE_DEBUG 0
#define ASYNC_LOG_DEBUG(...) do {                                           \
    if (0) _async_log_debug_ignoreall(__VA_ARGS__);                         \
} while (0)
template<class... Args>
static inline void _async_log_debug_ignoreall(Args&&...) { }
#else
#include <cstdio>
#define ASYNC_TRAMPOLINE_DEBUG 1
#define ASYNC_LOG_DEBUG(...) do {                                           \
    fprintf(stderr, "#DEBUG Async: " __VA_ARGS__);                          \
    fflush(stderr);                                                         \
} while (0)
#endif /* ifndef ASYNC_TRAMPOLINE_DEBUG */

#define ASYNC_FORMAT "<Async %p %s ref=%zu blocks=%zu>"
#define ASYNC_FORMAT_ARGS(aptr)                                             \
    (aptr),                                                                 \
    Async_maybe_type_name(aptr),                                            \
    Async_maybe_refcount(aptr),                                             \
    Async_maybe_blocked_size(aptr)

#ifdef __cpp_ref_qualifiers
#define MAYBE_MOVEREF &&
#else
#define MAYBE_MOVEREF
#endif

enum class Async_Type
{
    IS_UNINITIALIZED,

    CATEGORY_INITIALIZED,
    IS_PTR,
    IS_RAWTHUNK,
    IS_THUNK,
    IS_CONCAT,
    IS_FLOW,

    CATEGORY_COMPLETE,
    IS_CANCEL,

    CATEGORY_RESOLVED,
    IS_ERROR,
    IS_VALUE,
};

inline
const char*
Async_Type_name(enum Async_Type type)
{
    switch (type) {
        case Async_Type::IS_UNINITIALIZED:      return "IS_UNINITIALIZED";
        case Async_Type::CATEGORY_INITIALIZED:  return "CATEGORY_INITIALIZED";
        case Async_Type::IS_PTR:                return "IS_PTR";
        case Async_Type::IS_RAWTHUNK:           return "IS_RAWTHUNK";
        case Async_Type::IS_THUNK:              return "IS_THUNK";
        case Async_Type::IS_CONCAT:             return "IS_CONCAT";
        case Async_Type::IS_FLOW:               return "IS_FLOW";
        case Async_Type::CATEGORY_COMPLETE:     return "CATEGORY_COMPLETE";
        case Async_Type::IS_CANCEL:             return "IS_CANCEL";
        case Async_Type::CATEGORY_RESOLVED:     return "CATEGORY_RESOLVED";
        case Async_Type::IS_ERROR:              return "IS_ERROR";
        case Async_Type::IS_VALUE:              return "IS_VALUE";
        default:                                return "(unknown)";
    }
}

struct Async;

class AsyncRef
{
    Async* ptr;

    struct NoInc{};
public:
    static constexpr NoInc no_inc{};

    AsyncRef() noexcept : ptr{nullptr} {}
    AsyncRef(Async* ptr);
    AsyncRef(Async* ptr, NoInc) : ptr{ptr} {}

src/Async.h  view on Meta::CPAN


struct Async_RawThunk
{
    using Callback = std::function<AsyncRef(AsyncRef dependency)>;
    Callback    callback;
    AsyncRef    dependency;

    Async_RawThunk(Async_RawThunk&&) = default;
    ~Async_RawThunk() = default;
    auto operator=(Async_RawThunk&&) -> Async_RawThunk& = default;
};

struct Async_Thunk
{
    using Callback = std::function<AsyncRef(DestructibleTuple const& data)>;
    Callback    callback;
    AsyncRef    dependency;

    Async_Thunk(Async_Thunk&&) = default;
    ~Async_Thunk() = default;
    auto operator=(Async_Thunk&&) -> Async_Thunk& = default;
};

struct Async_Pair
{
    AsyncRef left;
    AsyncRef right;

    Async_Pair(Async_Pair&&) = default;
    ~Async_Pair() = default;
    auto operator=(Async_Pair&&) -> Async_Pair& = default;
};

struct Async_Flow
{
    AsyncRef left;
    AsyncRef right;
    Async_Type flow_type;
    enum Direction { THEN, OR } direction;

    Async_Flow(Async_Flow&&) = default;
    ~Async_Flow() = default;
    auto operator=(Async_Flow&&) -> Async_Flow& = default;
};

struct Async_Uninitialized {};

struct Async
{
    Async_Type type;
    size_t refcount;
    union {
        Async_Uninitialized as_uninitialized;
        AsyncRef            as_ptr;
        Async_Thunk         as_thunk;
        Async_Pair          as_binary;
        Async_Flow          as_flow;
        Destructible        as_error;
        DestructibleTuple   as_value;
    };
    std::vector<AsyncRef> blocked;

    Async() :
        type{Async_Type::IS_UNINITIALIZED},
        refcount{1},
        as_ptr{nullptr},
        blocked{}
    { }
    Async(Async&& other) : Async{} { set_from(std::move(other)); }
    ~Async() {
        assert(blocked.size() == 0);
        clear();
        assert(type == Async_Type::IS_UNINITIALIZED);
    }

    auto ref() noexcept -> Async& { refcount++; return *this; }
    auto unref() -> void;

    auto operator=(Async& other) -> Async&;
    auto clear() -> void;
    auto set_from(Async&& other) -> void;

    void set_to_Ptr         (AsyncRef target);
    void set_to_RawThunk    (Async_RawThunk::Callback callback, AsyncRef dep);
    void set_to_Thunk       (Async_Thunk::Callback    callback, AsyncRef dep);
    void set_to_Concat      (AsyncRef left, AsyncRef right);
    void set_to_Flow        (Async_Flow);
    void set_to_Cancel      ();
    void set_to_Error       (Destructible error);
    void set_to_Value       (DestructibleTuple values);

    auto add_blocked(AsyncRef blocked) -> void;

    auto ptr_follow() -> Async&;

    auto has_category(Async_Type type) -> bool
    { return ptr_follow().type >= type; }

    auto has_type(Async_Type type) -> bool
    { return ptr_follow().type == type; }

    static auto alloc() -> AsyncRef;
};

inline AsyncRef::AsyncRef(Async* ptr) : AsyncRef{ptr, no_inc} {
    if (ptr)
        ptr->ref();
}

inline auto AsyncRef::clear() -> void {
    if (ptr)
        ptr->unref();
    ptr = nullptr;
}

// functions used with debugging output
static inline auto Async_maybe_type_name(Async const* ptr) noexcept -> char const*
{ return ptr ? Async_Type_name(ptr->type) : "(NULL)"; }

static inline auto Async_maybe_refcount(Async const* ptr) noexcept -> size_t
{ return ptr ? ptr->refcount : 0; }

static inline auto Async_maybe_blocked_size(Async const* ptr) noexcept -> size_t
{ return ptr ? ptr->blocked.size() : 0; }


// Evaluation: Async_X_evaluate()
// Incomplete -> Complete
void
Async_eval(
        Async*  self,
        AsyncRef& next,
        AsyncRef& blocked);

inline auto AsyncRef::fold() -> AsyncRef&
{
    Async* target = &ptr->ptr_follow();
    if (target != ptr)
        *this = target;
    return *this;
}

inline static
AsyncRef&
Async_Ptr_fold(AsyncRef& ptr)
{
    return ptr.fold();
}

inline
bool
Async_has_type(
        Async* self,
        enum Async_Type type)
{ assert(self); return self->has_type(type); }

inline
bool
Async_has_category(
        Async* self,
        enum Async_Type category)
{ assert(self); return self->has_category(category); }

void
Async_run_until_completion(
        Async*  async);



( run in 0.406 second using v1.01-cache-2.11-cpan-13bb782fe5a )