EnTT: src/entt/signal/sigh.hpp Source File

EnTT 3.16.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>
54 class 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(noexcept(allocator_type{}))
71 : sigh{allocator_type{}} {}
72
77 explicit sigh(const allocator_type &allocator) noexcept
78 : calls{allocator} {}
79
84 sigh(const sigh &other)
85 : calls{other.calls} {}
86
92 sigh(const sigh &other, const allocator_type &allocator)
93 : calls{other.calls, allocator} {}
94
99 sigh(sigh &&other) noexcept
100 : calls{std::move(other.calls)} {}
101
107 sigh(sigh &&other, const allocator_type &allocator)
108 : calls{std::move(other.calls), allocator} {}
109
111 ~sigh() = default;
112
118 sigh &operator=(const sigh &other) {
119 calls = other.calls;
120 return *this;
121 }
122
128 sigh &operator=(sigh &&other) noexcept {
129 swap(other);
130 return *this;
131 }
132
137 void swap(sigh &other) noexcept {
138 using std::swap;
139 swap(calls, other.calls);
140 }
141
146 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
147 return calls.get_allocator();
148 }
149
154 [[nodiscard]] size_type size() const noexcept {
155 return calls.size();
156 }
157
162 [[nodiscard]] bool empty() const noexcept {
163 return calls.empty();
164 }
165
173 void publish(Args... args) const {
174 for(auto pos = calls.size(); pos; --pos) {
175 calls[pos - 1u](args...);
176 }
177 }
178
193 template<typename Func>
194 void collect(Func func, Args... args) const {
195 for(auto pos = calls.size(); pos; --pos) {
196 if constexpr(std::is_void_v<Ret> || !std::is_invocable_v<Func, Ret>) {
197 calls[pos - 1u](args...);
198
199 if constexpr(std::is_invocable_r_v<bool, Func>) {
200 if(func()) {
201 break;
202 }
203 } else {
204 func();
205 }
206 } else {
207 if constexpr(std::is_invocable_r_v<bool, Func, Ret>) {
208 if(func(calls[pos - 1u](args...))) {
209 break;
210 }
211 } else {
212 func(calls[pos - 1u](args...));
213 }
214 }
215 }
216 }
217
218private:
219 container_type calls;
220};
221
229 class connection {
230 template<typename>
231 friend class sink;
232
233 connection(delegate<void(void *)> fn, void *ref)
234 : disconnect{fn}, signal{ref} {}
235
236public:
238 connection()
239 : signal{} {}
240
245 [[nodiscard]] explicit operator bool() const noexcept {
246 return static_cast<bool>(disconnect);
247 }
248
250 void release() {
251 if(disconnect) {
252 disconnect(signal);
253 disconnect.reset();
254 }
255 }
256
257private:
258 delegate<void(void *)> disconnect;
259 void *signal;
260};
261
271 struct scoped_connection {
273 scoped_connection() = default;
274
279 scoped_connection(const connection &other)
280 : conn{other} {}
281
283 scoped_connection(const scoped_connection &) = delete;
284
289 scoped_connection(scoped_connection &&other) noexcept
290 : conn{std::exchange(other.conn, {})} {}
291
293 ~scoped_connection() {
294 conn.release();
295 }
296
301 scoped_connection &operator=(const scoped_connection &) = delete;
302
308 scoped_connection &operator=(scoped_connection &&other) noexcept {
309 conn = std::exchange(other.conn, {});
310 return *this;
311 }
312
318 scoped_connection &operator=(connection other) {
319 conn = other;
320 return *this;
321 }
322
327 [[nodiscard]] explicit operator bool() const noexcept {
328 return static_cast<bool>(conn);
329 }
330
332 void release() {
333 conn.release();
334 }
335
336private:
337 connection conn;
338};
339
359template<typename Ret, typename... Args, typename Allocator>
360 class sink<sigh<Ret(Args...), Allocator>> {
361 using signal_type = sigh<Ret(Args...), Allocator>;
362 using delegate_type = typename signal_type::delegate_type;
363 using difference_type = typename signal_type::container_type::difference_type;
364
365 template<auto Candidate, typename Type>
366 static void release(Type value_or_instance, void *signal) {
367 sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>(value_or_instance);
368 }
369
370 template<auto Candidate>
371 static void release(void *signal) {
372 sink{*static_cast<signal_type *>(signal)}.disconnect<Candidate>();
373 }
374
375 template<typename Func>
376 void disconnect_if(Func callback) {
377 auto &ref = signal_or_assert();
378
379 for(auto pos = ref.calls.size(); pos; --pos) {
380 if(auto &elem = ref.calls[pos - 1u]; callback(elem)) {
381 elem = std::move(ref.calls.back());
382 ref.calls.pop_back();
383 }
384 }
385 }
386
387 [[nodiscard]] auto &signal_or_assert() const noexcept {
388 ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal");
389 return *signal;
390 }
391
392public:
394 sink() noexcept
395 : signal{} {}
396
401 sink(sigh<Ret(Args...), Allocator> &ref) noexcept
402 : signal{&ref} {}
403
408 [[nodiscard]] bool empty() const noexcept {
409 return signal_or_assert().calls.empty();
410 }
411
417 template<auto Candidate>
418 connection connect() {
419 disconnect<Candidate>();
420
421 delegate_type call{};
422 call.template connect<Candidate>();
423 signal_or_assert().calls.push_back(std::move(call));
424
425 delegate<void(void *)> conn{};
426 conn.template connect<&release<Candidate>>();
427 return {conn, signal};
428 }
429
446 template<auto Candidate, typename Type>
447 connection connect(Type &value_or_instance) {
448 disconnect<Candidate>(value_or_instance);
449
450 delegate_type call{};
451 call.template connect<Candidate>(value_or_instance);
452 signal_or_assert().calls.push_back(std::move(call));
453
454 delegate<void(void *)> conn{};
455 conn.template connect<&release<Candidate, Type &>>(value_or_instance);
456 return {conn, signal};
457 }
458
470 template<auto Candidate, typename Type>
471 connection connect(Type *value_or_instance) {
472 disconnect<Candidate>(value_or_instance);
473
474 delegate_type call{};
475 call.template connect<Candidate>(value_or_instance);
476 signal_or_assert().calls.push_back(std::move(call));
477
478 delegate<void(void *)> conn{};
479 conn.template connect<&release<Candidate, Type *>>(value_or_instance);
480 return {conn, signal};
481 }
482
487 template<auto Candidate>
488 void disconnect() {
489 delegate_type call{};
490 call.template connect<Candidate>();
491 disconnect_if([&call](const auto &elem) { return elem == call; });
492 }
493
509 template<auto Candidate, typename Type>
510 void disconnect(Type &value_or_instance) {
511 delegate_type call{};
512 call.template connect<Candidate>(value_or_instance);
513 disconnect_if([&call](const auto &elem) { return elem == call; });
514 }
515
526 template<auto Candidate, typename Type>
527 void disconnect(Type *value_or_instance) {
528 delegate_type call{};
529 call.template connect<Candidate>(value_or_instance);
530 disconnect_if([&call](const auto &elem) { return elem == call; });
531 }
532
538 void disconnect(const void *value_or_instance) {
539 ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance");
540 disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; });
541 }
542
544 void disconnect() {
545 signal_or_assert().calls.clear();
546 }
547
552 [[nodiscard]] explicit operator bool() const noexcept {
553 return signal != nullptr;
554 }
555
556private:
557 signal_type *signal;
558};
559
570template<typename Ret, typename... Args, typename Allocator>
571sink(sigh<Ret(Args...), Allocator> &) -> sink<sigh<Ret(Args...), Allocator>>;
572
573} // namespace entt
574
575#endif
entt::connection
Connection class.
Definition sigh.hpp:229
entt::connection::connection
connection()
Default constructor.
Definition sigh.hpp:238
entt::connection::release
void release()
Breaks the connection.
Definition sigh.hpp:250
entt::delegate
Basic delegate implementation.
Definition delegate.hpp:51
entt::sigh< Ret(Args...), Allocator >::publish
void publish(Args... args) const
Triggers a signal.
Definition sigh.hpp:173
entt::sigh< Ret(Args...), Allocator >::allocator_type
Allocator allocator_type
Allocator type.
Definition sigh.hpp:63
entt::sigh< Ret(Args...), Allocator >::sigh
sigh() noexcept(noexcept(allocator_type{}))
Default constructor.
Definition sigh.hpp:70
entt::sigh< Ret(Args...), Allocator >::sink_type
sink< sigh< Ret(Args...), Allocator > > sink_type
Sink type.
Definition sigh.hpp:67
entt::sigh< Ret(Args...), Allocator >::sigh
sigh(const sigh &other)
Copy constructor.
Definition sigh.hpp:84
entt::sigh< Ret(Args...), Allocator >::~sigh
~sigh()=default
Default destructor.
entt::sigh< Ret(Args...), Allocator >::operator=
sigh & operator=(sigh &&other) noexcept
Move assignment operator.
Definition sigh.hpp:128
entt::sigh< Ret(Args...), Allocator >::swap
void swap(sigh &other) noexcept
Exchanges the contents with those of a given signal handler.
Definition sigh.hpp:137
entt::sigh< Ret(Args...), Allocator >::size
size_type size() const noexcept
Number of listeners connected to the signal.
Definition sigh.hpp:154
entt::sigh< Ret(Args...), Allocator >::sigh
sigh(sigh &&other, const allocator_type &allocator)
Allocator-extended move constructor.
Definition sigh.hpp:107
entt::sigh< Ret(Args...), Allocator >::sigh
sigh(sigh &&other) noexcept
Move constructor.
Definition sigh.hpp:99
entt::sigh< Ret(Args...), Allocator >::get_allocator
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition sigh.hpp:146
entt::sigh< Ret(Args...), Allocator >::sigh
sigh(const allocator_type &allocator) noexcept
Constructs a signal handler with a given allocator.
Definition sigh.hpp:77
entt::sigh< Ret(Args...), Allocator >::empty
bool empty() const noexcept
Returns false if at least a listener is connected to the signal.
Definition sigh.hpp:162
entt::sigh< Ret(Args...), Allocator >::size_type
std::size_t size_type
Unsigned integer type.
Definition sigh.hpp:65
entt::sigh< Ret(Args...), Allocator >::operator=
sigh & operator=(const sigh &other)
Copy assignment operator.
Definition sigh.hpp:118
entt::sigh< Ret(Args...), Allocator >::sigh
sigh(const sigh &other, const allocator_type &allocator)
Allocator-extended copy constructor.
Definition sigh.hpp:92
entt::sigh< Ret(Args...), Allocator >::collect
void collect(Func func, Args... args) const
Collects return values from the listeners.
Definition sigh.hpp:194
entt::sigh
Unmanaged signal handler.
Definition fwd.hpp:25
entt::sink< sigh< Ret(Args...), Allocator > >::disconnect
void disconnect(const void *value_or_instance)
Disconnects free functions with payload or bound members from a signal.
Definition sigh.hpp:538
entt::sink< sigh< Ret(Args...), Allocator > >::sink
sink() noexcept
Constructs an invalid sink.
Definition sigh.hpp:394
entt::sink< sigh< Ret(Args...), Allocator > >::sink
sink(sigh< Ret(Args...), Allocator > &ref) noexcept
Constructs a sink that is allowed to modify a given signal.
Definition sigh.hpp:401
entt::sink< sigh< Ret(Args...), Allocator > >::connect
connection connect(Type &value_or_instance)
Connects a free function with payload or a bound member to a signal.
Definition sigh.hpp:447
entt::sink< sigh< Ret(Args...), Allocator > >::empty
bool empty() const noexcept
Returns false if at least a listener is connected to the sink.
Definition sigh.hpp:408
entt::sink< sigh< Ret(Args...), Allocator > >::disconnect
void disconnect()
Disconnects all the listeners from a signal.
Definition sigh.hpp:544
entt::sink< sigh< Ret(Args...), Allocator > >::disconnect
void disconnect()
Disconnects a free function or an unbound member from a signal.
Definition sigh.hpp:488
entt::sink< sigh< Ret(Args...), Allocator > >::connect
connection connect()
Connects a free function or an unbound member to a signal.
Definition sigh.hpp:418
entt::sink< sigh< Ret(Args...), Allocator > >::connect
connection connect(Type *value_or_instance)
Connects a free function with payload or a bound member to a signal.
Definition sigh.hpp:471
entt::sink< sigh< Ret(Args...), Allocator > >::disconnect
void disconnect(Type &value_or_instance)
Disconnects a free function with payload or a bound member from a signal.
Definition sigh.hpp:510
entt::sink< sigh< Ret(Args...), Allocator > >::disconnect
void disconnect(Type *value_or_instance)
Disconnects a free function with payload or a bound member from a signal.
Definition sigh.hpp:527
entt::sink
Sink class.
Definition fwd.hpp:22
entt
EnTT default namespace.
Definition dense_map.hpp:22
entt::swap
constexpr void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs) noexcept
Swaps two compressed pair objects.
Definition compressed_pair.hpp:243
entt::any_policy::ref
@ ref
Aliasing mode, non-const reference.
Definition fwd.hpp:19
entt::sink
sink(sigh< Ret(Args...), Allocator > &) -> sink< sigh< Ret(Args...), Allocator > >
Deduction guide.
entt::scoped_connection::scoped_connection
scoped_connection()=default
Default constructor.
entt::scoped_connection::release
void release()
Breaks the connection.
Definition sigh.hpp:332
entt::scoped_connection::scoped_connection
scoped_connection(scoped_connection &&other) noexcept
Move constructor.
Definition sigh.hpp:289
entt::scoped_connection::~scoped_connection
~scoped_connection()
Automatically breaks the link on destruction.
Definition sigh.hpp:293
entt::scoped_connection::operator=
scoped_connection & operator=(const scoped_connection &)=delete
Default copy assignment operator, deleted on purpose.
entt::scoped_connection::scoped_connection
scoped_connection(const connection &other)
Constructs a scoped connection from a basic connection.
Definition sigh.hpp:279
entt::scoped_connection::scoped_connection
scoped_connection(const scoped_connection &)=delete
Default copy constructor, deleted on purpose.
entt::scoped_connection::operator=
scoped_connection & operator=(connection other)
Acquires a connection.
Definition sigh.hpp:318
entt::scoped_connection::operator=
scoped_connection & operator=(scoped_connection &&other) noexcept
Move assignment operator.
Definition sigh.hpp:308