mirror of https://github.com/procxx/kepka.git
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:
parent
101d4f6444
commit
f6ed3dff7f
|
@ -21,150 +21,107 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include "base/weak_unique_ptr.h"
|
||||||
|
|
||||||
|
// Guard lambda call by QObject* or enable_weak_from_this* pointers.
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
// Guard lambda call by one or many QObject* weak pointers.
|
|
||||||
|
|
||||||
namespace lambda_internal {
|
namespace lambda_internal {
|
||||||
|
|
||||||
template <int N, typename Lambda>
|
template <typename Lambda>
|
||||||
class guard_data {
|
class guard_with_QObject {
|
||||||
public:
|
public:
|
||||||
template <typename ...PointersAndLambda>
|
template <typename OtherLambda>
|
||||||
inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward<PointersAndLambda>(qobjectsAndLambda)...)) {
|
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 <
|
template <
|
||||||
typename ...Args,
|
typename ...OtherArgs,
|
||||||
typename return_type = decltype(std::declval<Lambda>()(std::declval<Args>()...))>
|
typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))>
|
||||||
inline auto operator()(Args&&... args) {
|
Return operator()(OtherArgs &&...args) {
|
||||||
for (int i = 0; i != N; ++i) {
|
return _guard
|
||||||
if (!_pointers[i]) {
|
? _callable(std::forward<OtherArgs>(args)...)
|
||||||
return return_type();
|
: Return();
|
||||||
}
|
|
||||||
}
|
|
||||||
return _lambda(std::forward<Args>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename ...Args,
|
typename ...OtherArgs,
|
||||||
typename return_type = decltype(std::declval<Lambda>()(std::declval<Args>()...))>
|
typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))>
|
||||||
inline auto operator()(Args&&... args) const {
|
Return operator()(OtherArgs &&...args) const {
|
||||||
for (int i = 0; i != N; ++i) {
|
return _guard
|
||||||
if (!_pointers[i]) {
|
? _callable(std::forward<OtherArgs>(args)...)
|
||||||
return return_type();
|
: Return();
|
||||||
}
|
|
||||||
}
|
|
||||||
return _lambda(std::forward<Args>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename ...PointersAndLambda>
|
QPointer<const QObject> _guard;
|
||||||
Lambda init(QPointer<QObject> *pointers, QObject *qobject, PointersAndLambda&&... qobjectsAndLambda) {
|
Lambda _callable;
|
||||||
*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;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int N, typename Lambda>
|
template <typename Lambda>
|
||||||
struct lambda_call_type<guard_data<N, Lambda>> {
|
class guard_with_weak {
|
||||||
using type = lambda_call_type_t<Lambda>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <int N, typename Lambda>
|
|
||||||
class guard {
|
|
||||||
public:
|
public:
|
||||||
template <typename Pointer, typename Other, typename ...PointersAndLambda>
|
template <typename OtherLambda>
|
||||||
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)...)) {
|
guard_with_weak(
|
||||||
static_assert(1 + 1 + sizeof...(PointersAndLambda) == N + 1, "Wrong argument count!");
|
const base::enable_weak_from_this *object,
|
||||||
}
|
OtherLambda &&other)
|
||||||
|
: _guard(base::make_weak_unique(object))
|
||||||
inline guard(const guard &other) : _data(std::make_unique<guard_data<N, Lambda>>(static_cast<const guard_data<N, Lambda> &>(*other._data))) {
|
, _callable(std::forward<OtherLambda>(other)) {
|
||||||
}
|
|
||||||
|
|
||||||
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 <
|
template <
|
||||||
typename ...Args,
|
typename ...OtherArgs,
|
||||||
typename = decltype(std::declval<Lambda>()(std::declval<Args>()...))>
|
typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))>
|
||||||
inline decltype(auto) operator()(Args&&... args) {
|
Return operator()(OtherArgs &&...args) {
|
||||||
return (*_data)(std::forward<Args>(args)...);
|
return _guard
|
||||||
|
? _callable(std::forward<OtherArgs>(args)...)
|
||||||
|
: Return{};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename ...Args,
|
typename ...OtherArgs,
|
||||||
typename = decltype(std::declval<Lambda>()(std::declval<Args>()...))>
|
typename Return = decltype(std::declval<Lambda>()(std::declval<OtherArgs>()...))>
|
||||||
inline decltype(auto) operator()(Args&&... args) const {
|
Return operator()(OtherArgs &&...args) const {
|
||||||
return (*_data)(std::forward<Args>(args)...);
|
return _guard
|
||||||
}
|
? _callable(std::forward<OtherArgs>(args)...)
|
||||||
|
: Return{};
|
||||||
bool isNull() const {
|
|
||||||
return !_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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>
|
template <typename Lambda>
|
||||||
struct lambda_call_type<guard<N, Lambda>> {
|
struct lambda_call_type<guard_with_QObject<Lambda>> {
|
||||||
using type = lambda_call_type_t<Lambda>;
|
using type = lambda_call_type_t<Lambda>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int N, int K, typename ...PointersAndLambda>
|
template <typename Lambda>
|
||||||
struct guard_type;
|
struct lambda_call_type<guard_with_weak<Lambda>> {
|
||||||
|
using type = lambda_call_type_t<Lambda>;
|
||||||
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 <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
|
} // namespace lambda_internal
|
||||||
|
|
||||||
template <typename ...PointersAndLambda>
|
template <typename Lambda>
|
||||||
inline lambda_internal::guard_t<PointersAndLambda...> lambda_guarded(PointersAndLambda&&... qobjectsAndLambda) {
|
inline auto lambda_guarded(const QObject *object, Lambda &&lambda) {
|
||||||
static_assert(sizeof...(PointersAndLambda) > 0, "Lambda should be passed here.");
|
using Guarded = lambda_internal::guard_with_QObject<
|
||||||
return lambda_internal::guard_t<PointersAndLambda...>(std::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
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
|
} // namespace base
|
||||||
|
|
|
@ -45,14 +45,16 @@ private:
|
||||||
template <typename Child>
|
template <typename Child>
|
||||||
friend class weak_unique_ptr;
|
friend class weak_unique_ptr;
|
||||||
|
|
||||||
std::shared_ptr<enable_weak_from_this*> getGuarded() {
|
std::shared_ptr<enable_weak_from_this*> getGuarded() const {
|
||||||
if (!_guarded) {
|
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;
|
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 {
|
class weak_unique_ptr {
|
||||||
public:
|
public:
|
||||||
weak_unique_ptr() = default;
|
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) {
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
weak_unique_ptr &operator=(const std::unique_ptr<T> &value) {
|
weak_unique_ptr &operator=(const std::unique_ptr<T> &value) {
|
||||||
|
|
|
@ -38,30 +38,95 @@ void CallDelayed(int duration, base::lambda_once<void()> &&lambda);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <int N, typename Lambda>
|
template <typename Lambda>
|
||||||
inline void CallDelayed(int duration, base::lambda_internal::guard<N, Lambda> &&guarded) {
|
inline void CallDelayed(
|
||||||
return internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); });
|
int duration,
|
||||||
|
base::lambda_internal::guard_with_QObject<Lambda> &&guarded) {
|
||||||
|
return internal::CallDelayed(
|
||||||
|
duration,
|
||||||
|
std::move(guarded));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Pointer, typename ...PointersAndLambda>
|
template <typename Lambda>
|
||||||
inline void CallDelayed(int duration, Pointer &&qobject, PointersAndLambda&&... qobjectsAndLambda) {
|
inline void CallDelayed(
|
||||||
auto guarded = base::lambda_guarded(std::forward<Pointer>(qobject), std::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
int duration,
|
||||||
return CallDelayed(duration, std::move(guarded));
|
base::lambda_internal::guard_with_weak<Lambda> &&guarded) {
|
||||||
|
return internal::CallDelayed(
|
||||||
|
duration,
|
||||||
|
std::move(guarded));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ...PointersAndLambda>
|
template <typename Lambda>
|
||||||
inline base::lambda<void()> LambdaDelayed(int duration, PointersAndLambda&&... qobjectsAndLambda) {
|
inline void CallDelayed(
|
||||||
auto guarded = base::lambda_guarded(std::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
int duration,
|
||||||
return [guarded = std::move(guarded), duration] {
|
const QObject *object,
|
||||||
internal::CallDelayed(duration, [guarded] { guarded(); });
|
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>
|
template <typename Lambda>
|
||||||
inline base::lambda_once<void()> LambdaDelayedOnce(int duration, PointersAndLambda&&... qobjectsAndLambda) {
|
inline auto LambdaDelayed(
|
||||||
auto guarded = base::lambda_guarded(std::forward<PointersAndLambda>(qobjectsAndLambda)...);
|
int duration,
|
||||||
return [guarded = std::move(guarded), duration]() mutable {
|
const base::enable_weak_from_this *object,
|
||||||
internal::CallDelayed(duration, [guarded = std::move(guarded)] { guarded(); });
|
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));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue