1#ifndef ENTT_SIGNAL_SIGH_HPP
2#define ENTT_SIGNAL_SIGH_HPP
22template<
typename Type>
34template<
typename Type,
typename Allocator>
53template<
typename Ret,
typename... Args,
typename Allocator>
54class sigh<Ret(Args...), Allocator> {
55 friend class sink<
sigh<Ret(Args...), Allocator>>;
57 using alloc_traits = std::allocator_traits<Allocator>;
59 using container_type = std::vector<delegate_type, typename alloc_traits::template rebind_alloc<delegate_type>>;
77 explicit sigh(
const allocator_type &allocator)
noexcept(std::is_nothrow_constructible_v<container_type, const allocator_type &>)
84 sigh(
const sigh &other)
noexcept(std::is_nothrow_copy_constructible_v<container_type>)
85 : calls{other.calls} {}
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} {}
99 sigh(
sigh &&other)
noexcept(std::is_nothrow_move_constructible_v<container_type>)
100 : calls{std::move(other.calls)} {}
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} {}
115 sigh &
operator=(
const sigh &other)
noexcept(std::is_nothrow_copy_assignable_v<container_type>) {
126 calls = std::move(other.calls);
134 void swap(
sigh &other)
noexcept(std::is_nothrow_swappable_v<container_type>) {
136 swap(calls, other.calls);
144 return calls.get_allocator();
159 [[nodiscard]]
bool empty() const noexcept {
160 return calls.empty();
171 for(
auto pos = calls.size(); pos; --pos) {
172 calls[pos - 1u](args...);
190 template<
typename Func>
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...);
196 if constexpr(std::is_invocable_r_v<bool, Func>) {
204 if constexpr(std::is_invocable_r_v<bool, Func, Ret>) {
205 if(func(calls[pos - 1u](args...))) {
209 func(calls[pos - 1u](args...));
216 container_type calls;
231 : disconnect{fn}, signal{
ref} {}
243 [[nodiscard]]
explicit operator bool() const noexcept {
244 return static_cast<bool>(disconnect);
288 : conn{std::exchange(other.conn, {})} {}
307 conn = std::exchange(other.conn, {});
317 conn = std::move(other);
325 [[nodiscard]]
explicit operator bool() const noexcept {
326 return static_cast<bool>(conn);
357template<
typename Ret,
typename... Args,
typename Allocator>
361 using difference_type =
typename signal_type::container_type::difference_type;
363 template<auto Cand
idate,
typename Type>
364 static void release(Type value_or_instance,
void *signal) {
365 sink{*
static_cast<signal_type *
>(signal)}.disconnect<Candidate>(value_or_instance);
368 template<auto Cand
idate>
369 static void release(
void *signal) {
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();
395 [[nodiscard]]
bool empty() const noexcept {
396 return signal->calls.empty();
407 template<
auto Candidate,
typename... Type>
409 disconnect<Candidate>(value_or_instance...);
411 delegate_type call{};
412 call.template connect<Candidate>(value_or_instance...);
413 signal->calls.push_back(std::move(call));
416 conn.template connect<&release<Candidate, Type...>>(value_or_instance...);
417 return {std::move(conn), signal};
427 template<
auto Candidate,
typename... Type>
429 delegate_type call{};
430 call.template connect<Candidate>(value_or_instance...);
431 disconnect_if([&call](
const auto &elem) {
return elem == call; });
440 if(value_or_instance) {
441 disconnect_if([value_or_instance](
const auto &elem) {
return elem.data() == value_or_instance; });
447 signal->calls.clear();
464template<
typename Ret,
typename... Args,
typename Allocator>
connection()
Default constructor.
void release()
Breaks the connection.
Utility class to use to send around functions and members.
Basic delegate implementation.
Unmanaged signal handler.
sigh(sigh &&other) noexcept(std::is_nothrow_move_constructible_v< container_type >)
Move constructor.
void publish(Args... args) const
Triggers a signal.
sigh & operator=(const sigh &other) noexcept(std::is_nothrow_copy_assignable_v< container_type >)
Copy assignment operator.
Allocator allocator_type
Allocator type.
void swap(sigh &other) noexcept(std::is_nothrow_swappable_v< container_type >)
Exchanges the contents with those of a given signal handler.
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.
sigh(const sigh &other) noexcept(std::is_nothrow_copy_constructible_v< container_type >)
Copy constructor.
sigh & operator=(sigh &&other) noexcept(std::is_nothrow_move_assignable_v< container_type >)
Move assignment operator.
size_type size() const noexcept
Number of listeners connected to the signal.
sigh() noexcept(std::is_nothrow_default_constructible_v< allocator_type > &&std::is_nothrow_constructible_v< container_type, const allocator_type & >)
Default constructor.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
sigh(sigh &&other, const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v< container_type, container_type &&, const allocator_type & >)
Allocator-extended move constructor.
bool empty() const noexcept
Returns false if at least a listener is connected to the signal.
std::size_t size_type
Unsigned integer type.
void collect(Func func, Args... args) const
Collects return values from the listeners.
sigh(const allocator_type &allocator) noexcept(std::is_nothrow_constructible_v< container_type, const allocator_type & >)
Constructs a signal handler with a given allocator.
Unmanaged signal handler.
void disconnect(const void *value_or_instance)
Disconnects free functions with payload or bound members from a signal.
sink(sigh< Ret(Args...), Allocator > &ref) noexcept
Constructs a sink that is allowed to modify a given signal.
bool empty() const noexcept
Returns false if at least a listener is connected to the sink.
void disconnect()
Disconnects all the listeners from a signal.
connection connect(Type &&...value_or_instance)
Connects a free function (with or without payload), a bound or an unbound member to a signal.
void disconnect(Type &&...value_or_instance)
Disconnects a free function (with or without payload), a bound or an unbound member from a signal.
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()=default
Default constructor.
void release()
Breaks the connection.
scoped_connection(scoped_connection &&other) noexcept
Move constructor.
~scoped_connection()
Automatically breaks the link on destruction.
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.
scoped_connection(const scoped_connection &)=delete
Default copy constructor, deleted on purpose.
scoped_connection & operator=(connection other)
Acquires a connection.
scoped_connection & operator=(scoped_connection &&other) noexcept
Move assignment operator.