diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index 4aedafb..c7a0a83 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -875,7 +875,7 @@ template auto make_ready_continuable(Args&&... args) { return make_continuable...>( detail::base::ready_continuable...>( - std::forward(args))); + std::forward(args)...)); } /// Returns a continuable_base with the parameterized result which instantly diff --git a/include/continuable/continuable-result.hpp b/include/continuable/continuable-result.hpp index 7d7538b..ac9eb8e 100644 --- a/include/continuable/continuable-result.hpp +++ b/include/continuable/continuable-result.hpp @@ -97,7 +97,10 @@ public: }; /// The result class can carry the three kinds of results an asynchronous -/// operation can return: no result, a value or an exception. +/// operation possibly can return, it's implemented in a variant like +/// data structure which is also specialized to hold arbitrary arguments. +/// +/// The result can be in the following three states: /// - *no result*: If the operation didn't finish /// - *a value*: If the operation finished successfully /// - *an exception*: If the operation finished with an exception @@ -106,9 +109,30 @@ class result { using trait_t = detail::result_trait; using surrogate_t = typename trait_t::surrogate_t; + struct init_arg_t {}; + template + friend result...> make_result(Args&&...); + + template ()...))>* = nullptr> + explicit result(init_arg_t, Args&&... values) + : variant_(trait_t::wrap(std::forward(values)...)) { + } + explicit result(init_arg_t, exception_t exception) + : variant_(std::move(exception)) { + } + public: using value_t = typename trait_t::value_t; + template (), std::declval()...))>* = nullptr> + explicit result(FirstArg&& first, Args&&... values) + : variant_(trait_t::wrap(std::forward(first), + std::forward(values)...)) { + } + result() = default; result(result const&) = default; result(result&&) = default; @@ -116,11 +140,6 @@ public: result& operator=(result&&) = default; ~result() = default; - template ()...))* = nullptr> - explicit result(Args&&... values) - : variant_(trait_t::wrap(std::forward(values)...)) { - } explicit result(exception_t exception) : variant_(std::move(exception)) { } result(empty_result) { @@ -138,86 +157,112 @@ public: return *this; } + /// Set the result to an empty state void set_empty() { variant_.set_empty(); } + /// Set the result to a the state which holds the corresponding value void set_value(T... values) { variant_ = trait_t::wrap(std::move(values)...); } + /// Set the result into a state which holds the corresponding exception void set_exception(exception_t exception) { variant_ = std::move(exception); } + /// Returns true if the state of the result is empty bool is_empty() const noexcept { return variant_.is_empty(); } + /// Returns true if the state of the result holds the result bool is_value() const noexcept { return variant_.template is(); } + /// Returns true if the state of the result holds an exception bool is_exception() const noexcept { return variant_.template is(); } + /// \copydoc is_value explicit constexpr operator bool() const noexcept { return is_value(); } - /// Returns the + /// Returns the values of the result, if the result doesn't hold the value + /// the behaviour is undefined but will assert in debug mode. decltype(auto) get_value() & noexcept { return trait_t::unwrap(variant_.template cast()); } + ///\copydoc get_value decltype(auto) get_value() const& noexcept { return trait_t::unwrap(variant_.template cast()); } + ///\copydoc get_value decltype(auto) get_value() && noexcept { return trait_t::unwrap(std::move(variant_).template cast()); } + ///\copydoc get_value decltype(auto) operator*() & noexcept { return get_value(); } + ///\copydoc get_value decltype(auto) operator*() const& noexcept { return get_value(); } + ///\copydoc get_value decltype(auto) operator*() && noexcept { return std::move(*this).get_value(); } + /// Returns the exception of the result, if the result doesn't hold an + /// exception the behaviour is undefined but will assert in debug mode. exception_t& get_exception() & noexcept { return variant_.template cast(); } + /// \copydoc get_exception exception_t const& get_exception() const& noexcept { return variant_.template cast(); } + /// \copydoc get_exception exception_t&& get_exception() && noexcept { return std::move(variant_).template cast(); } + /// Creates a present result from the given values + static result from(T... values) { + return result{init_arg_t{}, std::move(values)...}; + } + /// Creates a present result from the given exception + static result from(exception_t exception) { + return result{init_arg_t{}, std::move(exception)}; + } + private: detail::container::flat_variant variant_; }; +/// Returns the value at position I of the given result template decltype(auto) get(result& result) { return detail::result_trait::template get(result); } +/// \copydoc get template decltype(auto) get(result const& result) { return detail::result_trait::template get(result); } +/// \copydoc get template decltype(auto) get(result&& result) { return detail::result_trait::template get(std::move(result)); } -inline result<> make_result() { - result<> result; - result.set_value(); - return result; -} -template -auto make_result(T&&... values) { - return result...>(std::forward(values)...); +/// Creates a present result from the given values +template ...>> +Result make_result(T&&... values) { + return Result::from(std::forward(values)...); } /// \} } // namespace cti diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 972d372..5d0af04 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -73,11 +73,16 @@ template struct ready_continuable { std::tuple values_; - explicit ready_continuable(Args... values) : values_(std::move(values)) { + ready_continuable(ready_continuable&&) = default; + ready_continuable(ready_continuable const&) = default; + ready_continuable& operator=(ready_continuable&&) = default; + ready_continuable& operator=(ready_continuable const&) = default; + + explicit ready_continuable(Args... values) : values_(std::move(values)...) { } template - void operator()(Callback&& callback) && { + void operator()(Callback&& callback) { traits::unpack(std::forward(callback), std::move(values_)); } @@ -92,7 +97,7 @@ struct ready_continuable { template <> struct ready_continuable<> { template - void operator()(Callback&& callback) && { + void operator()(Callback&& callback) { util::invoke(std::forward(callback)); }