feat update
All checks were successful
linux-aarch64-cpu-gcc / linux-gcc-aarch64 (push) Successful in 1m52s
linux-arm-gcc / linux-gcc-armhf (push) Successful in 2m6s
linux-x64-gcc / linux-gcc (Release) (push) Successful in 1m59s
linux-mips64-gcc / linux-gcc-mips64el (Debug) (push) Successful in 2m46s
linux-x64-gcc / linux-gcc (Debug) (push) Successful in 2m48s
linux-mips64-gcc / linux-gcc-mips64el (Release) (push) Successful in 2m51s

This commit is contained in:
tqcq 2024-04-16 20:02:53 +08:00
parent 569d08139d
commit 440536676d
3 changed files with 161 additions and 23 deletions

View File

@ -10,8 +10,9 @@
#include "sled/synchronization/event.h" #include "sled/synchronization/event.h"
#include "sled/synchronization/mutex.h" #include "sled/synchronization/mutex.h"
#include "sled/task_queue/task_queue_base.h" #include "sled/task_queue/task_queue_base.h"
#include "sled/variant.h" #include "sled/utility/forward_on_copy.h"
#include <atomic> #include <atomic>
#include <future>
#include <list> #include <list>
namespace sled { namespace sled {
@ -48,7 +49,8 @@ struct FutureData {
~FutureData() { DecrementFuturesUsage(); } ~FutureData() { DecrementFuturesUsage(); }
std::atomic_int state{kNotCompletedFuture}; std::atomic_int state{kNotCompletedFuture};
sled::variant<sled::monostate, T, FailureT> value; // sled::variant<sled::monostate, T, FailureT> value;
sled::any value;
std::list<std::function<void(const T &)>> success_callbacks; std::list<std::function<void(const T &)>> success_callbacks;
std::list<std::function<void(const FailureT &)>> failure_callbacks; std::list<std::function<void(const FailureT &)>> failure_callbacks;
sled::Mutex mutex_; sled::Mutex mutex_;
@ -130,7 +132,8 @@ public:
if (!IsCompleted()) Wait(); if (!IsCompleted()) Wait();
if (IsSucceeded()) { if (IsSucceeded()) {
try { try {
return sled::get<T>(data_->value); // return sled::get<T>(data_->value);
return sled::any_cast<T>(data_->value);
} catch (...) {} } catch (...) {}
} }
return T(); return T();
@ -140,7 +143,8 @@ public:
{ {
SLED_ASSERT(data_ != nullptr, "Future is not valid"); SLED_ASSERT(data_ != nullptr, "Future is not valid");
if (!IsCompleted()) { Wait(); } if (!IsCompleted()) { Wait(); }
return sled::get<T>(data_->value); // return sled::get<T>(data_->value);
return sled::any_cast<T>(data_->value);
} }
FailureT FailureReason() const FailureT FailureReason() const
@ -149,7 +153,8 @@ public:
if (!IsCompleted()) { Wait(); } if (!IsCompleted()) { Wait(); }
if (IsFailed()) { if (IsFailed()) {
try { try {
return sled::get<FailureT>(data_->value); // return sled::get<FailureT>(data_->value);
return sled::any_cast<FailureT>(data_->value);
} catch (...) {} } catch (...) {}
} }
return FailureT(); return FailureT();
@ -176,7 +181,8 @@ public:
} }
if (call_it) { if (call_it) {
try { try {
f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value));
f(sled::any_cast<T>(data_->value));
} catch (...) {} } catch (...) {}
} }
return Future<T, FailureT>(data_); return Future<T, FailureT>(data_);
@ -203,7 +209,8 @@ public:
} }
if (call_it) { if (call_it) {
try { try {
f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value));
f(sled::any_cast<FailureT>(data_->value));
} catch (...) {} } catch (...) {}
} }
return Future<T, FailureT>(data_); return Future<T, FailureT>(data_);
@ -294,6 +301,20 @@ public:
return result; return result;
} }
template<typename Func, typename U = decltype(std::declval<eggs::invoke_result_t<Func, T>().Result()>)>
Future<U, FailureT> AndThen(Func &&f) const noexcept
{
return FlatMap([f](const T &) { return f(); });
}
template<typename T2, typename U = typename std::decay<T2>::type>
Future<U, FailureT> AndThenValue(T2 &&value) const noexcept
{
Future<U, FailureT> result = Future<U, FailureT>::Create();
auto forward_on_copy = sled::MakeForwardOnCopy(std::forward<T2>(value));
return Map([forward_on_copy](const T &) noexcept { return forward_on_copy.value(); });
}
Future<T, FailureT> Via(TaskQueueBase *task_queue) const noexcept Future<T, FailureT> Via(TaskQueueBase *task_queue) const noexcept
{ {
SLED_ASSERT(task_queue != nullptr, "TaskQueue is not valid"); SLED_ASSERT(task_queue != nullptr, "TaskQueue is not valid");
@ -365,6 +386,7 @@ private:
if (IsCompleted()) { return; } if (IsCompleted()) { return; }
try { try {
// data_->value.template emplace<T>(std::move(value));
// 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 (...) {}
@ -376,7 +398,8 @@ private:
for (const auto &f : callbacks) { for (const auto &f : callbacks) {
try { try {
f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value));
f(sled::any_cast<T>(data_->value));
} catch (...) {} } catch (...) {}
} }
} }
@ -396,6 +419,7 @@ private:
if (IsCompleted()) { return; } if (IsCompleted()) { return; }
try { try {
// data_->value.template emplace<FailureT>(std::move(reason)); // data_->value.template emplace<FailureT>(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(detail::kFailedFuture, std::memory_order_release);
@ -406,7 +430,8 @@ private:
for (const auto &f : callbacks) { for (const auto &f : callbacks) {
try { try {
f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value));
f(sled::any_cast<FailureT>(data_->value));
} catch (...) {} } catch (...) {}
} }
} }

