init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
This commit is contained in:
1689
Telegram/lib_tl/tl/generate_tl.py
Normal file
1689
Telegram/lib_tl/tl/generate_tl.py
Normal file
File diff suppressed because it is too large
Load Diff
15
Telegram/lib_tl/tl/tl_basic_types.cpp
Normal file
15
Telegram/lib_tl/tl/tl_basic_types.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "tl/tl_basic_types.h"
|
||||
|
||||
namespace tl {
|
||||
|
||||
QString utf16(const QByteArray &v) {
|
||||
return QString::fromUtf8(v);
|
||||
}
|
||||
|
||||
} // namespace tl
|
||||
683
Telegram/lib_tl/tl/tl_basic_types.h
Normal file
683
Telegram/lib_tl/tl/tl_basic_types.h
Normal file
@@ -0,0 +1,683 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/basic_types.h"
|
||||
#include "base/flags.h"
|
||||
#include "base/bytes.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace tl {
|
||||
namespace details {
|
||||
|
||||
struct zero_flags_helper {
|
||||
};
|
||||
|
||||
struct LengthCounter {
|
||||
uint32 length = 0;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename Accumulator>
|
||||
struct Writer;
|
||||
|
||||
template <typename Prime>
|
||||
struct Reader;
|
||||
|
||||
template <>
|
||||
struct Writer<details::LengthCounter> final {
|
||||
static void PutBytes(details::LengthCounter &to, const void *bytes, uint32 count) noexcept {
|
||||
constexpr auto kPrime = sizeof(uint32);
|
||||
const auto primes = (count / kPrime) + (count % kPrime ? 1 : 0);
|
||||
to.length += primes * kPrime;
|
||||
}
|
||||
static void Put(details::LengthCounter &to, uint32 value) noexcept {
|
||||
to.length += sizeof(uint32);
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename = decltype(
|
||||
std::declval<T>().write(std::declval<details::LengthCounter&>()))>
|
||||
uint32 count_length(const T &value) noexcept {
|
||||
auto counter = details::LengthCounter();
|
||||
value.write(counter);
|
||||
return counter.length;
|
||||
}
|
||||
|
||||
enum {
|
||||
id_int = 0xa8509bda,
|
||||
id_long = 0x22076cba,
|
||||
id_int128 = 0x4bb5362b,
|
||||
id_int256 = 0x929c32f,
|
||||
id_double = 0x2210c154,
|
||||
id_string = 0xb5286e24,
|
||||
id_vector = 0x1cb5c415,
|
||||
|
||||
id_bytes = id_string,
|
||||
id_flags = id_int,
|
||||
id_flags64 = id_long,
|
||||
};
|
||||
|
||||
class int_type {
|
||||
public:
|
||||
int32 v = 0;
|
||||
|
||||
constexpr int_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_int;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int) noexcept {
|
||||
if (!Reader<Prime>::Has(1, from, end) || cons != id_int) {
|
||||
return false;
|
||||
}
|
||||
v = static_cast<int32>(Reader<Prime>::Get(from, end));
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr int_type(int32 val) noexcept : v(val) {
|
||||
}
|
||||
|
||||
friend constexpr int_type make_int(int32 v) noexcept;
|
||||
};
|
||||
inline constexpr int_type make_int(int32 v) noexcept {
|
||||
return int_type(v);
|
||||
}
|
||||
|
||||
template <typename Flags>
|
||||
class flags_type {
|
||||
public:
|
||||
Flags v = 0;
|
||||
static_assert(
|
||||
sizeof(Flags) == sizeof(int32) || sizeof(Flags) == sizeof(int64),
|
||||
"flags_type are allowed only wrapping int32 or int64 flag types!");
|
||||
|
||||
constexpr flags_type() noexcept = default;
|
||||
constexpr flags_type(details::zero_flags_helper helper) noexcept {
|
||||
}
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return (sizeof(Flags) == sizeof(int32)) ? id_flags : id_flags64;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_flags) noexcept {
|
||||
if (!Reader<Prime>::Has(1, from, end) || cons != id_flags) {
|
||||
return false;
|
||||
}
|
||||
v = Flags::from_raw(static_cast<typename Flags::Type>(Reader<Prime>::Get(from, end)));
|
||||
if constexpr (sizeof(Flags) != sizeof(int32)) {
|
||||
if (!Reader<Prime>::Has(1, from, end)) {
|
||||
return false;
|
||||
}
|
||||
v |= Flags::from_raw(static_cast<typename Flags::Type>(Reader<Prime>::Get(from, end)) << 32);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
if constexpr (sizeof(Flags) == sizeof(int32)) {
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value()));
|
||||
} else {
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value() & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value() >> 32));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr flags_type(Flags val) noexcept : v(val) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
friend constexpr flags_type<base::flags<T>> make_flags(base::flags<T> v) noexcept;
|
||||
|
||||
template <typename T, typename>
|
||||
friend constexpr flags_type<base::flags<T>> make_flags(T v) noexcept;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr flags_type<base::flags<T>> make_flags(base::flags<T> v) noexcept {
|
||||
return flags_type<base::flags<T>>(v);
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<!std::is_same<T, int>::value>>
|
||||
inline constexpr flags_type<base::flags<T>> make_flags(T v) noexcept {
|
||||
return flags_type<base::flags<T>>(v);
|
||||
}
|
||||
|
||||
inline constexpr details::zero_flags_helper make_flags(void(details::zero_flags_helper::*)()) noexcept {
|
||||
return details::zero_flags_helper();
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const int_type &a, const int_type &b) noexcept {
|
||||
return a.v == b.v;
|
||||
}
|
||||
inline constexpr bool operator!=(const int_type &a, const int_type &b) noexcept {
|
||||
return a.v != b.v;
|
||||
}
|
||||
|
||||
class long_type {
|
||||
public:
|
||||
uint64 v = 0;
|
||||
|
||||
constexpr long_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_long;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_long) noexcept {
|
||||
if (!Reader<Prime>::Has(2, from, end) || cons != id_long) {
|
||||
return false;
|
||||
}
|
||||
v = static_cast<uint64>(Reader<Prime>::Get(from, end));
|
||||
v |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(v >> 32));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr long_type(uint64 val) noexcept : v(val) {
|
||||
}
|
||||
|
||||
friend constexpr long_type make_long(uint64 v) noexcept;
|
||||
};
|
||||
inline constexpr long_type make_long(uint64 v) noexcept {
|
||||
return long_type(v);
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const long_type &a, const long_type &b) noexcept {
|
||||
return a.v == b.v;
|
||||
}
|
||||
inline constexpr bool operator!=(const long_type &a, const long_type &b) noexcept {
|
||||
return a.v != b.v;
|
||||
}
|
||||
|
||||
class int64_type {
|
||||
public:
|
||||
int64 v = 0;
|
||||
|
||||
constexpr int64_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_long;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_long) noexcept {
|
||||
if (!Reader<Prime>::Has(2, from, end) || cons != id_long) {
|
||||
return false;
|
||||
}
|
||||
auto data = static_cast<uint64>(Reader<Prime>::Get(from, end));
|
||||
data |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
|
||||
v = static_cast<int64>(data);
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
const auto data = static_cast<uint64>(v);
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(data & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(data >> 32));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr int64_type(int64 val) noexcept : v(val) {
|
||||
}
|
||||
|
||||
friend constexpr int64_type make_int64(int64 v) noexcept;
|
||||
};
|
||||
inline constexpr int64_type make_int64(int64 v) noexcept {
|
||||
return int64_type(v);
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const int64_type &a, const int64_type &b) noexcept {
|
||||
return a.v == b.v;
|
||||
}
|
||||
inline constexpr bool operator!=(const int64_type &a, const int64_type &b) noexcept {
|
||||
return a.v != b.v;
|
||||
}
|
||||
|
||||
class int128_type {
|
||||
public:
|
||||
uint64 l = 0;
|
||||
uint64 h = 0;
|
||||
|
||||
constexpr int128_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_int128;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int128) noexcept {
|
||||
if (!Reader<Prime>::Has(4, from, end) || cons != id_int128) {
|
||||
return false;
|
||||
}
|
||||
l = static_cast<uint64>(Reader<Prime>::Get(from, end));
|
||||
l |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
|
||||
h = static_cast<uint64>(Reader<Prime>::Get(from, end));
|
||||
h |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(l & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(l >> 32));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(h & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(h >> 32));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr int128_type(uint64 low, uint64 high) noexcept : l(low), h(high) {
|
||||
}
|
||||
|
||||
friend constexpr int128_type make_int128(uint64 l, uint64 h) noexcept;
|
||||
};
|
||||
inline constexpr int128_type make_int128(uint64 l, uint64 h) noexcept {
|
||||
return int128_type(l, h);
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const int128_type &a, const int128_type &b) noexcept {
|
||||
return a.l == b.l && a.h == b.h;
|
||||
}
|
||||
inline constexpr bool operator!=(const int128_type &a, const int128_type &b) noexcept {
|
||||
return a.l != b.l || a.h != b.h;
|
||||
}
|
||||
|
||||
class int256_type {
|
||||
public:
|
||||
int128_type l;
|
||||
int128_type h;
|
||||
|
||||
constexpr int256_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_int256;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int256) noexcept {
|
||||
if (cons != id_int256) {
|
||||
return false;
|
||||
}
|
||||
return l.read(from, end) && h.read(from, end);
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
l.write(to);
|
||||
h.write(to);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr int256_type(int128_type low, int128_type high) noexcept : l(low), h(high) {
|
||||
}
|
||||
|
||||
friend constexpr int256_type make_int256(const int128_type &l, const int128_type &h) noexcept;
|
||||
};
|
||||
inline constexpr int256_type make_int256(const int128_type &l, const int128_type &h) noexcept {
|
||||
return int256_type(l, h);
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const int256_type &a, const int256_type &b) noexcept {
|
||||
return a.l == b.l && a.h == b.h;
|
||||
}
|
||||
inline constexpr bool operator!=(const int256_type &a, const int256_type &b) noexcept {
|
||||
return a.l != b.l || a.h != b.h;
|
||||
}
|
||||
|
||||
class double_type {
|
||||
public:
|
||||
float64 v = 0.;
|
||||
|
||||
constexpr double_type() noexcept = default;
|
||||
|
||||
constexpr uint32 type() const noexcept {
|
||||
return id_double;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_double) noexcept {
|
||||
if (!Reader<Prime>::Has(2, from, end) || cons != id_double) {
|
||||
return false;
|
||||
}
|
||||
auto nonaliased = static_cast<uint64>(Reader<Prime>::Get(from, end));
|
||||
nonaliased |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
|
||||
static_assert(sizeof(v) == sizeof(nonaliased));
|
||||
std::memcpy(&v, &nonaliased, sizeof(v));
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
auto nonaliased = uint64();
|
||||
static_assert(sizeof(v) == sizeof(nonaliased));
|
||||
std::memcpy(&nonaliased, &v, sizeof(v));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(nonaliased & 0xFFFFFFFFULL));
|
||||
Writer<Accumulator>::Put(to, static_cast<uint32>(nonaliased >> 32));
|
||||
}
|
||||
|
||||
private:
|
||||
explicit constexpr double_type(float64 val) noexcept : v(val) {
|
||||
}
|
||||
|
||||
friend constexpr double_type make_double(float64 v) noexcept;
|
||||
};
|
||||
inline constexpr double_type make_double(float64 v) noexcept {
|
||||
return double_type(v);
|
||||
}
|
||||
|
||||
inline constexpr bool operator==(const double_type &a, const double_type &b) noexcept {
|
||||
return a.v == b.v;
|
||||
}
|
||||
inline constexpr bool operator!=(const double_type &a, const double_type &b) noexcept {
|
||||
return a.v != b.v;
|
||||
}
|
||||
|
||||
class string_type;
|
||||
using bytes_type = string_type;
|
||||
|
||||
class string_type {
|
||||
public:
|
||||
string_type() noexcept = default;
|
||||
|
||||
uint32 type() const noexcept {
|
||||
return id_string;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_string) noexcept {
|
||||
if (!Reader<Prime>::Has(1, from, end) || cons != id_string) {
|
||||
return false;
|
||||
}
|
||||
const auto first = Reader<Prime>::Get(from, end);
|
||||
const auto last = (first & 0xFFU);
|
||||
if (last > 254) {
|
||||
return false;
|
||||
} else if (last == 0) {
|
||||
v = QByteArray();
|
||||
} else if (last == 1) {
|
||||
v = QByteArray(1, static_cast<char>((first >> 8) & 0xFFU));
|
||||
} else if (last == 2) {
|
||||
v = QByteArray(2, Qt::Uninitialized);
|
||||
v[0] = static_cast<char>((first >> 8) & 0xFFU);
|
||||
v[1] = static_cast<char>((first >> 16) & 0xFFU);
|
||||
} else if (last < 254) {
|
||||
v = QByteArray(last, Qt::Uninitialized);
|
||||
const auto remaining = last - 3;
|
||||
if (!Reader<Prime>::HasBytes(remaining, from, end)) {
|
||||
return false;
|
||||
}
|
||||
v[0] = static_cast<char>((first >> 8) & 0xFFU);
|
||||
v[1] = static_cast<char>((first >> 16) & 0xFFU);
|
||||
v[2] = static_cast<char>((first >> 24) & 0xFFU);
|
||||
Reader<Prime>::GetBytes(v.data() + 3, remaining, from, end);
|
||||
} else {
|
||||
const auto length = (first >> 8);
|
||||
if (!Reader<Prime>::HasBytes(length, from, end)) {
|
||||
return false;
|
||||
}
|
||||
v = QByteArray(length, Qt::Uninitialized);
|
||||
Reader<Prime>::GetBytes(v.data(), length, from, end);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
Expects(v.size() < 0x1000000);
|
||||
|
||||
const auto size = uint32(v.size());
|
||||
if (size == 0) {
|
||||
Writer<Accumulator>::Put(to, size);
|
||||
} else if (size == 1) {
|
||||
Writer<Accumulator>::Put(to, size
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8));
|
||||
} else if (size == 2) {
|
||||
Writer<Accumulator>::Put(to, size
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8)
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[1])) << 16));
|
||||
} else if (size < 254) {
|
||||
Writer<Accumulator>::Put(to, size
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8)
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[1])) << 16)
|
||||
| (static_cast<uint32>(static_cast<uchar>(v[2])) << 24));
|
||||
Writer<Accumulator>::PutBytes(to, v.data() + 3, size - 3);
|
||||
} else {
|
||||
const auto encoded = (size << 8) | 254U;
|
||||
Writer<Accumulator>::Put(to, encoded);
|
||||
Writer<Accumulator>::PutBytes(to, v.data(), size);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray v;
|
||||
|
||||
private:
|
||||
explicit string_type(QByteArray &&data) noexcept : v(std::move(data)) {
|
||||
}
|
||||
|
||||
friend string_type make_string(const std::string &v);
|
||||
friend string_type make_string(const QByteArray &v);
|
||||
friend string_type make_string(QByteArray &&v);
|
||||
friend string_type make_string(const QString &v);
|
||||
friend string_type make_string(const char *v);
|
||||
friend string_type make_string();
|
||||
|
||||
friend bytes_type make_bytes(const QByteArray &v);
|
||||
friend bytes_type make_bytes(QByteArray &&v);
|
||||
friend bytes_type make_bytes();
|
||||
|
||||
};
|
||||
|
||||
inline string_type make_string(const std::string &v) {
|
||||
return string_type(QByteArray(v.data(), v.size()));
|
||||
}
|
||||
inline string_type make_string(const QByteArray &v) {
|
||||
return string_type(QByteArray(v));
|
||||
}
|
||||
inline string_type make_string(QByteArray &&v) {
|
||||
return string_type(std::move(v));
|
||||
}
|
||||
inline string_type make_string(const QString &v) {
|
||||
return string_type(v.toUtf8());
|
||||
}
|
||||
inline string_type make_string(const char *v) {
|
||||
return string_type(QByteArray(v, strlen(v)));
|
||||
}
|
||||
inline string_type make_string() {
|
||||
return string_type(QByteArray());
|
||||
}
|
||||
inline bytes_type make_bytes(const QByteArray &v) {
|
||||
return bytes_type(QByteArray(v));
|
||||
}
|
||||
inline bytes_type make_bytes(QByteArray &&v) {
|
||||
return bytes_type(std::move(v));
|
||||
}
|
||||
inline bytes_type make_bytes() {
|
||||
return bytes_type(QByteArray());
|
||||
}
|
||||
inline bytes_type make_bytes(bytes::const_span buffer) {
|
||||
return make_bytes(QByteArray(
|
||||
reinterpret_cast<const char*>(buffer.data()),
|
||||
buffer.size()));
|
||||
}
|
||||
inline bytes_type make_bytes(const bytes::vector &buffer) {
|
||||
return make_bytes(bytes::make_span(buffer));
|
||||
}
|
||||
|
||||
inline bool operator==(const string_type &a, const string_type &b) {
|
||||
return a.v == b.v;
|
||||
}
|
||||
inline bool operator!=(const string_type &a, const string_type &b) {
|
||||
return a.v != b.v;
|
||||
}
|
||||
|
||||
QString utf16(const QByteArray &v);
|
||||
|
||||
inline QByteArray utf8(const QByteArray &v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
inline QString utf16(const string_type &v) {
|
||||
return utf16(v.v);
|
||||
}
|
||||
|
||||
inline QByteArray utf8(const string_type &v) {
|
||||
return utf8(v.v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class vector_type {
|
||||
public:
|
||||
vector_type() noexcept = default;
|
||||
|
||||
uint32 type() const noexcept {
|
||||
return id_vector;
|
||||
}
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_vector) noexcept {
|
||||
if (!Reader<Prime>::Has(1, from, end) || cons != id_vector) {
|
||||
return false;
|
||||
}
|
||||
auto count = Reader<Prime>::Get(from, end);
|
||||
|
||||
auto vector = QVector<T>(count, T());
|
||||
for (auto &item : vector) {
|
||||
if (!item.read(from, end)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
v = std::move(vector);
|
||||
return true;
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const noexcept {
|
||||
Writer<Accumulator>::Put(to, static_cast<int32>(v.size()));
|
||||
for (const auto &item : v) {
|
||||
item.write(to);
|
||||
}
|
||||
}
|
||||
|
||||
QVector<T> v;
|
||||
|
||||
private:
|
||||
explicit vector_type(QVector<T> &&data) noexcept : v(std::move(data)) {
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
friend vector_type<U> make_vector(uint32 count);
|
||||
template <typename U>
|
||||
friend vector_type<U> make_vector(uint32 count, const U &value);
|
||||
template <typename U>
|
||||
friend vector_type<U> make_vector(const QVector<U> &v);
|
||||
template <typename U>
|
||||
friend vector_type<U> make_vector(QVector<U> &&v);
|
||||
template <typename U>
|
||||
friend vector_type<U> make_vector();
|
||||
|
||||
};
|
||||
template <typename T>
|
||||
inline vector_type<T> make_vector(uint32 count) {
|
||||
return vector_type<T>(QVector<T>(count));
|
||||
}
|
||||
template <typename T>
|
||||
inline vector_type<T> make_vector(uint32 count, const T &value) {
|
||||
return vector_type<T>(QVector<T>(count, value));
|
||||
}
|
||||
template <typename T>
|
||||
inline vector_type<T> make_vector(const QVector<T> &v) {
|
||||
return vector_type<T>(QVector<T>(v));
|
||||
}
|
||||
template <typename T>
|
||||
inline vector_type<T> make_vector(QVector<T> &&v) {
|
||||
return vector_type<T>(std::move(v));
|
||||
}
|
||||
template <typename T>
|
||||
inline vector_type<T> make_vector() {
|
||||
return vector_type<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const vector_type<T> &a, const vector_type<T> &b) {
|
||||
return a.c_vector().v == b.c_vector().v;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool operator!=(const vector_type<T> &a, const vector_type<T> &b) {
|
||||
return a.c_vector().v != b.c_vector().v;
|
||||
}
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename Type>
|
||||
struct repeat_helper {
|
||||
using type = Type;
|
||||
};
|
||||
template <typename Type>
|
||||
using repeat = typename repeat_helper<Type>::type;
|
||||
|
||||
struct inner_helper {
|
||||
static void Check(...);
|
||||
template <typename Type, typename Result = decltype(std::declval<Type>().v)>
|
||||
static Result Check(const Type&);
|
||||
|
||||
template <typename Type>
|
||||
using type = std::decay_t<decltype(Check(std::declval<Type>()))>;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename T>
|
||||
class conditional {
|
||||
public:
|
||||
constexpr conditional() noexcept = default;
|
||||
constexpr conditional(const T *value) noexcept : _value(value) {
|
||||
}
|
||||
|
||||
constexpr operator const T*() const noexcept {
|
||||
return _value;
|
||||
}
|
||||
constexpr const T *operator->() const noexcept {
|
||||
Expects(_value != nullptr);
|
||||
|
||||
return _value;
|
||||
}
|
||||
constexpr const T &operator*() const noexcept {
|
||||
Expects(_value != nullptr);
|
||||
|
||||
return *_value;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Inner = details::inner_helper::type<T>,
|
||||
typename = std::enable_if_t<!std::is_same_v<Inner, void>>>
|
||||
constexpr Inner value_or(details::repeat<Inner> fallback) const noexcept {
|
||||
return _value ? _value->v : fallback;
|
||||
}
|
||||
|
||||
template <
|
||||
typename Inner = details::inner_helper::type<T>,
|
||||
typename = std::enable_if_t<!std::is_same_v<Inner, void>>>
|
||||
constexpr Inner value_or_empty() const noexcept {
|
||||
return _value ? _value->v : Inner();
|
||||
}
|
||||
|
||||
constexpr bool has_value() const noexcept {
|
||||
return (_value != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
const T *_value = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace tl
|
||||
67
Telegram/lib_tl/tl/tl_boxed.h
Normal file
67
Telegram/lib_tl/tl/tl_boxed.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/basic_types.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace tl {
|
||||
|
||||
template <typename Accumulator>
|
||||
struct Writer;
|
||||
|
||||
template <typename bare>
|
||||
class boxed : public bare {
|
||||
public:
|
||||
using bare::bare;
|
||||
|
||||
boxed() = default;
|
||||
boxed(const boxed<bare> &v) = default;
|
||||
boxed<bare> &operator=(const boxed<bare> &v) & = default;
|
||||
boxed(const bare &v) : bare(v) {
|
||||
}
|
||||
boxed<bare> &operator=(const bare &v) & {
|
||||
*((bare*)this) = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Prime>
|
||||
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = 0) {
|
||||
if (!Reader<Prime>::Has(1, from, end)) {
|
||||
return false;
|
||||
}
|
||||
cons = Reader<Prime>::Get(from, end);
|
||||
return bare::read(from, end, cons);
|
||||
}
|
||||
template <typename Accumulator>
|
||||
void write(Accumulator &to) const {
|
||||
Writer<Accumulator>::Put(to, bare::type());
|
||||
bare::write(to);
|
||||
}
|
||||
|
||||
using Unboxed = bare;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class boxed<boxed<T> > {
|
||||
using Unboxed = typename T::CantMakeBoxedBoxedType;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_boxed : std::false_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_boxed<boxed<T>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_boxed_v = is_boxed<T>::value;
|
||||
|
||||
} // namespace tl
|
||||
100
Telegram/lib_tl/tl/tl_type_owner.h
Normal file
100
Telegram/lib_tl/tl/tl_type_owner.h
Normal file
@@ -0,0 +1,100 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/algorithm.h"
|
||||
|
||||
namespace tl::details {
|
||||
|
||||
class type_data {
|
||||
public:
|
||||
type_data() = default;
|
||||
type_data(const type_data &other) = delete;
|
||||
type_data(type_data &&other) = delete;
|
||||
type_data &operator=(const type_data &other) = delete;
|
||||
type_data &operator=(type_data &&other) = delete;
|
||||
|
||||
virtual ~type_data() {
|
||||
}
|
||||
|
||||
private:
|
||||
void incrementCounter() const {
|
||||
_counter.ref();
|
||||
}
|
||||
bool decrementCounter() const {
|
||||
return _counter.deref();
|
||||
}
|
||||
friend class type_owner;
|
||||
|
||||
mutable QAtomicInt _counter = { 1 };
|
||||
|
||||
};
|
||||
|
||||
class type_owner {
|
||||
public:
|
||||
type_owner(type_owner &&other) : _data(base::take(other._data)) {
|
||||
}
|
||||
type_owner(const type_owner &other) : _data(other._data) {
|
||||
incrementCounter();
|
||||
}
|
||||
type_owner &operator=(type_owner &&other) {
|
||||
if (other._data != _data) {
|
||||
decrementCounter();
|
||||
_data = base::take(other._data);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
type_owner &operator=(const type_owner &other) {
|
||||
if (other._data != _data) {
|
||||
setData(other._data);
|
||||
incrementCounter();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~type_owner() {
|
||||
decrementCounter();
|
||||
}
|
||||
|
||||
protected:
|
||||
type_owner() = default;
|
||||
type_owner(const type_data *data) : _data(data) {
|
||||
}
|
||||
|
||||
void setData(const type_data *data) {
|
||||
decrementCounter();
|
||||
_data = data;
|
||||
}
|
||||
|
||||
// Unsafe cast, type should be checked by the caller.
|
||||
template <typename DataType>
|
||||
const DataType &queryData() const {
|
||||
Expects(_data != nullptr);
|
||||
|
||||
return static_cast<const DataType &>(*_data);
|
||||
}
|
||||
|
||||
bool hasData() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void incrementCounter() {
|
||||
if (_data) {
|
||||
_data->incrementCounter();
|
||||
}
|
||||
}
|
||||
void decrementCounter() {
|
||||
if (_data && !_data->decrementCounter()) {
|
||||
delete base::take(_data);
|
||||
}
|
||||
}
|
||||
|
||||
const type_data *_data = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace tl::details
|
||||
Reference in New Issue
Block a user