From 8f4d2f46081a7ce58981303ed4c2e7cfed6d9c74 Mon Sep 17 00:00:00 2001 From: bergmann Date: Fri, 15 Nov 2019 08:08:05 +0100 Subject: [PATCH] * Splitted result into future_result and stream_result (because the future_result does not need a 'done' state) * Refactored namespaces (trait classes are postfixed with '_trait'; internal namespaces are prefixed with __) --- include/asyncpp/future.h | 6 +- include/asyncpp/future.inl | 59 +++--- include/asyncpp/future.pre.h | 29 ++- include/asyncpp/future/and_then.h | 2 +- include/asyncpp/future/and_then.inl | 57 +++--- include/asyncpp/future/map.h | 2 +- include/asyncpp/future/map.inl | 47 +++-- include/asyncpp/result.h | 190 ++++++++++-------- include/asyncpp/result.inl | 292 +++++++++++++++------------- test/asyncpp/future_tests.cpp | 50 +++-- test/asyncpp/result_tests.cpp | 37 +++- 11 files changed, 405 insertions(+), 366 deletions(-) diff --git a/include/asyncpp/future.h b/include/asyncpp/future.h index f9b646a..16c5a0f 100644 --- a/include/asyncpp/future.h +++ b/include/asyncpp/future.h @@ -17,9 +17,9 @@ namespace asyncpp { using object_type = T_object; using clean_object_type = std::decay_t; - using impl_type = impl::future; - using value_type = typename impl_type::value_type; - using result_type = result; + using trait_type = future_trait; + using value_type = typename trait_type::value_type; + using result_type = future_result; object_type ref; diff --git a/include/asyncpp/future.inl b/include/asyncpp/future.inl index c1e4027..54e81b5 100644 --- a/include/asyncpp/future.inl +++ b/include/asyncpp/future.inl @@ -8,37 +8,34 @@ namespace asyncpp { - namespace impl + /* future_base */ + + template + template + auto future_base + ::map(X_future&& self, X_lambda&& p_lambda) { + using future_type = X_future; + using lambda_type = X_lambda; + using map_type = __future::map_impl; + + return as_future(map_type( + std::forward(self), + std::forward(p_lambda))); + } - template - template - auto future_base - ::map(X_future&& self, X_lambda&& p_lambda) - { - using future_type = X_future; - using lambda_type = X_lambda; - using map_type = future_impl::map_impl; - - return as_future(map_type( - std::forward(self), - std::forward(p_lambda))); - } - - template - template - auto future_base - ::and_then(X_future&& self, X_lambda&& p_lambda) - { - using future_type = X_future; - using lambda_type = X_lambda; - using and_then_type = future_impl::and_then_impl; - - return as_future(and_then_type( - std::forward(self), - std::forward(p_lambda))); - } + template + template + auto future_base + ::and_then(X_future&& self, X_lambda&& p_lambda) + { + using future_type = X_future; + using lambda_type = X_lambda; + using and_then_type = __future::and_then_impl; + return as_future(and_then_type( + std::forward(self), + std::forward(p_lambda))); } /* future */ @@ -59,7 +56,7 @@ namespace asyncpp typename future::result_type future ::poll() - { return impl_type::poll(*this); } + { return trait_type::poll(*this); } template< typename T_value, @@ -68,7 +65,7 @@ namespace asyncpp typename X_lambda> auto future ::map(X_lambda&& p_lambda) - { return impl_type::map(std::move(*this), std::forward(p_lambda)); } + { return trait_type::map(std::move(*this), std::forward(p_lambda)); } template< typename T_value, @@ -77,7 +74,7 @@ namespace asyncpp typename X_lambda> auto future ::and_then(X_lambda&& p_lambda) - { return impl_type::and_then(std::move(*this), std::forward(p_lambda)); } + { return trait_type::and_then(std::move(*this), std::forward(p_lambda)); } /* misc */ diff --git a/include/asyncpp/future.pre.h b/include/asyncpp/future.pre.h index df87319..dc6226f 100644 --- a/include/asyncpp/future.pre.h +++ b/include/asyncpp/future.pre.h @@ -3,30 +3,25 @@ namespace asyncpp { - namespace impl + template + struct future_base { + template + static inline auto poll(T_future& self) = delete; - template - struct future_base - { - template - static inline auto poll(T_future& self) = delete; + template + static inline auto map(T_future&& self, T_lambda&& p_lambda); - template - static inline auto map(T_future&& self, T_lambda&& p_lambda); + template + static inline auto and_then(T_future&& self, T_lambda&& p_lambda); + }; - template - static inline auto and_then(T_future&& self, T_lambda&& p_lambda); - }; - - template - struct future; - - } + template + struct future_trait; template< typename T_object, - typename T_impl = impl::future>> + typename T_impl = future_trait>> struct future; /** diff --git a/include/asyncpp/future/and_then.h b/include/asyncpp/future/and_then.h index c1180c3..8f15743 100644 --- a/include/asyncpp/future/and_then.h +++ b/include/asyncpp/future/and_then.h @@ -3,7 +3,7 @@ #include namespace asyncpp { -namespace future_impl { +namespace __future { template< typename T_future, diff --git a/include/asyncpp/future/and_then.inl b/include/asyncpp/future/and_then.inl index 3203c53..f7c513d 100644 --- a/include/asyncpp/future/and_then.inl +++ b/include/asyncpp/future/and_then.inl @@ -5,47 +5,46 @@ namespace asyncpp { - namespace impl + /* future_trait for ant_then_impl */ + + template< + typename T_future, + typename T_lambda> + struct future_trait<__future::and_then_impl, void> + : public future_base, void>> { + using and_then_type = __future::and_then_impl; + using inner_future_type = typename and_then_type::inner_future_type; + using value_type = typename inner_future_type::value_type; + using result_type = typename inner_future_type::result_type; - template< - typename T_future, - typename T_lambda> - struct future, void> - : public future_base, void>> + template + static inline auto poll(X_future& self) { - using and_then_type = future_impl::and_then_impl; - using inner_future_type = typename and_then_type::inner_future_type; - using value_type = typename inner_future_type::value_type; - using result_type = typename inner_future_type::result_type; - - template - static inline auto poll(X_future& self) + while (true) { - while (true) + if (self.ref.inner) { - if (self.ref.inner) - { - return self.ref.inner->poll(); - } - else - { - auto r = self.ref.outer.poll(); - if (!r) - return result_type::not_ready(); + return self.ref.inner->poll(); + } + else + { + auto r = self.ref.outer.poll(); + if (!r) + return result_type::not_ready(); - self.ref.inner = std::make_unique(as_future(self.ref.lambda(*r))); - } + self.ref.inner = std::make_unique(as_future(self.ref.lambda(*r))); } } - }; - - } + } + }; } namespace asyncpp { -namespace future_impl { +namespace __future { + + /* and_then_impl */ template< typename T_future, diff --git a/include/asyncpp/future/map.h b/include/asyncpp/future/map.h index e220a87..030bf74 100644 --- a/include/asyncpp/future/map.h +++ b/include/asyncpp/future/map.h @@ -1,7 +1,7 @@ #pragma once namespace asyncpp { -namespace future_impl { +namespace __future { template< typename T_future, diff --git a/include/asyncpp/future/map.inl b/include/asyncpp/future/map.inl index 469687a..a6f222b 100644 --- a/include/asyncpp/future/map.inl +++ b/include/asyncpp/future/map.inl @@ -5,38 +5,37 @@ namespace asyncpp { - namespace impl + /* future_trait for map_impl */ + + template< + typename T_future, + typename T_lambda> + struct future_trait<__future::map_impl, void> + : public future_base, void>> { + using future_type = T_future; + using inner_value_type = typename future_type::value_type; + using lambda_type = T_lambda; + using value_type = decltype(std::declval()(std::declval())); - template< - typename T_future, - typename T_lambda> - struct future, void> - : public future_base, void>> + template + static inline auto poll(X_future& self) { - using future_type = T_future; - using inner_value_type = typename future_type::value_type; - using lambda_type = T_lambda; - using value_type = decltype(std::declval()(std::declval())); + using result_type = future_result; - template - static inline auto poll(X_future& self) - { - using result_type = result; - - auto r = self.ref.future.poll(); - return r - ? result_type::ready(self.ref.lambda(*r)) - : result_type::not_ready(); - } - }; - - } + auto r = self.ref.future.poll(); + return r + ? result_type::ready(self.ref.lambda(*r)) + : result_type::not_ready(); + } + }; } namespace asyncpp { -namespace future_impl { +namespace __future { + + /* map_impl */ template< typename T_future, diff --git a/include/asyncpp/result.h b/include/asyncpp/result.h index 41427d7..0e97943 100644 --- a/include/asyncpp/result.h +++ b/include/asyncpp/result.h @@ -5,7 +5,15 @@ namespace asyncpp { - namespace impl + enum class result_status + { + unknown = 0, + not_ready, + ready, + done, + }; + + namespace __impl { struct result_not_ready @@ -25,94 +33,104 @@ namespace asyncpp inline result_ready(T_args&&... p_args); }; + template + struct result + { + public: + using value_type = T_value; + using not_ready_type = result_not_ready; + using ready_type = result_ready; + using done_type = result_done; + using storage_type = std::conditional_t< + for_stream, + std::variant, + std::variant>; + using clean_value_type = std::remove_reference_t; + using pointer_type = clean_value_type*; + using reference_type = clean_value_type&; + using const_pointer_type = clean_value_type const *; + using const_reference_type = clean_value_type const &; + + private: + storage_type _storage; //!< Stores the actual result. + + private: + /** + * @brief Constructor. + */ + inline result(storage_type&& p_storage); + + public: + /** + * @brief returns a result that is not ready. + */ + static inline auto& not_ready(); + + /** + * @brief returns a result that is not ready. + */ + template + static inline auto ready(X_args&&... p_args); + + /** + * @brief returns a result that is not ready. + */ + template< + bool X = for_stream, + typename = std::enable_if_t> + static inline auto& done(); + + public: + /** + * @brief Get the status of the result. + */ + template< + bool X = for_stream, + typename = std::enable_if_t> + inline result_status status() const; + + /** + * @brief Check if the result is not ready (is pending). + */ + inline bool is_not_ready() const; + + /** + * @brief Check if the result is ready (has a value). + */ + inline bool is_ready() const; + + /** + * @brief Check if the result is done (stream is finished). + */ + template< + bool X = for_stream, + typename = std::enable_if_t> + inline bool is_done() const; + + /** + * @brief Get the value of the result. + */ + inline reference_type value(); + + /** + * @brief Get the value of the result. + */ + inline const_reference_type value() const; + + public: + inline operator bool() const; + inline pointer_type operator-> (); + inline reference_type operator* (); + inline const_pointer_type operator-> () const; + inline const_reference_type operator* () const; + }; + } - enum class result_status - { - unknown = 0, - not_ready, - ready, - done, - }; + template + using future_result = __impl::result; template - struct result - { - public: - using value_type = T_value; - using not_ready_type = impl::result_not_ready; - using ready_type = impl::result_ready; - using done_type = impl::result_done; - using storage_type = std::variant; - using clean_value_type = std::remove_reference_t; - using pointer_type = clean_value_type*; - using reference_type = clean_value_type&; - using const_pointer_type = clean_value_type const *; - using const_reference_type = clean_value_type const &; - - private: - storage_type _storage; //!< Stores the actual result. - - private: - /** - * @brief Constructor. - */ - inline result(storage_type&& p_storage); - - public: - /** - * @brief returns a result that is not ready. - */ - static inline auto& not_ready(); - - /** - * @brief returns a result that is not ready. - */ - template - static inline auto ready(X_args&&... p_args); - - /** - * @brief returns a result that is not ready. - */ - static inline auto& done(); - - public: - /** - * @brief Get the status of the result. - */ - inline result_status status() const; - - /** - * @brief Check if the result is not ready (is pending). - */ - inline bool is_not_ready() const; - - /** - * @brief Check if the result is ready (has a value). - */ - inline bool is_ready() const; - - /** - * @brief Check if the result is done (stream is finished). - */ - inline bool is_done() const; - - /** - * @brief Get the value of the result. - */ - inline reference_type value(); - - /** - * @brief Get the value of the result. - */ - inline const_reference_type value() const; - - public: - inline operator bool() const; - inline pointer_type operator-> (); - inline reference_type operator* (); - inline const_pointer_type operator-> () const; - inline const_reference_type operator* () const; - }; + using stream_result = __impl::result; } diff --git a/include/asyncpp/result.inl b/include/asyncpp/result.inl index 116011a..074da4c 100644 --- a/include/asyncpp/result.inl +++ b/include/asyncpp/result.inl @@ -5,7 +5,7 @@ namespace asyncpp { - namespace impl + namespace __impl { /* result_ready */ @@ -17,163 +17,175 @@ namespace asyncpp : value(std::forward(p_args)...) { } - } - - /* result */ - - template - result - ::result(storage_type&& p_storage) - : _storage(std::move(p_storage)) - { } - - template - auto& result - ::not_ready() - { - static const result ret(storage_type(not_ready_type { })); - return ret; - } - - template - template - auto result - ::ready(X_args&&... p_args) - { return result(storage_type(ready_type(std::forward(p_args)...))); } - - template - auto& result - ::done() - { - static const result ret(storage_type(done_type { })); - return ret; - } - - template - result_status result - ::status() const - { - if (is_not_ready()) - return result_status::not_ready; - else if (is_ready()) - return result_status::ready; - else if (is_done()) - return result_status::done; - else - return result_status::unknown; - } - - template - bool result - ::is_not_ready() const - { return std::holds_alternative(_storage); } - - template - bool result - ::is_ready() const - { return std::holds_alternative(_storage); } - - template - bool result - ::is_done() const - { return std::holds_alternative(_storage); } - - template - typename result::reference_type - result - ::value() - { return std::get(_storage).value; } - - template - typename result::const_reference_type - result - ::value() const - { return std::get(_storage).value; } - - template - result - ::operator bool() const - { return is_ready(); } - - template - typename result::pointer_type - result - ::operator-> () - { return &value(); } - - template - typename result::reference_type - result - ::operator* () - { return value(); } - - template - typename result::const_pointer_type - result - ::operator-> () const - { return &value(); } - - template - typename result::const_reference_type - result - ::operator* () const - { return value(); } - - template<> - struct result - { - public: - using value_type = void; - - private: - result_status _status; + /* result */ - private: - inline result(result_status p_status) - : _status(p_status) + template + result + ::result(storage_type&& p_storage) + : _storage(std::move(p_storage)) { } - public: - static inline auto& not_ready() + template + auto& result + ::not_ready() { - static const result ret { result_status::not_ready }; + static const result ret(storage_type(not_ready_type { })); return ret; } + template template - static inline auto& ready(X_args&&... p_args) + auto result + ::ready(X_args&&... p_args) + { return result(storage_type(ready_type(std::forward(p_args)...))); } + + template + template + auto& result + ::done() { - static const result ret { result_status::ready }; + static const result ret(storage_type(done_type { })); return ret; } - static inline auto& done() + template + template + result_status result + ::status() const { - static const result ret { result_status::done }; - return ret; + if (is_not_ready()) + return result_status::not_ready; + else if (is_ready()) + return result_status::ready; + else if (is_done()) + return result_status::done; + else + return result_status::unknown; } - public: - inline result_status status() const - { return _status; } - - inline bool is_not_ready() const - { return _status == result_status::not_ready; } - - inline bool is_ready() const - { return _status == result_status::ready; } + template + bool result + ::is_not_ready() const + { return std::holds_alternative(_storage); } + + template + bool result + ::is_ready() const + { return std::holds_alternative(_storage); } + + template + template + bool result + ::is_done() const + { return std::holds_alternative(_storage); } + + template + typename result::reference_type + result + ::value() + { return std::get(_storage).value; } + + template + typename result::const_reference_type + result + ::value() const + { return std::get(_storage).value; } + + template + result + ::operator bool() const + { return is_ready(); } + + template + typename result::pointer_type + result + ::operator-> () + { return &value(); } + + template + typename result::reference_type + result + ::operator* () + { return value(); } + + template + typename result::const_pointer_type + result + ::operator-> () const + { return &value(); } + + template + typename result::const_reference_type + result + ::operator* () const + { return value(); } + + template + struct result + { + public: + using value_type = void; - inline bool is_done() const - { return _status == result_status::done; } + private: + result_status _status; - inline void value() - { throw std::runtime_error("'void' result does not store any value!"); } + private: + inline result(result_status p_status) + : _status(p_status) + { } - inline operator bool() const - { return _status == result_status::ready; } + public: + static inline auto& not_ready() + { + static const result ret { result_status::not_ready }; + return ret; + } + + template + static inline auto& ready(X_args&&... p_args) + { + static const result ret { result_status::ready }; + return ret; + } + + template< + bool X = for_stream, + typename = std::enable_if_t> + static inline auto& done() + { + static const result ret { result_status::done }; + return ret; + } + + public: + template< + bool X = for_stream, + typename = std::enable_if_t> + inline result_status status() const + { return _status; } + + inline bool is_not_ready() const + { return _status == result_status::not_ready; } + + inline bool is_ready() const + { return _status == result_status::ready; } + + template< + bool X = for_stream, + typename = std::enable_if_t> + inline bool is_done() const + { return _status == result_status::done; } + + inline void value() + { throw std::runtime_error("'void' result does not store any value!"); } + + inline operator bool() const + { return _status == result_status::ready; } + + inline void operator* () + { value(); } + }; - inline void operator* () - { value(); } - }; + } } diff --git a/test/asyncpp/future_tests.cpp b/test/asyncpp/future_tests.cpp index 2033aae..7affd4b 100644 --- a/test/asyncpp/future_tests.cpp +++ b/test/asyncpp/future_tests.cpp @@ -14,29 +14,24 @@ struct delay namespace asyncpp { - namespace impl + template<> + struct future_trait + : public future_base> { + using value_type = int&; - template<> - struct future - : public future_base> + template + static inline auto poll(T_future& self) { - using value_type = int&; + using result_type = future_result; - template - static inline auto poll(T_future& self) - { - using result_type = result; + if (self.ref.count >= self.ref.delay) + return result_type::ready(self.ref.count); - if (self.ref.count >= self.ref.delay) - return result_type::ready(self.ref.count); - - ++self.ref.count; - return result_type::not_ready(); - } - }; - - } + ++self.ref.count; + return result_type::not_ready(); + } + }; } @@ -46,26 +41,25 @@ TEST(future_tests, poll) auto f = as_future(d); auto r0 = f.poll(); - ASSERT_EQ(result_status::not_ready, r0.status()); + ASSERT_FALSE(r0); auto r1 = f.poll(); - ASSERT_EQ(result_status::not_ready, r1.status()); + ASSERT_FALSE(r1); auto r2 = f.poll(); - ASSERT_EQ(result_status::not_ready, r2.status()); + ASSERT_FALSE(r2); auto r3 = f.poll(); - ASSERT_EQ(result_status::not_ready, r3.status()); + ASSERT_FALSE(r3); auto r4 = f.poll(); - ASSERT_EQ(result_status::not_ready, r4.status()); + ASSERT_FALSE(r4); auto r = f.poll(); - ASSERT_TRUE(r); - ASSERT_EQ (result_status::ready, r.status()); - ASSERT_EQ (5, *r); - ASSERT_EQ (5, d.count); - ASSERT_EQ (&*r, &d.count); + ASSERT_TRUE (r); + ASSERT_EQ (5, *r); + ASSERT_EQ (5, d.count); + ASSERT_EQ (&*r, &d.count); } TEST(future_tests, map) diff --git a/test/asyncpp/result_tests.cpp b/test/asyncpp/result_tests.cpp index 4d844ce..d5bb37b 100644 --- a/test/asyncpp/result_tests.cpp +++ b/test/asyncpp/result_tests.cpp @@ -5,9 +5,34 @@ using namespace ::testing; using namespace ::asyncpp; -TEST(result_tests, not_ready) +TEST(result_tests, future_result___not_ready) { - using result_type = result; + using result_type = future_result; + + auto r = result_type::not_ready(); + + EXPECT_TRUE (r.is_not_ready()); + EXPECT_FALSE (r.is_ready()); + EXPECT_FALSE (r); + EXPECT_ANY_THROW(*r); +} + +TEST(result_tests, future_result___ready) +{ + using result_type = future_result; + + int i; + auto r = result_type::ready(i); + + EXPECT_FALSE (r.is_not_ready()); + EXPECT_TRUE (r.is_ready()); + EXPECT_TRUE (r); + EXPECT_EQ (&*r, &i); +} + +TEST(result_tests, stream_result___not_ready) +{ + using result_type = stream_result; auto r = result_type::not_ready(); @@ -19,9 +44,9 @@ TEST(result_tests, not_ready) EXPECT_ANY_THROW(*r); } -TEST(result_tests, ready) +TEST(result_tests, stream_result___ready) { - using result_type = result; + using result_type = stream_result; int i; auto r = result_type::ready(i); @@ -34,9 +59,9 @@ TEST(result_tests, ready) EXPECT_EQ (&*r, &i); } -TEST(result_tests, done) +TEST(result_tests, stream_result___done) { - using result_type = result; + using result_type = stream_result; auto r = result_type::done();