|
|
- /*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
- #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 <cstdint>
- #include <string>
- #include <tuple>
- #include <typeindex>
- #include <unordered_map>
-
- using namespace hash::literals;
-
- template <class T>
- static void serialize_any(const std::any& any, serialize_context& ctx)
- {
- serializer<T>().serialize(std::any_cast<T>(any), ctx);
- }
-
- template <class T>
- static void deserialize_any(std::any& any, deserialize_context& ctx)
- {
- T value;
- deserializer<T>().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<dict<std::uint32_t>>::serialize(const dict<std::uint32_t>& 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<bool>}},
- {std::type_index(typeid(std::uint8_t)), {"uint8"_fnv1a32, &serialize_any<std::uint8_t>}},
- {std::type_index(typeid(std::uint16_t)), {"uint16"_fnv1a32, &serialize_any<std::uint16_t>}},
- {std::type_index(typeid(std::uint32_t)), {"uint32"_fnv1a32, &serialize_any<std::uint32_t>}},
- {std::type_index(typeid(std::uint64_t)), {"uint64"_fnv1a32, &serialize_any<std::uint64_t>}},
- {std::type_index(typeid(std::int8_t)), {"int8"_fnv1a32, &serialize_any<std::int8_t>}},
- {std::type_index(typeid(std::int16_t)), {"int16"_fnv1a32, &serialize_any<std::int16_t>}},
- {std::type_index(typeid(std::int32_t)), {"int32"_fnv1a32, &serialize_any<std::int32_t>}},
- {std::type_index(typeid(std::int64_t)), {"int64"_fnv1a32, &serialize_any<std::int64_t>}},
- {std::type_index(typeid(float)), {"float"_fnv1a32, &serialize_any<float>}},
- {std::type_index(typeid(double)), {"double"_fnv1a32, &serialize_any<double>}},
- {std::type_index(typeid(std::string)), {"string"_fnv1a32, &serialize_any<std::string>}},
- {std::type_index(typeid(std::u8string)), {"u8string"_fnv1a32, &serialize_any<std::u8string>}},
- {std::type_index(typeid(std::u16string)), {"u16string"_fnv1a32, &serialize_any<std::u16string>}},
- {std::type_index(typeid(std::u32string)), {"u32string"_fnv1a32, &serialize_any<std::u32string>}}
- };
-
- // Write dict size
- std::uint64_t size = static_cast<std::uint64_t>(dict.size());
- ctx.write64(reinterpret_cast<const std::byte*>(&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<const std::byte*>(&type_hash), 1);
- ctx.write32(reinterpret_cast<const std::byte*>(&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<dict<std::uint32_t>>::deserialize(dict<std::uint32_t>& 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<bool>},
- {"uint8"_fnv1a32, &deserialize_any<std::uint8_t>},
- {"uint16"_fnv1a32, &deserialize_any<std::uint16_t>},
- {"uint32"_fnv1a32, &deserialize_any<std::uint32_t>},
- {"uint64"_fnv1a32, &deserialize_any<std::uint64_t>},
- {"int8"_fnv1a32, &deserialize_any<std::int8_t>},
- {"int16"_fnv1a32, &deserialize_any<std::int16_t>},
- {"int32"_fnv1a32, &deserialize_any<std::int32_t>},
- {"int64"_fnv1a32, &deserialize_any<std::int64_t>},
- {"float"_fnv1a32, &deserialize_any<float>},
- {"double"_fnv1a32, &deserialize_any<double>},
- {"string"_fnv1a32, &deserialize_any<std::string>},
- {"u8string"_fnv1a32, &deserialize_any<std::u8string>},
- {"u16string"_fnv1a32, &deserialize_any<std::u16string>},
- {"u32string"_fnv1a32, &deserialize_any<std::u32string>}
- };
-
- // Read dict size
- std::uint64_t size = 0;
- ctx.read64(reinterpret_cast<std::byte*>(&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<std::byte*>(&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<std::byte*>(&key), 1);
-
- // Deserialize entry value
- i->second(dict[key], ctx);
- }
- else
- {
- throw deserialize_error("Unsupported dict value type");
- }
- }
- };
|