1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#pragma once
#include "escape.h"
#include <util/string/cast.h>
#include <util/string/split.h>
namespace NTskvFormat {
namespace NDetail {
void DeserializeKvToStringBufs(const TStringBuf& kv, TStringBuf& key, TStringBuf& value, TString& buffer, bool unescape);
void DeserializeKvToStrings(const TStringBuf& kv, TString& key, TString& value, bool unescape);
}
template <typename T>
TString& SerializeMap(const T& data, TString& result) {
result.clear();
for (const auto& kv : data) {
if (result.size() > 0) {
result.push_back('\t');
}
Escape(ToString(kv.first), result);
result.push_back('=');
Escape(ToString(kv.second), result);
}
return result;
}
/**
* Deserializing to TStringBuf is faster, just remember that `data'
* must not be invalidated while `result' is still in use.
*/
template <typename T>
void DeserializeMap(const TStringBuf& data, T& result, TString& buffer, bool unescape = true) {
result.clear();
buffer.clear();
buffer.reserve(data.size());
TStringBuf key, value;
StringSplitter(data.begin(), data.end()).Split('\t').Consume([&](const TStringBuf kv){
NDetail::DeserializeKvToStringBufs(kv, key, value, buffer, unescape);
result[key] = value;
});
Y_ASSERT(buffer.size() <= data.size());
}
template <typename T>
void DeserializeMap(const TStringBuf& data, T& result, bool unescape = true) {
if constexpr(std::is_same<typename T::key_type, TStringBuf>::value ||
std::is_same<typename T::mapped_type, TStringBuf>::value)
{
DeserializeMap(data, result, result.DeserializeBuffer, unescape); // we can't unescape values w/o buffer
return;
}
result.clear();
TString key, value;
StringSplitter(data.begin(), data.end()).Split('\t').Consume([&](const TStringBuf kv){
NDetail::DeserializeKvToStrings(kv, key, value, unescape);
result[key] = value;
});
}
}
|