Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify lambdas, #164

Merged
merged 3 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Telegram/SourceFiles/apiwrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class ApiWrap : private MTP::Sender, private base::Subscriber {
void start();
void applyUpdates(const MTPUpdates &updates, quint64 sentMessageRandomId = 0);

using RequestMessageDataCallback = base::lambda<void(ChannelData *, MsgId)>;
using RequestMessageDataCallback = Fn<void(ChannelData *, MsgId)>;
void requestMessageData(ChannelData *channel, MsgId msgId, RequestMessageDataCallback callback);

void requestFullPeer(PeerData *peer);
Expand Down
4 changes: 2 additions & 2 deletions Telegram/SourceFiles/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ bool loggedOut() {

void logOut() {
if (auto mtproto = Messenger::Instance().mtp()) {
mtproto->logout(rpcDone(&loggedOut), rpcFail(&loggedOut));
mtproto->logout(rpcDone([] { return loggedOut(); }), rpcFail([] { return loggedOut(); }));
} else {
// We log out because we've forgotten passcode.
// So we just start mtproto from scratch.
Expand Down Expand Up @@ -1582,7 +1582,7 @@ PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
return i.value();
}

void enumerateUsers(base::lambda<void(UserData *)> action) {
void enumerateUsers(Fn<void(UserData *)> action) {
for_const (auto peer, peersData) {
if (auto user = peer->asUser()) {
action(user);
Expand Down
2 changes: 1 addition & 1 deletion Telegram/SourceFiles/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ inline ChatData *chatLoaded(ChatId chatId) {
inline ChannelData *channelLoaded(ChannelId channelId) {
return channel(channelId, PeerData::FullLoaded);
}
void enumerateUsers(base::lambda<void(UserData *)> action);
void enumerateUsers(Fn<void(UserData *)> action);

UserData *self();
PeerData *peerByName(const QString &username);
Expand Down
24 changes: 21 additions & 3 deletions Telegram/SourceFiles/base/lambda.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <cstddef> // std::max_align_t
#include <memory>

#ifndef CUSTOM_LAMBDA_WRAP

#include "base/unique_function.h"
#include <functional>

namespace base {

namespace lambda_internal {

template <typename Lambda> struct lambda_call_type { using type = decltype(&Lambda::operator()); };

} // namespace lambda_internal

template <typename Lambda> using lambda_call_type_t = typename lambda_internal::lambda_call_type<Lambda>::type;

} // namespace base

#else // CUSTOM_LAMBDA_WRAP

#ifndef Assert
#define LambdaAssertDefined
#define Assert(v) ((v) ? ((void)0) : std::abort())
Expand Down Expand Up @@ -63,9 +82,6 @@ template <typename Lambda> struct type_helper {

template <typename Lambda> using lambda_type = typename lambda_internal::type_helper<std::decay_t<Lambda>>::type;

template <typename Lambda>
constexpr bool lambda_is_mutable = lambda_internal::type_helper<std::decay_t<Lambda>>::is_mutable;

namespace lambda_internal {

constexpr auto kFullStorageSize = 32U;
Expand Down Expand Up @@ -416,3 +432,5 @@ template <typename Return, typename... Args> class lambda<Return(Args...)> final
#ifdef LambdaUnexpectedDefined
#undef Unexpected
#endif // LambdaUnexpectedDefined

#endif // CUSTOM_LAMBDA_WRAP
141 changes: 43 additions & 98 deletions Telegram/SourceFiles/base/lambda_guard.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,131 +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>

namespace base {

// Guard lambda call by one or many QObject* weak pointers.
// Guard lambda call by QObject* or enable_weak_from_this* pointers.

namespace base {
namespace lambda_internal {

template <int N, typename Lambda> class guard_data {
template <typename Lambda> class guard_with_QObject {
public:
using return_type = typename lambda_type<Lambda>::return_type;

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... Args> inline return_type operator()(Args &&... args) {
for (int i = 0; i != N; ++i) {
if (!_pointers[i]) {
return return_type();
}
}
return _lambda(std::forward<Args>(args)...);
template <typename OtherLambda>
guard_with_QObject(const QObject *object, OtherLambda &&other)
: _guard(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();
}

template <typename... Args> inline return_type 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];
Lambda _lambda;
QPointer<const QObject> _guard;
Lambda _callable;
};

template <int N, typename Lambda> class guard {
template <typename Lambda> class guard_with_weak {
public:
using return_type = typename lambda_type<Lambda>::return_type;

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... Args> inline return_type operator()(Args &&... args) {
return (*_data)(std::forward<Args>(args)...);
}

template <typename... Args> inline return_type operator()(Args &&... args) const {
return (*_data)(std::forward<Args>(args)...);
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{};
}

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, 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_QObject<Lambda>> {
using type = lambda_call_type_t<Lambda>;
};

template <int N, typename Lambda> struct guard_type<N, 0, Lambda> { using type = guard<N, 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;

template <int N, typename Lambda> struct type_helper<guard<N, Lambda>> {
using type = typename type_helper<Lambda>::type;
static constexpr auto is_mutable = type_helper<Lambda>::is_mutable;
template <typename Lambda> struct lambda_call_type<guard_with_weak<Lambda>> {
using type = lambda_call_type_t<Lambda>;
};

} // 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
9 changes: 3 additions & 6 deletions Telegram/SourceFiles/base/observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once

#include "base/assertion.h"
#include "base/lambda.h"
#include "base/type_traits.h"
#include "core/utils.h"
#include <QSharedPointer>
Expand All @@ -31,16 +30,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace base {
namespace internal {

using ObservableCallHandlers = base::lambda<void()>;
using ObservableCallHandlers = Fn<void()>;
void RegisterPendingObservable(ObservableCallHandlers *handlers);
void UnregisterActiveObservable(ObservableCallHandlers *handlers);
void UnregisterObservable(ObservableCallHandlers *handlers);

template <typename EventType> struct SubscriptionHandlerHelper {
using type = base::lambda<void(parameter_type<EventType>)>;
};
template <typename EventType> struct SubscriptionHandlerHelper { using type = Fn<void(parameter_type<EventType>)>; };

template <> struct SubscriptionHandlerHelper<void> { using type = base::lambda<void()>; };
template <> struct SubscriptionHandlerHelper<void> { using type = Fn<void()>; };

template <typename EventType> using SubscriptionHandler = typename SubscriptionHandlerHelper<EventType>::type;

Expand Down
3 changes: 1 addition & 2 deletions Telegram/SourceFiles/base/task_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once

#include "base/lambda.h"
#include "base/timer.h"
#include <QMutex>
#include <deque>
#include <memory>

namespace base {

using Task = lambda_once<void()>;
using Task = FnMut<void()>;

// An attempt to create/use a TaskQueue or one of the default queues
// after the main() has returned leads to an undefined behaviour.
Expand Down
4 changes: 2 additions & 2 deletions Telegram/SourceFiles/base/timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ QObject *TimersAdjuster() {

} // namespace

Timer::Timer(base::lambda<void()> callback)
Timer::Timer(Fn<void()> callback)
: QObject(nullptr)
, _callback(std::move(callback))
, _type(Qt::PreciseTimer)
Expand Down Expand Up @@ -108,7 +108,7 @@ void Timer::timerEvent(QTimerEvent *e) {
}
}

int DelayedCallTimer::call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type) {
int DelayedCallTimer::call(TimeMs timeout, FnMut<void()> callback, Qt::TimerType type) {
Expects(timeout >= 0);
if (!callback) {
return 0;
Expand Down
13 changes: 6 additions & 7 deletions Telegram/SourceFiles/base/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once

#include "base/lambda.h"
#include "base/observer.h"

using TimeMs = qint64;
Expand All @@ -29,14 +28,14 @@ namespace base {

class Timer final : private QObject {
public:
Timer(base::lambda<void()> callback = base::lambda<void()>());
Timer(Fn<void()> callback = Fn<void()>());

static Qt::TimerType DefaultType(TimeMs timeout) {
constexpr auto kThreshold = TimeMs(1000);
return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
}

void setCallback(base::lambda<void()> callback) {
void setCallback(Fn<void()> callback) {
_callback = std::move(callback);
}

Expand Down Expand Up @@ -86,7 +85,7 @@ class Timer final : private QObject {
return static_cast<Repeat>(_repeat);
}

base::lambda<void()> _callback;
Fn<void()> _callback;
TimeMs _next = 0;
int _timeout = 0;
int _timerId = 0;
Expand All @@ -98,18 +97,18 @@ class Timer final : private QObject {

class DelayedCallTimer final : private QObject {
public:
int call(TimeMs timeout, lambda_once<void()> callback) {
int call(TimeMs timeout, FnMut<void()> callback) {
return call(timeout, std::move(callback), Timer::DefaultType(timeout));
}

int call(TimeMs timeout, lambda_once<void()> callback, Qt::TimerType type);
int call(TimeMs timeout, FnMut<void()> callback, Qt::TimerType type);
void cancel(int callId);

protected:
void timerEvent(QTimerEvent *e) override;

private:
std::map<int, lambda_once<void()>> _callbacks; // Better to use flatmap.
std::map<int, FnMut<void()>> _callbacks; // Better to use flatmap.
};

} // namespace base
Loading