View File

@ -1,9 +1,11 @@
#include <sled/futures/future.h> #include <sled/futures/future.h>
#include <sled/system/thread.h> #include <sled/system/thread.h>
#include <type_traits>
TEST_SUITE("future") TEST_SUITE("future")
{ {
TEST_CASE("base success") TEST_CASE("base success")
{ {
sled::Promise<int, std::string> p; sled::Promise<int, std::string> p;
auto f = p.GetFuture(); auto f = p.GetFuture();
@ -12,6 +14,7 @@ TEST_SUITE("future")
CHECK(f.IsValid()); CHECK(f.IsValid());
CHECK_EQ(f.Result(), 42); CHECK_EQ(f.Result(), 42);
} }
TEST_CASE("base failed") TEST_CASE("base failed")
{ {
sled::Promise<int, std::string> p; sled::Promise<int, std::string> p;
@ -23,31 +26,65 @@ TEST_SUITE("future")
CHECK(f.IsValid()); CHECK(f.IsValid());
CHECK_EQ(f.FailureReason(), "error"); CHECK_EQ(f.FailureReason(), "error");
} }
TEST_CASE("throw")
{
sled::Promise<int, std::string> p;
auto f = p.GetFuture().Map([](int x) {
throw std::runtime_error("test");
return x;
});
p.Success(42);
REQUIRE(f.IsCompleted());
REQUIRE(f.IsFailed());
CHECK_EQ(f.FailureReason(), "test");
}
TEST_CASE("base failed")
{
sled::Promise<int, std::string> p;
auto f = p.GetFuture();
p.Failure("error");
REQUIRE(p.IsFilled());
REQUIRE(f.IsCompleted());
CHECK(f.Wait(-1));
CHECK(f.IsValid());
CHECK_EQ(f.FailureReason(), "error");
}
TEST_CASE("thread success") {} TEST_CASE("thread success") {}
TEST_CASE("map") TEST_CASE("Map")
{ {
sled::Promise<int, std::string> p; sled::Promise<int, std::string> p;
auto f = p.GetFuture(); auto f = p.GetFuture();
auto f2 = f.Map([](int i) { return i + 1; }); auto f2 = f.Map([](int i) { return i + 1; })
.Map([](int i) { return std::to_string(i) + "00"; })
.Map([](const std::string &str) {
std::stringstream ss(str);
int x;
ss >> x;
return x;
});
p.Success(42); p.Success(42);
CHECK(f2.Wait(-1)); CHECK(f2.Wait(-1));
CHECK_EQ(f2.Result(), 43); CHECK_EQ(f2.Result(), 4300);
} }
TEST_CASE("FlatMap") TEST_CASE("FlatMap")
{ {
// sled::Promise<int, std::string> p; sled::Promise<int, std::string> p;
// auto f = p.GetFuture().FlatMap([](int i) { auto f = p.GetFuture().FlatMap([](int i) {
// auto str = std::to_string(i); auto str = std::to_string(i);
// sled::Promise<std::string, std::string> p; sled::Promise<std::string, std::string> p;
// p.Success(str); p.Success(str);
//
// return p.GetFuture(); return p.GetFuture();
// }); });
// p.Success(42); p.Success(42);
// CHECK(f.Wait(-1)); CHECK(f.IsCompleted());
// CHECK_EQ(f.Result(), "42"); CHECK_EQ(f.Result(), "42");
} }
TEST_CASE("Via") TEST_CASE("Via")

View File

@ -0,0 +1,76 @@
#ifndef SLED_UTILITY_FORWARD_ON_COPY_H
#define SLED_UTILITY_FORWARD_ON_COPY_H
#pragma once
#include "sled/any.h"
namespace sled {
namespace detail {
struct ForwardOnCopyTag {};
};// namespace detail
template<typename T>
struct ForwardOnCopy {
ForwardOnCopy(ForwardOnCopy &other)
: is_moved_(other.is_moved_),
value_(is_moved_ ? other.value_ : std::move(other.value_))
{}
// ForwardOnCopy(ForwardOnCopy &&other) noexcept;
ForwardOnCopy &operator=(ForwardOnCopy &other)
{
is_moved_ = other.is_moved_;
value_ = is_moved_ ? other.value_ : std::move(other.value_);
return *this;
}
// ForwardOnCopy &operator=(ForwardOnCopy &&other) noexcept;
T value() const
{
if (is_moved_) {
return std::move(sled::any_cast<T>(value_));
} else {
return sled::any_cast<T>(value_);
}
}
private:
bool is_moved_;
sled::any value_;
};
template<typename T>
ForwardOnCopy<T>
MakeForwardOnCopy(T value)
{
ForwardOnCopy<T> result;
result.is_moved_ = false;
result.value_ = value;
return result;
}
template<typename T>
ForwardOnCopy<T>
MakeForwardOnCopy(T &value)
{
ForwardOnCopy<T> result;
result.is_moved_ = false;
result.value_ = value;
return result;
}
template<typename T>
ForwardOnCopy<T>
MakeForwardOnCopy(T &&value)
{
ForwardOnCopy<T> result;
result.is_moved_ = true;
result.value_ = std::move(value);
return result;
}
}// namespace sled
#endif// SLED_UTILITY_FORWARD_ON_COPY_H