From f6ed3dff7fc1e651127c581fbdc0844262310558 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 27 Oct 2017 20:00:56 +0300 Subject: [PATCH] Rewrite base::lambda_guard, use only one pointer. Support base::enable_weak_from_this for guarding, not only QObject, in base::lambda_guard, in App::CallDelayed and in App::LambdaDelayed. Allow only one guarding pointer, no places in code use more than one. --- Telegram/SourceFiles/base/lambda_guard.h | 171 ++++++++------------ Telegram/SourceFiles/base/weak_unique_ptr.h | 20 ++- Telegram/SourceFiles/facades.h | 99 ++++++++++-- 3 files changed, 160 insertions(+), 130 deletions(-) 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 +#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 -class guard_data { +template +class guard_with_QObject { public: - template - inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward(qobjectsAndLambda)...)) { - } - - inline guard_data(const guard_data &other) : _lambda(other._lambda) { - for (auto i = 0; i != N; ++i) { - _pointers[i] = other._pointers[i]; - } + template + guard_with_QObject(const QObject *object, OtherLambda &&other) + : _guard(object) + , _callable(std::forward(other)) { } template < - typename ...Args, - typename return_type = decltype(std::declval()(std::declval()...))> - inline auto operator()(Args&&... args) { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval()(std::declval()...))> + Return operator()(OtherArgs &&...args) { + return _guard + ? _callable(std::forward(args)...) + : Return(); } template < - typename ...Args, - typename return_type = decltype(std::declval()(std::declval()...))> - inline auto operator()(Args&&... args) const { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval()(std::declval()...))> + Return operator()(OtherArgs &&...args) const { + return _guard + ? _callable(std::forward(args)...) + : Return(); } private: - template - Lambda init(QPointer *pointers, QObject *qobject, PointersAndLambda&&... qobjectsAndLambda) { - *pointers = qobject; - return init(++pointers, std::forward(qobjectsAndLambda)...); - } - Lambda init(QPointer *pointers, Lambda &&lambda) { - return std::move(lambda); - } - - QPointer _pointers[N]; - mutable Lambda _lambda; + QPointer _guard; + Lambda _callable; }; -template -struct lambda_call_type> { - using type = lambda_call_type_t; -}; - -template -class guard { +template +class guard_with_weak { public: - template - inline guard(Pointer &&qobject, Other &&other, PointersAndLambda&&... qobjectsAndLambda) : _data(std::make_unique>(std::forward(qobject), std::forward(other), std::forward(qobjectsAndLambda)...)) { - static_assert(1 + 1 + sizeof...(PointersAndLambda) == N + 1, "Wrong argument count!"); - } - - inline guard(const guard &other) : _data(std::make_unique>(static_cast &>(*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 + guard_with_weak( + const base::enable_weak_from_this *object, + OtherLambda &&other) + : _guard(base::make_weak_unique(object)) + , _callable(std::forward(other)) { } template < - typename ...Args, - typename = decltype(std::declval()(std::declval()...))> - inline decltype(auto) operator()(Args&&... args) { - return (*_data)(std::forward(args)...); + typename ...OtherArgs, + typename Return = decltype(std::declval()(std::declval()...))> + Return operator()(OtherArgs &&...args) { + return _guard + ? _callable(std::forward(args)...) + : Return{}; } template < - typename ...Args, - typename = decltype(std::declval()(std::declval()...))> - inline decltype(auto) operator()(Args&&... args) const { - return (*_data)(std::forward(args)...); - } - - bool isNull() const { - return !_data; + typename ...OtherArgs, + typename Return = decltype(std::declval()(std::declval()...))> + Return operator()(OtherArgs &&...args) const { + return _guard + ? _callable(std::forward(args)...) + : Return{}; } private: - mutable std::unique_ptr> _data; + base::weak_unique_ptr _guard; + Lambda _callable; }; -template -struct lambda_call_type> { +template +struct lambda_call_type> { using type = lambda_call_type_t; }; -template -struct guard_type; - -template -struct guard_type { - using type = typename guard_type::type; +template +struct lambda_call_type> { + using type = lambda_call_type_t; }; -template -struct guard_type { - using type = guard>; -}; - -template -struct guard_type_helper { - static constexpr int N = sizeof...(PointersAndLambda); - using type = typename guard_type::type; -}; - -template -using guard_t = typename guard_type_helper::type; - } // namespace lambda_internal -template -inline lambda_internal::guard_t lambda_guarded(PointersAndLambda&&... qobjectsAndLambda) { - static_assert(sizeof...(PointersAndLambda) > 0, "Lambda should be passed here."); - return lambda_internal::guard_t(std::forward(qobjectsAndLambda)...); +template +inline auto lambda_guarded(const QObject *object, Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_QObject< + std::decay_t>; + return Guarded(object, std::forward(lambda)); +} + +template +inline auto lambda_guarded( + const base::enable_weak_from_this *object, + Lambda &&lambda) { + using Guarded = lambda_internal::guard_with_weak< + std::decay_t>; + return Guarded(object, std::forward(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 friend class weak_unique_ptr; - std::shared_ptr getGuarded() { + std::shared_ptr getGuarded() const { if (!_guarded) { - _guarded = std::make_shared(static_cast(this)); + _guarded = std::make_shared( + const_cast( + static_cast(this))); } return _guarded; } - std::shared_ptr _guarded; + mutable std::shared_ptr _guarded; }; @@ -60,13 +62,19 @@ template class weak_unique_ptr { public: weak_unique_ptr() = default; - weak_unique_ptr(T *value) : _guarded(value ? value->getGuarded() : std::shared_ptr()) { + weak_unique_ptr(T *value) + : _guarded(value + ? value->getGuarded() + : std::shared_ptr()) { } - weak_unique_ptr(const std::unique_ptr &value) : weak_unique_ptr(value.get()) { + weak_unique_ptr(const std::unique_ptr &value) + : weak_unique_ptr(value.get()) { } weak_unique_ptr &operator=(T *value) { - _guarded = value ? value->getGuarded() : std::shared_ptr(); + _guarded = value + ? value->getGuarded() + : std::shared_ptr(); return *this; } weak_unique_ptr &operator=(const std::unique_ptr &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 &&lambda); } // namespace internal -template -inline void CallDelayed(int duration, base::lambda_internal::guard &&guarded) { - return internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); }); +template +inline void CallDelayed( + int duration, + base::lambda_internal::guard_with_QObject &&guarded) { + return internal::CallDelayed( + duration, + std::move(guarded)); } -template -inline void CallDelayed(int duration, Pointer &&qobject, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward(qobject), std::forward(qobjectsAndLambda)...); - return CallDelayed(duration, std::move(guarded)); +template +inline void CallDelayed( + int duration, + base::lambda_internal::guard_with_weak &&guarded) { + return internal::CallDelayed( + duration, + std::move(guarded)); } -template -inline base::lambda LambdaDelayed(int duration, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward(qobjectsAndLambda)...); - return [guarded = std::move(guarded), duration] { - internal::CallDelayed(duration, [guarded] { guarded(); }); +template +inline void CallDelayed( + int duration, + const QObject *object, + Lambda &&lambda) { + return internal::CallDelayed( + duration, + base::lambda_guarded(object, std::forward(lambda))); +} + +template +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))); +} + +template +inline auto LambdaDelayed( + int duration, + const QObject *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward(lambda)); + return [saved = std::move(guarded), duration] { + auto copy = saved; + internal::CallDelayed(duration, std::move(copy)); }; } -template -inline base::lambda_once LambdaDelayedOnce(int duration, PointersAndLambda&&... qobjectsAndLambda) { - auto guarded = base::lambda_guarded(std::forward(qobjectsAndLambda)...); - return [guarded = std::move(guarded), duration]() mutable { - internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); }); +template +inline auto LambdaDelayed( + int duration, + const base::enable_weak_from_this *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward(lambda)); + return [saved = std::move(guarded), duration] { + auto copy = saved; + internal::CallDelayed(duration, std::move(copy)); + }; +} + +template +inline auto LambdaDelayedOnce( + int duration, + const QObject *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward(lambda)); + return [saved = std::move(guarded), duration]() mutable { + internal::CallDelayed(duration, std::move(saved)); + }; +} + +template +inline auto LambdaDelayedOnce( + int duration, + const base::enable_weak_from_this *object, + Lambda &&lambda) { + auto guarded = base::lambda_guarded( + object, + std::forward(lambda)); + return [saved = std::move(guarded), duration]() mutable { + internal::CallDelayed(duration, std::move(saved)); }; }