Minor fixes.

GitOrigin-RevId: ffac148f714da737dcc1b12e56352995866f93b4
This commit is contained in:
levlam 2018-12-19 23:35:13 +03:00
parent 82feae2065
commit cba0f62ba9
14 changed files with 186 additions and 184 deletions

View File

@ -19,6 +19,7 @@
namespace td { namespace td {
namespace mtproto { namespace mtproto {
// mtproto v1.0 // mtproto v1.0
template <class HeaderT> template <class HeaderT>
std::tuple<uint32, UInt128> Transport::calc_message_ack_and_key(const HeaderT &head, size_t data_size) { std::tuple<uint32, UInt128> Transport::calc_message_ack_and_key(const HeaderT &head, size_t data_size) {
@ -331,5 +332,6 @@ size_t Transport::write(const Storer &storer, const AuthKey &auth_key, PacketInf
return write_crypto(storer, auth_key, info, dest); return write_crypto(storer, auth_key, info, dest);
} }
} }
} // namespace mtproto } // namespace mtproto
} // namespace td } // namespace td

View File

@ -15,6 +15,7 @@
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/DhCache.h" #include "td/telegram/DhCache.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/NetQueryCreator.h" #include "td/telegram/net/NetQueryCreator.h"

View File

@ -16,6 +16,7 @@
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/Slice.h"
#include "td/utils/Time.h" #include "td/utils/Time.h"
#include <algorithm> #include <algorithm>

View File

@ -85,9 +85,9 @@ set(TDUTILS_SOURCE
td/utils/StackAllocator.cpp td/utils/StackAllocator.cpp
td/utils/Status.cpp td/utils/Status.cpp
td/utils/StringBuilder.cpp td/utils/StringBuilder.cpp
td/utils/tests.cpp
td/utils/Time.cpp td/utils/Time.cpp
td/utils/Timer.cpp td/utils/Timer.cpp
td/utils/tests.cpp
td/utils/tl_parsers.cpp td/utils/tl_parsers.cpp
td/utils/translit.cpp td/utils/translit.cpp
td/utils/unicode.cpp td/utils/unicode.cpp

View File

@ -1,20 +0,0 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/utils/BufferedStdin.h"
#include "td/utils/buffer.h"
#include "td/utils/port/detail/PollableFd.h"
namespace td {
class BufferedStdin {
public:
private:
PollableFdInfo info_;
ChainBufferWriter writer_;
ChainBufferReader reader_ = writer_.extract_reader();
};
} // namespace td

View File

@ -1,9 +0,0 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
namespace td {}

View File

@ -153,7 +153,7 @@ class DecTree {
P.first = std::move(Tree); P.first = std::move(Tree);
return P; return P;
} }
} // namespace td }
static unique_ptr<Node> merge_node(unique_ptr<Node> left, unique_ptr<Node> right) { static unique_ptr<Node> merge_node(unique_ptr<Node> left, unique_ptr<Node> right) {
if (left == nullptr) { if (left == nullptr) {

View File

@ -5,19 +5,138 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#if TD_MSVC #if TD_MSVC
#include <intrin.h> #include <intrin.h>
#endif #endif
namespace td { namespace td {
int32 count_leading_zeroes32(uint32 x);
int32 count_leading_zeroes64(uint64 x); inline int32 count_leading_zeroes32(uint32 x);
int32 count_trailing_zeroes32(uint32 x); inline int32 count_leading_zeroes64(uint64 x);
int32 count_trailing_zeroes64(uint64 x); inline int32 count_trailing_zeroes32(uint32 x);
uint32 bswap32(uint32 x); inline int32 count_trailing_zeroes64(uint64 x);
uint64 bswap64(uint64 x); inline uint32 bswap32(uint32 x);
int32 count_bits32(uint32 x); inline uint64 bswap64(uint64 x);
int32 count_bits64(uint64 x); inline int32 count_bits32(uint32 x);
inline int32 count_bits64(uint64 x);
#if TD_MSVC
inline int32 count_leading_zeroes32(uint32 x) {
unsigned long res = 0;
if (_BitScanReverse(&res, x)) {
return 31 - res;
}
return 32;
}
inline int32 count_leading_zeroes64(uint64 x) {
#if defined(_M_X64)
unsigned long res = 0;
if (_BitScanReverse64(&res, x)) {
return 63 - res;
}
return 64;
#else
if ((x >> 32) == 0) {
return count_leading_zeroes32(static_cast<uint32>(x)) + 32;
} else {
return count_leading_zeroes32(static_cast<uint32>(x >> 32));
}
#endif
}
inline int32 count_trailing_zeroes32(uint32 x) {
unsigned long res = 0;
if (_BitScanForward(&res, x)) {
return res;
}
return 32;
}
inline int32 count_trailing_zeroes64(uint64 x) {
#if defined(_M_X64)
unsigned long res = 0;
if (_BitScanForward64(&res, x)) {
return res;
}
return 64;
#else
if (static_cast<uint32>(x) == 0) {
return count_trailing_zeroes32(static_cast<uint32>(x >> 32)) + 32;
} else {
return count_trailing_zeroes32(static_cast<uint32>(x));
}
#endif
}
inline uint32 bswap32(uint32 x) {
return _byteswap_ulong(x);
}
inline uint64 bswap64(uint64 x) {
return _byteswap_uint64(x);
}
inline int32 count_bits32(uint32 x) {
return __popcnt(x);
}
inline int32 count_bits64(uint64 x) {
#if defined(_M_X64)
return __popcnt64(x);
#else
return count_bits32(static_cast<uint32>(x >> 32)) + count_bits32(static_cast<uint32>(x));
#endif
}
#else
inline int32 count_leading_zeroes32(uint32 x) {
if (x == 0) {
return 32;
}
return __builtin_clz(x);
}
inline int32 count_leading_zeroes64(uint64 x) {
if (x == 0) {
return 64;
}
return __builtin_clzll(x);
}
inline int32 count_trailing_zeroes32(uint32 x) {
if (x == 0) {
return 32;
}
return __builtin_ctz(x);
}
inline int32 count_trailing_zeroes64(uint64 x) {
if (x == 0) {
return 64;
}
return __builtin_ctzll(x);
}
inline uint32 bswap32(uint32 x) {
return __builtin_bswap32(x);
}
inline uint64 bswap64(uint64 x) {
return __builtin_bswap64(x);
}
inline int32 count_bits32(uint32 x) {
return __builtin_popcount(x);
}
inline int32 count_bits64(uint64 x) {
return __builtin_popcountll(x);
}
#endif
//TODO: optimize //TODO: optimize
inline int32 count_leading_zeroes_non_zero32(uint32 x) { inline int32 count_leading_zeroes_non_zero32(uint32 x) {
@ -37,104 +156,4 @@ inline int32 count_trailing_zeroes_non_zero64(uint64 x) {
return count_trailing_zeroes64(x); return count_trailing_zeroes64(x);
} }
#if TD_MSVC
inline int32 count_leading_zeroes32(uint32 x) {
unsigned long res = 0;
if (_BitScanReverse(&res, x)) {
return 31 - res;
}
return 32;
}
inline int32 count_leading_zeroes64(uint64 x) {
#if defined(_M_X64)
unsigned long res = 0;
if (_BitScanReverse64(&res, x)) {
return 63 - res;
}
return 64;
#else
if ((x >> 32) == 0) {
return count_leading_zeroes32(static_cast<uint32>(x)) + 32;
} else {
return count_leading_zeroes32(static_cast<uint32>(x >> 32));
}
#endif
}
inline int32 count_trailing_zeroes32(uint32 x) {
unsigned long res = 0;
if (_BitScanForward(&res, x)) {
return res;
}
return 32;
}
inline int32 count_trailing_zeroes64(uint64 x) {
#if defined(_M_X64)
unsigned long res = 0;
if (_BitScanForward64(&res, x)) {
return res;
}
return 64;
#else
if (static_cast<uint32>(x) == 0) {
return count_trailing_zeroes32(static_cast<uint32>(x >> 32)) + 32;
} else {
return count_trailing_zeroes32(static_cast<uint32>(x));
}
#endif
}
inline uint32 bswap32(uint32 x) {
return _byteswap_ulong(x);
}
inline uint64 bswap64(uint64 x) {
return _byteswap_uint64(x);
}
inline int32 count_bits32(uint32 x) {
return __popcnt(x);
}
inline int32 count_bits64(uint64 x) {
#if defined(_M_X64)
return __popcnt64(x);
#else
return count_bits32(static_cast<uint32>(x >> 32)) + count_bits32(static_cast<uint32>(x));
#endif
}
#else
inline int32 count_leading_zeroes32(uint32 x) {
if (x == 0) {
return 32;
}
return __builtin_clz(x);
}
inline int32 count_leading_zeroes64(uint64 x) {
if (x == 0) {
return 64;
}
return __builtin_clzll(x);
}
inline int32 count_trailing_zeroes32(uint32 x) {
if (x == 0) {
return 32;
}
return __builtin_ctz(x);
}
inline int32 count_trailing_zeroes64(uint64 x) {
if (x == 0) {
return 64;
}
return __builtin_ctzll(x);
}
inline uint32 bswap32(uint32 x) {
return __builtin_bswap32(x);
}
inline uint64 bswap64(uint64 x) {
return __builtin_bswap64(x);
}
inline int32 count_bits32(uint32 x) {
return __builtin_popcount(x);
}
inline int32 count_bits64(uint64 x) {
return __builtin_popcountll(x);
}
#endif
} // namespace td } // namespace td

View File

@ -8,6 +8,7 @@
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/PathView.h" #include "td/utils/PathView.h"
#include "td/utils/port/FileFd.h" #include "td/utils/port/FileFd.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
@ -17,31 +18,41 @@
namespace td { namespace td {
// TODO remove copypaste
Result<BufferSlice> read_file(CSlice path, int64 size, int64 offset) { Result<BufferSlice> read_file(CSlice path, int64 size, int64 offset) {
TRY_RESULT(from_file, FileFd::open(path, FileFd::Read)); TRY_RESULT(from_file, FileFd::open(path, FileFd::Read));
if (size == -1) { if (size == -1) {
size = from_file.get_size() - offset; size = from_file.get_size();
} }
if (size < 0) { if (size < 0) {
return Status::Error("Failed to read file: invalid size or offset"); return Status::Error("Failed to read file: invalid size");
} }
BufferWriter content{static_cast<size_t>(size), 0, 0}; if (offset < 0 || offset > size) {
TRY_RESULT(got_size, from_file.pread(content.as_slice(), offset)); return Status::Error("Failed to read file: invalid offset");
}
size -= offset;
BufferSlice content{narrow_cast<size_t>(size)};
TRY_RESULT(got_size, from_file.pread(as_slice(content), offset));
if (got_size != static_cast<size_t>(size)) { if (got_size != static_cast<size_t>(size)) {
return Status::Error("Failed to read file"); return Status::Error("Failed to read file");
} }
from_file.close(); from_file.close();
return content.as_buffer_slice(); return std::move(content);
} }
Result<std::string> read_file_str(CSlice path, int64 size, int64 offset) { Result<std::string> read_file_str(CSlice path, int64 size, int64 offset) {
TRY_RESULT(from_file, FileFd::open(path, FileFd::Read)); TRY_RESULT(from_file, FileFd::open(path, FileFd::Read));
if (size == -1) { if (size == -1) {
size = from_file.get_size() - offset; size = from_file.get_size();
} }
if (size < 0) { if (size < 0) {
return Status::Error("Failed to read file: invalid size or offset"); return Status::Error("Failed to read file: invalid size");
} }
std::string content(static_cast<size_t>(size), '\0'); if (offset < 0 || offset > size) {
return Status::Error("Failed to read file: invalid offset");
}
size -= offset;
std::string content(narrow_cast<size_t>(size), '\0');
TRY_RESULT(got_size, from_file.pread(content, offset)); TRY_RESULT(got_size, from_file.pread(content, offset));
if (got_size != static_cast<size_t>(size)) { if (got_size != static_cast<size_t>(size)) {
return Status::Error("Failed to read file"); return Status::Error("Failed to read file");

View File

@ -91,16 +91,6 @@ td::UInt<size> operator^(const UInt<size> &a, const UInt<size> &b) {
return res; return res;
} }
template <size_t size>
bool is_zero(const UInt<size> &a) {
for (size_t i = 0; i * 8 < size; i++) {
if (a.raw[i]) {
return false;
}
}
return true;
}
template <size_t size> template <size_t size>
int get_kth_bit(const UInt<size> &a, uint32 bit) { int get_kth_bit(const UInt<size> &a, uint32 bit) {
uint8 b = a.raw[bit / 8]; uint8 b = a.raw[bit / 8];

View File

@ -375,7 +375,7 @@ Status IPAddress::init_host_port(CSlice host, CSlice port, bool prefer_ipv6) {
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
LOG(DEBUG + 10) << "Try to init IP address of " << host << " with port " << port; LOG(INFO) << "Try to init IP address of " << host << " with port " << port;
auto err = getaddrinfo(host.c_str(), port.c_str(), &hints, &info); auto err = getaddrinfo(host.c_str(), port.c_str(), &hints, &info);
if (err != 0) { if (err != 0) {
#if TD_WINDOWS #if TD_WINDOWS
@ -440,7 +440,7 @@ Status IPAddress::init_sockaddr(sockaddr *addr, socklen_t len) {
} }
is_valid_ = true; is_valid_ = true;
LOG(DEBUG + 10) << "Have address " << get_ip_str() << " with port " << get_port(); LOG(INFO) << "Have address " << get_ip_str() << " with port " << get_port();
return Status::OK(); return Status::OK();
} }

View File

@ -6,14 +6,20 @@
// //
#include "td/utils/tests.h" #include "td/utils/tests.h"
#include "td/utils/base64.h"
#include "td/utils/crypto.h" #include "td/utils/crypto.h"
#include "td/utils/filesystem.h" #include "td/utils/filesystem.h"
#include "td/utils/Parser.h" #include "td/utils/Parser.h"
#include "td/utils/PathView.h" #include "td/utils/PathView.h"
#include "td/utils/port/path.h" #include "td/utils/port/path.h"
#include "td/utils/port/Stat.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
#include <map>
namespace td { namespace td {
struct TestInfo { struct TestInfo {
string name; string name;
string result_hash; // base64 string result_hash; // base64
@ -31,7 +37,7 @@ class RegressionTesterImpl : public RegressionTester {
unlink(db_path).ignore(); unlink(db_path).ignore();
} }
explicit RegressionTesterImpl(string db_path, string db_cache_dir) : db_path_(db_path), db_cache_dir_(db_cache_dir) { RegressionTesterImpl(string db_path, string db_cache_dir) : db_path_(db_path), db_cache_dir_(db_cache_dir) {
load_db(db_path); load_db(db_path);
if (db_cache_dir_.empty()) { if (db_cache_dir_.empty()) {
db_cache_dir_ = PathView(db_path).without_extension().str() + ".cache/"; db_cache_dir_ = PathView(db_path).without_extension().str() + ".cache/";
@ -118,15 +124,17 @@ class RegressionTesterImpl : public RegressionTester {
void RegressionTester::destroy(CSlice path) { void RegressionTester::destroy(CSlice path) {
RegressionTesterImpl::destroy(path); RegressionTesterImpl::destroy(path);
} }
std::unique_ptr<RegressionTester> RegressionTester::create(string db_path, string db_cache_dir) {
return std::make_unique<RegressionTesterImpl>(std::move(db_path), std::move(db_cache_dir)); unique_ptr<RegressionTester> RegressionTester::create(string db_path, string db_cache_dir) {
return td::make_unique<RegressionTesterImpl>(std::move(db_path), std::move(db_cache_dir));
} }
TestsRunner &TestsRunner::get_default() { TestsRunner &TestsRunner::get_default() {
static TestsRunner default_runner; static TestsRunner default_runner;
return default_runner; return default_runner;
} }
void TestsRunner::add_test(string name, std::unique_ptr<Test> test) { void TestsRunner::add_test(string name, unique_ptr<Test> test) {
for (auto &it : tests_) { for (auto &it : tests_) {
if (it.first == name) { if (it.first == name) {
LOG(FATAL) << "Test name collision " << name; LOG(FATAL) << "Test name collision " << name;
@ -135,14 +143,14 @@ void TestsRunner::add_test(string name, std::unique_ptr<Test> test) {
tests_.emplace_back(name, std::move(test)); tests_.emplace_back(name, std::move(test));
} }
void TestsRunner::add_substr_filter(std::string str) { void TestsRunner::add_substr_filter(string str) {
if (str[0] != '+' && str[0] != '-') { if (str[0] != '+' && str[0] != '-') {
str = "+" + str; str = "+" + str;
} }
substr_filters_.push_back(std::move(str)); substr_filters_.push_back(std::move(str));
} }
void TestsRunner::set_regression_tester(std::unique_ptr<RegressionTester> regression_tester) { void TestsRunner::set_regression_tester(unique_ptr<RegressionTester> regression_tester) {
regression_tester_ = std::move(regression_tester); regression_tester_ = std::move(regression_tester);
} }
@ -154,6 +162,7 @@ void TestsRunner::run_all() {
while (run_all_step()) { while (run_all_step()) {
} }
} }
bool TestsRunner::run_all_step() { bool TestsRunner::run_all_step() {
Guard guard(this); Guard guard(this);
if (state_.it == state_.end) { if (state_.it == state_.end) {
@ -167,14 +176,14 @@ bool TestsRunner::run_all_step() {
if (!state_.is_running) { if (!state_.is_running) {
bool ok = true; bool ok = true;
for (const auto &filter : substr_filters_) { for (const auto &filter : substr_filters_) {
bool is_match = name.find(filter.substr(1)) != std::string::npos; bool is_match = name.find(filter.substr(1)) != string::npos;
if (is_match != (filter[0] == '+')) { if (is_match != (filter[0] == '+')) {
ok = false; ok = false;
break; break;
} }
} }
if (!ok) { if (!ok) {
state_.it++; ++state_.it;
continue; continue;
} }
LOG(ERROR) << "Run test " << tag("name", name); LOG(ERROR) << "Run test " << tag("name", name);
@ -191,7 +200,7 @@ bool TestsRunner::run_all_step() {
regression_tester_->save_db(); regression_tester_->save_db();
} }
state_.is_running = false; state_.is_running = false;
state_.it++; ++state_.it;
} }
auto ret = state_.it != state_.end; auto ret = state_.it != state_.end;
@ -214,4 +223,5 @@ Status TestsRunner::verify(Slice data) {
} }
return regression_tester_->verify_test(PSLICE() << name() << "_default", data); return regression_tester_->verify_test(PSLICE() << name() << "_default", data);
} }
} // namespace td } // namespace td

View File

@ -9,17 +9,14 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Context.h" #include "td/utils/Context.h"
#include "td/utils/format.h" #include "td/utils/format.h"
#include "td/utils/List.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/port/thread.h" #include "td/utils/port/thread.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "td/utils/optional.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/Time.h"
#include <atomic> #include <atomic>
#include <map> #include <utility>
#define REGISTER_TESTS(x) \ #define REGISTER_TESTS(x) \
void TD_CONCAT(register_tests_, x)() { \ void TD_CONCAT(register_tests_, x)() { \
@ -33,7 +30,7 @@ class RegressionTester {
public: public:
virtual ~RegressionTester() = default; virtual ~RegressionTester() = default;
static void destroy(CSlice db_path); static void destroy(CSlice db_path);
static std::unique_ptr<RegressionTester> create(string db_path, string db_cache_dir = ""); static unique_ptr<RegressionTester> create(string db_path, string db_cache_dir = "");
virtual Status verify_test(Slice name, Slice result) = 0; virtual Status verify_test(Slice name, Slice result) = 0;
virtual void save_db() = 0; virtual void save_db() = 0;
@ -68,12 +65,12 @@ class TestsRunner : public TestContext {
public: public:
static TestsRunner &get_default(); static TestsRunner &get_default();
void add_test(string name, std::unique_ptr<Test> test); void add_test(string name, unique_ptr<Test> test);
void add_substr_filter(std::string str); void add_substr_filter(string str);
void set_stress_flag(bool flag); void set_stress_flag(bool flag);
void run_all(); void run_all();
bool run_all_step(); bool run_all_step();
void set_regression_tester(std::unique_ptr<RegressionTester> regression_tester); void set_regression_tester(unique_ptr<RegressionTester> regression_tester);
private: private:
struct State { struct State {
@ -83,10 +80,10 @@ class TestsRunner : public TestContext {
size_t end{0}; size_t end{0};
}; };
bool stress_flag_{false}; bool stress_flag_{false};
std::vector<std::string> substr_filters_; vector<string> substr_filters_;
std::vector<std::pair<string, std::unique_ptr<Test>>> tests_; vector<std::pair<string, unique_ptr<Test>>> tests_;
State state_; State state_;
std::unique_ptr<RegressionTester> regression_tester_; unique_ptr<RegressionTester> regression_tester_;
Slice name() override; Slice name() override;
Status verify(Slice data) override; Status verify(Slice data) override;
@ -96,7 +93,7 @@ template <class T>
class RegisterTest { class RegisterTest {
public: public:
RegisterTest(string name, TestsRunner &runner = TestsRunner::get_default()) { RegisterTest(string name, TestsRunner &runner = TestsRunner::get_default()) {
runner.add_test(name, std::make_unique<T>()); runner.add_test(name, make_unique<T>());
} }
}; };
@ -121,8 +118,8 @@ inline string rand_string(char from, char to, int len) {
return res; return res;
} }
inline std::vector<string> rand_split(string str) { inline vector<string> rand_split(string str) {
std::vector<string> res; vector<string> res;
size_t pos = 0; size_t pos = 0;
while (pos < str.size()) { while (pos < str.size()) {
size_t len; size_t len;

View File

@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/base64.h" #include "td/utils/base64.h"
#include "td/utils/bits.h"
#include "td/utils/BigNum.h" #include "td/utils/BigNum.h"
#include "td/utils/bits.h"
#include "td/utils/HttpUrl.h" #include "td/utils/HttpUrl.h"
#include "td/utils/invoke.h" #include "td/utils/invoke.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"