diff --git a/Telegram/SourceFiles/base/lambda_guard.h b/Telegram/SourceFiles/base/lambda_guard.h index 735dfe486..da835b8e2 100644 --- a/Telegram/SourceFiles/base/lambda_guard.h +++ b/Telegram/SourceFiles/base/lambda_guard.h @@ -21,150 +21,107 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include <QPointer> +#include "base/weak_unique_ptr.h" + +// Guard lambda call by QObject* or enable_weak_from_this* pointers. namespace base { - -// Guard lambda call by one or many QObject* weak pointers. - namespace lambda_internal { -template <int N, typename Lambda> -class guard_data { +template <typename Lambda> +class guard_with_QObject { public: - template <typename ...PointersAndLambda> - inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward<PointersAndLambda>(qobjectsAndLambda)...)) { - } - - inline guard_data(const guard_data &other) : _lambda(other._lambda) { - for (auto i = 0; i != N; ++i) { - _pointers[i] = other._pointers[i]; - } + template <typename OtherLambda> + guard_with_QObject(const QObject *object, OtherLambda &&other) + : _guard(object) + , _callable(std::forward<OtherLambda>(other)) { } template < - typename ...Args, - typename return_type = decltype(std::declval<Lambda>()(std::declval<Args>()...))> - inline auto operator()(Args&&... args) { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward<Args>(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))> + Return operator()(OtherArgs &&...args) { + return _guard + ? _callable(std::forward<OtherArgs>(args)...) + : Return(); } template < - typename ...Args, - typename return_type = decltype(std::declval<Lambda>()(std::declval<Args>()...))> - inline auto operator()(Args&&... args) const { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward<Args>(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))> + Return operator()(OtherArgs &&...args) const { + return _guard + ? _callable(std::forward<OtherArgs>(args)...) + : Return(); } private: - template <typename ...PointersAndLambda> - Lambda init(QPointer<QObject> *pointers, QObject *qobject, PointersAndLambda&&... qobjectsAndLambda) { - *pointers = qobject; - return init(++pointers, std::forward<PointersAndLambda>(qobjectsAndLambda)...); - } - Lambda init(QPointer<QObject> *pointers, Lambda &&lambda) { - return std::move(lambda); - } - - QPointer<QObject> _pointers[N]; - mutable Lambda _lambda; + QPointer<const QObject> _guard; + Lambda _callable; }; -template <int N, typename Lambda> -struct lambda_call_type<guard_data<N, Lambda>> { - using type = lambda_call_type_t<Lambda>; -}; - -template <int N, typename Lambda> -class guard { +template <typename Lambda> +class guard_with_weak { public: - template <typename Pointer, typename Other, typename ...PointersAndLambda> - inline guard(Pointer &&qobject, Other &&other, PointersAndLambda&&... qobjectsAndLambda) : _data(std::make_unique<guard_data<N, Lambda>>(std::forward<Pointer>(qobject), std::forward<Other>(other), std::forward<PointersAndLambda>(qobjectsAndLambda)...)) { - static_assert(1 + 1 + sizeof...(PointersAndLambda) == N + 1, "Wrong argument count!"); - } - - inline guard(const guard &other) : _data(std::make_unique<guard_data<N, Lambda>>(static_cast<const guard_data<N, Lambda> &>(*other._data))) { - } - - inline guard(guard &&other) : _data(std::move(other._data)) { - } - - inline guard &operator=(const guard &&other) { - _data = std::move(other._data); - return *this; - } - - inline guard &operator=(guard &&other) { - _data = std::move(other._data); - return *this; + template <typename OtherLambda> + guard_with_weak( + const base::enable_weak_from_this *object, + OtherLambda &&other) + : _guard(base::make_weak_unique(object)) + , _callable(std::forward<OtherLambda>(other)) { } template < - typename ...Args, - typename = decltype(std::declval<Lambda>()(std::declval<Args>()...))> - inline decltype(auto) operator()(Args&&... args) { - return (*_data)(std::forward<Args>(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))> + Return operator()(OtherArgs &&...args) { + return _guard + ? _callable(std::forward<OtherArgs>(args)...) + : Return{}; } template < - typename ...Args, - typename = decltype(std::declval<Lambda>()(std::declval<Args>()...))> - inline decltype(auto) operator()(Args&&... args) const { - return (*_data)(std::forward<Args>(args)...); - } - - bool isNull() const { - return !_data; + typename ...OtherArgs, + typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))> + Return operator()(OtherArgs &&...args) const { + return _guard + ? _callable(std::forward<OtherArgs>(args)...) + : Return{}; } private: - mutable std::unique_ptr<guard_data<N, Lambda>> _data; + base::weak_unique_ptr<const base::enable_weak_from_this> _guard; + Lambda _callable; }; -template <int N, typename Lambda> -struct lambda_call_type<guard<N, Lambda>> { +template <typename Lambda> +struct lambda_call_type<guard_with_QObject<Lambda>> { using type = lambda_call_type_t<Lambda>; }; -template <int N, int K, typename ...PointersAndLambda> -struct guard_type; - -template <int N, int K, typename Pointer, typename ...PointersAndLambda> -struct guard_type<N, K, Pointer, PointersAndLambda...> { - using type = typename guard_type<N, K - 1, PointersAndLambda...>::type; +template <typename Lambda> +struct lambda_call_type<guard_with_weak<Lambda>> { + using type = lambda_call_type_t<Lambda>; }; -template <int N, typename Lambda> -struct guard_type<N, 0, Lambda> { - using type = guard<N, std::decay_t<Lambda>>; -}; - -template <typename ...PointersAndLambda> -struct guard_type_helper { - static constexpr int N = sizeof...(PointersAndLambda); - using type = typename guard_type<N - 1, N - 1, PointersAndLambda...>::type; -}; - -template <typename ...PointersAndLambda> -using guard_t = typename guard_type_helper<PointersAndLambda...>::type; - } // namespace lambda_internal -template <typename ...PointersAndLambda> -inline lambda_internal::guard_t<PointersAndLambda...> lambda_guarded(PointersAndLambda&&... qobjectsAndLambda) { - static_assert(sizeof...(PointersAndLambda) > 0, "Lambda should be passed here."); - return lambda_internal::guard_t<PointersAndLambda...>(std::forward<PointersAndLambda>(qobjectsAndLambda)...); +template <typename Lambda> +inline auto lambda_guarded(const QObject *object, Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_QObject< + std::decay_t<Lambda>>; + return Guarded(object, std::forward<Lambda>(lambda)); +} + +template <typename Lambda> +inline auto lambda_guarded( + const base::enable_weak_from_this *object, + Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_weak< + std::decay_t<Lambda>>; + return Guarded(object, std::forward<Lambda>(lambda)); } } // namespace base diff --git a/Telegram/SourceFiles/base/weak_unique_ptr.h b/Telegram/SourceFiles/base/weak_unique_ptr.h index dd74f6d43..d16ff02d9 100644 --- a/Telegram/SourceFiles/base/weak_unique_ptr.h +++ b/Telegram/SourceFiles/base/weak_unique_ptr.h @@ -45,14 +45,16 @@ private: template <typename Child> friend class weak_unique_ptr; - std::shared_ptr<enable_weak_from_this*> getGuarded() { + std::shared_ptr<enable_weak_from_this*> getGuarded() const { if (!_guarded) { - _guarded = std::make_shared<enable_weak_from_this*>(static_cast<enable_weak_from_this*>(this)); + _guarded = std::make_shared<enable_weak_from_this*>( + const_cast<enable_weak_from_this*>( + static_cast<const enable_weak_from_this*>(this))); } return _guarded; } - std::shared_ptr<enable_weak_from_this*> _guarded; + mutable std::shared_ptr<enable_weak_from_this*> _guarded; }; @@ -60,13 +62,19 @@ template <typename T> class weak_unique_ptr { public: weak_unique_ptr() = default; - weak_unique_ptr(T *value) : _guarded(value ? value->getGuarded() : std::shared_ptr<enable_weak_from_this*>()) { + weak_unique_ptr(T *value) + : _guarded(value + ? value->getGuarded() + : std::shared_ptr<enable_weak_from_this*>()) { } - weak_unique_ptr(const std::unique_ptr<T> &value) : weak_unique_ptr(value.get()) { + weak_unique_ptr(const std::unique_ptr<T> &value) + : weak_unique_ptr(value.get()) { } weak_unique_ptr &operator=(T *value) { - _guarded = value ? value->getGuarded() : std::shared_ptr<enable_weak_from_this*>(); + _guarded = value + ? value->getGuarded() + : std::shared_ptr<enable_weak_from_this*>(); return *this; } weak_unique_ptr &operator=(const std::unique_ptr<T> &value) { diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index fb4ceaa70..839c51670 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -38,30 +38,95 @@ void CallDelayed(int duration, base::lambda_once<void()> &&lambda); } // namespace internal -template <int N, typename Lambda> -inline void CallDelayed(int duration, base::lambda_internal::guard<N, Lambda> &&guarded) { - return internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); }); +template <typename Lambda> +inline void CallDelayed( + int duration, + base::lambda_internal::guard_with_QObject<Lambda> &&guarded) { + return internal::CallDelayed( + duration, + std::move(guarded)); } -template <typename Pointer, typename ...PointersAndLambda> -inline void CallDelayed(int duration, Pointer &&qobject, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward<Pointer>(qobject), std::forward<PointersAndLambda>(qobjectsAndLambda)...); - return CallDelayed(duration, std::move(guarded)); +template <typename Lambda> +inline void CallDelayed( + int duration, + base::lambda_internal::guard_with_weak<Lambda> &&guarded) { + return internal::CallDelayed( + duration, + std::move(guarded)); } -template <typename ...PointersAndLambda> -inline base::lambda<void()> LambdaDelayed(int duration, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward<PointersAndLambda>(qobjectsAndLambda)...); - return [guarded = std::move(guarded), duration] { - internal::CallDelayed(duration, [guarded] { guarded(); }); +template <typename Lambda> +inline void CallDelayed( + int duration, + const QObject *object, + Lambda &&lambda) { + return internal::CallDelayed( + duration, + base::lambda_guarded(object, std::forward<Lambda>(lambda))); +} + +template <typename Lambda> +inline void CallDelayed( + int duration, + const base::enable_weak_from_this *object, + Lambda &&lambda) { + return internal::CallDelayed( + duration, + base::lambda_guarded(object, std::forward<Lambda>(lambda))); +} + +template <typename Lambda> +inline auto LambdaDelayed( + int duration, + const QObject *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward<Lambda>(lambda)); + return [saved = std::move(guarded), duration] { + auto copy = saved; + internal::CallDelayed(duration, std::move(copy)); }; } -template <typename ...PointersAndLambda> -inline base::lambda_once<void()> LambdaDelayedOnce(int duration, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward<PointersAndLambda>(qobjectsAndLambda)...); - return [guarded = std::move(guarded), duration]() mutable { - internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); }); +template <typename Lambda> +inline auto LambdaDelayed( + int duration, + const base::enable_weak_from_this *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward<Lambda>(lambda)); + return [saved = std::move(guarded), duration] { + auto copy = saved; + internal::CallDelayed(duration, std::move(copy)); + }; +} + +template <typename Lambda> +inline auto LambdaDelayedOnce( + int duration, + const QObject *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward<Lambda>(lambda)); + return [saved = std::move(guarded), duration]() mutable { + internal::CallDelayed(duration, std::move(saved)); + }; +} + +template <typename Lambda> +inline auto LambdaDelayedOnce( + int duration, + const base::enable_weak_from_this *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward<Lambda>(lambda)); + return [saved = std::move(guarded), duration]() mutable { + internal::CallDelayed(duration, std::move(saved)); }; }