tdesktop/Telegram/SourceFiles/rpl/mappers.h

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