#include "TupleCodec.h" #include #include #include #include #include namespace nt::TupleCodec { static std::vector Sorted(std::vector attrs) { std::sort(attrs.begin(), attrs.end(), [](const Attribute& a, const Attribute& b) { return a.name < b.name; }); return attrs; } std::string Hash(const std::vector& attrs) { auto bytes = Serialize(attrs); return picosha2::hash256_hex_string(bytes.begin(), bytes.end()); } std::vector Serialize(const std::vector& attrs) { // Format: [uint32_le name_len][name][uint32_le value_len][value] ... // Attributes are stored in sorted name order for determinism. std::vector out; auto write_u32 = [&](uint32_t n) { out.push_back(static_cast(n)); out.push_back(static_cast(n >> 8)); out.push_back(static_cast(n >> 16)); out.push_back(static_cast(n >> 24)); }; for (const auto& a : Sorted({attrs.begin(), attrs.end()})) { write_u32(static_cast(a.name.size())); out.insert(out.end(), a.name.begin(), a.name.end()); write_u32(static_cast(a.value.size())); out.insert(out.end(), a.value.begin(), a.value.end()); } return out; } std::vector Deserialize(const std::vector& bytes) { auto read_u32 = [&](size_t pos) -> uint32_t { return static_cast(bytes[pos]) | (static_cast(bytes[pos + 1]) << 8) | (static_cast(bytes[pos + 2]) << 16) | (static_cast(bytes[pos + 3]) << 24); }; std::vector result; size_t pos = 0; while (pos + 8 <= bytes.size()) { uint32_t name_len = read_u32(pos); pos += 4; std::string name(reinterpret_cast(bytes.data() + pos), name_len); pos += name_len; uint32_t value_len = read_u32(pos); pos += 4; std::string value(reinterpret_cast(bytes.data() + pos), value_len); pos += value_len; result.push_back({std::move(name), std::move(value)}); } return result; } } // namespace nt::TupleCodec