13#include "../executor.hpp"
27namespace morph::bridge::detail {
43template <
typename Binding>
44class SubscriptionRegistry {
58 void addSubscription(
const std::shared_ptr<Binding>& binding, std::type_index type,
59 std::function<
void(
const std::any&)> sink, ::morph::exec::IExecutor* exec) {
60 for (
auto& entry : _subscriptions) {
61 auto owner = entry.binding.lock();
62 if (owner && owner.get() == binding.get() && entry.type == type) {
63 entry.sink = std::move(sink);
68 _subscriptions.emplace_back(binding, type, std::move(sink), exec);
69 _count.store(_subscriptions.size(), std::memory_order_relaxed);
75 void removeSubscription(
const std::shared_ptr<Binding>& binding, std::type_index type) {
76 std::erase_if(_subscriptions, [&](
const Entry& entry) {
77 auto owner = entry.binding.lock();
78 return !owner || (owner.get() == binding.get() && entry.type == type);
80 _count.store(_subscriptions.size(), std::memory_order_relaxed);
89 [[nodiscard]]
bool hasSubscribers() const noexcept {
return _count.load(std::memory_order_relaxed) != 0U; }
108 void publishResult(::morph::exec::detail::ModelId mid, std::type_index type,
const std::any& value) {
109 std::erase_if(_subscriptions, [](
const Entry& entry) {
return entry.binding.expired(); });
110 _count.store(_subscriptions.size(), std::memory_order_relaxed);
111 std::vector<std::pair<std::function<void(
const std::any&)>, ::morph::exec::IExecutor*>> targets;
112 for (
const auto& entry : _subscriptions) {
113 auto owner = entry.binding.lock();
114 if (owner && entry.type == type && owner->currentId.load() == mid.v && entry.sink) {
115 targets.emplace_back(entry.sink, entry.exec);
118 for (
auto& [sink, exec] : targets) {
119 if (exec !=
nullptr) {
120 exec->
post([sink, value] { sink(value); });
129 [[nodiscard]] std::size_t size()
const {
return _subscriptions.size(); }
133 Entry(std::weak_ptr<Binding> bindingIn, std::type_index typeIn, std::function<
void(
const std::any&)> sinkIn,
134 ::morph::exec::IExecutor* execIn)
135 : binding{std::move(bindingIn)}, type{typeIn}, sink{std::move(sinkIn)}, exec{execIn} {}
137 std::weak_ptr<Binding> binding;
138 std::type_index type;
139 std::function<void(
const std::any&)> sink;
140 ::morph::exec::IExecutor* exec =
nullptr;
143 std::vector<Entry> _subscriptions;
144 std::atomic<std::size_t> _count{0};
morph's strands: one per model instance, from core-cpp's core::async::KeyedStrands,...
virtual void post(std::function< void()> task)=0
Schedules task for asynchronous execution.