💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.7 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "utility/dict.hpp"
  20. #include "resources/serializer.hpp"
  21. #include "resources/serialize-error.hpp"
  22. #include "resources/deserializer.hpp"
  23. #include "resources/deserialize-error.hpp"
  24. #include "utility/hash/fnv1a.hpp"
  25. #include <cstdint>
  26. #include <string>
  27. #include <tuple>
  28. #include <typeindex>
  29. #include <unordered_map>
  30. using namespace hash::literals;
  31. template <class T>
  32. static void serialize_any(const std::any& any, serialize_context& ctx)
  33. {
  34. serializer<T>().serialize(std::any_cast<T>(any), ctx);
  35. }
  36. template <class T>
  37. static void deserialize_any(std::any& any, deserialize_context& ctx)
  38. {
  39. T value;
  40. deserializer<T>().deserialize(value, ctx);
  41. any = std::move(value);
  42. }
  43. /**
  44. * Serializes a dict with an unsigned 32-bit key.
  45. *
  46. * @throw serialize_error Write error.
  47. * @throw serialize_error Unsupported dict value type.
  48. */
  49. template <>
  50. void serializer<dict<std::uint32_t>>::serialize(const dict<std::uint32_t>& dict, serialize_context& ctx)
  51. {
  52. // Map type indices to tuples containing a type hash and serialize function pointer
  53. static const std::unordered_map
  54. <
  55. std::type_index,
  56. std::tuple
  57. <
  58. std::uint32_t,
  59. void (*)(const std::any&, serialize_context&)
  60. >
  61. > type_map
  62. {
  63. {std::type_index(typeid(bool)), {"bool"_fnv1a32, &serialize_any<bool>}},
  64. {std::type_index(typeid(std::uint8_t)), {"uint8"_fnv1a32, &serialize_any<std::uint8_t>}},
  65. {std::type_index(typeid(std::uint16_t)), {"uint16"_fnv1a32, &serialize_any<std::uint16_t>}},
  66. {std::type_index(typeid(std::uint32_t)), {"uint32"_fnv1a32, &serialize_any<std::uint32_t>}},
  67. {std::type_index(typeid(std::uint64_t)), {"uint64"_fnv1a32, &serialize_any<std::uint64_t>}},
  68. {std::type_index(typeid(std::int8_t)), {"int8"_fnv1a32, &serialize_any<std::int8_t>}},
  69. {std::type_index(typeid(std::int16_t)), {"int16"_fnv1a32, &serialize_any<std::int16_t>}},
  70. {std::type_index(typeid(std::int32_t)), {"int32"_fnv1a32, &serialize_any<std::int32_t>}},
  71. {std::type_index(typeid(std::int64_t)), {"int64"_fnv1a32, &serialize_any<std::int64_t>}},
  72. {std::type_index(typeid(float)), {"float"_fnv1a32, &serialize_any<float>}},
  73. {std::type_index(typeid(double)), {"double"_fnv1a32, &serialize_any<double>}},
  74. {std::type_index(typeid(std::string)), {"string"_fnv1a32, &serialize_any<std::string>}},
  75. {std::type_index(typeid(std::u8string)), {"u8string"_fnv1a32, &serialize_any<std::u8string>}},
  76. {std::type_index(typeid(std::u16string)), {"u16string"_fnv1a32, &serialize_any<std::u16string>}},
  77. {std::type_index(typeid(std::u32string)), {"u32string"_fnv1a32, &serialize_any<std::u32string>}}
  78. };
  79. // Write dict size
  80. std::uint64_t size = static_cast<std::uint64_t>(dict.size());
  81. ctx.write64(reinterpret_cast<const std::byte*>(&size), 1);
  82. // Write dict entries
  83. for (const auto& [key, value]: dict)
  84. {
  85. if (auto i = type_map.find(value.type()); i != type_map.end())
  86. {
  87. const auto& [type_hash, type_serializer] = i->second;
  88. // Write entry type hash and key
  89. ctx.write32(reinterpret_cast<const std::byte*>(&type_hash), 1);
  90. ctx.write32(reinterpret_cast<const std::byte*>(&key), 1);
  91. // Serialize entry value
  92. type_serializer(value, ctx);
  93. }
  94. else
  95. {
  96. throw serialize_error("Unsupported dict value type");
  97. }
  98. }
  99. };
  100. /**
  101. * Deserializes a dict with an unsigned 32-bit key.
  102. *
  103. * @throw deserialize_error Write error.
  104. * @throw deserialize_error Unsupported dict value type.
  105. */
  106. template <>
  107. void deserializer<dict<std::uint32_t>>::deserialize(dict<std::uint32_t>& dict, deserialize_context& ctx)
  108. {
  109. // Map type hashes to deserialize function pointers
  110. static const std::unordered_map
  111. <
  112. std::uint32_t,
  113. void (*)(std::any&, deserialize_context&)
  114. > type_map
  115. {
  116. {"bool"_fnv1a32, &deserialize_any<bool>},
  117. {"uint8"_fnv1a32, &deserialize_any<std::uint8_t>},
  118. {"uint16"_fnv1a32, &deserialize_any<std::uint16_t>},
  119. {"uint32"_fnv1a32, &deserialize_any<std::uint32_t>},
  120. {"uint64"_fnv1a32, &deserialize_any<std::uint64_t>},
  121. {"int8"_fnv1a32, &deserialize_any<std::int8_t>},
  122. {"int16"_fnv1a32, &deserialize_any<std::int16_t>},
  123. {"int32"_fnv1a32, &deserialize_any<std::int32_t>},
  124. {"int64"_fnv1a32, &deserialize_any<std::int64_t>},
  125. {"float"_fnv1a32, &deserialize_any<float>},
  126. {"double"_fnv1a32, &deserialize_any<double>},
  127. {"string"_fnv1a32, &deserialize_any<std::string>},
  128. {"u8string"_fnv1a32, &deserialize_any<std::u8string>},
  129. {"u16string"_fnv1a32, &deserialize_any<std::u16string>},
  130. {"u32string"_fnv1a32, &deserialize_any<std::u32string>}
  131. };
  132. // Read dict size
  133. std::uint64_t size = 0;
  134. ctx.read64(reinterpret_cast<std::byte*>(&size), 1);
  135. // Read dict entries
  136. for (std::size_t i = 0; i < size; ++i)
  137. {
  138. // Read entry type hash
  139. std::uint32_t type_hash = 0;
  140. ctx.read32(reinterpret_cast<std::byte*>(&type_hash), 1);
  141. if (auto i = type_map.find(type_hash); i != type_map.end())
  142. {
  143. // Read entry key
  144. std::uint32_t key = 0;
  145. ctx.read32(reinterpret_cast<std::byte*>(&key), 1);
  146. // Deserialize entry value
  147. i->second(dict[key], ctx);
  148. }
  149. else
  150. {
  151. throw deserialize_error("Unsupported dict value type");
  152. }
  153. }
  154. };