From e7bace9ab3f41ed500021cee62b904fcb1ee04e0 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. (cherry picked from commit f6ed3df) --- Telegram/SourceFiles/base/lambda_guard.h | 140 ++++++-------------- Telegram/SourceFiles/base/weak_unique_ptr.h | 7 +- Telegram/SourceFiles/facades.h | 55 +++++--- 3 files changed, 83 insertions(+), 119 deletions(-) diff --git a/Telegram/SourceFiles/base/lambda_guard.h b/Telegram/SourceFiles/base/lambda_guard.h index 59b01a040..785139330 100644 --- a/Telegram/SourceFiles/base/lambda_guard.h +++ b/Telegram/SourceFiles/base/lambda_guard.h @@ -21,134 +21,76 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "base/lambda.h" +#include "base/weak_unique_ptr.h" #include +// 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)...)) {} + template + guard_with_QObject(const QObject *object, OtherLambda &&other) + : _guard(object) + , _callable(std::forward(other)) {} - inline guard_data(const guard_data &other) - : _lambda(other._lambda) { - for (auto i = 0; i != N; ++i) { - _pointers[i] = other._pointers[i]; - } + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) { + return _guard ? _callable(std::forward(args)...) : Return(); } - template ()(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)...); - } - - template ()(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)...); + template ()(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!"); + template + guard_with_weak(const base::enable_weak_from_this *object, OtherLambda &&other) + : _guard(base::make_weak_unique(object)) + , _callable(std::forward(other)) {} + + template ()(std::declval()...))> + Return operator()(OtherArgs &&... args) { + return _guard ? _callable(std::forward(args)...) : Return{}; } - 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 ()(std::declval()...))> - inline decltype(auto) operator()(Args &&... args) { - return (*_data)(std::forward(args)...); - } - - template ()(std::declval()...))> - inline decltype(auto) operator()(Args &&... args) const { - return (*_data)(std::forward(args)...); - } - - bool isNull() const { - return !_data; + template ()(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>; + 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>; + 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 5347d95ab..140fbf3fd 100644 --- a/Telegram/SourceFiles/base/weak_unique_ptr.h +++ b/Telegram/SourceFiles/base/weak_unique_ptr.h @@ -46,14 +46,15 @@ public: 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; }; template class weak_unique_ptr { diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 33948bf3b..f8446f9f4 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -44,32 +44,53 @@ 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 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 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 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)); }; +} + void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo = 0); bool insertBotCommand(const QString &cmd); void activateBotCommand(const HistoryItem *msg, int row, int col);