475 lines
10 KiB
C++
475 lines
10 KiB
C++
/*
|
|
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 <typename Type>
|
|
constexpr bool is_mapper_v = std::is_base_of_v<
|
|
base_mapper,
|
|
std::decay_t<Type>>;
|
|
|
|
template <std::size_t Index>
|
|
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<Index - 1>::call(
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <
|
|
typename ...Args,
|
|
typename = std::enable_if_t<(sizeof...(Args) > Index)>>
|
|
constexpr auto operator()(Args &&...args) const {
|
|
return call(std::forward<Args>(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>(arg);
|
|
}
|
|
|
|
template <
|
|
typename Arg,
|
|
typename ...Args>
|
|
constexpr auto operator()(Arg &&arg, Args &&...args) const {
|
|
return std::forward<Arg>(arg);
|
|
}
|
|
|
|
};
|
|
|
|
template <typename Type>
|
|
class value_mapper : public base_mapper {
|
|
public:
|
|
template <typename OtherType>
|
|
constexpr value_mapper(OtherType &&value)
|
|
: _value(std::forward<OtherType>(value)) {
|
|
}
|
|
|
|
template <typename ...Args>
|
|
constexpr auto operator()(Args &&...args) const {
|
|
return _value;
|
|
}
|
|
|
|
private:
|
|
Type _value;
|
|
|
|
};
|
|
|
|
template <typename Type>
|
|
struct wrap_mapper {
|
|
using type = std::conditional_t<
|
|
is_mapper_v<Type>,
|
|
Type,
|
|
value_mapper<Type>>;
|
|
};
|
|
|
|
template <typename Type>
|
|
using wrap_mapper_t = typename wrap_mapper<Type>::type;
|
|
|
|
template <typename Type, typename Operator>
|
|
class unary_operator_mapper : public base_mapper {
|
|
using TypeWrapper = wrap_mapper_t<std::decay_t<Type>>;
|
|
|
|
public:
|
|
template <typename OtherType>
|
|
constexpr unary_operator_mapper(OtherType &&value)
|
|
: _value(std::forward<OtherType>(value)) {
|
|
}
|
|
|
|
template <
|
|
typename ...Args,
|
|
typename Result = decltype((Operator{})(
|
|
std::declval<TypeWrapper>()(std::declval<Args>()...)))>
|
|
constexpr std::decay_t<Result> operator()(Args &&...args) const {
|
|
return (Operator{})(
|
|
_value(std::forward<Args>(args)...));
|
|
}
|
|
|
|
private:
|
|
TypeWrapper _value;
|
|
|
|
};
|
|
|
|
template <typename Left, typename Right, typename Operator>
|
|
class binary_operator_mapper : public base_mapper {
|
|
using LeftWrapper = wrap_mapper_t<std::decay_t<Left>>;
|
|
using RightWrapper = wrap_mapper_t<std::decay_t<Right>>;
|
|
|
|
public:
|
|
template <typename OtherLeft, typename OtherRight>
|
|
constexpr binary_operator_mapper(OtherLeft &&left, OtherRight &&right)
|
|
: _left(std::forward<OtherLeft>(left))
|
|
, _right(std::forward<OtherRight>(right)) {
|
|
}
|
|
|
|
template <
|
|
typename ...Args,
|
|
typename Result = decltype((Operator{})(
|
|
std::declval<LeftWrapper>()(std::declval<Args>()...),
|
|
std::declval<RightWrapper>()(std::declval<Args>()...)))>
|
|
constexpr std::decay_t<Result> operator()(Args &&...args) const {
|
|
return (Operator{})(
|
|
_left(std::forward<Args>(args)...),
|
|
_right(std::forward<Args>(args)...));
|
|
}
|
|
|
|
private:
|
|
LeftWrapper _left;
|
|
RightWrapper _right;
|
|
|
|
};
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator+(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::plus<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator-(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::minus<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator*(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::multiplies<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator/(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::divides<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator%(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::modulus<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Type,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Type>
|
|
>>
|
|
inline auto operator-(Type &&value) {
|
|
return unary_operator_mapper<
|
|
Type,
|
|
std::negate<>>(
|
|
std::forward<Type>(value));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator<(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::less<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator<=(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::less_equal<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator>(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::greater<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator>=(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::greater_equal<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator==(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::equal_to<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator!=(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::not_equal_to<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator&&(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::logical_and<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator||(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::logical_or<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Type,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Type>
|
|
>>
|
|
inline auto operator!(Type &&value) {
|
|
return unary_operator_mapper<
|
|
Type,
|
|
std::logical_not<>>(
|
|
std::forward<Type>(value));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator&(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::bit_and<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator|(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::bit_or<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Left,
|
|
typename Right,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Left> || is_mapper_v<Right>
|
|
>>
|
|
inline auto operator^(Left &&left, Right &&right) {
|
|
return binary_operator_mapper<
|
|
Left,
|
|
Right,
|
|
std::bit_xor<>>(
|
|
std::forward<Left>(left),
|
|
std::forward<Right>(right));
|
|
}
|
|
|
|
template <
|
|
typename Type,
|
|
typename = std::enable_if_t<
|
|
is_mapper_v<Type>
|
|
>>
|
|
inline auto operator~(Type &&value) {
|
|
return unary_operator_mapper<
|
|
Type,
|
|
std::bit_not<>>(
|
|
std::forward<Type>(value));
|
|
}
|
|
|
|
template <typename ...Mappers>
|
|
class tuple_mapper {
|
|
template <typename ...Args>
|
|
using tuple_result = std::tuple<decltype(
|
|
std::declval<wrap_mapper_t<std::decay_t<Mappers>>>()(
|
|
std::declval<Args>()...))...>;
|
|
public:
|
|
template <typename ...OtherMappers>
|
|
tuple_mapper(OtherMappers &&...mappers) : _mappers(
|
|
std::forward<OtherMappers>(mappers)...) {
|
|
}
|
|
|
|
template <typename ...Args>
|
|
constexpr tuple_result<Args...> operator()(
|
|
Args &&...args) const {
|
|
constexpr auto kArity = sizeof...(Mappers);
|
|
return call_helper(
|
|
std::make_index_sequence<kArity>(),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
private:
|
|
template <typename ...Args, std::size_t ...I>
|
|
inline tuple_result<Args...> call_helper(
|
|
std::index_sequence<I...>,
|
|
Args &&...args) const {
|
|
return std::make_tuple(
|
|
std::get<I>(_mappers)(std::forward<Args>(args)...)...);
|
|
}
|
|
|
|
std::tuple<wrap_mapper_t<std::decay_t<Mappers>>...> _mappers;
|
|
|
|
};
|
|
|
|
template <typename ...Args>
|
|
tuple_mapper<Args...> tuple(Args &&...args) {
|
|
return tuple_mapper<Args...>(std::forward<Args>(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
|