#pragma once #include <cstdint> #include <cstring> #include <list> #include <string> #include <string_view> #include <type_traits> #include <unordered_map> #include <vector> #ifdef BUF_CHK # define DO_BUF_CHK() assert(datamax > data) # define BUF_CHK_VAR uintptr_t datamax #else # define DO_BUF_CHK() # define BUF_CHK_VAR #endif template <class T> struct is_safe_obj : std::integral_constant<bool, !std::is_class<std::remove_reference_t<T>>::value> {}; typedef unsigned int bsize_t; class RBStream { public: uintptr_t data; BUF_CHK_VAR; RBStream(void *dat, size_t len) { data = (uintptr_t)dat; (void)len; #ifdef BUF_CHK datamax = data; datamax += len; #endif } RBStream(std::string_view x) { *this = {(void *)x.data(), (size_t)x.size()}; } private: template <typename T1, typename T2> void __get(std::unordered_map<T1, T2> &x) { bsize_t sz; __get(sz); x.reserve(sz); for (bsize_t i = 0; i < sz; ++i) { T1 local; T2 local2; __get(local); __get(local2); x.insert({std::move(local), std::move(local2)}); } } template <typename T1> void __get(std::vector<T1> &x) { bsize_t sz; __get(sz); x.reserve(sz); for (bsize_t i = 0; i < sz; ++i) { T1 local; __get(local); x.push_back(std::move(local)); } } template <typename T1> void __get(std::list<T1> &x) { bsize_t sz; __get(sz); for (bsize_t i = 0; i < sz; ++i) { T1 local; __get(local); x.push_back(std::move(local)); } } void __get(std::string &x) { bsize_t sz; __get(sz); x.reserve(sz); x.append((const char *)data, sz); data += sz; DO_BUF_CHK(); } template <typename T> void __get(T &x) { if constexpr (is_safe_obj<T>()) { static_assert(!std::is_reference<T>()); memcpy(&x, (void *)data, sizeof(x)); data += sizeof(T); DO_BUF_CHK(); } else { x.unpack(*this); } } public: template <typename... T> void apply(T &... args) { (__get(args), ...); } void read(void *dst, size_t n) { memcpy(dst, (void *)data, n); data += n; DO_BUF_CHK(); } }; template <typename container> class WBStreamImpl { public: container data; private: template <typename T1, typename T2> void __put(std::unordered_map<T1, T2> const &x) { bsize_t sz = (bsize_t)x.size(); __put(sz); for (auto &[k, v] : x) { __put(k); __put(v); } } template <typename T2> void __put(std::vector<T2> const &x) { bsize_t sz = x.size(); __put(sz); for (auto i = x.begin(); i != x.end(); ++i) { __put(*i); } } template <typename T2> void __put(std::list<T2> const &x) { bsize_t sz = (bsize_t)x.size(); __put(sz); for (auto i = x.begin(); i != x.end(); ++i) { __put(*i); } } void __put(std::string const &x) { __put((bsize_t)x.size()); data.append(x); } void __put(std::string_view const &x) { __put((bsize_t)x.size()); data.append(x); } template <typename T> void __put(T const &x) { if constexpr (is_safe_obj<T>()) { data.append((const char *)&x, sizeof(T)); } else { x.pack(*this); } } public: WBStreamImpl() {} WBStreamImpl(container &&x) : data(x) {} template <typename... T> void apply(T const &... args) { (__put(args), ...); } void write(const void *src, size_t n) { data.append((const char *)src, n); } operator std::string_view() { return data; } }; using WBStream = WBStreamImpl<std::string>; struct BinVariant { /*long long or string*/ union VType { long long x; std::string y; VType() {} ~VType() {} } v; unsigned char type; BinVariant(long long x) { type = 1; v.x = x; } BinVariant(std::string &&x) { type = 2; new (&v.y) std::string(std::move(x)); } BinVariant(std::string const &x) { type = 2; new (&v.y) std::string(x); } BinVariant() { type = 0; } ~BinVariant() { if (type == 2) { v.y.~basic_string(); } } void unpack(RBStream &rs) { rs.apply(type); switch (type) { case 1: { rs.apply(v.x); } break; case 2: { new (&v.y) std::string(); rs.apply(v.y); } } } void pack(WBStream &ws) const { ws.apply(type); switch (type) { case 1: { ws.apply(v.x); } break; case 2: { ws.apply(v.y); } } } }; static inline unsigned long long ZigZag(long long x) { return (x << 1) ^ (x >> 63); }