MetaImGUI 1.0.0
ImGui Application Template for C++20
Loading...
Searching...
No Matches
Signal.h
Go to the documentation of this file.
1/*
2 MetaImGUI
3 Copyright (C) 2026 A P Nicholson
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19#pragma once
20
21#include <cstddef>
22#include <functional>
23#include <memory>
24#include <unordered_map>
25#include <utility>
26#include <vector>
27
28namespace MetaImGUI {
29
30template <typename... Args>
31class Signal;
32
44public:
45 Connection() = default;
46 Connection(const Connection&) = delete;
47 Connection& operator=(const Connection&) = delete;
48
49 Connection(Connection&& other) noexcept : m_disconnect(std::exchange(other.m_disconnect, {})) {}
50
51 Connection& operator=(Connection&& other) noexcept {
52 if (this != &other) {
53 Reset();
54 m_disconnect = std::exchange(other.m_disconnect, {});
55 }
56 return *this;
57 }
58
60 Reset();
61 }
62
64 void Reset() {
65 if (m_disconnect) {
66 m_disconnect();
67 m_disconnect = nullptr;
68 }
69 }
70
72 void Release() {
73 m_disconnect = nullptr;
74 }
75
76 [[nodiscard]] bool IsConnected() const noexcept {
77 return static_cast<bool>(m_disconnect);
78 }
79
80private:
81 template <typename... Args>
82 friend class Signal;
83 explicit Connection(std::function<void()> disconnect) : m_disconnect(std::move(disconnect)) {}
84
85 std::function<void()> m_disconnect;
86};
87
99template <typename... Args>
100class Signal {
101public:
102 using SlotId = std::size_t;
103 using Slot = std::function<void(Args...)>;
104
105 Signal() = default;
106
107 // Non-copyable: a copy would have ambiguous ownership of the slot table.
108 Signal(const Signal&) = delete;
109 Signal& operator=(const Signal&) = delete;
110
111 // Non-movable: outstanding Connections capture a weak_ptr to our state,
112 // which a move would invalidate the address-stability assumption that
113 // simpler designs rely on. Heap-store the Signal if you need to move it.
114 Signal(Signal&&) = delete;
115 Signal& operator=(Signal&&) = delete;
116
117 ~Signal() = default;
118
122 [[nodiscard]] Connection Connect(Slot slot) {
123 const SlotId id = m_state->nextId++;
124 m_state->slots.emplace(id, std::move(slot));
125 std::weak_ptr<State> weak = m_state;
126 return Connection([weak, id]() {
127 if (auto state = weak.lock()) {
128 state->slots.erase(id);
129 }
130 });
131 }
132
139 void Emit(Args... args) const {
140 std::vector<Slot> snapshot;
141 snapshot.reserve(m_state->slots.size());
142 for (const auto& entry : m_state->slots) {
143 snapshot.push_back(entry.second);
144 }
145 for (auto& slot : snapshot) {
146 slot(args...);
147 }
148 }
149
150 [[nodiscard]] std::size_t SlotCount() const noexcept {
151 return m_state->slots.size();
152 }
153
154private:
155 struct State {
156 std::unordered_map<SlotId, Slot> slots;
157 SlotId nextId = 0;
158 };
159 std::shared_ptr<State> m_state = std::make_shared<State>();
160};
161
162} // namespace MetaImGUI
RAII handle that owns a single subscription to a Signal.
Definition Signal.h:43
void Release()
Detach without disconnecting — caller takes responsibility.
Definition Signal.h:72
Connection & operator=(const Connection &)=delete
Connection(Connection &&other) noexcept
Definition Signal.h:49
bool IsConnected() const noexcept
Definition Signal.h:76
Connection(const Connection &)=delete
Connection & operator=(Connection &&other) noexcept
Definition Signal.h:51
void Reset()
Disconnect now (idempotent).
Definition Signal.h:64
A single-threaded multicast event source.
Definition Signal.h:100
Connection Connect(Slot slot)
Subscribe a slot.
Definition Signal.h:122
std::size_t SlotCount() const noexcept
Definition Signal.h:150
std::function< void(Args...)> Slot
Definition Signal.h:103
void Emit(Args... args) const
Fire the signal.
Definition Signal.h:139
std::size_t SlotId
Definition Signal.h:102
Signal(const Signal &)=delete
Signal & operator=(const Signal &)=delete
Signal(Signal &&)=delete
Signal & operator=(Signal &&)=delete