mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
initial commit
This commit is contained in:
commit
c2da007f40
1610 changed files with 398047 additions and 0 deletions
303
tdutils/td/utils/Variant.h
Normal file
303
tdutils/td/utils/Variant.h
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace td {
|
||||
namespace detail {
|
||||
|
||||
template <size_t... Args>
|
||||
class MaxSizeImpl {};
|
||||
|
||||
template <class T>
|
||||
constexpr const T &constexpr_max(const T &a, const T &b) {
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
template <size_t Res, size_t X, size_t... Args>
|
||||
class MaxSizeImpl<Res, X, Args...> {
|
||||
public:
|
||||
static constexpr size_t value = MaxSizeImpl<constexpr_max(Res, X), Args...>::value;
|
||||
};
|
||||
|
||||
template <size_t Res>
|
||||
class MaxSizeImpl<Res> {
|
||||
public:
|
||||
static constexpr size_t value = Res;
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
class MaxSize {
|
||||
public:
|
||||
static constexpr size_t value = MaxSizeImpl<0, sizeof(Args)...>::value;
|
||||
};
|
||||
|
||||
template <size_t to_skip, class... Args>
|
||||
class IthTypeImpl {};
|
||||
template <class Res, class... Args>
|
||||
class IthTypeImpl<0, Res, Args...> {
|
||||
public:
|
||||
using type = Res;
|
||||
};
|
||||
template <size_t pos, class Skip, class... Args>
|
||||
class IthTypeImpl<pos, Skip, Args...> : public IthTypeImpl<pos - 1, Args...> {};
|
||||
|
||||
class Dummy {};
|
||||
|
||||
template <size_t pos, class... Args>
|
||||
class IthType : public IthTypeImpl<pos, Args..., Dummy> {};
|
||||
|
||||
template <bool ok, int offset, class... Types>
|
||||
class FindTypeOffsetImpl {};
|
||||
|
||||
template <int offset, class... Types>
|
||||
class FindTypeOffsetImpl<true, offset, Types...> {
|
||||
public:
|
||||
static constexpr int value = offset;
|
||||
};
|
||||
template <int offset, class T, class S, class... Types>
|
||||
class FindTypeOffsetImpl<false, offset, T, S, Types...>
|
||||
: public FindTypeOffsetImpl<std::is_same<T, S>::value, offset + 1, T, Types...> {};
|
||||
template <class T, class... Types>
|
||||
class FindTypeOffset : public FindTypeOffsetImpl<false, -1, T, Types...> {};
|
||||
|
||||
template <int offset, class... Types>
|
||||
class ForEachTypeImpl {};
|
||||
|
||||
template <int offset>
|
||||
class ForEachTypeImpl<offset, Dummy> {
|
||||
public:
|
||||
template <class F>
|
||||
static void visit(F &&f) {
|
||||
}
|
||||
};
|
||||
|
||||
template <int offset, class T, class... Types>
|
||||
class ForEachTypeImpl<offset, T, Types...> {
|
||||
public:
|
||||
template <class F>
|
||||
static void visit(F &&f) {
|
||||
f(offset, static_cast<T *>(nullptr));
|
||||
ForEachTypeImpl<offset + 1, Types...>::visit(f);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... Types>
|
||||
class ForEachType {
|
||||
public:
|
||||
template <class F>
|
||||
static void visit(F &&f) {
|
||||
ForEachTypeImpl<0, Types..., Dummy>::visit(f);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class... Types>
|
||||
class Variant {
|
||||
public:
|
||||
static constexpr int npos = -1;
|
||||
Variant() {
|
||||
}
|
||||
Variant(Variant &&other) noexcept {
|
||||
other.visit([&](auto &&value) { this->init_empty(std::forward<decltype(value)>(value)); });
|
||||
}
|
||||
Variant(const Variant &other) {
|
||||
other.visit([&](auto &&value) { this->init_empty(std::forward<decltype(value)>(value)); });
|
||||
}
|
||||
Variant &operator=(Variant &&other) {
|
||||
clear();
|
||||
other.visit([&](auto &&value) { this->init_empty(std::forward<decltype(value)>(value)); });
|
||||
return *this;
|
||||
}
|
||||
Variant &operator=(const Variant &other) {
|
||||
clear();
|
||||
other.visit([&](auto &&value) { this->init_empty(std::forward<decltype(value)>(value)); });
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Variant &other) const {
|
||||
if (offset_ != other.offset_) {
|
||||
return false;
|
||||
}
|
||||
bool res = false;
|
||||
for_each([&](int offset, auto *ptr) {
|
||||
using T = std::decay_t<decltype(*ptr)>;
|
||||
if (offset == offset_) {
|
||||
res = this->get<T>() == other.template get<T>();
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
bool operator<(const Variant &other) const {
|
||||
if (offset_ != other.offset_) {
|
||||
return offset_ < other.offset_;
|
||||
}
|
||||
bool res = false;
|
||||
for_each([&](int offset, auto *ptr) {
|
||||
using T = std::decay_t<decltype(*ptr)>;
|
||||
if (offset == offset_) {
|
||||
res = this->get<T>() < other.template get<T>();
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T, std::enable_if_t<!std::is_same<std::decay_t<T>, Variant>::value, int> = 0>
|
||||
Variant(T &&t) {
|
||||
init_empty(std::forward<T>(t));
|
||||
}
|
||||
template <class T, std::enable_if_t<!std::is_same<std::decay_t<T>, Variant>::value, int> = 0>
|
||||
Variant &operator=(T &&t) {
|
||||
clear();
|
||||
init_empty(std::forward<T>(t));
|
||||
return *this;
|
||||
}
|
||||
template <class T>
|
||||
static constexpr int offset() {
|
||||
return detail::FindTypeOffset<std::decay_t<T>, Types...>::value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void init_empty(T &&t) {
|
||||
LOG_CHECK(offset_ == npos) << offset_
|
||||
#if TD_CLANG || TD_GCC
|
||||
<< ' ' << __PRETTY_FUNCTION__
|
||||
#endif
|
||||
;
|
||||
offset_ = offset<T>();
|
||||
new (&get<T>()) std::decay_t<T>(std::forward<T>(t));
|
||||
}
|
||||
~Variant() {
|
||||
clear();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void visit(F &&f) {
|
||||
for_each([&](int offset, auto *ptr) {
|
||||
using T = std::decay_t<decltype(*ptr)>;
|
||||
if (offset == offset_) {
|
||||
f(std::move(*this->get_unsafe<T>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
template <class F>
|
||||
void for_each(F &&f) {
|
||||
detail::ForEachType<Types...>::visit(f);
|
||||
}
|
||||
template <class F>
|
||||
void visit(F &&f) const {
|
||||
for_each([&](int offset, auto *ptr) {
|
||||
using T = std::decay_t<decltype(*ptr)>;
|
||||
if (offset == offset_) {
|
||||
f(std::move(*this->get_unsafe<T>()));
|
||||
}
|
||||
});
|
||||
}
|
||||
template <class F>
|
||||
void for_each(F &&f) const {
|
||||
detail::ForEachType<Types...>::visit(f);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
visit([](auto &&value) {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
value.~T();
|
||||
});
|
||||
offset_ = npos;
|
||||
}
|
||||
|
||||
template <int offset>
|
||||
auto &get() {
|
||||
CHECK(offset == offset_);
|
||||
return *get_unsafe<offset>();
|
||||
}
|
||||
template <class T>
|
||||
auto &get() {
|
||||
return get<offset<T>()>();
|
||||
}
|
||||
|
||||
template <int offset>
|
||||
const auto &get() const {
|
||||
CHECK(offset == offset_);
|
||||
return *get_unsafe<offset>();
|
||||
}
|
||||
template <class T>
|
||||
const auto &get() const {
|
||||
return get<offset<T>()>();
|
||||
}
|
||||
|
||||
int32 get_offset() const {
|
||||
return offset_;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
int64 align_;
|
||||
char data_[detail::MaxSize<Types...>::value];
|
||||
};
|
||||
int offset_{npos};
|
||||
|
||||
template <class T>
|
||||
auto *get_unsafe() {
|
||||
return reinterpret_cast<T *>(data_);
|
||||
}
|
||||
|
||||
template <int offset>
|
||||
auto *get_unsafe() {
|
||||
using T = typename detail::IthType<offset, Types...>::type;
|
||||
return get_unsafe<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const auto *get_unsafe() const {
|
||||
return reinterpret_cast<const T *>(data_);
|
||||
}
|
||||
|
||||
template <int offset>
|
||||
const auto *get_unsafe() const {
|
||||
using T = typename detail::IthType<offset, Types...>::type;
|
||||
return get_unsafe<T>();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... Types>
|
||||
auto &get(Variant<Types...> &v) {
|
||||
return v.template get<T>();
|
||||
}
|
||||
template <class T, class... Types>
|
||||
auto &get(const Variant<Types...> &v) {
|
||||
return v.template get<T>();
|
||||
}
|
||||
template <int T, class... Types>
|
||||
auto &get(Variant<Types...> &v) {
|
||||
return v.template get<T>();
|
||||
}
|
||||
template <int T, class... Types>
|
||||
auto &get(const Variant<Types...> &v) {
|
||||
return v.template get<T>();
|
||||
}
|
||||
|
||||
} // namespace td
|
Loading…
Add table
Add a link
Reference in a new issue