aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/json/writer/json_value.h
blob: 79d1a4cb3b7d3cbe2f553b0a1b2ba6fa8726c416 (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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#pragma once

#include <library/cpp/json/common/defs.h>

#include <util/generic/string.h>
#include <util/generic/hash.h>
#include <util/generic/vector.h>
#include <util/generic/deque.h>
#include <util/generic/utility.h> 
#include <util/generic/yexception.h>

namespace NJson {
    enum EJsonValueType {
        JSON_UNDEFINED /* "Undefined" */,
        JSON_NULL /* "Null" */,
        JSON_BOOLEAN /* "Boolean" */,
        JSON_INTEGER /* "Integer" */,
        JSON_DOUBLE /* "Double" */,
        JSON_STRING /* "String" */,
        JSON_MAP /* "Map" */,
        JSON_ARRAY /* "Array" */,
        JSON_UINTEGER /* "UInteger" */
    };

    class TJsonValue;

    class IScanCallback {
    public:
        virtual ~IScanCallback() = default;

        virtual bool Do(const TString& path, TJsonValue* parent, TJsonValue& value) = 0;
    };

    class TJsonValue {
        void Clear() noexcept;

    public:
        typedef THashMap<TString, TJsonValue> TMapType;
        typedef TDeque<TJsonValue> TArray;

        TJsonValue() noexcept = default;
        TJsonValue(EJsonValueType type);
        TJsonValue(bool value) noexcept;
        TJsonValue(int value) noexcept;
        TJsonValue(unsigned int value) noexcept;
        TJsonValue(long value) noexcept;
        TJsonValue(unsigned long value) noexcept;
        TJsonValue(long long value) noexcept;
        TJsonValue(unsigned long long value) noexcept;
        TJsonValue(double value) noexcept;
        TJsonValue(TString value);
        TJsonValue(const char* value);
        template <class T>
        TJsonValue(const T*) = delete;
        TJsonValue(TStringBuf value);

        TJsonValue(const std::string& s)
            : TJsonValue(TStringBuf(s))
        {
        }

        TJsonValue(const TJsonValue& vval);
        TJsonValue(TJsonValue&& vval) noexcept;

        TJsonValue& operator=(const TJsonValue& val);
        TJsonValue& operator=(TJsonValue&& val) noexcept;

        ~TJsonValue() {
            Clear();
        }

        EJsonValueType GetType() const noexcept;
        TJsonValue& SetType(EJsonValueType type);

        TJsonValue& SetValue(const TJsonValue& value);
        TJsonValue& SetValue(TJsonValue&& value);

        // for Map
        TJsonValue& InsertValue(const TString& key, const TJsonValue& value);
        TJsonValue& InsertValue(TStringBuf key, const TJsonValue& value);
        TJsonValue& InsertValue(const char* key, const TJsonValue& value);
        TJsonValue& InsertValue(const TString& key, TJsonValue&& value);
        TJsonValue& InsertValue(TStringBuf key, TJsonValue&& value);
        TJsonValue& InsertValue(const char* key, TJsonValue&& value);

        // for Array
        TJsonValue& AppendValue(const TJsonValue& value);
        TJsonValue& AppendValue(TJsonValue&& value);
        TJsonValue& Back();
        const TJsonValue& Back() const;

        bool GetValueByPath(TStringBuf path, TJsonValue& result, char delimiter = '.') const;
        bool SetValueByPath(TStringBuf path, const TJsonValue& value, char delimiter = '.');
        bool SetValueByPath(TStringBuf path, TJsonValue&& value, char delimiter = '.');

        // returns NULL on failure
        const TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') const noexcept;
        TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') noexcept;

        void EraseValue(TStringBuf key);
        void EraseValue(size_t index);

        TJsonValue& operator[](size_t idx);
        TJsonValue& operator[](const TStringBuf& key);
        const TJsonValue& operator[](size_t idx) const noexcept;
        const TJsonValue& operator[](const TStringBuf& key) const noexcept;

        bool GetBoolean() const;
        long long GetInteger() const;
        unsigned long long GetUInteger() const;
        double GetDouble() const;
        const TString& GetString() const;
        const TMapType& GetMap() const;
        const TArray& GetArray() const;

        //throwing TJsonException possible
        bool GetBooleanSafe() const;
        long long GetIntegerSafe() const;
        unsigned long long GetUIntegerSafe() const;
        double GetDoubleSafe() const;
        const TString& GetStringSafe() const;
        const TMapType& GetMapSafe() const;
        TMapType& GetMapSafe();
        const TArray& GetArraySafe() const;
        TArray& GetArraySafe();

        bool GetBooleanSafe(bool defaultValue) const;
        long long GetIntegerSafe(long long defaultValue) const;
        unsigned long long GetUIntegerSafe(unsigned long long defaultValue) const;
        double GetDoubleSafe(double defaultValue) const;
        TString GetStringSafe(const TString& defaultValue) const;

        bool GetBooleanRobust() const noexcept;
        long long GetIntegerRobust() const noexcept;
        unsigned long long GetUIntegerRobust() const noexcept;
        double GetDoubleRobust() const noexcept;
        TString GetStringRobust() const;

        // Exception-free accessors
        bool GetBoolean(bool* value) const noexcept;
        bool GetInteger(long long* value) const noexcept;
        bool GetUInteger(unsigned long long* value) const noexcept;
        bool GetDouble(double* value) const noexcept;
        bool GetMapPointer(const TMapType** value) const noexcept;
        bool GetArrayPointer(const TArray** value) const noexcept;

        bool GetString(TString* value) const;
        bool GetMap(TMapType* value) const;
        bool GetArray(TArray* value) const;
        bool GetValue(size_t index, TJsonValue* value) const;
        bool GetValue(TStringBuf key, TJsonValue* value) const;
        bool GetValuePointer(size_t index, const TJsonValue** value) const noexcept;
        bool GetValuePointer(TStringBuf key, const TJsonValue** value) const noexcept;
        bool GetValuePointer(TStringBuf key, TJsonValue** value) noexcept;

        // Checking for defined non-null value
        bool IsDefined() const noexcept {
            return Type != JSON_UNDEFINED && Type != JSON_NULL;
        }

        bool IsNull() const noexcept;
        bool IsBoolean() const noexcept;
        bool IsDouble() const noexcept;
        bool IsString() const noexcept;
        bool IsMap() const noexcept;
        bool IsArray() const noexcept;

        /// @return true if JSON_INTEGER or (JSON_UINTEGER and Value <= Max<long long>)
        bool IsInteger() const noexcept;

        /// @return true if JSON_UINTEGER or (JSON_INTEGER and Value >= 0)
        bool IsUInteger() const noexcept;

        bool Has(const TStringBuf& key) const noexcept;
        bool Has(size_t key) const noexcept;

        void Scan(IScanCallback& callback);

        /// Non-robust comparison.
        bool operator==(const TJsonValue& rhs) const;

        bool operator!=(const TJsonValue& rhs) const {
            return !(*this == rhs);
        }

        void Swap(TJsonValue& rhs) noexcept;

        // save using util/ysaveload.h serialization (not to JSON stream)
        void Save(IOutputStream* s) const;

        // load using util/ysaveload.h serialization (not as JSON stream)
        void Load(IInputStream* s);

        static const TJsonValue UNDEFINED;

    private:
        EJsonValueType Type = JSON_UNDEFINED;
        union TValueUnion {
            bool Boolean;
            long long Integer;
            unsigned long long UInteger;
            double Double;
            TString String;
            TMapType* Map;
            TArray* Array;

            TValueUnion() noexcept {
                Zero(*this); 
            }
            ~TValueUnion() noexcept {
            }
        };
        TValueUnion Value;
        void DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback);
        void SwapWithUndefined(TJsonValue& output) noexcept;

        /**
            @throw yexception if Back shouldn't be called on the object.
         */
        void BackChecks() const;
    };

    inline bool GetBoolean(const TJsonValue& jv, size_t index, bool* value) noexcept {
        return jv[index].GetBoolean(value);
    }

    inline bool GetInteger(const TJsonValue& jv, size_t index, long long* value) noexcept {
        return jv[index].GetInteger(value);
    }

    inline bool GetUInteger(const TJsonValue& jv, size_t index, unsigned long long* value) noexcept {
        return jv[index].GetUInteger(value);
    }

    inline bool GetDouble(const TJsonValue& jv, size_t index, double* value) noexcept {
        return jv[index].GetDouble(value);
    }

    inline bool GetString(const TJsonValue& jv, size_t index, TString* value) {
        return jv[index].GetString(value);
    }

    bool GetMapPointer(const TJsonValue& jv, size_t index, const TJsonValue::TMapType** value);
    bool GetArrayPointer(const TJsonValue& jv, size_t index, const TJsonValue::TArray** value);

    inline bool GetBoolean(const TJsonValue& jv, TStringBuf key, bool* value) noexcept {
        return jv[key].GetBoolean(value);
    }

    inline bool GetInteger(const TJsonValue& jv, TStringBuf key, long long* value) noexcept {
        return jv[key].GetInteger(value);
    }

    inline bool GetUInteger(const TJsonValue& jv, TStringBuf key, unsigned long long* value) noexcept {
        return jv[key].GetUInteger(value);
    }

    inline bool GetDouble(const TJsonValue& jv, TStringBuf key, double* value) noexcept {
        return jv[key].GetDouble(value);
    }

    inline bool GetString(const TJsonValue& jv, TStringBuf key, TString* value) {
        return jv[key].GetString(value);
    }

    bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value);
    bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value);

    class TJsonMap: public TJsonValue {
    public:
        TJsonMap()
            : TJsonValue(NJson::JSON_MAP)
        {}

        TJsonMap(const std::initializer_list<std::pair<TString, TJsonValue>>& list)
            : TJsonValue(NJson::JSON_MAP)
        {
            GetMapSafe() = THashMap<TString, TJsonValue>(list);
        }
    };

    class TJsonArray: public TJsonValue {
    public:
        TJsonArray()
            : TJsonValue(NJson::JSON_ARRAY)
        {}

        TJsonArray(const std::initializer_list<TJsonValue>& list)
            : TJsonValue(NJson::JSON_ARRAY)
        {
            GetArraySafe() = TJsonValue::TArray(list);
        }
    };
}