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/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>; diff --git a/src/rpp/rpp/subjects/fwd.hpp b/src/rpp/rpp/subjects/fwd.hpp index bc55f27e6..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 @@ -38,54 +40,21 @@ 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 { -namespace details -{ - template - struct extract_subject_type : std::false_type - { - }; - - template - struct extract_subject_type> : std::true_type - { - using type = TT; - }; - -} // 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::extract_subject_type>::value; +concept subject = rpp::utils::is_base_of_v; } diff --git a/src/rpp/rpp/subjects/publish_subject.hpp b/src/rpp/rpp/subjects/publish_subject.hpp index 427e8c763..bbdb170d9 100644 --- a/src/rpp/rpp/subjects/publish_subject.hpp +++ b/src/rpp/rpp/subjects/publish_subject.hpp @@ -61,4 +61,26 @@ 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> +{ +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 b9f8911ff..76b28d536 100644 --- a/src/rpp/rpp/subjects/serialized_subject.hpp +++ b/src/rpp/rpp/subjects/serialized_subject.hpp @@ -82,4 +82,20 @@ 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> +{ +public: + using details::base_subject>::base_subject; +}; +} \ No newline at end of file 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..ffd637cc5 100644 --- a/src/rpp/rpp/utils/tuple.hpp +++ b/src/rpp/rpp/utils/tuple.hpp @@ -86,12 +86,16 @@ class RPP_EMPTY_BASES tuple_impl, Args...> : pri private: template - constexpr static T type_at_index(const tuple_leaf&); + 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())); + 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..a9483bf4c 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,24 @@ struct types template using iterable_value_t = std::iter_value_t()))>; +namespace details +{ + template typename Base> + struct traits + { + 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 = !std::is_same_v::extract_params(std::declval*>())), std::false_type>; + +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 {