Coverage Report

Created: 2025-06-13 06:48

/src/oneDNN/src/graph/utils/json.hpp
Line
Count
Source (jump to first uncovered line)
1
/*******************************************************************************
2
 * Copyright 2020-2025 Intel Corporation
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 *******************************************************************************/
16
17
#ifndef GRAPH_UTILS_JSON_HPP
18
#define GRAPH_UTILS_JSON_HPP
19
20
#include <algorithm>
21
#include <cctype>
22
#include <fstream>
23
#include <iostream>
24
#include <list>
25
#include <map>
26
#include <memory>
27
#include <sstream>
28
#include <string>
29
#include <utility>
30
#include <vector>
31
#include <unordered_map>
32
33
namespace dnnl {
34
namespace impl {
35
namespace graph {
36
namespace utils {
37
namespace json {
38
39
/*!
40
 * \brief template to select type based on condition
41
 * For example, if_else_type<true, int, float>::Type will give int
42
 * \tparam cond the condition
43
 * \tparam Then the typename to be returned if cond is true
44
 * \tparam Else typename to be returned if cond is false
45
 */
46
47
template <bool cond, typename Then, typename Else>
48
struct if_else_type;
49
50
/*!
51
 * \brief generic serialization json
52
 * \tparam T the type to be serialized
53
 */
54
template <typename T>
55
struct json_handler_t;
56
57
template <typename T>
58
struct common_json_t;
59
60
/*!
61
 * \brief json to write any type.
62
 */
63
class json_writer_t {
64
public:
65
0
    json_writer_t(std::ostream *os) : os_(os) {}
66
    /*!
67
     * \brief object begin
68
     * \param multi_line whether to start an multi_line array.
69
     */
70
    inline void begin_object();
71
    /*! \brief object end. */
72
    inline void end_object();
73
    /*!
74
     * \brief write key value pair in the object.
75
     */
76
    template <typename valuetype>
77
    inline void write_keyvalue(const std::string &key, const valuetype &value);
78
    /*!
79
     * \brief write a number.
80
     */
81
    template <typename valuetype>
82
    inline void write_number(const valuetype &v);
83
    /*!
84
     * \brief write a string.
85
     */
86
    inline void write_string(const std::string &s);
87
    /*!
88
     * \brief array begin.
89
     * \param multi_line if true, write multi_line.
90
     */
91
    inline void begin_array(bool multi_line = true);
92
    /*! \brief array end. */
93
    inline void end_array();
94
    /*!
95
     * \brief write array separator.
96
     */
97
    inline void write_array_seperator();
98
    /*!
99
     * \brief write array value.
100
     */
101
    template <typename valuetype>
102
    inline void write_array_item(const valuetype &value);
103
104
    inline void write_newline();
105
106
private:
107
    std::ostream *os_;
108
    /*!
109
     * \brief record how many element in the current scope.
110
     */
111
    std::vector<size_t> scope_count_;
112
    /*! \brief record if current pos is a multiline scope */
113
    std::vector<bool> scope_multi_line_;
114
    /*!
115
     * \brief write seperator space and newlines
116
     */
117
    inline void write_seperator();
118
};
119
120
class json_reader_t {
121
public:
122
323
    explicit json_reader_t(std::istream *is) : is_(is) {}
123
    /*!
124
     * \brief parse json string.
125
     */
126
    inline void read_string(std::string *out_str);
127
    /*!
128
     * \brief read number.
129
     */
130
    template <typename valuetype>
131
    inline void read_number(valuetype *out_value);
132
    /*!
133
     * \brief parse an object begin.
134
     */
135
    inline void begin_object();
136
    /*!
137
     * \brief parse an object end.
138
     */
139
    inline void begin_array();
140
    /*!
141
     * \brief read next object, if true, will read next object.
142
     */
143
    inline bool next_object_item(std::string *out_key);
144
    /*!
145
     * \brief read next object, if true, will read next object.
146
     */
147
    inline bool next_array_item();
148
    /*!
149
     * \brief read next value.
150
     */
151
    template <typename valuetype>
152
    inline void read(valuetype *out_value);
153
154
private:
155
    std::istream *is_;
156
    /*!
157
     * \brief record element size in the current.
158
     */
159
    std::vector<size_t> scope_count_;
160
    /*!
161
     * \brief read next nonspace char.
162
     */
163
    inline int next_nonspace();
164
    inline int peeknext_nonspace();
165
    /*!
166
   * \brief get the next char from the input.
167
   */
168
    inline int next_char();
169
    inline int peeknext_char();
170
};
171
172
class read_helper_t {
173
public:
174
    /*!
175
   * \brief declare field
176
   */
177
    template <typename T>
178
    inline void declare_field(const std::string &key, T *addr) {
179
        //declare_fieldInternal(key, addr);
180
        if (map_.count(key) == 0) {
181
            entry_t e;
182
            e.func = reader_function<T>;
183
            e.addr = static_cast<void *>(addr);
184
            map_[key] = e;
185
        }
186
    }
187
    /*!
188
   * \brief read all fields according to declare.
189
   */
190
    inline bool read_fields(json_reader_t *reader);
191
192
private:
193
    /*!
194
     * \brief reader function to store T.
195
     */
196
    template <typename T>
197
    inline static void reader_function(json_reader_t *reader, void *addr);
198
    /*! \brief callback type to reader function */
199
    using readfunc = void (*)(json_reader_t *reader, void *addr);
200
    /*! \brief data entry */
201
    struct entry_t {
202
        readfunc func;
203
        /*! \brief store the address data for reading json*/
204
        void *addr;
205
    };
206
    /*! \brief reader callback */
207
    std::map<std::string, entry_t> map_;
208
};
209
210
template <typename then, typename other>
211
struct if_else_type<true, then, other> {
212
    using type = then;
213
};
214
215
template <typename then, typename other>
216
struct if_else_type<false, then, other> {
217
    using type = other;
218
};
219
220
template <typename valuetype>
221
struct num_json_t {
222
    inline static void write(json_writer_t *writer, const valuetype &value) {
223
        writer->write_number<valuetype>(value);
224
    }
225
    inline static void read(json_reader_t *reader, valuetype *value) {
226
        reader->read_number<valuetype>(value);
227
    }
228
};
229
230
template <typename valuetype>
231
struct common_json_t {
232
    inline static void write(json_writer_t *writer, const valuetype &value) {
233
        value.save(writer);
234
    }
235
    inline static void read(json_reader_t *reader, valuetype *value) {
236
        value->load(reader);
237
    }
238
};
239
240
template <typename valuetype>
241
struct common_json_t<std::shared_ptr<valuetype>> {
242
    inline static void write(
243
            json_writer_t *writer, const std::shared_ptr<valuetype> &value) {
244
        auto *v = value.get();
245
        v->save(writer);
246
    }
247
248
    inline static void read(
249
            json_reader_t *reader, std::shared_ptr<valuetype> *value) {
250
        auto ptr = std::make_shared<valuetype>();
251
        auto *v = ptr.get();
252
        v->load(reader);
253
        *value = std::move(ptr);
254
    }
255
};
256
257
template <typename CT>
258
struct array_json_t {
259
    inline static void write(json_writer_t *writer, const CT &array) {
260
        writer->begin_array();
261
        for (typename CT::const_iterator it = array.begin(); it != array.end();
262
                ++it) {
263
            writer->write_array_item(*it);
264
        }
265
        writer->end_array();
266
    }
267
    inline static void read(json_reader_t *reader, CT *array) {
268
        using elemtype = typename CT::value_type;
269
        array->clear();
270
        reader->begin_array();
271
        while (reader->next_array_item()) {
272
            elemtype value;
273
            json_handler_t<elemtype>::read(reader, &value);
274
            array->insert(array->end(), value);
275
        }
276
    }
277
};
278
279
template <typename CT>
280
struct map_json_t {
281
    inline static void write(json_writer_t *writer, const CT &map) {
282
        writer->begin_object();
283
        for (typename CT::const_iterator it = map.begin(); it != map.end();
284
                ++it) {
285
            writer->write_keyvalue(it->first, it->second);
286
        }
287
        writer->end_object();
288
    }
289
    inline static void read(json_reader_t *reader, CT *map) {
290
        using elemtype = typename CT::mapped_type;
291
        map->clear();
292
        reader->begin_object();
293
        std::string key;
294
        while (reader->next_object_item(&key)) {
295
            elemtype value;
296
            reader->read(&value);
297
            (*map)[key] = std::move(value);
298
        }
299
    }
300
};
301
302
template <>
303
struct json_handler_t<std::string> {
304
0
    inline static void write(json_writer_t *writer, const std::string &value) {
305
0
        writer->write_string(value);
306
0
    }
307
0
    inline static void read(json_reader_t *reader, std::string *str) {
308
0
        reader->read_string(str);
309
0
    }
310
};
311
312
template <typename T>
313
struct json_handler_t<std::map<std::string, T>>
314
    : public map_json_t<std::map<std::string, T>> {};
315
316
template <typename T>
317
struct json_handler_t<std::unordered_map<std::string, T>>
318
    : public map_json_t<std::unordered_map<std::string, T>> {};
319
320
template <typename T>
321
struct json_handler_t<std::vector<T>> : public array_json_t<std::vector<T>> {};
322
323
template <typename T>
324
struct json_handler_t<std::list<T>> : public array_json_t<std::list<T>> {};
325
/*!
326
 * \brief generic serialization json
327
 */
328
template <typename T>
329
struct json_handler_t {
330
    inline static void write(json_writer_t *writer, const T &data) {
331
        using Tjson = typename if_else_type<std::is_arithmetic<T>::value,
332
                num_json_t<T>, common_json_t<T>>::type;
333
        Tjson::write(writer, data);
334
    }
335
    inline static void read(json_reader_t *reader, T *data) {
336
        using Tjson = typename if_else_type<std::is_arithmetic<T>::value,
337
                num_json_t<T>, common_json_t<T>>::type;
338
        Tjson::read(reader, data);
339
    }
340
};
341
342
0
inline void json_writer_t::begin_object() {
343
0
    *os_ << "{";
344
0
    scope_multi_line_.push_back(true);
345
0
    scope_count_.push_back(0);
346
0
}
347
348
template <typename valuetype>
349
inline void json_writer_t::write_keyvalue(
350
        const std::string &key, const valuetype &value) {
351
    if (scope_count_.back() > 0) { *os_ << ","; }
352
    write_seperator();
353
    *os_ << '\"';
354
    *os_ << key;
355
    *os_ << "\": ";
356
    scope_count_.back() += 1;
357
    json_handler_t<valuetype>::write(this, value);
358
}
359
360
template <typename valuetype>
361
inline void json_writer_t::write_number(const valuetype &v) {
362
    *os_ << v;
363
}
364
365
0
inline void json_writer_t::write_string(const std::string &s) {
366
0
    *os_ << '\"';
367
0
    for (size_t i = 0; i < s.length(); ++i) {
368
0
        char ch = s[i];
369
0
        switch (ch) {
370
0
            case '\r': *os_ << "\\r"; break;
371
0
            case '\n': *os_ << "\\n"; break;
372
0
            case '\\': *os_ << "\\\\"; break;
373
0
            case '\t': *os_ << "\\t"; break;
374
0
            case '\"': *os_ << "\\\""; break;
375
0
            default: *os_ << ch;
376
0
        }
377
0
    }
378
0
    *os_ << '\"';
379
0
}
380
381
0
inline void json_writer_t::begin_array(bool multi_line) {
382
0
    *os_ << '[';
383
0
    scope_multi_line_.push_back(multi_line);
384
0
    scope_count_.push_back(0);
385
0
}
386
387
0
inline void json_writer_t::end_array() {
388
0
    if (!scope_count_.empty() && !scope_multi_line_.empty()) {
389
0
        bool newline = scope_multi_line_.back();
390
0
        size_t nelem = scope_count_.back();
391
0
        scope_multi_line_.pop_back();
392
0
        scope_count_.pop_back();
393
0
        if (newline && nelem != 0) write_seperator();
394
0
    }
395
0
    *os_ << ']';
396
0
}
397
398
0
inline void json_writer_t::write_array_seperator() {
399
0
    if (scope_count_.back() != 0) { *os_ << ","; }
400
0
    scope_count_.back() += 1;
401
0
    write_seperator();
402
0
}
403
404
template <typename valuetype>
405
inline void json_writer_t::write_array_item(const valuetype &value) {
406
    this->write_array_seperator();
407
    json::json_handler_t<valuetype>::write(this, value);
408
}
409
410
0
inline void json_writer_t::end_object() {
411
0
    if (!scope_count_.empty() && !scope_multi_line_.empty()) {
412
0
        bool newline = scope_multi_line_.back();
413
0
        size_t nelem = scope_count_.back();
414
0
        scope_multi_line_.pop_back();
415
0
        scope_count_.pop_back();
416
0
        if (newline && nelem != 0) write_seperator();
417
0
    }
418
0
    *os_ << '}';
419
0
}
420
421
0
inline void json_writer_t::write_seperator() {
422
0
    if (scope_multi_line_.empty() || scope_multi_line_.back()) {
423
0
        *os_ << '\n';
424
0
        *os_ << std::string(scope_multi_line_.size() * 2, ' ');
425
0
    }
426
0
}
427
428
0
inline void json_writer_t::write_newline() {
429
0
    *os_ << '\n';
430
0
}
431
432
1.94M
inline int json_reader_t::next_char() {
433
1.94M
    return is_->get();
434
1.94M
}
435
436
490
inline int json_reader_t::peeknext_char() {
437
490
    return is_->peek();
438
490
}
439
440
1.58M
inline int json_reader_t::next_nonspace() {
441
1.58M
    int ch;
442
1.58M
    do {
443
1.58M
        ch = next_char();
444
1.58M
    } while (isspace(ch));
445
1.58M
    return ch;
446
1.58M
}
447
448
287
inline int json_reader_t::peeknext_nonspace() {
449
287
    int ch;
450
490
    while (true) {
451
490
        ch = peeknext_char();
452
490
        if (!isspace(ch)) break;
453
203
        next_char();
454
203
    }
455
287
    return ch;
456
287
}
457
458
527k
inline void json_reader_t::read_string(std::string *out_str) {
459
527k
    int ch = next_nonspace();
460
527k
    if (ch == '\"') {
461
2.06k
        std::ostringstream output;
462
359k
        while (true) {
463
359k
            ch = next_char();
464
359k
            if (ch == '\\') {
465
4.33k
                char sch = static_cast<char>(next_char());
466
4.33k
                switch (sch) {
467
1.14k
                    case 'r': output << "\r"; break;
468
546
                    case 'n': output << "\r"; break;
469
980
                    case '\\': output << "\r"; break;
470
1.17k
                    case 't': output << "\r"; break;
471
481
                    case '\"': output << "\r"; break;
472
6
                    default: throw("unknown string escape.");
473
4.33k
                }
474
355k
            } else {
475
355k
                if (ch == '\"') break;
476
353k
                output << static_cast<char>(ch);
477
353k
            }
478
357k
            if (ch == EOF || ch == '\r' || ch == '\n') {
479
109
                throw("error at!");
480
0
                return;
481
109
            }
482
357k
        }
483
1.95k
        *out_str = output.str();
484
1.95k
    }
485
527k
}
486
487
template <typename valuetype>
488
inline void json_reader_t::read_number(valuetype *out_value) {
489
    *is_ >> *out_value;
490
}
491
492
323
inline void json_reader_t::begin_object() {
493
323
    int ch = next_nonspace();
494
323
    if (ch == '{') { scope_count_.push_back(0); }
495
323
}
496
497
0
inline void json_reader_t::begin_array() {
498
0
    int ch = next_nonspace();
499
0
    if (ch == '[') { scope_count_.push_back(0); }
500
0
}
501
502
527k
inline bool json_reader_t::next_object_item(std::string *out_key) {
503
527k
    bool next = true;
504
527k
    if (scope_count_.empty()) { return false; }
505
527k
    if (scope_count_.back() != 0) {
506
526k
        int ch = next_nonspace();
507
526k
        if (ch == EOF) {
508
29
            next = false;
509
526k
        } else if (ch == '}') {
510
1
            next = false;
511
526k
        } else {
512
526k
            if (ch != ',') { return false; }
513
526k
        }
514
526k
    } else {
515
287
        int ch = peeknext_nonspace();
516
287
        if (ch == '}') {
517
1
            next_char();
518
1
            next = false;
519
1
        }
520
287
    }
521
527k
    if (!next) {
522
31
        scope_count_.pop_back();
523
31
        return false;
524
527k
    } else {
525
527k
        scope_count_.back() += 1;
526
527k
        read_string(out_key);
527
527k
        int ch = next_nonspace();
528
527k
        return (ch == ':');
529
527k
    }
530
527k
}
531
532
0
inline bool json_reader_t::next_array_item() {
533
0
    bool next = true;
534
0
    if (scope_count_.empty()) { return false; }
535
0
    if (scope_count_.back() != 0) {
536
0
        int ch = next_nonspace();
537
0
        if (ch == EOF) {
538
0
            next = false;
539
0
        } else if (ch == ']') {
540
0
            next = false;
541
0
        } else {
542
0
            if (ch != ',') { return false; }
543
0
        }
544
0
    } else {
545
0
        int ch = peeknext_nonspace();
546
0
        if (ch == ']') {
547
0
            next_char();
548
0
            next = false;
549
0
        }
550
0
    }
551
0
    if (!next) {
552
0
        scope_count_.pop_back();
553
0
        return false;
554
0
    } else {
555
0
        scope_count_.back() += 1;
556
0
        return true;
557
0
    }
558
0
}
559
560
template <typename valuetype>
561
inline void json_reader_t::read(valuetype *out_value) {
562
    json::json_handler_t<valuetype>::read(this, out_value);
563
}
564
565
323
inline bool read_helper_t::read_fields(json_reader_t *reader) {
566
323
    reader->begin_object();
567
323
    std::map<std::string, int> visited;
568
323
    std::string key;
569
527k
    while (reader->next_object_item(&key)) {
570
526k
        if (map_.count(key) != 0) {
571
0
            entry_t e = map_[key];
572
0
            (*e.func)(reader, e.addr);
573
0
            visited[key] = 0;
574
0
        }
575
526k
    }
576
323
    if (visited.size() != map_.size()) {
577
0
        for (std::map<std::string, entry_t>::iterator it = map_.begin();
578
0
                it != map_.end(); ++it) {
579
0
            if (visited.count(it->first) != 1) { return false; }
580
0
        }
581
0
    }
582
323
    return true;
583
323
}
584
585
template <typename T>
586
inline void read_helper_t::reader_function(json_reader_t *reader, void *addr) {
587
    json::json_handler_t<T>::read(reader, static_cast<T *>(addr));
588
}
589
590
} // namespace json
591
} // namespace utils
592
} // namespace graph
593
} // namespace impl
594
} // namespace dnnl
595
596
#endif