/*
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 .
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include
#include
#include
namespace td {
namespace detail {
template
class MaxSizeImpl {};
template
constexpr const T &constexpr_max(const T &a, const T &b) {
return a < b ? b : a;
}
template
class MaxSizeImpl {
public:
static constexpr size_t value = MaxSizeImpl::value;
};
template
class MaxSizeImpl {
public:
static constexpr size_t value = Res;
};
template
class MaxSize {
public:
static constexpr size_t value = MaxSizeImpl<0, sizeof(Args)...>::value;
};
template
class IthTypeImpl {};
template
class IthTypeImpl<0, Res, Args...> {
public:
using type = Res;
};
template
class IthTypeImpl : public IthTypeImpl {};
class Dummy {};
template
class IthType : public IthTypeImpl {};
template
class FindTypeOffsetImpl {};
template
class FindTypeOffsetImpl {
public:
static constexpr int value = offset;
};
template
class FindTypeOffsetImpl
: public FindTypeOffsetImpl::value, offset + 1, T, Types...> {};
template
class FindTypeOffset : public FindTypeOffsetImpl {};
template
class ForEachTypeImpl {};
template
class ForEachTypeImpl {
public:
template
static void visit(F &&f) {
}
};
template
class ForEachTypeImpl {
public:
template
static void visit(F &&f) {
f(offset, static_cast(nullptr));
ForEachTypeImpl::visit(f);
}
};
template
class ForEachType {
public:
template
static void visit(F &&f) {
ForEachTypeImpl<0, Types..., Dummy>::visit(f);
}
};
} // namespace detail
template
class Variant {
public:
static constexpr int npos = -1;
Variant() {
}
Variant(Variant &&other) noexcept {
other.visit([&](auto &&value) { this->init_empty(std::forward(value)); });
}
Variant(const Variant &other) {
other.visit([&](auto &&value) { this->init_empty(std::forward(value)); });
}
Variant &operator=(Variant &&other) {
clear();
other.visit([&](auto &&value) { this->init_empty(std::forward(value)); });
return *this;
}
Variant &operator=(const Variant &other) {
clear();
other.visit([&](auto &&value) { this->init_empty(std::forward(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;
if (offset == offset_) {
res = this->get() == other.template get();
}
});
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;
if (offset == offset_) {
res = this->get() < other.template get();
}
});
return res;
}
template , Variant>::value, int> = 0>
Variant(T &&t) {
init_empty(std::forward(t));
}
template , Variant>::value, int> = 0>
Variant &operator=(T &&t) {
clear();
init_empty(std::forward(t));
return *this;
}
template
static constexpr int offset() {
return detail::FindTypeOffset, Types...>::value;
}
template
void init_empty(T &&t) {
LOG_CHECK(offset_ == npos) << offset_
#if TD_CLANG || TD_GCC
<< ' ' << __PRETTY_FUNCTION__
#endif
;
offset_ = offset();
new (&get()) std::decay_t(std::forward(t));
}
~Variant() {
clear();
}
template
void visit(F &&f) {
for_each([&](int offset, auto *ptr) {
using T = std::decay_t;
if (offset == offset_) {
f(std::move(*this->get_unsafe()));
}
});
}
template
void for_each(F &&f) {
detail::ForEachType::visit(f);
}
template
void visit(F &&f) const {
for_each([&](int offset, auto *ptr) {
using T = std::decay_t;
if (offset == offset_) {
f(std::move(*this->get_unsafe()));
}
});
}
template
void for_each(F &&f) const {
detail::ForEachType::visit(f);
}
void clear() {
visit([](auto &&value) {
using T = std::decay_t;
value.~T();
});
offset_ = npos;
}
template
auto &get() {
CHECK(offset == offset_);
return *get_unsafe();
}
template
auto &get() {
return get()>();
}
template
const auto &get() const {
CHECK(offset == offset_);
return *get_unsafe();
}
template
const auto &get() const {
return get()>();
}
int32 get_offset() const {
return offset_;
}
private:
union {
int64 align_;
char data_[detail::MaxSize::value];
};
int offset_{npos};
template
auto *get_unsafe() {
return reinterpret_cast(data_);
}
template
auto *get_unsafe() {
using T = typename detail::IthType::type;
return get_unsafe();
}
template
const auto *get_unsafe() const {
return reinterpret_cast(data_);
}
template
const auto *get_unsafe() const {
using T = typename detail::IthType::type;
return get_unsafe();
}
};
template
auto &get(Variant &v) {
return v.template get();
}
template
auto &get(const Variant &v) {
return v.template get();
}
template
auto &get(Variant &v) {
return v.template get();
}
template
auto &get(const Variant &v) {
return v.template get();
}
} // namespace td