diff --git a/Telegram/SourceFiles/base/lambda.h b/Telegram/SourceFiles/base/lambda.h index 4c5a645e9..48742ce75 100644 --- a/Telegram/SourceFiles/base/lambda.h +++ b/Telegram/SourceFiles/base/lambda.h @@ -22,6 +22,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include +#ifndef Assert +#define LambdaAssertDefined +#define Assert(v) ((v) ? ((void)0) : std::abort()) +#endif // Assert + +#ifndef Unexpected +#define LambdaUnexpectedDefined +#define Unexpected(v) std::abort() +#endif // Unexpected + namespace base { template class lambda_once; @@ -240,7 +250,6 @@ struct vtable_impl : public vtable_once_impl(*source_lambda)); } static Return const_call_method(const void *storage, Args... args) { - static_assert(!lambda_is_mutable, "For mutable lambda use base::lambda_once wrapper"); return (*static_cast(storage))(std::forward(args)...); } vtable_impl() : Parent( @@ -441,139 +450,12 @@ public: }; -// Guard lambda call by one or many QObject* weak pointers. - -namespace lambda_internal { - -template -class guard_data { -public: - using return_type = typename lambda_type::return_type; - - template - inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward(qobjectsAndLambda)...)) { - } - - inline guard_data(const guard_data &other) : _lambda(other._lambda) { - for (auto i = 0; i != N; ++i) { - _pointers[i] = other._pointers[i]; - } - } - - template - inline return_type operator()(Args&&... args) { - for (int i = 0; i != N; ++i) { - if (!_pointers[i]) { - return return_type(); - } - } - return _lambda(std::forward(args)...); - } - - template - 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)...); - } - -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]; - Lambda _lambda; - -}; - -template -class guard { -public: - using return_type = typename lambda_type::return_type; - - 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!"); - } - - 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 - inline return_type operator()(Args&&... args) { - return (*_data)(std::forward(args)...); - } - - template - inline return_type operator()(Args&&... args) const { - return (*_data)(std::forward(args)...); - } - - bool isNull() const { - return !_data; - } - -private: - mutable std::unique_ptr> _data; - -}; - -template -struct guard_type; - -template -struct guard_type { - using type = typename guard_type::type; -}; - -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; - -template -struct type_helper> { - using type = typename type_helper::type; - static constexpr auto is_mutable = type_helper::is_mutable; -}; - -} // 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)...); -} - } // namespace base + +#ifdef LambdaAssertDefined +#undef Assert +#endif // LambdaAssertDefined + +#ifdef LambdaUnexpectedDefined +#undef Unexpected +#endif // LambdaUnexpectedDefined diff --git a/Telegram/SourceFiles/base/lambda_guard.h b/Telegram/SourceFiles/base/lambda_guard.h new file mode 100644 index 000000000..c68825d3c --- /dev/null +++ b/Telegram/SourceFiles/base/lambda_guard.h @@ -0,0 +1,162 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include + +namespace base { + +// Guard lambda call by one or many QObject* weak pointers. + +namespace lambda_internal { + +template +class guard_data { +public: + using return_type = typename lambda_type::return_type; + + template + inline guard_data(PointersAndLambda&&... qobjectsAndLambda) : _lambda(init(_pointers, std::forward(qobjectsAndLambda)...)) { + } + + inline guard_data(const guard_data &other) : _lambda(other._lambda) { + for (auto i = 0; i != N; ++i) { + _pointers[i] = other._pointers[i]; + } + } + + template + inline return_type operator()(Args&&... args) { + for (int i = 0; i != N; ++i) { + if (!_pointers[i]) { + return return_type(); + } + } + return _lambda(std::forward(args)...); + } + + template + 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)...); + } + +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]; + Lambda _lambda; + +}; + +template +class guard { +public: + using return_type = typename lambda_type::return_type; + + 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!"); + } + + 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 + inline return_type operator()(Args&&... args) { + return (*_data)(std::forward(args)...); + } + + template + inline return_type operator()(Args&&... args) const { + return (*_data)(std::forward(args)...); + } + + bool isNull() const { + return !_data; + } + +private: + mutable std::unique_ptr> _data; + +}; + +template +struct guard_type; + +template +struct guard_type { + using type = typename guard_type::type; +}; + +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; + +template +struct type_helper> { + using type = typename type_helper::type; + static constexpr auto is_mutable = type_helper::is_mutable; +}; + +} // 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)...); +} + +} // namespace base diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 3c4a3e96f..9c1d5f5e3 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -79,6 +79,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "logs.h" #include "core/utils.h" #include "base/lambda.h" +#include "base/lambda_guard.h" #include "config.h" #include "mtproto/facade.h" diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 65cc1a42c..ef66965f6 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -5,6 +5,7 @@ <(src_loc)/base/flat_map.h <(src_loc)/base/flat_set.h <(src_loc)/base/lambda.h +<(src_loc)/base/lambda_guard.h <(src_loc)/base/observer.cpp <(src_loc)/base/observer.h <(src_loc)/base/ordered_set.h