#pragma once #include #include #include #include #include namespace observable_detail { struct HandlerTable { virtual ~HandlerTable() = default; virtual void erase(int id) = 0; }; } class Connection { public: Connection() = default; Connection(std::weak_ptr table, int id) : table_(std::move(table)), id_(id) {} Connection(Connection &&other) noexcept { *this = std::move(other); } Connection &operator=(Connection &&other) noexcept { if (this != &other) { disconnect(); table_ = std::move(other.table_); id_ = std::exchange(other.id_, -1); } return *this; } Connection(const Connection &) = delete; Connection &operator=(const Connection &) = delete; ~Connection() { disconnect(); } void disconnect() { if (auto table = table_.lock()) table->erase(id_); table_.reset(); id_ = -1; } private: std::weak_ptr table_; int id_ = -1; }; using Connections = std::vector; template class Observable { public: using Handler = std::function; Observable() = default; Observable(const Observable &) = delete; Observable &operator=(const Observable &) = delete; [[nodiscard]] Connection connect(Handler handler) { int id = table_->next_id++; table_->handlers.emplace(id, std::make_shared(std::move(handler))); return Connection(table_, id); } void operator()(Args... args) const { auto table = table_; std::vector ids; ids.reserve(table->handlers.size()); for (const auto &[id, _] : table->handlers) ids.push_back(id); for (int id : ids) { auto it = table->handlers.find(id); if (it == table->handlers.end()) continue; auto handler = it->second; (*handler)(args...); } } private: struct Table : observable_detail::HandlerTable { std::map> handlers; int next_id = 0; void erase(int id) override { handlers.erase(id); } }; std::shared_ptr table_ = std::make_shared
(); };