Rewrite base::lambda_guard, use only one pointer.

(cherry picked from commit f6ed3df)
This commit is contained in:
John Preston 2017-10-27 20:00:56 +03:00 committed by Alex
parent f488d5f9c1
commit e7bace9ab3
3 changed files with 83 additions and 119 deletions

View File

@ -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 <QPointer>
// 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)...)) {}
template <typename OtherLambda>
guard_with_QObject(const QObject *object, OtherLambda &&other)
: _guard(object)
, _callable(std::forward<OtherLambda>(other)) {}
inline guard_data(const guard_data &other)
: _lambda(other._lambda) {
for (auto i = 0; i != N; ++i) {
_pointers[i] = other._pointers[i];
}
template <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) {
for (int i = 0; i != N; ++i) {
if (!_pointers[i]) {
return return_type();
}
}
return _lambda(std::forward<Args>(args)...);
}
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)...);
template <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!");
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... OtherArgs, typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))>
Return operator()(OtherArgs &&... args) {
return _guard ? _callable(std::forward<OtherArgs>(args)...) : Return{};
}
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... Args, typename = decltype(std::declval<Lambda>()(std::declval<Args>()...))>
inline decltype(auto) operator()(Args &&... args) {
return (*_data)(std::forward<Args>(args)...);
}
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;
template <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

View File

@ -46,14 +46,15 @@ public:
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;
};
template <typename T> class weak_unique_ptr {

View File

@ -44,32 +44,53 @@ 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... 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 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 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)); };
}
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);