180 lines
3.8 KiB
C++
Executable File
180 lines
3.8 KiB
C++
Executable File
// License: Modified MIT (NON-AI)
|
|
// See the LICENSE file in the root directory for license information.
|
|
// Copyright 2026 Timothy Prepscius
|
|
|
|
#pragma once
|
|
|
|
#include "FutureChain.h"
|
|
#include "Futures.hpp"
|
|
#include <tjp/core/ptr/Ptr.hpp>
|
|
#include <type_traits>
|
|
#include <tjp/core/algorithm/copy_of.hpp>
|
|
#include <tjp/core/threads/Lock.hpp>
|
|
#include <tjp/core/debug/Debug.h>
|
|
|
|
namespace tjp {
|
|
namespace core {
|
|
namespace future_chain_detail {
|
|
|
|
struct FutureParent
|
|
{
|
|
virtual ~FutureParent() {}
|
|
} ;
|
|
|
|
template<typename FutureGeneratorParameter>
|
|
struct FutureExecutor : FutureParent
|
|
{
|
|
virtual void execute(const FutureGeneratorParameter ¶meter) = 0;
|
|
} ;
|
|
|
|
template<typename FutureGeneratorParameter, typename FutureGenerator>
|
|
struct FutureNode : FutureExecutor<FutureGeneratorParameter>
|
|
{
|
|
FutureGenerator futureGenerator;
|
|
|
|
typedef decltype(futureGenerator(FutureGeneratorParameter())) FutureType;
|
|
typedef Promise<typename FutureType::value_type> PromiseType;
|
|
|
|
typedef FutureExecutor<FutureType> Child;
|
|
|
|
WeakPtr<FutureNode> self;
|
|
StrongPtr<FutureParent> parent;
|
|
Future<void> next;
|
|
|
|
PromiseType promise;
|
|
FutureType future;
|
|
|
|
WeakPtr<Child> link;
|
|
|
|
FutureNode(FutureGenerator &&futureGenerator_, const StrongPtr<FutureParent> &parent_) :
|
|
futureGenerator(std::move(futureGenerator_)),
|
|
parent(parent_)
|
|
{
|
|
future = promise.get_future();
|
|
}
|
|
|
|
~FutureNode()
|
|
{
|
|
xDebugLine();
|
|
}
|
|
|
|
static auto generate(FutureGenerator &&futureGenerator_, const StrongPtr<FutureParent> &parent_)
|
|
{
|
|
auto v = strong<FutureNode<FutureGeneratorParameter, FutureGenerator>>(std::move(futureGenerator_), parent_);
|
|
v->self = weak(v);
|
|
return v;
|
|
}
|
|
|
|
template<typename F,
|
|
typename std::enable_if<std::is_invocable<F, FutureType>::value, F>::type* = nullptr
|
|
>
|
|
auto add(F &&nextFutureGenerator)
|
|
{
|
|
auto child = FutureNode<FutureType, F>::generate(std::move(nextFutureGenerator), strong(self));
|
|
|
|
if (future.is_set())
|
|
{
|
|
child->execute(future);
|
|
return child;
|
|
}
|
|
|
|
link = weak(child);
|
|
return child;
|
|
}
|
|
|
|
template<typename F,
|
|
typename std::enable_if<std::is_invocable<F>::value, F>::type* = nullptr
|
|
>
|
|
auto add(F &&nextFutureGenerator)
|
|
{
|
|
return add(
|
|
[nextFutureGenerator=std::move(nextFutureGenerator)](auto &&f) {
|
|
f.get();
|
|
return nextFutureGenerator();
|
|
}
|
|
);
|
|
}
|
|
|
|
void execute(const FutureGeneratorParameter ¶meter) override
|
|
{
|
|
parent = nullptr;
|
|
|
|
try
|
|
{
|
|
next = futureGenerator(copy_of(parameter)).then(
|
|
[self_=this->self, this](auto &&f) {
|
|
if (auto self = strong(self_))
|
|
{
|
|
promise.consume([](auto &&f){ return f.get(); }, std::move(f));
|
|
executeChildren(future);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
promise.set_exception(copy_of(e));
|
|
executeChildren(future);
|
|
}
|
|
}
|
|
|
|
void executeChildren(const FutureType &f)
|
|
{
|
|
if (auto child = strong(this->link))
|
|
{
|
|
executeChild(child, f);
|
|
}
|
|
}
|
|
|
|
void executeChild(const StrongPtr<Child> &child, const FutureType &f)
|
|
{
|
|
child->execute(f);
|
|
}
|
|
|
|
FutureType get_future()
|
|
{
|
|
return future.then([self = strong(this->self)](auto &&f) {
|
|
return f.get();
|
|
});
|
|
}
|
|
};
|
|
|
|
inline
|
|
auto FutureChain()
|
|
{
|
|
auto empty = [](Future<void> &&) {
|
|
return future_of_value();
|
|
};
|
|
auto chain =
|
|
FutureNode<Future<void>, decltype(empty)>::generate(
|
|
std::move(empty),
|
|
nullptr
|
|
);
|
|
chain->execute(Future<void>());
|
|
|
|
return chain;
|
|
}
|
|
|
|
} // namespace future_chain_detail
|
|
|
|
template<typename A, typename B>
|
|
auto future_chain_(A &&a, B &&b)
|
|
{
|
|
return a->add(std::forward<B>(b));
|
|
} ;
|
|
|
|
template<typename A, typename B, typename ...T>
|
|
auto future_chain_(A &&a, B &&b, T &&...t)
|
|
{
|
|
return future_chain_(a->add(std::forward<B>(b)), std::forward<T>(t)...);
|
|
} ;
|
|
|
|
template<typename ...T>
|
|
auto future_chain(T &&...t)
|
|
{
|
|
return future_chain_(future_chain_detail::FutureChain(), std::forward<T>(t)...)->get_future();
|
|
} ;
|
|
|
|
} // namespace
|
|
} // namespace
|