Skip to content

Commit

Permalink
Export chat messages photos and documents.
Browse files Browse the repository at this point in the history
Also rename .visit() with .match() in MTP types.
Also add base::match_method() and base::match() for base::variant.
Also add base::match() and .match() for base::optional_variant.
  • Loading branch information
john-preston committed Jun 13, 2018
1 parent 0e9793b commit 83786dd
Show file tree
Hide file tree
Showing 13 changed files with 559 additions and 126 deletions.
28 changes: 28 additions & 0 deletions Telegram/SourceFiles/base/match_method.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
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

#include <rpl/details/callable.h>

namespace base {

template <typename Data, typename Method, typename ...Methods>
inline decltype(auto) match_method(
Data &&data,
Method &&method,
Methods &&...methods) {
if constexpr (rpl::details::is_callable_plain_v<Method, Data&&>) {
return std::forward<Method>(method)(std::forward<Data>(data));
} else {
return match_method(
std::forward<Data>(data),
std::forward<Methods>(methods)...);
}
}

} // namespace base
23 changes: 23 additions & 0 deletions Telegram/SourceFiles/base/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ class optional_variant {
return _impl.template get_unchecked<T>();
}

template <typename ...Methods>
decltype(auto) match(Methods &&...methods) {
return base::match(_impl, std::forward<Methods>(methods)...);
}
template <typename ...Methods>
decltype(auto) match(Methods &&...methods) const {
return base::match(_impl, std::forward<Methods>(methods)...);
}

private:
variant<none_type, Types...> _impl;

Expand All @@ -124,6 +133,20 @@ inline const T *get_if(const optional_variant<Types...> *v) {
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
}

template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
optional_variant<Types...> &value,
Methods &&...methods) {
return value.match(std::forward<Methods>(methods)...);
}

template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
const optional_variant<Types...> &value,
Methods &&...methods) {
return value.match(std::forward<Methods>(methods)...);
}

template <typename Type>
class optional;

Expand Down
84 changes: 73 additions & 11 deletions Telegram/SourceFiles/base/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ For license and copyright information please follow this link:
#pragma once

#include <mapbox/variant.hpp>
#include <rpl/details/type_list.h>
#include "base/match_method.h"
#include "base/assertion.h"

// We use base::variant<> alias and base::get_if() helper while we don't have std::variant<>.
namespace base {
Expand All @@ -25,20 +28,79 @@ inline const T *get_if(const variant<Types...> *v) {
return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
}

// Simplified visit
template <typename Method, typename... Types>
inline auto visit(Method &&method, const variant<Types...> &value) {
return value.match(std::forward<Method>(method));
}
namespace type_list = rpl::details::type_list;

template <typename ...Types>
struct normalized_variant {
using list = type_list::list<Types...>;
using distinct = type_list::distinct_t<list>;
using type = std::conditional_t<
type_list::size_v<distinct> == 1,
type_list::get_t<0, distinct>,
type_list::extract_to_t<distinct, base::variant>>;
};

template <typename ...Types>
using normalized_variant_t
= typename normalized_variant<Types...>::type;

template <typename TypeList, typename Variant, typename ...Methods>
struct match_helper;

template <
typename Type,
typename ...Types,
typename Variant,
typename ...Methods>
struct match_helper<type_list::list<Type, Types...>, Variant, Methods...> {
static decltype(auto) call(Variant &value, Methods &&...methods) {
if (const auto v = get_if<Type>(&value)) {
return match_method(
*v,
std::forward<Methods>(methods)...);
}
return match_helper<
type_list::list<Types...>,
Variant,
Methods...>::call(
value,
std::forward<Methods>(methods)...);
}
};

template <
typename Type,
typename Variant,
typename ...Methods>
struct match_helper<type_list::list<Type>, Variant, Methods...> {
static decltype(auto) call(Variant &value, Methods &&...methods) {
if (const auto v = get_if<Type>(&value)) {
return match_method(
*v,
std::forward<Methods>(methods)...);
}
Unexpected("Valueless variant in base::match().");
}
};

template <typename Method, typename... Types>
inline auto visit(Method &&method, variant<Types...> &value) {
return value.match(std::forward<Method>(method));
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
variant<Types...> &value,
Methods &&...methods) {
return match_helper<
type_list::list<Types...>,
variant<Types...>,
Methods...>::call(value, std::forward<Methods>(methods)...);
}

template <typename Method, typename... Types>
inline auto visit(Method &&method, variant<Types...> &&value) {
return value.match(std::forward<Method>(method));
template <typename ...Types, typename ...Methods>
inline decltype(auto) match(
const variant<Types...> &value,
Methods &&...methods) {
return match_helper<
type_list::list<Types...>,
const variant<Types...>,
Methods...>::call(value, std::forward<Methods>(methods)...);
}

} // namespace base
12 changes: 6 additions & 6 deletions Telegram/SourceFiles/codegen/scheme/codegen_scheme.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def addTextSerializeInit(lst, dct):

switchLines += '\tcase mtpc_' + name + ': '; # for by-type-id type constructor
getters += '\tconst MTPD' + name + ' &c_' + name + '() const;\n'; # const getter
visitor += '\tcase mtpc_' + name + ': return VisitData(c_' + name + '(), std::forward<Callback>(callback), std::forward<Callbacks>(callbacks)...);\n';
visitor += '\tcase mtpc_' + name + ': return base::match_method(c_' + name + '(), std::forward<Method>(method), std::forward<Methods>(methods)...);\n';

forwards += 'class MTPD' + name + ';\n'; # data class forward declaration
if (len(prms) > len(trivialConditions)):
Expand Down Expand Up @@ -771,14 +771,14 @@ def addTextSerializeInit(lst, dct):
typesText += getters;
if (withType):
typesText += '\n';
typesText += '\ttemplate <typename Callback, typename ...Callbacks>\n';
typesText += '\tdecltype(auto) visit(Callback &&callback, Callbacks &&...callbacks) const;\n';
visitorMethods += 'template <typename Callback, typename ...Callbacks>\n';
visitorMethods += 'decltype(auto) MTP' + restype + '::visit(Callback &&callback, Callbacks &&...callbacks) const {\n';
typesText += '\ttemplate <typename Method, typename ...Methods>\n';
typesText += '\tdecltype(auto) match(Method &&method, Methods &&...methods) const;\n';
visitorMethods += 'template <typename Method, typename ...Methods>\n';
visitorMethods += 'decltype(auto) MTP' + restype + '::match(Method &&method, Methods &&...methods) const {\n';
visitorMethods += '\tswitch (_type) {\n';
visitorMethods += visitor;
visitorMethods += '\t}\n';
visitorMethods += '\tUnexpected("Type in MTP' + restype + '::visit.");\n';
visitorMethods += '\tUnexpected("Type in MTP' + restype + '::match.");\n';
visitorMethods += '}\n\n';

typesText += '\n\tuint32 innerLength() const;\n'; # size method
Expand Down
Loading

0 comments on commit 83786dd

Please sign in to comment.