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.
This commit is contained in:
John Preston 2017-10-27 20:00:56 +03:00
parent 101d4f6444
commit f6ed3dff7f
3 changed files with 160 additions and 130 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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));
};
}