From adccb3a8a6ebc6557e42bf5b7874789b319abfee Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Sat, 6 Jan 2024 00:19:10 +0300 Subject: [PATCH 1/7] Proper forwarding for subjects --- src/rpp/rpp/subjects/fwd.hpp | 22 ++------------------- src/rpp/rpp/subjects/publish_subject.hpp | 20 ++++++++++++++++++- src/rpp/rpp/subjects/serialized_subject.hpp | 14 ++++++++++++- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/rpp/rpp/subjects/fwd.hpp b/src/rpp/rpp/subjects/fwd.hpp index bc55f27e6..27b90b975 100644 --- a/src/rpp/rpp/subjects/fwd.hpp +++ b/src/rpp/rpp/subjects/fwd.hpp @@ -38,29 +38,11 @@ class serialized_strategy; namespace rpp::subjects { -/** - * @brief Subject which just multicasts values to observers subscribed on it. It contains two parts: observer and observable at the same time. - * - * @details Each observer obtains only values which emitted after corresponding subscribe. on_error/on_completer/unsubscribe cached and provided to new observers if any - * - * @warning this subject is not synchronized/serialized! It means, that expected to call callbacks of observer in the serialized way to follow observable contract: "Observables must issue notifications to observers serially (not in parallel).". If you are not sure or need extra serialization, please, use serialized_subject. - * - * @tparam Type value provided by this subject - * - * @ingroup subjects - * @see https://reactivex.io/documentation/subject.html - */ template -using publish_subject = details::base_subject>; +class publish_subject; -/** - * @brief Same as rpp::subjects::publish_subject, but on_next/on_error/on_completed calls are serialized via mutex - * - * @ingroup subjects - * @see https://reactivex.io/documentation/subject.html - */ template -using serialized_subject = details::base_subject>; +class serialized_subject; } namespace rpp::subjects::utils diff --git a/src/rpp/rpp/subjects/publish_subject.hpp b/src/rpp/rpp/subjects/publish_subject.hpp index 427e8c763..9461e73eb 100644 --- a/src/rpp/rpp/subjects/publish_subject.hpp +++ b/src/rpp/rpp/subjects/publish_subject.hpp @@ -61,4 +61,22 @@ class publish_strategy private: std::shared_ptr> m_state = std::make_shared>(); }; -} // namespace rpp::subjects::details \ No newline at end of file +} // namespace rpp::subjects::details + +namespace rpp::subjects +{ +/** + * @brief Subject which just multicasts values to observers subscribed on it. It contains two parts: observer and observable at the same time. + * + * @details Each observer obtains only values which emitted after corresponding subscribe. on_error/on_completer/unsubscribe cached and provided to new observers if any + * + * @warning this subject is not synchronized/serialized! It means, that expected to call callbacks of observer in the serialized way to follow observable contract: "Observables must issue notifications to observers serially (not in parallel).". If you are not sure or need extra serialization, please, use serialized_subject. + * + * @tparam Type value provided by this subject + * + * @ingroup subjects + * @see https://reactivex.io/documentation/subject.html + */ +template +class publish_subject final : public details::base_subject>{}; +} \ No newline at end of file diff --git a/src/rpp/rpp/subjects/serialized_subject.hpp b/src/rpp/rpp/subjects/serialized_subject.hpp index b9f8911ff..48c955cec 100644 --- a/src/rpp/rpp/subjects/serialized_subject.hpp +++ b/src/rpp/rpp/subjects/serialized_subject.hpp @@ -82,4 +82,16 @@ class serialized_strategy private: std::shared_ptr m_state = std::make_shared(); }; -} // namespace rpp::subjects::details \ No newline at end of file +} // namespace rpp::subjects::details + +namespace rpp::subjects +{ +/** + * @brief Same as rpp::subjects::publish_subject, but on_next/on_error/on_completed calls are serialized via mutex + * + * @ingroup subjects + * @see https://reactivex.io/documentation/subject.html + */ +template +class serialized_subject final : public details::base_subject>{}; +} \ No newline at end of file From 9d6e3a3acfec2b410033c50405485a669e55bfdd Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Sat, 6 Jan 2024 01:05:47 +0300 Subject: [PATCH 2/7] allow ctor --- src/rpp/rpp/subjects/publish_subject.hpp | 6 +++++- src/rpp/rpp/subjects/serialized_subject.hpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rpp/rpp/subjects/publish_subject.hpp b/src/rpp/rpp/subjects/publish_subject.hpp index 9461e73eb..bbdb170d9 100644 --- a/src/rpp/rpp/subjects/publish_subject.hpp +++ b/src/rpp/rpp/subjects/publish_subject.hpp @@ -78,5 +78,9 @@ namespace rpp::subjects * @see https://reactivex.io/documentation/subject.html */ template -class publish_subject final : public details::base_subject>{}; +class publish_subject final : public details::base_subject> +{ +public: + using details::base_subject>::base_subject; +}; } \ No newline at end of file diff --git a/src/rpp/rpp/subjects/serialized_subject.hpp b/src/rpp/rpp/subjects/serialized_subject.hpp index 48c955cec..76b28d536 100644 --- a/src/rpp/rpp/subjects/serialized_subject.hpp +++ b/src/rpp/rpp/subjects/serialized_subject.hpp @@ -93,5 +93,9 @@ namespace rpp::subjects * @see https://reactivex.io/documentation/subject.html */ template -class serialized_subject final : public details::base_subject>{}; +class serialized_subject final : public details::base_subject> +{ +public: + using details::base_subject>::base_subject; +}; } \ No newline at end of file From 8a4e6252bbd995ff018e8784f38411482b97dd24 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Sun, 7 Jan 2024 19:09:12 +0300 Subject: [PATCH 3/7] fix --- src/rpp/rpp/subjects/fwd.hpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/rpp/rpp/subjects/fwd.hpp b/src/rpp/rpp/subjects/fwd.hpp index 27b90b975..515384ded 100644 --- a/src/rpp/rpp/subjects/fwd.hpp +++ b/src/rpp/rpp/subjects/fwd.hpp @@ -49,15 +49,23 @@ namespace rpp::subjects::utils { namespace details { - template - struct extract_subject_type : std::false_type + template + struct extract_subject_type { + template + constexpr static TT deduce(const rpp::subjects::details::base_subject&); + + using type = decltype(deduce(std::declval>())); }; - template - struct extract_subject_type> : std::true_type + template + struct is_subject_t { - using type = TT; + template + constexpr static std::true_type deduce(const rpp::subjects::details::base_subject&); + constexpr static std::false_type deduce(...); + + using type = decltype(deduce(std::declval*>())); }; } // namespace details @@ -69,5 +77,5 @@ using extract_subject_type_t = typename details::extract_subject_type -concept subject = rpp::subjects::utils::details::extract_subject_type>::value; +concept subject = rpp::subjects::utils::details::is_subject_t>::type::value; } From c08e5ee68614ddd53886e1c921685495e6e42e23 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Mon, 8 Jan 2024 01:04:01 +0300 Subject: [PATCH 4/7] fixup --- src/rpp/rpp/observables/fwd.hpp | 32 +++------------------------ src/rpp/rpp/subjects/fwd.hpp | 29 ++++-------------------- src/rpp/rpp/utils/function_traits.hpp | 18 ++++++--------- src/rpp/rpp/utils/tuple.hpp | 10 ++++++--- src/rpp/rpp/utils/utils.hpp | 22 ++++++++++++++++++ 5 files changed, 43 insertions(+), 68 deletions(-) diff --git a/src/rpp/rpp/observables/fwd.hpp b/src/rpp/rpp/observables/fwd.hpp index 804117356..be2c56ba5 100644 --- a/src/rpp/rpp/observables/fwd.hpp +++ b/src/rpp/rpp/observables/fwd.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace rpp::constraint { @@ -52,24 +53,10 @@ template -struct is_observable_t -{ - template - constexpr static std::true_type deduce(const rpp::observable*); - constexpr static std::false_type deduce(...); - - using type = decltype(deduce(std::declval*>())); -}; - -} // namespace rpp::utils::details - namespace rpp::constraint { template -concept observable = rpp::utils::details::is_observable_t>::type::value; +concept observable = rpp::utils::is_base_of_v; } namespace rpp @@ -80,21 +67,8 @@ class connectable_observable; namespace rpp::utils { -namespace details -{ - template - struct extract_observable_type - { - template - constexpr static T deduce(const rpp::observable&); - - using type = decltype(deduce(std::declval>())); - }; - -} // namespace details - template -using extract_observable_type_t = typename details::extract_observable_type>::type; +using extract_observable_type_t = typename rpp::utils::extract_base_type_params_t::template type_at_index_t<0>; } // namespace rpp::utils namespace rpp::constraint diff --git a/src/rpp/rpp/subjects/fwd.hpp b/src/rpp/rpp/subjects/fwd.hpp index 515384ded..8ecbf4c7c 100644 --- a/src/rpp/rpp/subjects/fwd.hpp +++ b/src/rpp/rpp/subjects/fwd.hpp @@ -14,6 +14,8 @@ #include +#include + namespace rpp::subjects::details { namespace constraint @@ -47,35 +49,12 @@ class serialized_subject; namespace rpp::subjects::utils { -namespace details -{ - template - struct extract_subject_type - { - template - constexpr static TT deduce(const rpp::subjects::details::base_subject&); - - using type = decltype(deduce(std::declval>())); - }; - - template - struct is_subject_t - { - template - constexpr static std::true_type deduce(const rpp::subjects::details::base_subject&); - constexpr static std::false_type deduce(...); - - using type = decltype(deduce(std::declval*>())); - }; - -} // namespace details - template -using extract_subject_type_t = typename details::extract_subject_type>::type; +using extract_subject_type_t = typename rpp::utils::extract_base_type_params_t::template type_at_index_t<0>; } // namespace rpp::utils namespace rpp::constraint { template -concept subject = rpp::subjects::utils::details::is_subject_t>::type::value; +concept subject = rpp::utils::is_base_of_v; } diff --git a/src/rpp/rpp/utils/function_traits.hpp b/src/rpp/rpp/utils/function_traits.hpp index db53cdd17..cf587a891 100644 --- a/src/rpp/rpp/utils/function_traits.hpp +++ b/src/rpp/rpp/utils/function_traits.hpp @@ -10,7 +10,7 @@ #pragma once -#include +#include #include namespace rpp::utils @@ -73,19 +73,15 @@ template struct function_traits { using result = R; - using arguments = std::tuple; + using arguments = rpp::utils::tuple...>; - template - requires (sizeof...(Args) > i) - using argument = std::tuple_element_t; + template + requires (sizeof...(Args) > I) + using argument = typename arguments::template type_at_index_t; }; -template -using function_argument_t = typename function_traits::template argument; - - -template -using decayed_function_argument_t = std::decay_t>; +template +using decayed_function_argument_t = typename function_traits::template argument; template using decayed_invoke_result_t = std::decay_t>; diff --git a/src/rpp/rpp/utils/tuple.hpp b/src/rpp/rpp/utils/tuple.hpp index a3f709631..544c9e41c 100644 --- a/src/rpp/rpp/utils/tuple.hpp +++ b/src/rpp/rpp/utils/tuple.hpp @@ -84,14 +84,18 @@ class RPP_EMPTY_BASES tuple_impl, Args...> : pri return static_cast>*>(this)->get(); } -private: +// private: + template - constexpr static T type_at_index(const tuple_leaf&); + constexpr static T type_at_index_impl(const tuple_leaf*); + + template + constexpr static auto type_at_index() -> decltype(type_at_index_impl(std::declval())); public: template requires (I < sizeof...(Args)) - using type_at_index_t = decltype(type_at_index(std::declval())); + using type_at_index_t = decltype(type_at_index()); }; } diff --git a/src/rpp/rpp/utils/utils.hpp b/src/rpp/rpp/utils/utils.hpp index 3f122b37e..55e7a82a6 100644 --- a/src/rpp/rpp/utils/utils.hpp +++ b/src/rpp/rpp/utils/utils.hpp @@ -12,6 +12,7 @@ #include #include +#include #include @@ -30,6 +31,27 @@ struct types template using iterable_value_t = std::iter_value_t()))>; +namespace details +{ + template typename Base> + struct traits + { + template + constexpr static std::true_type convertible_from(const Base*); + constexpr static std::false_type convertible_from(...); + + template + constexpr static rpp::utils::tuple extract_params(const Base*); + }; +} + +template typename Base> +concept is_base_of_v = decltype(details::traits::convertible_from(std::declval*>()))::value; + +template typename Base> + requires is_base_of_v +using extract_base_type_params_t = decltype(details::traits::extract_params(std::declval*>())); + template constexpr std::add_const_t& as_const(const T& v) noexcept { From c7d0b651d498acd7bce2b385e33e4c457a09f6fb Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Mon, 8 Jan 2024 01:09:56 +0300 Subject: [PATCH 5/7] update --- src/rpp/rpp/utils/tuple.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpp/rpp/utils/tuple.hpp b/src/rpp/rpp/utils/tuple.hpp index 544c9e41c..ffd637cc5 100644 --- a/src/rpp/rpp/utils/tuple.hpp +++ b/src/rpp/rpp/utils/tuple.hpp @@ -84,15 +84,15 @@ class RPP_EMPTY_BASES tuple_impl, Args...> : pri return static_cast>*>(this)->get(); } -// private: - +private: template constexpr static T type_at_index_impl(const tuple_leaf*); +public: + template constexpr static auto type_at_index() -> decltype(type_at_index_impl(std::declval())); -public: template requires (I < sizeof...(Args)) using type_at_index_t = decltype(type_at_index()); From cda41b968c5574b5d31c386874eb87670efc70de Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Mon, 8 Jan 2024 01:23:53 +0300 Subject: [PATCH 6/7] handle observers --- src/rpp/rpp/observers/fwd.hpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/rpp/rpp/observers/fwd.hpp b/src/rpp/rpp/observers/fwd.hpp index a51030a1d..020875566 100644 --- a/src/rpp/rpp/observers/fwd.hpp +++ b/src/rpp/rpp/observers/fwd.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -231,29 +232,14 @@ using fake_observer = rpp::observer; namespace rpp::utils { -namespace details -{ - template - struct extract_observer_type : std::false_type - { - }; - - template - struct extract_observer_type> : std::true_type - { - using type = TT; - }; - -} // namespace details - template -using extract_observer_type_t = typename details::extract_observer_type::type; +using extract_observer_type_t = typename rpp::utils::extract_base_type_params_t::template type_at_index_t<0>; } // namespace rpp::utils namespace rpp::constraint { template -concept observer = rpp::utils::details::extract_observer_type>::value; +concept observer = rpp::utils::is_base_of_v; template concept observer_of_type = observer> && std::same_as>, Type>; From 12e97289e30841907748c3099b9364cc3dadb2dc Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Mon, 8 Jan 2024 10:52:43 +0300 Subject: [PATCH 7/7] simplify --- src/rpp/rpp/utils/utils.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rpp/rpp/utils/utils.hpp b/src/rpp/rpp/utils/utils.hpp index 55e7a82a6..a9483bf4c 100644 --- a/src/rpp/rpp/utils/utils.hpp +++ b/src/rpp/rpp/utils/utils.hpp @@ -36,17 +36,14 @@ namespace details template typename Base> struct traits { - template - constexpr static std::true_type convertible_from(const Base*); - constexpr static std::false_type convertible_from(...); - template constexpr static rpp::utils::tuple extract_params(const Base*); + constexpr static std::false_type extract_params(...); }; } template typename Base> -concept is_base_of_v = decltype(details::traits::convertible_from(std::declval*>()))::value; +concept is_base_of_v = !std::is_same_v::extract_params(std::declval*>())), std::false_type>; template typename Base> requires is_base_of_v