1 /**
2 Copyright: Copyright (c) 2017-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.serialization.hashtable;
8 
9 import voxelman.log;
10 import std.range : save;
11 import voxelman.serialization;
12 import voxelman.container.buffer;
13 import voxelman.container.hash.map;
14 import voxelman.container.hash.set;
15 
16 void serializeMap(HashMapT, Sink)(ref HashMapT hashmap, auto ref Sink sink)
17 {
18 	if (hashmap.empty) return;
19 
20 	encodeCborMapHeader(sink, hashmap.length);
21 	foreach(key, value; hashmap) {
22 		encodeCbor!(Yes.Flatten)(sink, key);
23 		encodeCbor!(Yes.Flatten)(sink, value);
24 	}
25 }
26 
27 void serializeMapPartial(HashMapT, Key, Sink)(ref HashMapT hashmap, auto ref Sink sink, HashSet!Key externalKeys)
28 {
29 	if (hashmap.empty || externalKeys.empty) return;
30 
31 	encodeCborMapHeader(sink);
32 
33 	if (externalKeys.length < hashmap.length) {
34 		foreach(key; externalKeys) {
35 			if (auto value = key in hashmap) {
36 				encodeCbor!(Yes.Flatten)(sink, key);
37 				encodeCbor!(Yes.Flatten)(sink, *value);
38 			}
39 		}
40 	} else {
41 		foreach(key, value; hashmap) {
42 			if (externalKeys[key]) {
43 				encodeCbor!(Yes.Flatten)(sink, key);
44 				encodeCbor!(Yes.Flatten)(sink, value);
45 			}
46 		}
47 	}
48 	encodeCborBreak(sink);
49 }
50 
51 void deserializeMap(HashMapT)(ref HashMapT hashmap, ubyte[] input)
52 {
53 	if (input.length == 0) return;
54 	CborToken token = decodeCborToken(input);
55 	if (token.type == CborTokenType.mapHeader) {
56 		size_t lengthToRead = cast(size_t)token.uinteger;
57 		hashmap.reserve(lengthToRead);
58 		while (lengthToRead > 0) {
59 			auto key = decodeCborSingle!(HashMapT.KeyT, Yes.Flatten)(input);
60 			auto value = decodeCborSingleDup!(HashMapT.ValueT, Yes.Flatten)(input);
61 			hashmap[key] = value;
62 			--lengthToRead;
63 		}
64 	} else if (token.type == CborTokenType.mapIndefiniteHeader) {
65 		while (true) {
66 			token = decodeCborToken(input.save);
67 			if (token.type == CborTokenType.breakCode) {
68 				break;
69 			} else {
70 				auto key = decodeCborSingle!(HashMapT.KeyT, Yes.Flatten)(input);
71 				auto value = decodeCborSingleDup!(HashMapT.ValueT, Yes.Flatten)(input);
72 				hashmap[key] = value;
73 			}
74 		}
75 	}
76 }
77 
78 
79 void serializeSet(HashSetT, Sink)(ref HashSetT hashset, auto ref Sink sink)
80 {
81 	if (hashset.empty) return;
82 
83 	encodeCborArrayHeader(sink, hashset.length);
84 	foreach(key; hashset) {
85 		encodeCbor!(Yes.Flatten)(sink, key);
86 	}
87 }
88 
89 void serializeSetPartial(Key, Sink)(ref HashSet!Key hashset, auto ref Sink sink, HashSet!Key externalKeys)
90 {
91 	if (hashset.empty || externalKeys.empty) return;
92 	encodeCborMapHeader(sink);
93 
94 	if (externalKeys.length < hashset.length) {
95 		foreach(key; externalKeys)
96 			if (hashset[key]) encodeCbor!(Yes.Flatten)(sink, key);
97 	} else {
98 		foreach(key; hashset)
99 			if (externalKeys[key]) encodeCbor!(Yes.Flatten)(sink, key);
100 	}
101 	encodeCborBreak(sink);
102 }
103 
104 void deserializeSet(Key)(ref HashSet!Key hashset, ubyte[] input)
105 {
106 	if (input.length == 0) return;
107 	CborToken token = decodeCborToken(input);
108 	if (token.type == CborTokenType.arrayHeader) {
109 		size_t lengthToRead = cast(size_t)token.uinteger;
110 		hashset.reserve(lengthToRead);
111 		while (lengthToRead > 0) {
112 			hashset.put(decodeCborSingle!(Key, Yes.Flatten)(input));
113 			--lengthToRead;
114 		}
115 	} else if (token.type == CborTokenType.arrayIndefiniteHeader) {
116 		while (true) {
117 			token = decodeCborToken(input.save);
118 			if (token.type == CborTokenType.breakCode)
119 				break;
120 			else
121 				hashset.put(decodeCborSingle!(Key, Yes.Flatten)(input));
122 		}
123 	}
124 }