mirror of
				https://github.com/ton-blockchain/ton
				synced 2025-03-09 15:40:10 +00:00 
			
		
		
		
	- updated tonlib - updated validator - updated documentation - first version of http over rldp proxy
		
			
				
	
	
		
			307 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    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-2020 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_;
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return offset_ == npos;
 | 
						|
  }
 | 
						|
 | 
						|
 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
 |