16#include "AUI/Common/ADeque.h"
17#include "AUI/Common/AObject.h"
18#include "AUI/Thread/AMutex.h"
19#include "AAbstractSignal.h"
20#include "AUI/Traits/values.h"
22namespace aui::detail::signal {
23template<
size_t I,
typename TupleInitial,
typename TupleAll>
24auto resizeTuple(TupleInitial initial, TupleAll all) {
25 if constexpr (I == 0) {
28 return resizeTuple<I - 1>(std::tuple_cat(initial, std::make_tuple(std::get<std::tuple_size_v<TupleInitial>>(all))), all);
32template<aui::not_overloaded_lambda Lambda,
typename... Args>
33inline void callIgnoringExcessArgs(Lambda&& lambda,
const Args&...
args) {
34 static constexpr size_t EXPECTED_ARG_COUNT = std::tuple_size_v<typename lambda_info<std::decay_t<Lambda>>
::args>;
35 auto smallerTuple = resizeTuple<EXPECTED_ARG_COUNT>(std::make_tuple(), std::make_tuple(std::cref(
args)...));
36 std::apply(lambda, smallerTuple);
39template <
typename Projection>
40struct projection_info {
42 aui::pointer_to_member<Projection> || aui::not_overloaded_lambda<Projection> ||
43 aui::function_pointer<Projection>,
44 "projection is required to be an pointer-to-member or not overloaded lambda or function pointer");
47template<aui::po
inter_to_member Projection>
48struct projection_info<Projection> {
50 template <
typename... T>
53 template <
typename First,
typename... T>
54 struct cat<First, std::tuple<T...>> {
55 using type = std::tuple<First, T...>;
59 using info =
typename aui::member<Projection>;
60 using return_t =
typename info::return_t;
61 using args =
typename cat<typename info::clazz&, typename info::args>::type;
64template<aui::not_overloaded_lambda Projection>
65struct projection_info<Projection> {
66 using info =
typename aui::lambda_info<Projection>;
67 using return_t =
typename info::return_t;
68 using args =
typename info::args;
71template<aui::function_po
inter Projection>
72struct projection_info<Projection> {
73 using info =
typename aui::function_info<Projection>;
74 using return_t =
typename info::return_t;
75 using args =
typename info::args;
79template<
typename AnySignal,
81struct ProjectedSignal {
82 friend class ::AObject;
85 std::decay_t<Projection> projection;
87 ProjectedSignal(AnySignal& base, Projection projection) : base(base), projection(std::move(projection)) {}
89 using projection_info_t = aui::detail::signal::projection_info<Projection>;
91 using projection_returns_t =
typename projection_info_t::return_t;
93 static constexpr bool IS_PROJECTION_RETURNS_TUPLE = aui::is_tuple<projection_returns_t>;
95 using emits_args_t = std::conditional_t<IS_PROJECTION_RETURNS_TUPLE,
97 std::tuple<projection_returns_t>>;
99 template <convertible_to<AObjectBase*> Object, not_overloaded_lambda Lambda>
100 void connect(Object objectBase, Lambda&& lambda) {
103 tuple_visitor<typename projection_info_t::args>::for_each_all([&]<
typename... ProjectionArgs>() {
104 return [invocable = std::forward<Lambda>(lambda),
105 projection = projection](
const std::decay_t<ProjectionArgs>&...
args) {
106 auto result = std::invoke(projection,
args...);
107 if constexpr (IS_PROJECTION_RETURNS_TUPLE) {
108 std::apply(invocable, std::move(result));
110 std::invoke(invocable, std::move(result));
116 operator bool()
const {
121 template <not_overloaded_lambda Lambda>
122 auto makeRawInvocable(Lambda&& lambda)
const {
123 return tuple_visitor<emits_args_t>::for_each_all([&]<
typename... ProjectionResult>() {
124 return [lambda = std::forward<Lambda>(lambda)](
const std::decay_t<ProjectionResult>&...
args){
125 aui::detail::signal::callIgnoringExcessArgs(lambda,
args...);
133template<
typename... Args>
136 friend class AObject;
137 friend class UIDataBindingTest_APropertyPrecomputed_Complex_Test;
138 template<
typename AnySignal,
140 friend struct aui::detail::signal::ProjectedSignal;
142 template <
typename T>
143 friend class AWatchable;
145 using func_t = std::function<void(Args...)>;
146 using emits_args_t = std::tuple<Args...>;
148 template<
typename Projection>
149 auto projected(Projection&& projection)
const {
150 return aui::detail::signal::ProjectedSignal(
const_cast<ASignal&
>(*
this), std::forward<Projection>(projection));
155 std::tuple<Args...> args;
157 void invokeSignal(AObject* emitter) {
158 signal.invokeSignal(emitter, std::move(args));
163 return {*
this, std::make_tuple(std::move(args)...)};
167 ASignal(ASignal&&) noexcept = default;
168 ASignal(const ASignal&) = delete;
170 virtual ~ASignal() noexcept
172 for (
const _<slot>& slot : mSlots)
174 unlinkSlot(slot->objectBase);
183 operator bool()
const {
184 return !mSlots.empty();
187 void clearAllConnections() const noexcept
override
189 clearAllConnectionsIf([](
const auto&){
return true; });
191 void clearAllConnectionsWith(aui::no_escape<AObjectBase>
object)
const noexcept override
193 clearAllConnectionsIf([&](
const _<slot>& p){
return p->objectBase ==
object.ptr(); });
197 bool hasConnectionsWith(aui::no_escape<AObjectBase>
object)
const noexcept override {
198 return std::any_of(mSlots.begin(), mSlots.end(), [&](
const _<slot>& s) {
199 return s->objectBase == object.ptr();
206 AObjectBase* objectBase;
209 bool isDisconnected =
false;
212 mutable AVector<_<slot>> mSlots;
214 void invokeSignal(AObject* emitter,
const std::tuple<Args...>& args = {});
216 template <aui::convertible_to<AObjectBase*> Object, aui::not_overloaded_lambda Lambda>
217 void connect(Object objectBase, Lambda&& lambda) {
218 AObject*
object =
nullptr;
219 if constexpr (
requires {
object = objectBase; }) {
222 mSlots.push_back(_new<slot>(slot { objectBase, object, makeRawInvocable(std::forward<Lambda>(lambda)) }));
223 linkSlot(objectBase);
226 void addGenericObserver(AObjectBase*
object, std::function<
void()> observer)
override {
227 connect(
object, [observer = std::move(observer)] {
232 template<aui::not_overloaded_lambda Lambda>
233 auto makeRawInvocable(Lambda&& lambda)
const
235 return [lambda = std::forward<Lambda>(lambda)](
const Args&...
args){
236 aui::detail::signal::callIgnoringExcessArgs(lambda,
args...);
242 template<
typename Predicate>
243 void clearAllConnectionsIf(Predicate&& predicate)
const noexcept {
248 AVector<func_t> slotsToRemove;
250 slotsToRemove.reserve(mSlots.size());
251 mSlots.
removeIf([&slotsToRemove, predicate = std::move(predicate)](
const _<slot>& p) {
253 slotsToRemove << std::move(p->func);
259 slotsToRemove.clear();
262#include <AUI/Thread/AThread.h>
264template <
typename ... Args>
265void ASignal<Args...>::invokeSignal(
AObject* emitter,
const std::tuple<Args...>& args)
272 if (emitter !=
nullptr) {
273 if (
auto sharedPtr = weakPtrFromObject(emitter).lock()) {
274 emitterPtr = std::move(
static_cast<_<AObject>>(sharedPtr));
278 auto slots = std::move(mSlots);
279 for (
auto i = slots.begin(); i != slots.end();)
283 if (
slot.object !=
nullptr) {
284 receiverWeakPtr = weakPtrFromObject(
slot.object);
293 if (receiverWeakPtr.lock() !=
nullptr) {
294 slot.object->getThread()->enqueue(
295 [
this, receiverWeakPtr = std::move(receiverWeakPtr),
slot = *i, args = args]() {
296 if (
slot->isDisconnected) {
299 if (
auto receiverPtr = receiverWeakPtr.lock()) {
300 AAbstractSignal::isDisconnected() =
false;
301 (std::apply)(
slot->func, args);
302 if (AAbstractSignal::isDisconnected()) {
303 unlinkSlot(receiverPtr.get());
304 slot->isDisconnected =
true;
314 AAbstractSignal::isDisconnected() =
false;
316 if (
auto sharedPtr = receiverWeakPtr.lock()) {
317 receiverPtr = std::move(sharedPtr);
320 (std::apply)(
slot.func, args);
321 if (AAbstractSignal::isDisconnected()) {
322 unlinkSlot(
slot.object);
331 if (mSlots.empty()) {
332 mSlots = std::move(slots);
335 mSlots.insert(mSlots.begin(), std::make_move_iterator(slots.begin()), std::make_move_iterator(slots.end()));
338 AAbstractSignal::isDisconnected() =
false;
347template<
typename... Args>
350#define signals public
Base class for signal.
Definition AAbstractSignal.h:368
A base object class.
Definition AObject.h:39
static _< AAbstractThread > current()
Definition AThread.cpp:197
void removeIf(Predicate &&predicate) noexcept
Definition AVector.h:334
AOptional< std::size_t > removeFirst(const StoredType &item) noexcept
Definition AVector.h:130
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:178
API_AUI_CORE const ACommandLineArgs & args() noexcept
Definition OSAndroid.cpp:29
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:348
#define slot(v)
Passes some variable and type of the variable separated by comma. It's convenient to use with the con...
Definition kAUI.h:88
#define AUI_MARK_AS_USED(variable)
Marks the variable as being used.
Definition macros.h:50
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:51