EnTT 3.13.0
Loading...
Searching...
No Matches
sigh.hpp
1#ifndef ENTT_SIGNAL_SIGH_HPP
2#define ENTT_SIGNAL_SIGH_HPP
3
4#include <cstddef>
5#include <memory>
6#include <type_traits>
7#include <utility>
8#include <vector>
9#include "delegate.hpp"
10#include "fwd.hpp"
11
12namespace entt {
13
22template<typename Type>
23class sink;
24
34template<typename Type, typename Allocator>
35class sigh;
36
53template<typename Ret, typename... Args, typename Allocator>
54class sigh<Ret(Args...), Allocator> {
55 friend class sink<sigh<Ret(Args...), Allocator>>;
56
57 using alloc_traits = std::allocator_traits<Allocator>;
58 using delegate_type = delegate<Ret(Args...)>;
59 using container_type = std::vector<delegate_type, typename alloc_traits::template rebind_alloc<delegate_type>>;
60
61public:
63 using allocator_type = Allocator;
65 using size_type = std::size_t;
67 using sink_type = sink<sigh<Ret(Args...), Allocator>>;
68
70 sigh() noexcept(std::is_nothrow_default_constructible_v<allocator_type> &&std::is_nothrow_constructible_v<container_type, const allocator_type &>)
71 : sigh{allocator_type{}} {}
72
77 explicit sigh(const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v<container_type, const allocator_type &>)
78 : calls{allocator} {}
79
84 sigh(const sigh &other) noexcept(std::is_nothrow_copy_constructible_v<container_type>)
85 : calls{other.calls} {}
86
92 sigh(const sigh &other, const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v<container_type, const container_type &, const allocator_type &>)
93 : calls{other.calls, allocator} {}
94
99 sigh(sigh &&other) noexcept(std::is_nothrow_move_constructible_v<container_type>)
100 : calls{std::move(other.calls)} {}
101
107 sigh(sigh &&other, const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v<container_type, container_type &&, const allocator_type &>)
108 : calls{std::move(other.calls), allocator} {}
109
115 sigh &operator=(const sigh &other) noexcept(std::is_nothrow_copy_assignable_v<container_type>) {
116 calls = other.calls;
117 return *this;
118 }
119
125 sigh &operator=(sigh &&other) noexcept(std::is_nothrow_move_assignable_v<container_type>) {
126 calls = std::move(other.calls);
127 return *this;
128 }
129
134 void swap(sigh &other) noexcept(std::is_nothrow_swappable_v<container_type>) {
135 using std::swap;
136 swap(calls, other.calls);
137 }
138
143 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
144 return calls.get_allocator();
145 }
146
151 [[nodiscard]] size_type size() const noexcept {
152 return calls.size();
153 }
154
159 [[nodiscard]] bool empty() const noexcept {
160 return calls.empty();
161 }
162
170 void publish(Args... args) const {
171 for(auto pos = calls.size(); pos; --pos) {
172 calls[pos - 1u](args...);
173 }
174 }
175
190 template<typename Func>
191 void collect(Func func, Args... args) const {
192 for(auto pos = calls.size(); pos; --pos) {
193 if constexpr(std::is_void_v<Ret> || !std::is_invocable_v<Func, Ret>) {
194 calls[pos - 1u](args...);
195
196 if constexpr(std::is_invocable_r_v<bool, Func>) {
197 if(func()) {
198 break;
199 }
200 } else {
201 func();
202 }
203 } else {
204 if constexpr(std::is_invocable_r_v<bool, Func, Ret>) {
205 if(func(calls[pos - 1u](args...))) {
206 break;
207 }
208 } else {
209 func(calls[pos - 1u](args...));
210 }
211 }
212 }
213 }
214
215private:
216 container_type calls;
217};
218
227 template<typename>
228 friend class sink;
229
230 connection(delegate<void(void *)> fn, void *ref)
231 : disconnect{fn}, signal{ref} {}
232
233public:
236 : disconnect{},
237 signal{} {}
238
243 [[nodiscard]] explicit operator bool() const noexcept {
244 return static_cast<bool>(disconnect);
245 }
246
248 void release() {
249 if(disconnect) {
250 disconnect(signal);
251 disconnect.reset();
252 }
253 }
254
255private:
256 delegate<void(void *)> disconnect;
257 void *signal;
258};
259
271 scoped_connection() = default;
272
278 : conn{other} {}
279
282
288 : conn{std::exchange(other.conn, {})} {}
289
292 conn.release();
293 }
294
300
307 conn = std::exchange(other.conn, {});
308 return *this;
309 }
310
317 conn = std::move(other);
318 return *this;
319 }
320
325 [[nodiscard]] explicit operator bool() const noexcept {
326 return static_cast<bool>(conn);
327 }
328
330 void release() {
331 conn.release();
332 }
333
334private:
335 connection conn;
336};
337
357template<typename Ret, typename... Args, typename Allocator>
358class sink<sigh<Ret(Args...), Allocator>> {
359 using signal_type = sigh<Ret(Args...), Allocator>;
360 using delegate_type = typename signal_type::delegate_type;
361 using difference_type = typename signal_type::container_type::difference_type;
362
363 template<auto Candidate, typename Type>
364 static void release(Type value_or_instance, void *signal) {
365 sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
366 }
367
368 template<auto Candidate>
369 static void release(void *signal) {
370 sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>();
371 }
372
373 template<typename Func>
374 void disconnect_if(Func callback) {
375 for(auto pos = signal->calls.size(); pos; --pos) {
376 if(auto &elem = signal->calls[pos - 1u]; callback(elem)) {
377 elem = std::move(signal->calls.back());
378 signal->calls.pop_back();
379 }
380 }
381 }
382
383public:
388 sink(sigh<Ret(Args...), Allocator> &ref) noexcept
389 : signal{&ref} {}
390
395 [[nodiscard]] bool empty() const noexcept {
396 return signal->calls.empty();
397 }
398
407 template<auto Candidate, typename... Type>
408 connection connect(Type &&...value_or_instance) {
409 disconnect<Candidate>(value_or_instance...);
410
411 delegate_type call{};
412 call.template connect<Candidate>(value_or_instance...);
413 signal->calls.push_back(std::move(call));
414
415 delegate<void(void *)> conn{};
416 conn.template connect<&release<Candidate, Type...>>(value_or_instance...);
417 return {std::move(conn), signal};
418 }
419
427 template<auto Candidate, typename... Type>
428 void disconnect(Type &&...value_or_instance) {
429 delegate_type call{};
430 call.template connect<Candidate>(value_or_instance...);
431 disconnect_if([&call](const auto &elem) { return elem == call; });
432 }
433
439 void disconnect(const void *value_or_instance) {
440 if(value_or_instance) {
441 disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; });
442 }
443 }
444
446 void disconnect() {
447 signal->calls.clear();
448 }
449
450private:
451 signal_type *signal;
452};
453
464template<typename Ret, typename... Args, typename Allocator>
465sink(sigh<Ret(Args...), Allocator> &) -> sink<sigh<Ret(Args...), Allocator>>;
466
467} // namespace entt
468
469#endif
Connection class.
Definition sigh.hpp:226
connection()
Default constructor.
Definition sigh.hpp:235
void release()
Breaks the connection.
Definition sigh.hpp:248
Utility class to use to send around functions and members.
Definition delegate.hpp:66
Basic delegate implementation.
Definition delegate.hpp:51
Unmanaged signal handler.
Definition sigh.hpp:54
sigh(sigh &&other) noexcept(std::is_nothrow_move_constructible_v< container_type >)
Move constructor.
Definition sigh.hpp:99
void publish(Args... args) const
Triggers a signal.
Definition sigh.hpp:170
sigh & operator=(const sigh &other) noexcept(std::is_nothrow_copy_assignable_v< container_type >)
Copy assignment operator.
Definition sigh.hpp:115
Allocator allocator_type
Allocator type.
Definition sigh.hpp:63
void swap(sigh &other) noexcept(std::is_nothrow_swappable_v< container_type >)
Exchanges the contents with those of a given signal handler.
Definition sigh.hpp:134
sigh(const sigh &other, const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v< container_type, const container_type &, const allocator_type & >)
Allocator-extended copy constructor.
Definition sigh.hpp:92
sigh(const sigh &other) noexcept(std::is_nothrow_copy_constructible_v< container_type >)
Copy constructor.
Definition sigh.hpp:84
sigh & operator=(sigh &&other) noexcept(std::is_nothrow_move_assignable_v< container_type >)
Move assignment operator.
Definition sigh.hpp:125
size_type size() const noexcept
Number of listeners connected to the signal.
Definition sigh.hpp:151
sigh() noexcept(std::is_nothrow_default_constructible_v< allocator_type > &&std::is_nothrow_constructible_v< container_type, const allocator_type & >)
Default constructor.
Definition sigh.hpp:70
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition sigh.hpp:143
sigh(sigh &&other, const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v< container_type, container_type &&, const allocator_type & >)
Allocator-extended move constructor.
Definition sigh.hpp:107
bool empty() const noexcept
Returns false if at least a listener is connected to the signal.
Definition sigh.hpp:159
std::size_t size_type
Unsigned integer type.
Definition sigh.hpp:65
void collect(Func func, Args... args) const
Collects return values from the listeners.
Definition sigh.hpp:191
sigh(const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v< container_type, const allocator_type & >)
Constructs a signal handler with a given allocator.
Definition sigh.hpp:77
Unmanaged signal handler.
Definition fwd.hpp:25
void disconnect(const void *value_or_instance)
Disconnects free functions with payload or bound members from a signal.
Definition sigh.hpp:439
sink(sigh< Ret(Args...), Allocator > &ref) noexcept
Constructs a sink that is allowed to modify a given signal.
Definition sigh.hpp:388
bool empty() const noexcept
Returns false if at least a listener is connected to the sink.
Definition sigh.hpp:395
void disconnect()
Disconnects all the listeners from a signal.
Definition sigh.hpp:446
connection connect(Type &&...value_or_instance)
Connects a free function (with or without payload), a bound or an unbound member to a signal.
Definition sigh.hpp:408
void disconnect(Type &&...value_or_instance)
Disconnects a free function (with or without payload), a bound or an unbound member from a signal.
Definition sigh.hpp:428
Sink class.
Definition fwd.hpp:22
EnTT default namespace.
Definition dense_map.hpp:21
constexpr void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs)
Swaps two compressed pair objects.
@ ref
Aliasing mode, the object points to a non-const element.
sink(sigh< Ret(Args...), Allocator > &) -> sink< sigh< Ret(Args...), Allocator > >
Deduction guide.
Scoped connection class.
Definition sigh.hpp:269
scoped_connection()=default
Default constructor.
void release()
Breaks the connection.
Definition sigh.hpp:330
scoped_connection(scoped_connection &&other) noexcept
Move constructor.
Definition sigh.hpp:287
~scoped_connection()
Automatically breaks the link on destruction.
Definition sigh.hpp:291
scoped_connection & operator=(const scoped_connection &)=delete
Default copy assignment operator, deleted on purpose.
scoped_connection(const connection &other)
Constructs a scoped connection from a basic connection.
Definition sigh.hpp:277
scoped_connection(const scoped_connection &)=delete
Default copy constructor, deleted on purpose.
scoped_connection & operator=(connection other)
Acquires a connection.
Definition sigh.hpp:316
scoped_connection & operator=(scoped_connection &&other) noexcept
Move assignment operator.
Definition sigh.hpp:306