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 }