Multilevel Deduplication Engine (MDE)
Loading...
Searching...
No Matches
mde_serialization.hpp
Go to the documentation of this file.
1
13#ifndef MDE_SERIALIZATION_H
14#define MDE_SERIALIZATION_H
15
16#include "mde_common.hpp"
17#include <fstream>
18#include <nlohmann/json.hpp>
19
20namespace mde {
21
22namespace slz {
23
24using JSON = nlohmann::json;
25
31template<typename T>
33 JSON save(const T &val);
34 T load(const JSON &j);
35};
36
37
46template<typename T>
48 JSON save(const T &val) {
49 return JSON(val);
50 }
51
52 T load(const JSON &j) {
53 return j.get<T>();
54 }
55};
56
57struct SerializationError : public std::invalid_argument {
59 std::invalid_argument(message.c_str()) {}
60};
61
69template<typename MapT>
71 JSON ret = JSON::array();
72 for (auto &i : map) {
73 ret.push_back(JSON::array({JSON::array({i.first.left, i.first.right}), i.second}));
74 }
75 return ret;
76}
77
86template<typename MapT>
88 map.clear();
89
90 if (!obj.is_array()) {
91 throw SerializationError("Expected array (root)");
92 }
93
94 for (auto &tuple : obj) {
95 if (!tuple.is_array() || !(tuple.size() == 2)) {
96 throw SerializationError("Expected array of size 2 (root[*])");
97 } else if (!tuple[0].is_array() || !(tuple[0].size() == 2)) {
98 throw SerializationError("Expected array of size 2 (root[*][0])");
99 } else if (!tuple[0][0].is_number_integer() || !tuple[0][1].is_number_integer()) {
100 throw SerializationError("Expected array of size 2 (root[*][0][0,1])");
101 } else if (!tuple[1].is_number_integer()) {
102 throw SerializationError("Expected array of size 2 (root[*][1])");
103 }
104 map.insert({{tuple[0][0], tuple[0][1]}, tuple[1]});
105 }
106}
107
115template<typename MapT>
117 JSON ret = JSON::array();
118 for (auto &i : map) {
119 JSON::array({i.first, i.second});
120 }
121 return ret;
122}
123
132template<typename MapT>
134 map.clear();
135
136 if (!obj.is_array()) {
137 throw SerializationError("Expected array (root)");
138 }
139
140 for (auto &tuple : obj) {
141 if (!tuple.is_array() || !(tuple.size() == 2)) {
142 throw SerializationError("Expected array of size 2 (root[*])");
143 } else if (!tuple[0].is_number_integer() || !tuple[1].is_number_integer()) {
144 throw SerializationError("Expected array of size 2 (root[*][0,1])");
145 }
146 map.insert({tuple[0], tuple[1]});
147 }
148}
149
158template<typename StoreT, typename Serializer>
160 JSON ret = JSON::array();
161 for (Size set_index = 0; set_index < store.size(); set_index++) {
162 JSON set_arr = JSON::array();
163 for (auto &elem : *store.at(set_index).get()) {
164 set_arr.push_back(serializer.save(elem.get_key()));
165 }
166 ret.push_back(set_arr);
167 }
168 return ret;
169}
170
180template<typename MDET, typename Serializer>
182
183 using PropertyElement = typename MDET::PropertyElement;
184
185 if (!obj.is_array()) {
186 throw SerializationError("Expected array (root)");
187 }
188
189 for (Size set_index = 0; set_index < obj.size(); set_index++) {
191 if (!obj[set_index].is_array()) {
192 throw SerializationError("Expected array (root[*])");
193 }
194 for (auto &i : obj[set_index]) {
195 data.push_back(PropertyElement(serializer.load(i)));
196 }
197 mde.register_set(std::move(data));
198 }
199}
200
209template<typename Serializer, typename StoreT>
211 JSON ret = JSON::array();
212
213 for (Size set_index = 0; set_index < store.size(); set_index++) {
214 JSON set_arr = JSON::array();
215
216 for (auto &elem : *store.at(set_index).get()) {
217 JSON child_arr = JSON::array();
218
219 std::apply([&child_arr](const auto&... args) {
220 (child_arr.push_back(args.value), ...);
221 }, elem.get_value());
222
223 set_arr.push_back(
224 JSON::array({
225 serializer.save(elem.get_key()),
227 })
228 );
229 }
230 ret.push_back(set_arr);
231 }
232 return ret;
233}
234
235template <typename Tuple, std::size_t... Is>
236Tuple json_list_to_tuple_internal(const JSON& l, std::index_sequence<Is...>) {
237 return Tuple{ (l[Is].template get<size_t>())... };
238}
239
240template <typename Tuple>
242 constexpr std::size_t N = std::tuple_size_v<Tuple>;
243 return json_list_to_tuple_internal<Tuple>(l, std::make_index_sequence<N>{});
244}
245
255template<typename Serializer, typename MDET>
257
258 using PropertyElement = typename MDET::PropertyElement;
259 using ChildValueList = typename MDET::Nesting::ChildValueList;
260 constexpr const Size num_children = MDET::Nesting::num_children;
261
262 if (!obj.is_array()) {
263 throw SerializationError("Expected array (root)");
264 }
265
266 for (Size set_index = 0; set_index < obj.size(); set_index++) {
268 if (!obj[set_index].is_array()) {
269 throw SerializationError("Expected array (root[*])");
270 }
271 for (auto &i : obj[set_index]) {
272 if (i.size() != 2) {
273 throw SerializationError("Expected array of size 2 (root[*][*])");
274 } else if (!i[1].is_array() || i[1].size() != num_children) {
275 throw SerializationError(
276 "Expected array of size " + std::to_string(num_children) +
277 " (root[*][1])");
278 }
280 data.push_back(PropertyElement(serializer.load(i[0]), cvl));
281 }
282 mde.register_set(std::move(data));
283 }
284}
285
286template<typename MDET>
288 MDET &root, JSON &obj,
290
291 if (visited.count(&root) > 0) {
292 // MDE_DEBUG(std::cout << "Already found '" << root.name << "' <" << &root << ">\n";);
293 // MDE_DEBUG(std::cout << "Path: " << path << "\n";);
294 return;
295 } else {
296 // MDE_DEBUG(std::cout << "Visited '" << root.name << "' <" << &root << ">\n";);
297 // MDE_DEBUG(std::cout << "Path: " << path << "\n";);
298 visited.insert(&root);
299 }
300
301 obj[path] = root.to_json();
302
303 std::apply([&](auto&... child_refs) {
304 // Local counter for this node's children
305 [[maybe_unused]] Size i = 0;
306
307 // The fold expression calls this lambda for EACH child in the pack
308 ([&](auto& child) {
309 String current_path = path + std::to_string(i++) + "/";
311 }(child_refs), ...);
312 }, root.get_reflist());
313}
314
326template<typename MDET>
329 String path = "/";
330 JSON obj = JSON::object();
331 obj["mde_version"] = MDE_VERSION_STRING;
333
334 return obj;
335}
336
337template<typename MDET>
339 MDET &root, const JSON &obj,
341
342 if (visited.count(&root) > 0) {
343 // MDE_DEBUG(std::cout << "Already found '" << root.name << "' <" << &root << ">\n";);
344 // MDE_DEBUG(std::cout << "Path: " << path << "\n";);
345 return;
346 } else {
347 // MDE_DEBUG(std::cout << "Visited '" << root.name << "' <" << &root << ">\n";);
348 // MDE_DEBUG(std::cout << "Path: " << path << "\n";);
349 visited.insert(&root);
350 }
351
352 root.load_from_json(obj[path]);
353
354 std::apply([&](auto&... child_refs) {
355 // Local counter for this node's children
356 [[maybe_unused]] Size i = 0;
357
358 // The fold expression calls this lambda for EACH child in the pack
359 ([&](auto& child) {
360 String current_path = path + std::to_string(i++) + "/";
362 }(child_refs), ...);
363 }, root.get_reflist());
364}
365
372template<typename MDET>
378
387 return obj.dump();
388}
389
391 return JSON::to_bson(obj);
392}
393
402inline bool json_to_file(const JSON &obj, const String &file_path) {
403 std::ofstream f(file_path);
404
405 if (!f.is_open()) {
406 return false;
407 }
408
409 f << obj;
410 return true;
411}
412
413inline bool json_to_file_bson(const JSON &obj, const String &file_path) {
414 std::ofstream f(file_path, std::ios::out | std::ios::binary);
415
416 if (!f.is_open()) {
417 return false;
418 }
419
421 f.write(reinterpret_cast<const char *>(data.data()), data.size());
422 return true;
423}
424
426 std::ifstream f(file_path);
427
428 if (!f.is_open()) {
429 throw SerializationError("Could not open '" + file_path + "'");
430 }
431
432 return JSON::parse(f);
433}
434
436 std::ifstream f(file_path);
437
438 if (!f.is_open()) {
439 throw SerializationError("Could not open '" + file_path + "'");
440 }
441
442 return JSON::from_bson(f);
443}
444
445template<typename MDET>
446bool save(const MDET &mde, const String &file_path) {
448}
449
450template<typename MDET>
451bool save_bson(const MDET &mde, const String &file_path) {
453}
454
455template<typename MDET>
459
460template<typename MDET>
464
465}; // END namespace slz
466
467}; // END namespace mde
468
469#endif
Any common components go into this file.
#define MDE_VERSION_STRING
void load_bson(MDET &mde, const String &file_path)
void register_storage_from_json(MDET &mde, const JSON &obj, Serializer &serializer)
Inserts data from the JSON representation to the equivalent C++ data strucure for a PropertySetStorag...
void register_storage_from_json_nested(MDET &mde, const JSON &obj, Serializer &serializer)
Inserts data from the JSON representation to the equivalent C++ data strucure for a PropertySetStorag...
void load(MDET &mde, const String &file_path)
bool json_to_file_bson(const JSON &obj, const String &file_path)
bool save_bson(const MDET &mde, const String &file_path)
JSON unary_operation_map_to_json(const MapT &map)
Converts an integer -> integer map to JSON.
Tuple json_list_to_tuple_internal(const JSON &l, std::index_sequence< Is... >)
void unary_operation_map_from_json(MapT &map, const JSON &obj)
Inserts data from the JSON representation to the equivalent C++ data strucure for the integer -> inte...
void mde_from_json_internal(MDET &root, const JSON &obj, HashSet< void * > &visited, String &path)
JSON binary_operation_map_to_json(const MapT &map)
Converts OperationNode -> integer maps to JSON.
Tuple json_list_to_tuple(const JSON &l)
JSON mde_to_json(MDET &root)
Converts an MDE and its referenced child MDEs to JSON. The individual MDEs are identified using paths...
bool save(const MDET &mde, const String &file_path)
JSON load_bson_file(const String &file_path)
Vector< uint8_t > json_to_bson(const JSON &obj)
nlohmann::json JSON
JSON storage_array_to_json_nested(const StoreT &store, Serializer &serializer)
Converts an MDE storage array to JSON in the nested case.
bool json_to_file(const JSON &obj, const String &file_path)
Writes a JSON object to a file.
void binary_operation_map_from_json(MapT &map, const JSON &obj)
Inserts data from the JSON representation to the equivalent C++ data strucure for the OperationNode -...
String json_to_string(const JSON &obj)
Returns a string representation of the supplied JSON object.
void mde_to_json_internal(MDET &root, JSON &obj, HashSet< void * > &visited, String &path)
JSON load_json_file(const String &file_path)
JSON storage_array_to_json(const StoreT &store, Serializer &serializer)
Converts a storage array to its JSON representation.
void mde_from_json(MDET &root, const JSON &obj)
Loads all data from the supplied JSON object into MDE.
Definition mde.hpp:16
std::size_t Size
std::string String
std::hash< T > DefaultHash
Default serialization behavior. If the type of the property in MDE is something that can be directly ...
SerializationError(const String &message)
Struct for serializing/deserializing values in MDE.
JSON save(const T &val)
T load(const JSON &j)