Files
core_future/tjp/core/future/FutureChain.hpp
2026-03-06 09:28:09 -05:00

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 &parameter) = 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 &parameter) 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