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

171 lines
3.0 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 "PromiseLocked.h"
#include "Future.hpp"
#include <tjp/core/type_traits/is_callable.hpp>
namespace tjp {
namespace core {
template<typename T>
struct PromiseLocked
{
Mutex m;
bool owned = false;
Promise<T> promise;
std::tuple<bool, Future<T>> own_future()
{
auto l = lock_of(m);
if (promise.is_set() || owned)
return { false, promise.get_future() };
owned = true;
return { true, promise.get_future() };
}
template <typename U=T,
typename std::enable_if<!std::is_void<U>::value, U>::type* = nullptr
>
void set_value (U &&t)
{
auto l = lock_of(m);
debug_assert(owned);
promise.set_value(t);
owned = false;
}
template <typename U=T,
typename std::enable_if<!std::is_void<U>::value, U>::type* = nullptr
>
void set_value (const U &t)
{
auto l = lock_of(m);
debug_assert(owned);
promise.set_value(t);
owned = false;
}
template <typename U=void,
typename std::enable_if<std::is_void<U>::value, U>::type* = nullptr
>
void set_value ()
{
auto l = lock_of(m);
debug_assert(owned);
promise.set_value();
owned = false;
}
void set_exception (Exception &&e)
{
auto l = lock_of(m);
debug_assert(owned);
promise.set_exception(std::move(e));
owned = false;
}
template<typename F,
typename std::enable_if<std::is_invocable<F>::value>::type* = nullptr
>
void consume (F &&f)
{
auto l = lock_of(m);
debug_assert(owned);
promise.consume(std::forward<F>(f));
owned = false;
}
template<typename F,
typename std::enable_if<std::is_invocable<F>::value>::type* = nullptr
>
void reset_consume (F &&f)
{
debug_assert(owned);
Promise<T> o = reset();
o.consume(std::forward<F>(f));
}
template<typename F,
typename std::enable_if<!std::is_invocable<F>::value>::type* = nullptr
>
void consume (F &&f)
{
consume([&f]() { return f.get(); });
}
template<typename F,
typename std::enable_if<!std::is_invocable<F>::value>::type* = nullptr
>
void reset_consume (F &&f)
{
reset_consume([&f]() { return f.get(); });
}
template<typename V>
void consume_value (const V &v)
{
auto l = lock_of(m);
debug_assert(owned);
set_value(v);
owned = false;
}
template<typename V>
void reset_consume_value (const V &v)
{
debug_assert(owned);
Promise<T> o = reset();
o.set_value(v);
}
void release ()
{
auto l = lock_of(m);
debug_assert(owned);
owned = false;
}
Promise<T> reset ()
{
auto l = lock_of(m);
owned = false;
auto r = std::move(promise);
promise = {};
return r;
}
} ;
template<typename R, typename F>
PromiseLocked<R> &promise_of_and_reset(PromiseLocked<R> &p, F &&f)
{
p.reset_consume(std::forward<F>(f));
return p;
}
template<typename R, typename V>
PromiseLocked<R> &promise_of_and_reset_value(PromiseLocked<R> &p, const V &v)
{
p.reset_consume_value(v);
return p;
}
} // namespace
} // namespace