231 lines
3.8 KiB
C++
Executable File
231 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 "PromiseOfFutures.h"
|
|
#include "Futures.hpp"
|
|
#include <tjp/core/ptr/Ptr.hpp>
|
|
#include <tjp/core/log/Log.h>
|
|
#include <tjp/core/log/LogOf.h>
|
|
|
|
#include <atomic>
|
|
|
|
namespace tjp {
|
|
namespace core {
|
|
|
|
// TODO: PromiseOfFutures should go away and instead just have FuturesFuture
|
|
// TODO: this class can cause a memory leak, if the underlying future is not triggered
|
|
|
|
template<typename T>
|
|
struct PromiseOfFutures
|
|
{
|
|
typedef PromiseOfFutures<T> Self;
|
|
typedef StrongPtr<Self> Instance;
|
|
WeakPtr<Self> self;
|
|
|
|
T value;
|
|
StrongPtr<Exception> exception;
|
|
Futures futures;
|
|
|
|
Promise<T> promise;
|
|
std::atomic<size_t> outstanding = 1;
|
|
|
|
void onCompletion()
|
|
{
|
|
auto outstanding_ = --outstanding;
|
|
fLogDebug(logOfThis(this) << "onCompletion " << outstanding_);
|
|
|
|
if (outstanding_ == 0)
|
|
{
|
|
if (exception)
|
|
{
|
|
xLogDebug(logOfThis(this) << "exception");
|
|
promise.set_exception(Exception(*exception));
|
|
}
|
|
else
|
|
{
|
|
xLogDebug(logOfThis(this) << "value");
|
|
promise.set_value(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FT>
|
|
auto add(FT &&f)
|
|
{
|
|
auto outstanding_ = ++outstanding;
|
|
fLogDebug(logOfThis(this) << "add " << outstanding_);
|
|
|
|
return futures.add(f.template then<>([self_=this->self, this](auto &&f_)
|
|
{
|
|
if (auto self = strong(self_))
|
|
{
|
|
try
|
|
{
|
|
f_.get();
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
exception = strong<Exception>(e);
|
|
}
|
|
|
|
onCompletion();
|
|
}
|
|
}));
|
|
}
|
|
|
|
auto get_promise ()
|
|
{
|
|
return promise;
|
|
}
|
|
|
|
auto get_future ()
|
|
{
|
|
onCompletion();
|
|
|
|
return promise.get_future()
|
|
.then([self=strong(this->self)](auto &&f) {
|
|
return f.get();
|
|
})
|
|
.then([](auto &&f) { return f.get(); });
|
|
}
|
|
|
|
template<typename F>
|
|
void consume(F &&f)
|
|
{
|
|
try
|
|
{
|
|
value = f.get();
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
exception = strong<Exception>(e);
|
|
}
|
|
}
|
|
|
|
template<typename F>
|
|
void consume_throw_exception(F &&f)
|
|
{
|
|
value = f.get();
|
|
}
|
|
|
|
void set(const T &t)
|
|
{
|
|
value = t;
|
|
}
|
|
|
|
static StrongPtr<PromiseOfFutures> generate()
|
|
{
|
|
auto v = strong<PromiseOfFutures>();
|
|
v->self = weak(v);
|
|
|
|
return v;
|
|
}
|
|
|
|
public:
|
|
PromiseOfFutures() {}
|
|
} ;
|
|
|
|
template<>
|
|
struct PromiseOfFutures<void>
|
|
{
|
|
typedef PromiseOfFutures<void> Self;
|
|
typedef StrongPtr<Self> Instance;
|
|
WeakPtr<Self> self;
|
|
|
|
StrongPtr<Exception> exception;
|
|
Futures futures;
|
|
|
|
Promise<void> promise;
|
|
size_t outstanding = 1;
|
|
|
|
void onCompletion()
|
|
{
|
|
auto outstanding_ = --outstanding;
|
|
fLogDebug(logOfThis(this) << "onCompletion " << outstanding_);
|
|
|
|
if (outstanding_ == 0)
|
|
{
|
|
if (exception)
|
|
{
|
|
xLogDebug(logOfThis(this) << "exception");
|
|
promise.set_exception(Exception(*exception));
|
|
}
|
|
else
|
|
{
|
|
xLogDebug(logOfThis(this) << "value");
|
|
promise.set_value();
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename FT>
|
|
auto add(FT &&f)
|
|
{
|
|
auto outstanding_ = ++outstanding;
|
|
(void)outstanding_;
|
|
fLogDebug(logOfThis(this) << "add " << outstanding_);
|
|
|
|
return futures.add(f.template then<>([self_=this->self, this](auto &&f_)
|
|
{
|
|
if (auto self = strong(self_))
|
|
{
|
|
try
|
|
{
|
|
f_.get();
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
exception = strong<Exception>(e);
|
|
}
|
|
|
|
onCompletion();
|
|
}
|
|
}));
|
|
}
|
|
|
|
auto get_future ()
|
|
{
|
|
onCompletion();
|
|
return promise.get_future().then([self=strong(this->self)](auto &&f) {
|
|
return f.get();
|
|
});
|
|
}
|
|
|
|
template<typename F>
|
|
void consume(F &&f)
|
|
{
|
|
try
|
|
{
|
|
f.get();
|
|
}
|
|
catch (Exception &e)
|
|
{
|
|
exception = strong<Exception>(e);
|
|
}
|
|
}
|
|
|
|
template<typename F>
|
|
void consume_throw_exception(F &&f)
|
|
{
|
|
f.get();
|
|
}
|
|
|
|
static StrongPtr<PromiseOfFutures> generate()
|
|
{
|
|
auto v = strong<PromiseOfFutures>();
|
|
v->self = weak(v);
|
|
|
|
return v;
|
|
}
|
|
|
|
public:
|
|
PromiseOfFutures() {}
|
|
|
|
} ;
|
|
|
|
} // namespace
|
|
} // namespace
|