Loading src/sled/futures/future.h +34 −9 Original line number Diff line number Diff line Loading @@ -10,8 +10,9 @@ #include "sled/synchronization/event.h" #include "sled/synchronization/mutex.h" #include "sled/task_queue/task_queue_base.h" #include "sled/variant.h" #include "sled/utility/forward_on_copy.h" #include <atomic> #include <future> #include <list> namespace sled { Loading Loading @@ -48,7 +49,8 @@ struct FutureData { ~FutureData() { DecrementFuturesUsage(); } 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 FailureT &)>> failure_callbacks; sled::Mutex mutex_; Loading Loading @@ -130,7 +132,8 @@ public: if (!IsCompleted()) Wait(); if (IsSucceeded()) { try { return sled::get<T>(data_->value); // return sled::get<T>(data_->value); return sled::any_cast<T>(data_->value); } catch (...) {} } return T(); Loading @@ -140,7 +143,8 @@ public: { SLED_ASSERT(data_ != nullptr, "Future is not valid"); 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 Loading @@ -149,7 +153,8 @@ public: if (!IsCompleted()) { Wait(); } if (IsFailed()) { try { return sled::get<FailureT>(data_->value); // return sled::get<FailureT>(data_->value); return sled::any_cast<FailureT>(data_->value); } catch (...) {} } return FailureT(); Loading @@ -176,7 +181,8 @@ public: } if (call_it) { try { f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value)); f(sled::any_cast<T>(data_->value)); } catch (...) {} } return Future<T, FailureT>(data_); Loading @@ -203,7 +209,8 @@ public: } if (call_it) { try { f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value)); f(sled::any_cast<FailureT>(data_->value)); } catch (...) {} } return Future<T, FailureT>(data_); Loading Loading @@ -294,6 +301,20 @@ public: 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 { SLED_ASSERT(task_queue != nullptr, "TaskQueue is not valid"); Loading Loading @@ -365,6 +386,7 @@ private: if (IsCompleted()) { return; } try { // data_->value.template emplace<T>(std::move(value)); // data_->value.template emplace<T>(std::move(value)); data_->value = std::move(value); } catch (...) {} Loading @@ -376,7 +398,8 @@ private: for (const auto &f : callbacks) { try { f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value)); f(sled::any_cast<T>(data_->value)); } catch (...) {} } } Loading @@ -396,6 +419,7 @@ private: if (IsCompleted()) { return; } try { // data_->value.template emplace<FailureT>(std::move(reason)); // data_->value = std::move(reason); data_->value = std::move(reason); } catch (...) {} data_->state.store(detail::kFailedFuture, std::memory_order_release); Loading @@ -406,7 +430,8 @@ private: for (const auto &f : callbacks) { try { f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value)); f(sled::any_cast<FailureT>(data_->value)); } catch (...) {} } } Loading src/sled/futures/future_test.cc +51 −14 Original line number Diff line number Diff line #include <sled/futures/future.h> #include <sled/system/thread.h> #include <type_traits> TEST_SUITE("future") { TEST_CASE("base success") { sled::Promise<int, std::string> p; auto f = p.GetFuture(); Loading @@ -12,6 +14,7 @@ TEST_SUITE("future") CHECK(f.IsValid()); CHECK_EQ(f.Result(), 42); } TEST_CASE("base failed") { sled::Promise<int, std::string> p; Loading @@ -23,31 +26,65 @@ TEST_SUITE("future") CHECK(f.IsValid()); 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("map") TEST_CASE("Map") { sled::Promise<int, std::string> p; 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); CHECK(f2.Wait(-1)); CHECK_EQ(f2.Result(), 43); CHECK_EQ(f2.Result(), 4300); } TEST_CASE("FlatMap") { // sled::Promise<int, std::string> p; // auto f = p.GetFuture().FlatMap([](int i) { // auto str = std::to_string(i); // sled::Promise<std::string, std::string> p; // p.Success(str); // // return p.GetFuture(); // }); // p.Success(42); // CHECK(f.Wait(-1)); // CHECK_EQ(f.Result(), "42"); sled::Promise<int, std::string> p; auto f = p.GetFuture().FlatMap([](int i) { auto str = std::to_string(i); sled::Promise<std::string, std::string> p; p.Success(str); return p.GetFuture(); }); p.Success(42); CHECK(f.IsCompleted()); CHECK_EQ(f.Result(), "42"); } TEST_CASE("Via") Loading src/sled/utility/forward_on_copy.h 0 → 100644 +76 −0 Original line number Diff line number Diff line #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 Loading
src/sled/futures/future.h +34 −9 Original line number Diff line number Diff line Loading @@ -10,8 +10,9 @@ #include "sled/synchronization/event.h" #include "sled/synchronization/mutex.h" #include "sled/task_queue/task_queue_base.h" #include "sled/variant.h" #include "sled/utility/forward_on_copy.h" #include <atomic> #include <future> #include <list> namespace sled { Loading Loading @@ -48,7 +49,8 @@ struct FutureData { ~FutureData() { DecrementFuturesUsage(); } 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 FailureT &)>> failure_callbacks; sled::Mutex mutex_; Loading Loading @@ -130,7 +132,8 @@ public: if (!IsCompleted()) Wait(); if (IsSucceeded()) { try { return sled::get<T>(data_->value); // return sled::get<T>(data_->value); return sled::any_cast<T>(data_->value); } catch (...) {} } return T(); Loading @@ -140,7 +143,8 @@ public: { SLED_ASSERT(data_ != nullptr, "Future is not valid"); 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 Loading @@ -149,7 +153,8 @@ public: if (!IsCompleted()) { Wait(); } if (IsFailed()) { try { return sled::get<FailureT>(data_->value); // return sled::get<FailureT>(data_->value); return sled::any_cast<FailureT>(data_->value); } catch (...) {} } return FailureT(); Loading @@ -176,7 +181,8 @@ public: } if (call_it) { try { f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value)); f(sled::any_cast<T>(data_->value)); } catch (...) {} } return Future<T, FailureT>(data_); Loading @@ -203,7 +209,8 @@ public: } if (call_it) { try { f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value)); f(sled::any_cast<FailureT>(data_->value)); } catch (...) {} } return Future<T, FailureT>(data_); Loading Loading @@ -294,6 +301,20 @@ public: 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 { SLED_ASSERT(task_queue != nullptr, "TaskQueue is not valid"); Loading Loading @@ -365,6 +386,7 @@ private: if (IsCompleted()) { return; } try { // data_->value.template emplace<T>(std::move(value)); // data_->value.template emplace<T>(std::move(value)); data_->value = std::move(value); } catch (...) {} Loading @@ -376,7 +398,8 @@ private: for (const auto &f : callbacks) { try { f(sled::get<T>(data_->value)); // f(sled::get<T>(data_->value)); f(sled::any_cast<T>(data_->value)); } catch (...) {} } } Loading @@ -396,6 +419,7 @@ private: if (IsCompleted()) { return; } try { // data_->value.template emplace<FailureT>(std::move(reason)); // data_->value = std::move(reason); data_->value = std::move(reason); } catch (...) {} data_->state.store(detail::kFailedFuture, std::memory_order_release); Loading @@ -406,7 +430,8 @@ private: for (const auto &f : callbacks) { try { f(sled::get<FailureT>(data_->value)); // f(sled::get<FailureT>(data_->value)); f(sled::any_cast<FailureT>(data_->value)); } catch (...) {} } } Loading
src/sled/futures/future_test.cc +51 −14 Original line number Diff line number Diff line #include <sled/futures/future.h> #include <sled/system/thread.h> #include <type_traits> TEST_SUITE("future") { TEST_CASE("base success") { sled::Promise<int, std::string> p; auto f = p.GetFuture(); Loading @@ -12,6 +14,7 @@ TEST_SUITE("future") CHECK(f.IsValid()); CHECK_EQ(f.Result(), 42); } TEST_CASE("base failed") { sled::Promise<int, std::string> p; Loading @@ -23,31 +26,65 @@ TEST_SUITE("future") CHECK(f.IsValid()); 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("map") TEST_CASE("Map") { sled::Promise<int, std::string> p; 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); CHECK(f2.Wait(-1)); CHECK_EQ(f2.Result(), 43); CHECK_EQ(f2.Result(), 4300); } TEST_CASE("FlatMap") { // sled::Promise<int, std::string> p; // auto f = p.GetFuture().FlatMap([](int i) { // auto str = std::to_string(i); // sled::Promise<std::string, std::string> p; // p.Success(str); // // return p.GetFuture(); // }); // p.Success(42); // CHECK(f.Wait(-1)); // CHECK_EQ(f.Result(), "42"); sled::Promise<int, std::string> p; auto f = p.GetFuture().FlatMap([](int i) { auto str = std::to_string(i); sled::Promise<std::string, std::string> p; p.Success(str); return p.GetFuture(); }); p.Success(42); CHECK(f.IsCompleted()); CHECK_EQ(f.Result(), "42"); } TEST_CASE("Via") Loading
src/sled/utility/forward_on_copy.h 0 → 100644 +76 −0 Original line number Diff line number Diff line #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