/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #include "utility/dict.hpp" #include "resources/serializer.hpp" #include "resources/serialize-error.hpp" #include "resources/deserializer.hpp" #include "resources/deserialize-error.hpp" #include "utility/hash/fnv1a.hpp" #include #include #include #include #include using namespace hash::literals; template static void serialize_any(const std::any& any, serialize_context& ctx) { serializer().serialize(std::any_cast(any), ctx); } template static void deserialize_any(std::any& any, deserialize_context& ctx) { T value; deserializer().deserialize(value, ctx); any = std::move(value); } /** * Serializes a dict with an unsigned 32-bit key. * * @throw serialize_error Write error. * @throw serialize_error Unsupported dict value type. */ template <> void serializer>::serialize(const dict& dict, serialize_context& ctx) { // Map type indices to tuples containing a type hash and serialize function pointer static const std::unordered_map < std::type_index, std::tuple < std::uint32_t, void (*)(const std::any&, serialize_context&) > > type_map { {std::type_index(typeid(bool)), {"bool"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::uint8_t)), {"uint8"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::uint16_t)), {"uint16"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::uint32_t)), {"uint32"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::uint64_t)), {"uint64"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::int8_t)), {"int8"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::int16_t)), {"int16"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::int32_t)), {"int32"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::int64_t)), {"int64"_fnv1a32, &serialize_any}}, {std::type_index(typeid(float)), {"float"_fnv1a32, &serialize_any}}, {std::type_index(typeid(double)), {"double"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::string)), {"string"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::u8string)), {"u8string"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::u16string)), {"u16string"_fnv1a32, &serialize_any}}, {std::type_index(typeid(std::u32string)), {"u32string"_fnv1a32, &serialize_any}} }; // Write dict size std::uint64_t size = static_cast(dict.size()); ctx.write64(reinterpret_cast(&size), 1); // Write dict entries for (const auto& [key, value]: dict) { if (auto i = type_map.find(value.type()); i != type_map.end()) { const auto& [type_hash, type_serializer] = i->second; // Write entry type hash and key ctx.write32(reinterpret_cast(&type_hash), 1); ctx.write32(reinterpret_cast(&key), 1); // Serialize entry value type_serializer(value, ctx); } else { throw serialize_error("Unsupported dict value type"); } } }; /** * Deserializes a dict with an unsigned 32-bit key. * * @throw deserialize_error Write error. * @throw deserialize_error Unsupported dict value type. */ template <> void deserializer>::deserialize(dict& dict, deserialize_context& ctx) { // Map type hashes to deserialize function pointers static const std::unordered_map < std::uint32_t, void (*)(std::any&, deserialize_context&) > type_map { {"bool"_fnv1a32, &deserialize_any}, {"uint8"_fnv1a32, &deserialize_any}, {"uint16"_fnv1a32, &deserialize_any}, {"uint32"_fnv1a32, &deserialize_any}, {"uint64"_fnv1a32, &deserialize_any}, {"int8"_fnv1a32, &deserialize_any}, {"int16"_fnv1a32, &deserialize_any}, {"int32"_fnv1a32, &deserialize_any}, {"int64"_fnv1a32, &deserialize_any}, {"float"_fnv1a32, &deserialize_any}, {"double"_fnv1a32, &deserialize_any}, {"string"_fnv1a32, &deserialize_any}, {"u8string"_fnv1a32, &deserialize_any}, {"u16string"_fnv1a32, &deserialize_any}, {"u32string"_fnv1a32, &deserialize_any} }; // Read dict size std::uint64_t size = 0; ctx.read64(reinterpret_cast(&size), 1); // Read dict entries for (std::size_t i = 0; i < size; ++i) { // Read entry type hash std::uint32_t type_hash = 0; ctx.read32(reinterpret_cast(&type_hash), 1); if (auto i = type_map.find(type_hash); i != type_map.end()) { // Read entry key std::uint32_t key = 0; ctx.read32(reinterpret_cast(&key), 1); // Deserialize entry value i->second(dict[key], ctx); } else { throw deserialize_error("Unsupported dict value type"); } } };