Optimize util::signal & support signal<Args...>

This commit is contained in:
Nikita Lisitsa 2023-06-20 02:11:49 +03:00
parent d7c8d8710c
commit 4befa1cad7
9 changed files with 44 additions and 62 deletions

View file

@ -25,7 +25,7 @@ namespace psemek::react
node->external_signal(node->value()); node->external_signal(node->value());
}; };
auto inner_internal_token = std::make_shared<util::signal<void>::subscription_token>(); auto inner_internal_token = std::make_shared<util::signal<>::subscription_token>();
auto inner_external_token = std::make_shared<typename util::signal<T>::subscription_token>(); auto inner_external_token = std::make_shared<typename util::signal<T>::subscription_token>();
auto external_subscriber = [weak_node, inner_internal_token, inner_external_token, internal_subscriber, inner_external_subscriber](value<T> const & x){ auto external_subscriber = [weak_node, inner_internal_token, inner_external_token, internal_subscriber, inner_external_subscriber](value<T> const & x){

View file

@ -73,7 +73,7 @@ namespace psemek::react
} }
}; };
std::vector<util::signal<void>::subscription_token> internal_tokens; std::vector<util::signal<>::subscription_token> internal_tokens;
std::vector<typename util::signal<T>::subscription_token> external_tokens; std::vector<typename util::signal<T>::subscription_token> external_tokens;
internal_tokens.reserve(args.size()); internal_tokens.reserve(args.size());

View file

@ -80,7 +80,7 @@ namespace psemek::react
: value<void>(detail::internal_tag{}, std::make_shared<detail::node<void>>()) : value<void>(detail::internal_tag{}, std::make_shared<detail::node<void>>())
{} {}
source(util::signal<void>::subscriber subscriber) source(util::signal<>::subscriber subscriber)
: source() : source()
{ {
subscribtion_token_ = subscribe(std::move(subscriber)); subscribtion_token_ = subscribe(std::move(subscriber));
@ -96,7 +96,7 @@ namespace psemek::react
} }
private: private:
util::signal<void>::subscription_token subscribtion_token_; util::signal<>::subscription_token subscribtion_token_;
}; };
template <typename T> template <typename T>

View file

@ -20,7 +20,9 @@ namespace psemek::react
template <typename T> template <typename T>
struct node struct node
{ {
util::signal<void> internal_signal; using external_subscriber = typename util::signal<T>::subscriber;
util::signal<> internal_signal;
util::signal<T> external_signal; util::signal<T> external_signal;
util::function<T()> getter; util::function<T()> getter;
std::optional<T> cached_value; std::optional<T> cached_value;
@ -37,8 +39,10 @@ namespace psemek::react
template <> template <>
struct node<void> struct node<void>
{ {
util::signal<void> internal_signal; using external_subscriber = typename util::signal<>::subscriber;
util::signal<void> external_signal;
util::signal<> internal_signal;
util::signal<> external_signal;
void value() void value()
{} {}
@ -99,7 +103,7 @@ namespace psemek::react
return node_->value(); return node_->value();
} }
[[nodiscard]] auto subscribe(typename util::signal<T>::subscriber subscriber, bool call = false) const [[nodiscard]] auto subscribe(typename detail::node<T>::external_subscriber subscriber, bool call = false) const
{ {
if (call) if (call)
{ {

View file

@ -20,16 +20,16 @@ namespace psemek::ui::impl
virtual void set_child_keys(std::vector<std::optional<key>> keys); virtual void set_child_keys(std::vector<std::optional<key>> keys);
virtual std::vector<std::unique_ptr<component>> release_children(); virtual std::vector<std::unique_ptr<component>> release_children();
virtual util::signal<void>::subscription_token release_children_token(); virtual util::signal<>::subscription_token release_children_token();
virtual std::vector<util::signal<void>::subscription_token> release_child_tokens(); virtual std::vector<util::signal<>::subscription_token> release_child_tokens();
virtual std::vector<std::optional<key>> release_child_keys(); virtual std::vector<std::optional<key>> release_child_keys();
util::span<std::unique_ptr<component> const> children() const override; util::span<std::unique_ptr<component> const> children() const override;
private: private:
util::signal<void>::subscription_token children_token_; util::signal<>::subscription_token children_token_;
std::vector<std::unique_ptr<component>> children_; std::vector<std::unique_ptr<component>> children_;
std::vector<util::signal<void>::subscription_token> child_tokens_; std::vector<util::signal<>::subscription_token> child_tokens_;
std::vector<std::optional<key>> child_keys_; std::vector<std::optional<key>> child_keys_;
}; };

View file

@ -15,13 +15,13 @@ namespace psemek::ui::impl
util::span<std::unique_ptr<component> const> children() const override; util::span<std::unique_ptr<component> const> children() const override;
virtual void set_child(std::unique_ptr<component> child); virtual void set_child(std::unique_ptr<component> child);
virtual void set_child_token(util::signal<void>::subscription_token token); virtual void set_child_token(util::signal<>::subscription_token token);
virtual component * child() const; virtual component * child() const;
virtual std::unique_ptr<component> release_child(); virtual std::unique_ptr<component> release_child();
virtual util::signal<void>::subscription_token release_child_token(); virtual util::signal<>::subscription_token release_child_token();
private: private:
util::signal<void>::subscription_token child_token_; util::signal<>::subscription_token child_token_;
std::unique_ptr<component> child_; std::unique_ptr<component> child_;
}; };

View file

@ -28,12 +28,12 @@ namespace psemek::ui::impl
return std::move(children_); return std::move(children_);
} }
util::signal<void>::subscription_token container::release_children_token() util::signal<>::subscription_token container::release_children_token()
{ {
return std::move(children_token_); return std::move(children_token_);
} }
std::vector<util::signal<void>::subscription_token> container::release_child_tokens() std::vector<util::signal<>::subscription_token> container::release_child_tokens()
{ {
return std::move(child_tokens_); return std::move(child_tokens_);
} }

