#pragma once #include "indexer/complex/serdes_utils.hpp" #include "indexer/complex/tree_node.hpp" #include "coding/reader.hpp" #include "coding/varint.hpp" #include "coding/writer.hpp" #include "base/logging.hpp" #include "base/stl_helpers.hpp" #include <string> #include <vector> namespace complex { class ComplexSerdes { public: using Ids = std::vector<uint32_t>; enum class Version : uint8_t { // There aren't optimized serialization and deserialization. It's experimental verison. // todo(m.andrianov): Explore better ways for serialization and deserialization. V0, }; static Version const kLatestVersion; template <typename Sink> static void Serialize(Sink & sink, tree_node::Forest<Ids> const & forest) { SerializeLatestVersion(sink); Serialize(sink, kLatestVersion, forest); } template <typename Reader> static void Deserialize(Reader & reader, tree_node::Forest<Ids> & forest) { ReaderSource<decltype(reader)> src(reader); auto const version = DeserializeVersion(src); Deserialize(src, version, forest); } template <typename Sink> static void Serialize(Sink & sink, Version version, tree_node::Forest<Ids> const & forest) { switch (version) { case Version::V0: V0::Serialize(sink, forest); break; default: UNREACHABLE(); } } template <typename Src> static void Deserialize(Src & src, Version version, tree_node::Forest<Ids> & forest) { switch (version) { case Version::V0: V0::Deserialize(src, forest); break; default: UNREACHABLE(); } } private: class V0 { public: template <typename Sink> static void Serialize(Sink & sink, tree_node::Forest<Ids> const & forest) { forest.ForEachTree([&](auto const & tree) { Serialize(sink, tree); }); } template <typename Src> static void Deserialize(Src & src, tree_node::Forest<Ids> & forest) { while (src.Size() > 0) { tree_node::types::Ptr<Ids> tree; Deserialize(src, tree); forest.Append(tree); } } private: template <typename Sink> static void Serialize(Sink & sink, tree_node::types::Ptr<Ids> const & tree) { tree_node::PreOrderVisit(tree, [&](auto const & node) { coding_utils::WriteCollectionPrimitive(sink, node->GetData()); auto const size = base::checked_cast<coding_utils::CollectionSizeType>(node->GetChildren().size()); WriteVarUint(sink, size); }); } template <typename Src> static void Deserialize(Src & src, tree_node::types::Ptr<Ids> & tree) { std::function<void(tree_node::types::Ptr<Ids> &)> deserializeTree; deserializeTree = [&](auto & tree) { Ids ids; coding_utils::ReadCollectionPrimitive(src, std::back_inserter(ids)); tree = tree_node::MakeTreeNode(std::move(ids)); auto const size = ReadVarUint<coding_utils::CollectionSizeType>(src); tree_node::types::Ptrs<Ids> children(size); for (auto & n : children) { deserializeTree(n); n->SetParent(tree); } tree->SetChildren(std::move(children)); }; deserializeTree(tree); } }; template <typename Sink> static void SerializeLatestVersion(Sink & sink) { WriteToSink(sink, base::Underlying(kLatestVersion)); } template <typename Src> static Version DeserializeVersion(Src & src) { return static_cast<Version>(ReadPrimitiveFromSource<std::underlying_type_t<Version>>(src)); } }; } // namespace complex