feat add future
This commit is contained in:
parent
440536676d
commit
5d07e41460
@ -2,7 +2,7 @@
|
|||||||
#include "sled/futures/future.h"
|
#include "sled/futures/future.h"
|
||||||
|
|
||||||
namespace sled {
|
namespace sled {
|
||||||
namespace detail {
|
namespace future_detail {
|
||||||
void
|
void
|
||||||
IncrementFuturesUsage()
|
IncrementFuturesUsage()
|
||||||
{}
|
{}
|
||||||
@ -11,5 +11,5 @@ void
|
|||||||
DecrementFuturesUsage()
|
DecrementFuturesUsage()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
}// namespace detail
|
}// namespace future_detail
|
||||||
}// namespace sled
|
}// namespace sled
|
||||||
|
@ -12,11 +12,10 @@
|
|||||||
#include "sled/task_queue/task_queue_base.h"
|
#include "sled/task_queue/task_queue_base.h"
|
||||||
#include "sled/utility/forward_on_copy.h"
|
#include "sled/utility/forward_on_copy.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <future>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
namespace sled {
|
namespace sled {
|
||||||
namespace detail {
|
namespace future_detail {
|
||||||
template<typename F, typename... Args>
|
template<typename F, typename... Args>
|
||||||
struct is_invocable : std::is_constructible<std::function<void(Args...)>,
|
struct is_invocable : std::is_constructible<std::function<void(Args...)>,
|
||||||
std::reference_wrapper<typename std::remove_reference<F>::type>> {};
|
std::reference_wrapper<typename std::remove_reference<F>::type>> {};
|
||||||
@ -55,7 +54,7 @@ struct FutureData {
|
|||||||
std::list<std::function<void(const FailureT &)>> failure_callbacks;
|
std::list<std::function<void(const FailureT &)>> failure_callbacks;
|
||||||
sled::Mutex mutex_;
|
sled::Mutex mutex_;
|
||||||
};
|
};
|
||||||
}// namespace detail
|
}// namespace future_detail
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -66,7 +65,7 @@ class Future {
|
|||||||
template<typename T2, typename FailureT2>
|
template<typename T2, typename FailureT2>
|
||||||
friend class Future;
|
friend class Future;
|
||||||
friend class Promise<T, FailureT>;
|
friend class Promise<T, FailureT>;
|
||||||
friend struct detail::FutureData<T, FailureT>;
|
friend struct future_detail::FutureData<T, FailureT>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Value = T;
|
using Value = T;
|
||||||
@ -90,19 +89,19 @@ public:
|
|||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
int value = data_->state.load(std::memory_order_acquire);
|
int value = data_->state.load(std::memory_order_acquire);
|
||||||
return value == detail::kSuccessFuture || value == detail::kFailedFuture;
|
return value == future_detail::kSuccessFuture || value == future_detail::kFailedFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFailed() const noexcept
|
bool IsFailed() const noexcept
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
return data_->state.load(std::memory_order_acquire) == detail::kFailedFuture;
|
return data_->state.load(std::memory_order_acquire) == future_detail::kFailedFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSucceeded() const noexcept
|
bool IsSucceeded() const noexcept
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
return data_->state.load(std::memory_order_acquire) == detail::kSuccessFuture;
|
return data_->state.load(std::memory_order_acquire) == future_detail::kSuccessFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValid() const noexcept { return static_cast<bool>(data_); }
|
bool IsValid() const noexcept { return static_cast<bool>(data_); }
|
||||||
@ -160,7 +159,7 @@ public:
|
|||||||
return FailureT();
|
return FailureT();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func, typename = typename std::enable_if<detail::is_invocable<Func, T>::value>::type>
|
template<typename Func, typename = typename std::enable_if<future_detail::is_invocable<Func, T>::value>::type>
|
||||||
Future<T, FailureT> OnSuccess(Func &&f) const noexcept
|
Future<T, FailureT> OnSuccess(Func &&f) const noexcept
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
@ -173,9 +172,9 @@ public:
|
|||||||
try {
|
try {
|
||||||
data_->success_callbacks.emplace_back(std::forward<Func>(f));
|
data_->success_callbacks.emplace_back(std::forward<Func>(f));
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
return Future<T, FailureT>::Failed(detail::ExceptionFailure<FailureT>(e));
|
return Future<T, FailureT>::Failed(future_detail::ExceptionFailure<FailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return Future<T, FailureT>::Failed(detail::ExceptionFailure<FailureT>());
|
return Future<T, FailureT>::Failed(future_detail::ExceptionFailure<FailureT>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +187,7 @@ public:
|
|||||||
return Future<T, FailureT>(data_);
|
return Future<T, FailureT>(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func, typename = detail::enable_if_t<detail::is_invocable<Func, FailureT>::value>>
|
template<typename Func, typename = future_detail::enable_if_t<future_detail::is_invocable<Func, FailureT>::value>>
|
||||||
Future<T, FailureT> OnFailure(Func &&f) const noexcept
|
Future<T, FailureT> OnFailure(Func &&f) const noexcept
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
@ -201,9 +200,9 @@ public:
|
|||||||
try {
|
try {
|
||||||
data_->failure_callbacks.emplace_back(std::forward<Func>(f));
|
data_->failure_callbacks.emplace_back(std::forward<Func>(f));
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
return Future<T, FailureT>::Failed(detail::ExceptionFailure<FailureT>(e));
|
return Future<T, FailureT>::Failed(future_detail::ExceptionFailure<FailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return Future<T, FailureT>::Failed(detail::ExceptionFailure<FailureT>());
|
return Future<T, FailureT>::Failed(future_detail::ExceptionFailure<FailureT>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +215,7 @@ public:
|
|||||||
return Future<T, FailureT>(data_);
|
return Future<T, FailureT>(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func, typename = detail::enable_if_t<detail::is_invocable<Func>::value>>
|
template<typename Func, typename = future_detail::enable_if_t<future_detail::is_invocable<Func>::value>>
|
||||||
Future<T, FailureT> OnComplete(Func &&f) const noexcept
|
Future<T, FailureT> OnComplete(Func &&f) const noexcept
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
@ -225,7 +224,7 @@ public:
|
|||||||
return Future<T, FailureT>(data_);
|
return Future<T, FailureT>(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func, typename = detail::enable_if_t<detail::is_invocable_r<bool, Func, T>::value>>
|
template<typename Func, typename = future_detail::enable_if_t<future_detail::is_invocable_r<bool, Func, T>::value>>
|
||||||
Future<T, FailureT>
|
Future<T, FailureT>
|
||||||
Filter(Func &&f,
|
Filter(Func &&f,
|
||||||
const FailureT &rejected = failure::FailureFromString<FailureT>("Result wasn't good enough")) const noexcept
|
const FailureT &rejected = failure::FailureFromString<FailureT>("Result wasn't good enough")) const noexcept
|
||||||
@ -239,9 +238,9 @@ public:
|
|||||||
result.FillFailure(rejected);
|
result.FillFailure(rejected);
|
||||||
}
|
}
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>(e));
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>());
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
OnFailure([result](const FailureT &failure) noexcept { result.FillFailure(failure); });
|
OnFailure([result](const FailureT &failure) noexcept { result.FillFailure(failure); });
|
||||||
@ -256,9 +255,9 @@ public:
|
|||||||
try {
|
try {
|
||||||
result.FillSuccess(f(v));
|
result.FillSuccess(f(v));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>(e));
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>());
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
||||||
@ -274,9 +273,9 @@ public:
|
|||||||
try {
|
try {
|
||||||
result.FillFailure(f(failure));
|
result.FillFailure(f(failure));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
result.FillFailure(detail::ExceptionFailure<OtherFailureT>(e));
|
result.FillFailure(future_detail::ExceptionFailure<OtherFailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
result.FillFailure(detail::ExceptionFailure<OtherFailureT>());
|
result.FillFailure(future_detail::ExceptionFailure<OtherFailureT>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
@ -292,9 +291,9 @@ public:
|
|||||||
f(v).OnSuccess([result](const U &v) mutable noexcept { result.FillSuccess(v); })
|
f(v).OnSuccess([result](const U &v) mutable noexcept { result.FillSuccess(v); })
|
||||||
.OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
.OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>(e));
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>(e));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
result.FillFailure(detail::ExceptionFailure<FailureT>());
|
result.FillFailure(future_detail::ExceptionFailure<FailureT>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
OnFailure([result](const FailureT &failure) mutable noexcept { result.FillFailure(failure); });
|
||||||
@ -355,12 +354,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Future(std::shared_ptr<detail::FutureData<T, FailureT>> other_data) { data_ = other_data; }
|
explicit Future(std::shared_ptr<future_detail::FutureData<T, FailureT>> other_data) { data_ = other_data; }
|
||||||
|
|
||||||
inline static Future<T, FailureT> Create()
|
inline static Future<T, FailureT> Create()
|
||||||
{
|
{
|
||||||
Future<T, FailureT> result;
|
Future<T, FailureT> result;
|
||||||
result.data_ = std::make_shared<detail::FutureData<T, FailureT>>();
|
result.data_ = std::make_shared<future_detail::FutureData<T, FailureT>>();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,9 +372,9 @@ private:
|
|||||||
void FillSuccess(T &&value)
|
void FillSuccess(T &&value)
|
||||||
{
|
{
|
||||||
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
SLED_ASSERT(data_ != nullptr, "Future is not valid");
|
||||||
if (detail::HasLastFailure()) {
|
if (future_detail::HasLastFailure()) {
|
||||||
FailureT failure = detail::LastFailure<FailureT>();
|
FailureT failure = future_detail::LastFailure<FailureT>();
|
||||||
detail::InvalidateLastFailure();
|
future_detail::InvalidateLastFailure();
|
||||||
FillFailure(std::move(failure));
|
FillFailure(std::move(failure));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -390,7 +389,7 @@ private:
|
|||||||
// data_->value.template emplace<T>(std::move(value));
|
// data_->value.template emplace<T>(std::move(value));
|
||||||
data_->value = std::move(value);
|
data_->value = std::move(value);
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
data_->state.store(detail::kSuccessFuture, std::memory_order_release);
|
data_->state.store(future_detail::kSuccessFuture, std::memory_order_release);
|
||||||
callbacks = std::move(data_->success_callbacks);
|
callbacks = std::move(data_->success_callbacks);
|
||||||
data_->success_callbacks = std::list<std::function<void(const T &)>>();
|
data_->success_callbacks = std::list<std::function<void(const T &)>>();
|
||||||
data_->failure_callbacks.clear();
|
data_->failure_callbacks.clear();
|
||||||
@ -422,7 +421,7 @@ private:
|
|||||||
// data_->value = std::move(reason);
|
// data_->value = std::move(reason);
|
||||||
data_->value = std::move(reason);
|
data_->value = std::move(reason);
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
data_->state.store(detail::kFailedFuture, std::memory_order_release);
|
data_->state.store(future_detail::kFailedFuture, std::memory_order_release);
|
||||||
callbacks = std::move(data_->failure_callbacks);
|
callbacks = std::move(data_->failure_callbacks);
|
||||||
data_->failure_callbacks = std::list<std::function<void(const FailureT &)>>();
|
data_->failure_callbacks = std::list<std::function<void(const FailureT &)>>();
|
||||||
data_->success_callbacks.clear();
|
data_->success_callbacks.clear();
|
||||||
@ -436,7 +435,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<detail::FutureData<T, FailureT>> data_;
|
std::shared_ptr<future_detail::FutureData<T, FailureT>> data_;
|
||||||
};
|
};
|
||||||
}// namespace sled
|
}// namespace sled
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "sled/futures/internal/failure_handling.h"
|
#include "sled/futures/internal/failure_handling.h"
|
||||||
|
|
||||||
namespace sled {
|
namespace sled {
|
||||||
namespace detail {
|
namespace future_detail {
|
||||||
static thread_local sled::any last_failure;
|
static thread_local sled::any last_failure;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -28,5 +28,5 @@ SetLastFailure(const sled::any &failure) noexcept
|
|||||||
last_failure = failure;
|
last_failure = failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
}// namespace detail
|
}// namespace future_detail
|
||||||
}// namespace sled
|
}// namespace sled
|
||||||
|
@ -31,7 +31,7 @@ FailureFromString<std::string>(std::string &&str)
|
|||||||
|
|
||||||
}// namespace failure
|
}// namespace failure
|
||||||
|
|
||||||
namespace detail {
|
namespace future_detail {
|
||||||
bool HasLastFailure() noexcept;
|
bool HasLastFailure() noexcept;
|
||||||
void InvalidateLastFailure() noexcept;
|
void InvalidateLastFailure() noexcept;
|
||||||
const sled::any &LastFailureAny() noexcept;
|
const sled::any &LastFailureAny() noexcept;
|
||||||
@ -69,7 +69,7 @@ ExceptionFailure()
|
|||||||
{
|
{
|
||||||
return failure::FailureFromString<FailureT>("Exception");
|
return failure::FailureFromString<FailureT>("Exception");
|
||||||
}
|
}
|
||||||
}// namespace detail
|
}// namespace future_detail
|
||||||
|
|
||||||
template<typename T, typename FailureT>
|
template<typename T, typename FailureT>
|
||||||
class Future;
|
class Future;
|
||||||
@ -87,7 +87,7 @@ struct WithFuture {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
operator T() const noexcept
|
operator T() const noexcept
|
||||||
{
|
{
|
||||||
detail::SetLastFailure(std::move(failure_));
|
future_detail::SetLastFailure(std::move(failure_));
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "sled/filesystem/temporary_file.h"
|
#include "sled/filesystem/temporary_file.h"
|
||||||
|
|
||||||
// futures
|
// futures
|
||||||
// #include "sled/futures/promise.h"
|
#include "sled/futures/future.h"
|
||||||
#include "sled/ioc/ioc.h"
|
#include "sled/ioc/ioc.h"
|
||||||
|
|
||||||
// lang
|
// lang
|
||||||
|
Loading…
Reference in New Issue
Block a user