View file

@ -13,7 +13,7 @@ namespace psemek::ui::impl
child_ = std::move(child); child_ = std::move(child);
} }
void single_container::set_child_token(util::signal<void>::subscription_token token) void single_container::set_child_token(util::signal<>::subscription_token token)
{ {
child_token_ = std::move(token); child_token_ = std::move(token);
} }
@ -28,7 +28,7 @@ namespace psemek::ui::impl
return std::move(child_); return std::move(child_);
} }
util::signal<void>::subscription_token single_container::release_child_token() util::signal<>::subscription_token single_container::release_child_token()
{ {
return std::move(child_token_); return std::move(child_token_);
} }

View file

@ -2,16 +2,17 @@
#include <psemek/util/function.hpp> #include <psemek/util/function.hpp>
#include <list> #include <vector>
#include <memory> #include <memory>
namespace psemek::util namespace psemek::util
{ {
template <typename T> template <typename ... Args>
struct signal struct signal
{ {
using subscriber = function<void(T const &)>; using subscriber = function<void(Args const & ...)>;
using subscription_token = std::shared_ptr<void>; using subscription_token = std::shared_ptr<void>;
[[nodiscard]] subscription_token subscribe(subscriber callback) const [[nodiscard]] subscription_token subscribe(subscriber callback) const
@ -21,59 +22,36 @@ namespace psemek::util
return token; return token;
} }
void operator()(T const & value) void operator()(Args const & ... args)
{ {
auto begin = subscribers_.begin(); auto subscribers = std::move(subscribers_);
auto end = subscribers_.end();
auto begin = subscribers.begin();
auto end = subscribers.end();
auto alive_end = begin;
for (auto it = begin; it != end;) for (auto it = begin; it != end;)
{ {
if (auto callback = it->lock()) if (auto callback = it->lock())
{ {
(*callback)(value); (*callback)(args...);
if (alive_end != it)
*alive_end = std::move(*it);
++it; ++it;
++alive_end;
} }
else else
it = subscribers_.erase(it); ++it;
} }
subscribers.erase(alive_end, end);
for (auto & s : subscribers_)
subscribers.push_back(std::move(s));
subscribers_ = std::move(subscribers);
} }
private: private:
mutable std::list<std::weak_ptr<subscriber>> subscribers_; mutable std::vector<std::weak_ptr<subscriber>> subscribers_;
};
template <>
struct signal<void>
{
using subscriber = function<void()>;
using subscription_token = std::shared_ptr<void>;
[[nodiscard]] subscription_token subscribe(subscriber callback) const
{
auto token = std::make_shared<subscriber>(std::move(callback));
subscribers_.push_back(std::weak_ptr{token});
return token;
}
void operator()()
{
auto begin = subscribers_.begin();
auto end = subscribers_.end();
for (auto it = begin; it != end;)
{
if (auto callback = it->lock())
{
(*callback)();
++it;
}
else
it = subscribers_.erase(it);
}
}
private:
mutable std::list<std::weak_ptr<subscriber>> subscribers_;
}; };
} }