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

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