/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once namespace rpl { namespace details { struct base_mapper { }; template constexpr bool is_mapper_v = std::is_base_of_v< base_mapper, std::decay_t>; template struct argument_mapper : base_mapper { template < typename Arg, typename ...Args, typename = std::enable_if_t<(sizeof...(Args) >= Index)>> static constexpr decltype(auto) call(Arg &&arg, Args &&...args) { return argument_mapper::call( std::forward(args)...); } template < typename ...Args, typename = std::enable_if_t<(sizeof...(Args) > Index)>> constexpr auto operator()(Args &&...args) const { return call(std::forward(args)...); } }; template <> struct argument_mapper<0> : base_mapper { template < typename Arg, typename ...Args> static constexpr decltype(auto) call(Arg &&arg, Args &&...args) { return std::forward(arg); } template < typename Arg, typename ...Args> constexpr auto operator()(Arg &&arg, Args &&...args) const { return std::forward(arg); } }; template class value_mapper : public base_mapper { public: template constexpr value_mapper(OtherType &&value) : _value(std::forward(value)) { } template constexpr auto operator()(Args &&...args) const { return _value; } private: Type _value; }; template struct wrap_mapper { using type = std::conditional_t< is_mapper_v, Type, value_mapper>; }; template using wrap_mapper_t = typename wrap_mapper::type; template class unary_operator_mapper : public base_mapper { using TypeWrapper = wrap_mapper_t>; public: template constexpr unary_operator_mapper(OtherType &&value) : _value(std::forward(value)) { } template < typename ...Args, typename Result = decltype((Operator{})( std::declval()(std::declval()...)))> constexpr std::decay_t operator()(Args &&...args) const { return (Operator{})( _value(std::forward(args)...)); } private: TypeWrapper _value; }; template class binary_operator_mapper : public base_mapper { using LeftWrapper = wrap_mapper_t>; using RightWrapper = wrap_mapper_t>; public: template constexpr binary_operator_mapper(OtherLeft &&left, OtherRight &&right) : _left(std::forward(left)) , _right(std::forward(right)) { } template < typename ...Args, typename Result = decltype((Operator{})( std::declval()(std::declval()...), std::declval()(std::declval()...)))> constexpr std::decay_t operator()(Args &&...args) const { return (Operator{})( _left(std::forward(args)...), _right(std::forward(args)...)); } private: LeftWrapper _left; RightWrapper _right; }; template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator+(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::plus<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator-(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::minus<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator*(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::multiplies<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator/(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::divides<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator%(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::modulus<>>( std::forward(left), std::forward(right)); } template < typename Type, typename = std::enable_if_t< is_mapper_v >> inline auto operator-(Type &&value) { return unary_operator_mapper< Type, std::negate<>>( std::forward(value)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator<(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::less<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator<=(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::less_equal<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator>(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::greater<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator>=(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::greater_equal<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator==(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::equal_to<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator!=(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::not_equal_to<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator&&(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::logical_and<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator||(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::logical_or<>>( std::forward(left), std::forward(right)); } template < typename Type, typename = std::enable_if_t< is_mapper_v >> inline auto operator!(Type &&value) { return unary_operator_mapper< Type, std::logical_not<>>( std::forward(value)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator&(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::bit_and<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator|(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::bit_or<>>( std::forward(left), std::forward(right)); } template < typename Left, typename Right, typename = std::enable_if_t< is_mapper_v || is_mapper_v >> inline auto operator^(Left &&left, Right &&right) { return binary_operator_mapper< Left, Right, std::bit_xor<>>( std::forward(left), std::forward(right)); } template < typename Type, typename = std::enable_if_t< is_mapper_v >> inline auto operator~(Type &&value) { return unary_operator_mapper< Type, std::bit_not<>>( std::forward(value)); } template class tuple_mapper { template using tuple_result = std::tuple>>()( std::declval()...))...>; public: template tuple_mapper(OtherMappers &&...mappers) : _mappers( std::forward(mappers)...) { } template constexpr tuple_result operator()( Args &&...args) const { constexpr auto kArity = sizeof...(Mappers); return call_helper( std::make_index_sequence(), std::forward(args)...); } private: template inline tuple_result call_helper( std::index_sequence, Args &&...args) const { return std::make_tuple( std::get(_mappers)(std::forward(args)...)...); } std::tuple>...> _mappers; }; template tuple_mapper tuple(Args &&...args) { return tuple_mapper(std::forward(args)...); } } // namespace details namespace mappers { constexpr const details::argument_mapper<0> _1; constexpr const details::argument_mapper<1> _2; constexpr const details::argument_mapper<2> _3; constexpr const details::argument_mapper<3> _4; constexpr const details::argument_mapper<4> _5; constexpr const details::argument_mapper<5> _6; constexpr const details::argument_mapper<6> _7; constexpr const details::argument_mapper<7> _8; constexpr const details::argument_mapper<8> _9; constexpr const details::argument_mapper<9> _10; constexpr const auto _1_of_two = ((void)_2, _1); } // namespace mappers } // namespace rpl