aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/string_utils/tskv_format/tskv_map.h
blob: 4f4978fcf5072e5e2b5df73e162219f76e3e26ce (plain) (blame)
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;
        });
    }
}