diff --git a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py index 3fa944ca2..7bce245d9 100644 --- a/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py +++ b/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py @@ -84,6 +84,7 @@ factories = ''; flagOperators = ''; methods = ''; inlineMethods = ''; +visitorMethods = ''; textSerializeInit = ''; textSerializeMethods = ''; forwards = ''; @@ -577,6 +578,7 @@ for restype in typesList: switchLines = ''; friendDecl = ''; getters = ''; + visitor = ''; reader = ''; writer = ''; sizeList = []; @@ -594,9 +596,14 @@ for restype in typesList: trivialConditions = data[7]; dataText = ''; - dataText += '\nclass MTPD' + name + ' : public MTP::internal::TypeData {\n'; # data class + if (len(prms) > len(trivialConditions)): + withData = 1; + dataText += '\nclass MTPD' + name + ' : public MTP::internal::TypeData {\n'; # data class + else: + dataText += '\nclass MTPD' + name + ' {\n'; # empty data class for visitors dataText += 'public:\n'; - + dataText += '\ttemplate \n'; + dataText += '\tstatic constexpr bool Is() { return std::is_same_v, MTPD' + name + '>; };\n\n'; sizeList = []; creatorParams = []; creatorParamsList = []; @@ -626,13 +633,15 @@ for restype in typesList: dataText += '\tbool has_' + paramName + '() const { return v' + hasFlags + '.v & Flag::f_' + paramName + '; }\n'; dataText += '\n'; - dataText += '\tMTPD' + name + '() = default;\n'; # default constructor - switchLines += '\t\tcase mtpc_' + name + ': '; # for by-type-id type constructor - if (len(prms) > len(trivialConditions)): - switchLines += 'setData(new MTPD' + name + '()); '; - withData = 1; + 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), std::forward(callbacks)...);\n'; + + forwards += 'class MTPD' + name + ';\n'; # data class forward declaration + if (len(prms) > len(trivialConditions)): + dataText += '\tMTPD' + name + '() = default;\n'; # default constructor + switchLines += 'setData(new MTPD' + name + '()); '; - getters += '\tconst MTPD' + name + ' &c_' + name + '() const;\n'; # const getter constructsBodies += 'const MTPD' + name + ' &MTP' + restype + '::c_' + name + '() const {\n'; if (withType): constructsBodies += '\tExpects(_type == mtpc_' + name + ');\n\n'; @@ -662,8 +671,8 @@ for restype in typesList: creatorParamsList.append('_' + paramName); prmsInit.append('v' + paramName + '(_' + paramName + ')'); if (withType): - readText += '\t\t'; - writeText += '\t\t'; + readText += '\t'; + writeText += '\t'; if (paramName in conditions): readText += '\tif (v->has_' + paramName + '()) { v->v' + paramName + '.read(from, end); } else { v->v' + paramName + ' = MTP' + paramType + '(); }\n'; writeText += '\tif (v.has_' + paramName + '()) v.v' + paramName + '.write(to);\n'; @@ -673,8 +682,6 @@ for restype in typesList: writeText += '\tv.v' + paramName + '.write(to);\n'; sizeList.append('v.v' + paramName + '.innerLength()'); - forwards += 'class MTPD' + name + ';\n'; # data class forward declaration - dataText += ', '.join(prmsStr) + ');\n'; constructsBodies += 'MTPD' + name + '::MTPD' + name + '(' + ', '.join(prmsStr) + ') : ' + ', '.join(prmsInit) + ' {\n}\n'; @@ -685,20 +692,26 @@ for restype in typesList: continue; paramType = prms[paramName]; dataText += '\tMTP' + paramType + ' v' + paramName + ';\n'; - sizeCases += '\t\tcase mtpc_' + name + ': {\n'; - sizeCases += '\t\t\tconst MTPD' + name + ' &v(c_' + name + '());\n'; - sizeCases += '\t\t\treturn ' + ' + '.join(sizeList) + ';\n'; - sizeCases += '\t\t}\n'; + sizeCases += '\tcase mtpc_' + name + ': {\n'; + sizeCases += '\t\tconst MTPD' + name + ' &v(c_' + name + '());\n'; + sizeCases += '\t\treturn ' + ' + '.join(sizeList) + ';\n'; + sizeCases += '\t}\n'; sizeFast = '\tconst MTPD' + name + ' &v(c_' + name + '());\n\treturn ' + ' + '.join(sizeList) + ';\n'; newFast = 'new MTPD' + name + '()'; else: + constructsBodies += 'const MTPD' + name + ' &MTP' + restype + '::c_' + name + '() const {\n'; + if (withType): + constructsBodies += '\tExpects(_type == mtpc_' + name + ');\n\n'; + constructsBodies += '\tstatic const MTPD' + name + ' result;\n'; + constructsBodies += '\treturn result;\n'; + constructsBodies += '}\n'; + sizeFast = '\treturn 0;\n'; switchLines += 'break;\n'; dataText += '};\n'; # class ending - if (len(prms) > len(trivialConditions)): - dataTexts += dataText; # add data class + dataTexts += dataText; # add data class if (not friendDecl): friendDecl += '\tfriend class MTP::internal::TypeCreator;\n'; @@ -717,18 +730,18 @@ for restype in typesList: creatorsBodies += '}\n'; if (withType): - reader += '\t\tcase mtpc_' + name + ': _type = cons; '; # read switch line + reader += '\tcase mtpc_' + name + ': _type = cons; '; # read switch line if (len(prms) > len(trivialConditions)): reader += '{\n'; - reader += '\t\t\tauto v = new MTPD' + name + '();\n'; - reader += '\t\t\tsetData(v);\n'; + reader += '\t\tauto v = new MTPD' + name + '();\n'; + reader += '\t\tsetData(v);\n'; reader += readText; - reader += '\t\t} break;\n'; + reader += '\t} break;\n'; - writer += '\t\tcase mtpc_' + name + ': {\n'; # write switch line - writer += '\t\t\tauto &v = c_' + name + '();\n'; + writer += '\tcase mtpc_' + name + ': {\n'; # write switch line + writer += '\t\tauto &v = c_' + name + '();\n'; writer += writeText; - writer += '\t\t} break;\n'; + writer += '\t} break;\n'; else: reader += 'break;\n'; else: @@ -737,7 +750,7 @@ for restype in typesList: reader += '\tsetData(v);\n'; reader += readText; - writer += '\tauto &v = c_' + name + '();\n'; + writer += '\tconst auto &v = c_' + name + '();\n'; writer += writeText; forwards += '\n'; @@ -756,6 +769,17 @@ for restype in typesList: if (withData): typesText += getters; + if (withType): + typesText += '\n'; + typesText += '\ttemplate \n'; + typesText += '\tdecltype(auto) visit(Callback &&callback, Callbacks &&...callbacks) const;\n'; + visitorMethods += 'template \n'; + visitorMethods += 'decltype(auto) MTP' + restype + '::visit(Callback &&callback, Callbacks &&...callbacks) const {\n'; + visitorMethods += '\tswitch (_type) {\n'; + visitorMethods += visitor; + visitorMethods += '\t}\n'; + visitorMethods += '\tUnexpected("Type in MTP' + restype + '::visit.");\n'; + visitorMethods += '}\n\n'; typesText += '\n\tuint32 innerLength() const;\n'; # size method methods += '\nuint32 MTP' + restype + '::innerLength() const {\n'; @@ -788,7 +812,7 @@ for restype in typesList: if (withType): methods += '\tswitch (cons) {\n' methods += reader; - methods += '\t\tdefault: throw mtpErrorUnexpected(cons, "MTP' + restype + '");\n'; + methods += '\tdefault: throw mtpErrorUnexpected(cons, "MTP' + restype + '");\n'; methods += '\t}\n'; else: methods += reader; @@ -814,7 +838,7 @@ for restype in typesList: methods += ' {\n'; methods += '\tswitch (type) {\n'; # type id check methods += switchLines; - methods += '\t\tdefault: throw mtpErrorBadTypeId(type, "MTP' + restype + '");\n\t}\n'; + methods += '\tdefault: throw mtpErrorBadTypeId(type, "MTP' + restype + '");\n\t}\n'; methods += '}\n'; # by-type-id constructor end if (withData): @@ -953,6 +977,8 @@ enum {\n\ ' + funcsText + '\n\ // Template methods definition\n\ ' + inlineMethods + '\n\ +// Visitor definition\n\ +' + visitorMethods + '\n\ // Flag operators definition\n\ ' + flagOperators + '\n\ // Factory methods declaration\n\ diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 539592b56..4b3587eae 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include +#include #include "core/basic_types.h" #include "base/flags.h" #include "base/bytes.h" @@ -229,6 +230,18 @@ protected: return static_cast(*_data); } + template + static decltype(auto) VisitData( + const Data &data, + Callback &&callback, + Callbacks &&...callbacks) { + if constexpr (rpl::details::is_callable_plain_v) { + return std::forward(callback)(data); + } else { + return VisitData(data, std::forward(callbacks)...); + } + } + private: void incrementCounter() { if (_data) {