#pragma once #include #include #include #include #include #include #include #include #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 struct is_safe_obj : std::integral_constant>::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 void __get(std::unordered_map &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 void __get(std::vector &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 void __get(std::list &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 void __get(T &x) { if constexpr (is_safe_obj()) { static_assert(!std::is_reference()); memcpy(&x, (void *)data, sizeof(x)); data += sizeof(T); DO_BUF_CHK(); } else { x.unpack(*this); } } public: template void apply(T &... args) { (__get(args), ...); } void read(void *dst, size_t n) { memcpy(dst, (void *)data, n); data += n; DO_BUF_CHK(); } }; template class WBStreamImpl { public: container data; private: template void __put(std::unordered_map const &x) { bsize_t sz = (bsize_t)x.size(); __put(sz); for (auto &[k, v] : x) { __put(k); __put(v); } } template void __put(std::vector const &x) { bsize_t sz = x.size(); __put(sz); for (auto i = x.begin(); i != x.end(); ++i) { __put(*i); } } template void __put(std::list 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 void __put(T const &x) { if constexpr (is_safe_obj()) { data.append((const char *)&x, sizeof(T)); } else { x.pack(*this); } } public: WBStreamImpl() {} WBStreamImpl(container &&x) : data(x) {} template 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; 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); }