Antkeeper  0.0.1
dict.cpp
Go to the documentation of this file.
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 
20 #include <engine/utility/dict.hpp>
27 #include <cstdint>
28 #include <string>
29 #include <tuple>
30 #include <typeindex>
31 #include <unordered_map>
32 
33 using namespace hash::literals;
34 
35 template <class T>
36 static void serialize_any(const std::any& any, serialize_context& ctx)
37 {
38  serializer<T>().serialize(std::any_cast<T>(any), ctx);
39 }
40 
41 template <class T>
42 static void deserialize_any(std::any& any, deserialize_context& ctx)
43 {
44  T value;
45  deserializer<T>().deserialize(value, ctx);
46  any = std::move(value);
47 }
48 
58 template <>
60 {
61  // Map type indices to tuples containing a type hash and serialize function pointer
62  static const std::unordered_map
63  <
64  std::type_index,
65  std::tuple
66  <
68  void (*)(const std::any&, serialize_context&)
69  >
70  > type_map
71  {
72  {std::type_index(typeid(bool)), {"bool", &serialize_any<bool>}},
73  {std::type_index(typeid(std::uint8_t)), {"uint8", &serialize_any<std::uint8_t>}},
74  {std::type_index(typeid(std::uint16_t)), {"uint16", &serialize_any<std::uint16_t>}},
75  {std::type_index(typeid(std::uint32_t)), {"uint32", &serialize_any<std::uint32_t>}},
76  {std::type_index(typeid(std::uint64_t)), {"uint64", &serialize_any<std::uint64_t>}},
77  {std::type_index(typeid(std::int8_t)), {"int8", &serialize_any<std::int8_t>}},
78  {std::type_index(typeid(std::int16_t)), {"int16", &serialize_any<std::int16_t>}},
79  {std::type_index(typeid(std::int32_t)), {"int32", &serialize_any<std::int32_t>}},
80  {std::type_index(typeid(std::int64_t)), {"int64", &serialize_any<std::int64_t>}},
81  {std::type_index(typeid(float)), {"float", &serialize_any<float>}},
82  {std::type_index(typeid(double)), {"double", &serialize_any<double>}},
83  {std::type_index(typeid(std::string)), {"string", &serialize_any<std::string>}},
84  {std::type_index(typeid(std::u8string)), {"u8string", &serialize_any<std::u8string>}},
85  {std::type_index(typeid(std::u16string)), {"u16string", &serialize_any<std::u16string>}},
86  {std::type_index(typeid(std::u32string)), {"u32string", &serialize_any<std::u32string>}}
87  };
88 
89  // Write dict size
90  std::uint64_t size = static_cast<std::uint64_t>(dict.size());
91  ctx.write64<std::endian::big>(reinterpret_cast<const std::byte*>(&size), 1);
92 
93  // Write dict entries
94  for (const auto& [key, value]: dict)
95  {
96  if (auto i = type_map.find(value.type()); i != type_map.end())
97  {
98  const auto& [type_hash, type_serializer] = i->second;
99 
100  // Write entry type hash and key
101  ctx.write32<std::endian::big>(reinterpret_cast<const std::byte*>(&type_hash), 1);
102  ctx.write32<std::endian::big>(reinterpret_cast<const std::byte*>(&key), 1);
103 
104  // Serialize entry value
105  type_serializer(value, ctx);
106  }
107  else
108  {
109  throw serialize_error("Unsupported dict value type");
110  }
111  }
112 }
113 
123 template <>
125 {
126  // Map type hashes to deserialize function pointers
127  static const std::unordered_map
128  <
130  void (*)(std::any&, deserialize_context&)
131  > type_map
132  {
133  {"bool", &deserialize_any<bool>},
134  {"uint8", &deserialize_any<std::uint8_t>},
135  {"uint16", &deserialize_any<std::uint16_t>},
136  {"uint32", &deserialize_any<std::uint32_t>},
137  {"uint64", &deserialize_any<std::uint64_t>},
138  {"int8", &deserialize_any<std::int8_t>},
139  {"int16", &deserialize_any<std::int16_t>},
140  {"int32", &deserialize_any<std::int32_t>},
141  {"int64", &deserialize_any<std::int64_t>},
142  {"float", &deserialize_any<float>},
143  {"double", &deserialize_any<double>},
144  {"string", &deserialize_any<std::string>},
145  {"u8string", &deserialize_any<std::u8string>},
146  {"u16string", &deserialize_any<std::u16string>},
147  {"u32string", &deserialize_any<std::u32string>}
148  };
149 
150  dict.clear();
151 
152  // Read dict size
153  std::uint64_t size = 0;
154  ctx.read64<std::endian::big>(reinterpret_cast<std::byte*>(&size), 1);
155 
156  // Read dict entries
157  for (std::size_t i = 0; i < size; ++i)
158  {
159  // Read entry type hash
160  std::uint32_t type_hash = 0;
161  ctx.read32<std::endian::big>(reinterpret_cast<std::byte*>(&type_hash), 1);
162 
163  if (auto i = type_map.find(type_hash); i != type_map.end())
164  {
165  // Read entry key
166  hash::fnv1a32_t key;
167  ctx.read32<std::endian::big>(reinterpret_cast<std::byte*>(&key), 1);
168 
169  // Deserialize entry value
170  i->second(dict[key], ctx);
171  }
172  else
173  {
174  throw deserialize_error("Unsupported dict value type");
175  }
176  }
177 }
178 
179 template <>
181 {
182  auto resource = std::make_unique<dict<hash::fnv1a32_t>>();
183 
184  deserializer<dict<hash::fnv1a32_t>>().deserialize(*resource, ctx);
185 
186  return resource;
187 }
An exception of this type is thrown when an error occurs during deserialization.
Templated resource loader.
Manages the loading, caching, and saving of resources.
An exception of this type is thrown when an error occurs during serialization.
std::unordered_map< Key, std::any > dict
Unordered dictionary type.
Definition: dict.hpp:32
User-defined literals for compile-time string hashing.
Definition: fnv1a.hpp:232
constexpr bool any(const vector< bool, N > &x) noexcept
Checks if any elements of a boolean vector are true.
Definition: vector.hpp:1043
Provides access to a deserialization state.
std::size_t read32(std::byte *data, std::size_t count) noexcept(false)
Reads 32-bit (double word) data.
std::size_t read64(std::byte *data, std::size_t count) noexcept(false)
Reads 64-bit (quad word) data.
Specializations of deserializer define the deserialization process for a given type.
void deserialize(T &value, deserialize_context &ctx)
Deserializes a value.
32-bit FNV-1a hash value.
Definition: fnv1a.hpp:117
Provides access to a serialization state.
std::size_t write32(const std::byte *data, std::size_t count) noexcept(false)
Writes 32-bit (double word) data.
std::size_t write64(const std::byte *data, std::size_t count) noexcept(false)
Writes 64-bit (quad word) data.
Specializations of serializer define the serialization process for a given type.
Definition: serializer.hpp:32
void serialize(const T &value, serialize_context &ctx)
Serializes a value.