/* 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 "base/build_config.h" #include #ifdef COMPILER_GCC namespace std { template using bool_constant = integral_constant; template constexpr auto tuple_size_v = std::tuple_size::value; template constexpr auto is_rvalue_reference_v = is_rvalue_reference::value; template constexpr auto is_base_of_v = is_base_of::value; template constexpr auto is_same_v = is_same::value; namespace detail { template constexpr decltype(auto) apply_impl( Method &&method, Tuple &&tuple, index_sequence) { return forward(method)(get(forward(tuple))...); } } // namespace detail template constexpr decltype(auto) apply(Method &&method, Tuple&& tuple) { return detail::apply_impl( forward(method), forward(tuple), make_index_sequence>>{}); } } // namespace std #endif // COMPILER_GCC namespace rpl { namespace details { template const Arg &const_ref_val() noexcept; template Arg &lvalue_ref_val() noexcept; using false_t = char; struct true_t { false_t data[2]; }; static_assert(sizeof(false_t) != sizeof(true_t), "I can't work :("); template < typename Method, typename ...Args, typename = decltype(std::declval()( std::declval()...))> true_t test_callable_plain(Method &&, Args &&...) noexcept; false_t test_callable_plain(...) noexcept; template struct is_callable_plain : std::bool_constant<( sizeof(test_callable_plain( std::declval(), std::declval()... )) == sizeof(true_t))> { }; template constexpr bool is_callable_plain_v = is_callable_plain::value; template < typename Method, typename ...Types, typename = decltype(std::declval()( std::declval()...))> true_t test_callable_tuple( Method &&, std::tuple &&) noexcept; false_t test_callable_tuple(...) noexcept; template constexpr bool is_callable_tuple_v = (sizeof(test_callable_tuple( std::declval(), std::declval())) == sizeof(true_t)); template struct is_callable_tuple : std::bool_constant< is_callable_tuple_v> { }; template struct is_callable; template struct is_callable : std::bool_constant< is_callable_plain_v> { }; template struct is_callable : std::bool_constant< is_callable_plain_v || is_callable_tuple_v> { }; template constexpr bool is_callable_v = is_callable::value; template inline decltype(auto) callable_helper(Method &&method, Arg &&arg, std::true_type) { return std::forward(method)(std::forward(arg)); } template inline decltype(auto) callable_helper(Method &&method, Arg &&arg, std::false_type) { return std::apply( std::forward(method), std::forward(arg)); } template inline decltype(auto) callable_invoke(Method &&method, Arg &&arg) { return callable_helper( std::forward(method), std::forward(arg), is_callable_plain()); } template using callable_result = decltype(callable_invoke( std::declval(), std::declval())); template < typename Method, typename Arg, typename = decltype(std::declval()( const_ref_val>()))> true_t test_allows_const_ref(Method &&, Arg &&) noexcept; false_t test_allows_const_ref(...) noexcept; template constexpr bool allows_const_ref_v = (sizeof(test_allows_const_ref( std::declval(), std::declval())) == sizeof(true_t)); template struct allows_const_ref : std::bool_constant< allows_const_ref_v> { }; template inline decltype(auto) const_ref_call_helper( Method &&method, const Arg &arg, std::true_type) { return callable_invoke(std::forward(method), arg); } template inline decltype(auto) const_ref_call_helper( Method &&method, const Arg &arg, std::false_type) { auto copy = arg; return callable_invoke( std::forward(method), std::move(copy)); } template inline decltype(auto) const_ref_call_invoke( Method &&method, const Arg &arg) { return const_ref_call_helper( std::forward(method), arg, allows_const_ref()); } } // namespace details } // namespace rpl