Coverage Report

Created: 2026-08-17 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/staj_event.hpp
Line
Count
Source
1
// Copyright 2013-2026 Daniel Parker
2
// Distributed under the Boost license, Version 1.0.
3
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5
// See https://github.com/danielaparker/jsoncons for latest version
6
7
#ifndef JSONCONS_STAJ_EVENT_HPP
8
#define JSONCONS_STAJ_EVENT_HPP
9
10
#include <array> // std::array
11
#include <cstddef>
12
#include <cstdint>
13
#include <functional> // std::function
14
#include <ios>
15
#include <ostream> 
16
#include <memory> // std::allocator
17
#include <system_error>
18
#include <type_traits> // std::enable_if
19
20
#include <jsoncons/config/compiler_support.hpp>
21
#include <jsoncons/conv_error.hpp>
22
#include <jsoncons/utility/write_number.hpp>
23
#include <jsoncons/generic_visitor.hpp>
24
#include <jsoncons/json_exception.hpp>
25
#include <jsoncons/json_parser.hpp>
26
#include <jsoncons/json_type.hpp>
27
#include <jsoncons/json_visitor.hpp>
28
#include <jsoncons/semantic_tag.hpp>
29
#include <jsoncons/ser_utils.hpp>
30
#include <jsoncons/sink.hpp>
31
#include <jsoncons/utility/bigint.hpp>
32
#include <jsoncons/utility/more_type_traits.hpp>
33
34
#include <jsoncons/utility/conversion.hpp>
35
36
namespace jsoncons {
37
38
enum class staj_events : uint64_t
39
{
40
    string_value      = 1,
41
    byte_string_value = 2,
42
    null_value        = 4,
43
    bool_value        = 8,
44
    int64_value       = 16,
45
    uint64_value      = 32,
46
    half_value        = 64,
47
    double_value      = 128,
48
    begin_object      = 256,
49
    end_object        = 512,   
50
    begin_array       = 1024,
51
    end_array         = 2048,
52
    key_flag          = 4096,
53
    key               = key_flag | string_value,
54
    id                = key_flag | uint64_value
55
};
56
57
using staj_event_type = staj_events; // For backwards compatibility
58
59
JSONCONS_ATTRIBUTE_NODISCARD
60
constexpr staj_events
61
operator|(staj_events lhs, staj_events rhs) noexcept
62
0
{ return (staj_events)((uint64_t)lhs | (uint64_t)rhs); }
63
64
JSONCONS_ATTRIBUTE_NODISCARD
65
constexpr staj_events
66
operator&(staj_events lhs, staj_events rhs) noexcept
67
0
{ return (staj_events)((uint64_t)lhs & (uint64_t)rhs); }
68
69
JSONCONS_ATTRIBUTE_NODISCARD
70
constexpr staj_events
71
operator^(staj_events lhs, staj_events rhs) noexcept
72
0
{ return (staj_events)((uint64_t)lhs ^ (uint64_t)rhs); }
73
74
JSONCONS_ATTRIBUTE_NODISCARD
75
constexpr staj_events
76
operator~(staj_events types) noexcept
77
0
{ return (staj_events)~(uint64_t)types; }
78
79
constexpr staj_events&
80
operator|=(staj_events& lhs, staj_events rhs) noexcept
81
0
{ return lhs = lhs | rhs; }
82
83
constexpr staj_events&
84
operator&=(staj_events& lhs, staj_events rhs) noexcept
85
0
{ return lhs = lhs & rhs; }
86
87
constexpr staj_events&
88
operator^=(staj_events& lhs, staj_events rhs) noexcept
89
0
{ return lhs = lhs ^ rhs; }
90
91
inline bool is_begin_container(staj_events types) noexcept
92
0
{
93
0
    static constexpr staj_events mask{ staj_events::begin_object | staj_events::begin_array };
94
0
    return (types & mask) != staj_events{};
95
0
}
96
97
inline bool is_end_container(staj_events types) noexcept
98
0
{
99
0
    static constexpr staj_events mask{ staj_events::end_object | staj_events::end_array };
100
0
    return (types & mask) != staj_events{};
101
0
}
102
103
template <typename CharT>
104
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, staj_events tag)
105
{
106
    static constexpr const CharT* begin_array_literal = JSONCONS_CSTRING_CONSTANT(CharT, "begin_array");
107
    static constexpr const CharT* end_array_literal = JSONCONS_CSTRING_CONSTANT(CharT, "end_array");
108
    static constexpr const CharT* begin_object_literal = JSONCONS_CSTRING_CONSTANT(CharT, "begin_object");
109
    static constexpr const CharT* end_object_literal = JSONCONS_CSTRING_CONSTANT(CharT, "end_object");
110
    static constexpr const CharT* key_literal = JSONCONS_CSTRING_CONSTANT(CharT, "key");
111
    static constexpr const CharT* string_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "string_value");
112
    static constexpr const CharT* byte_string_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string_value");
113
    static constexpr const CharT* null_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "null_value");
114
    static constexpr const CharT* bool_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "bool_value");
115
    static constexpr const CharT* uint64_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "uint64_value");
116
    static constexpr const CharT* int64_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "int64_value");
117
    static constexpr const CharT* half_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "half_value");
118
    static constexpr const CharT* double_value_literal = JSONCONS_CSTRING_CONSTANT(CharT, "double_value");
119
120
    switch (tag & ~staj_events::key_flag)
121
    {
122
        case staj_events::begin_array:
123
        {
124
            os << begin_array_literal;
125
            break;
126
        }
127
        case staj_events::end_array:
128
        {
129
            os << end_array_literal;
130
            break;
131
        }
132
        case staj_events::begin_object:
133
        {
134
            os << begin_object_literal;
135
            break;
136
        }
137
        case staj_events::end_object:
138
        {
139
            os << end_object_literal;
140
            break;
141
        }
142
        case staj_events::string_value:
143
        {
144
            os << string_value_literal;
145
            break;
146
        }
147
        case staj_events::byte_string_value:
148
        {
149
            os << byte_string_value_literal;
150
            break;
151
        }
152
        case staj_events::null_value:
153
        {
154
            os << null_value_literal;
155
            break;
156
        }
157
        case staj_events::bool_value:
158
        {
159
            os << bool_value_literal;
160
            break;
161
        }
162
        case staj_events::int64_value:
163
        {
164
            os << int64_value_literal;
165
            break;
166
        }
167
        case staj_events::uint64_value:
168
        {
169
            os << uint64_value_literal;
170
            break;
171
        }
172
        case staj_events::half_value:
173
        {
174
            os << half_value_literal;
175
            break;
176
        }
177
        case staj_events::double_value:
178
        {
179
            os << double_value_literal;
180
            break;
181
        }
182
        default:
183
        {
184
            break;
185
        }
186
    }
187
    if ((tag & staj_events::key_flag) != staj_events{})
188
    {
189
        os << ' ' << key_literal;
190
    }
191
    return os;
192
}
193
194
template <typename CharT>
195
class basic_staj_event
196
{
197
    staj_events event_flags_;
198
    semantic_tag tag_;
199
    uint64_t raw_tag_{0};
200
    union
201
    {
202
        bool bool_value_;
203
        int64_t int64_value_;
204
        uint64_t uint64_value_;
205
        uint16_t half_value_;
206
        double double_value_;
207
        const CharT* string_data_;
208
        const uint8_t* byte_string_data_;
209
    } value_;
210
    std::size_t length_{0};
211
212
    staj_events storage_tag() const
213
    {
214
        static constexpr staj_events mask = ~staj_events::key_flag;
215
        return event_flags_ & mask;
216
    }
217
public:
218
    using char_type = CharT;
219
    using string_view_type = jsoncons::basic_string_view<char_type>;
220
221
    basic_staj_event(staj_events event_type, semantic_tag tag = semantic_tag::none,
222
        staj_events key_flag = staj_events{})
223
        : event_flags_(event_type | key_flag), tag_(tag), value_()
224
    {
225
    }
226
227
    basic_staj_event(staj_events event_type, std::size_t length, 
228
        semantic_tag tag = semantic_tag::none,
229
        staj_events key_flag = staj_events{})
230
        : event_flags_(event_type | key_flag), tag_(tag), value_(), length_(length)
231
    {
232
    }
233
234
    basic_staj_event(bool value, semantic_tag tag,
235
        staj_events key_flag = staj_events{})
236
        : event_flags_(staj_events::bool_value | key_flag), tag_(tag)
237
    {
238
        value_.bool_value_ = value;
239
    }
240
241
    basic_staj_event(int64_t value, semantic_tag tag,
242
        staj_events key_flag = staj_events{})
243
        : event_flags_(staj_events::int64_value | key_flag), tag_(tag)
244
    {
245
        value_.int64_value_ = value;
246
    }
247
248
    basic_staj_event(uint64_t value, semantic_tag tag,
249
        staj_events key_flag = staj_events{})
250
        : event_flags_(staj_events::uint64_value | key_flag), tag_(tag)
251
    {
252
        value_.uint64_value_ = value;
253
    }
254
255
    basic_staj_event(half_arg_t, uint16_t value, semantic_tag tag,
256
        staj_events key_flag = staj_events{})
257
        : event_flags_(staj_events::half_value | key_flag), tag_(tag)
258
    {
259
        value_.half_value_ = value;
260
    }
261
262
    basic_staj_event(double value, semantic_tag tag,
263
        staj_events key_flag = staj_events{})
264
        : event_flags_(staj_events::double_value | key_flag), tag_(tag)
265
    {
266
        value_.double_value_ = value;
267
    }
268
269
    basic_staj_event(const string_view_type& s,
270
        staj_events event_type,
271
        semantic_tag tag = semantic_tag::none,
272
        staj_events key_flag = staj_events{})
273
        : event_flags_(event_type | key_flag), tag_(tag), length_(s.length())
274
    {
275
        value_.string_data_ = s.data();
276
    }
277
278
    basic_staj_event(const byte_string_view& s,
279
        staj_events event_type,
280
        semantic_tag tag,
281
        staj_events key_flag = staj_events{})
282
        : event_flags_(event_type | key_flag), tag_(tag), length_(s.size())
283
    {
284
        value_.byte_string_data_ = s.data();
285
    }
286
287
    basic_staj_event(const byte_string_view& s,
288
        staj_events event_type,
289
        uint64_t raw_tag,
290
        staj_events key_flag = staj_events{})
291
        : event_flags_(event_type | key_flag), tag_(semantic_tag::ext), raw_tag_(raw_tag), length_(s.size())
292
    {
293
        value_.byte_string_data_ = s.data();
294
    }
295
    
296
    ~basic_staj_event() = default;
297
298
    std::size_t size() const
299
    {
300
        return length_;
301
    }
302
303
    template <typename T>
304
    T get() const
305
    {
306
        std::error_code ec;
307
        T val = get<T>(ec);
308
        if (JSONCONS_UNLIKELY(ec))
309
        {
310
            JSONCONS_THROW(ser_error(ec));
311
        }
312
        return val;
313
    }
314
315
    template <typename T>
316
    T get(std::error_code& ec) const
317
    {
318
        return get_<T>(std::allocator<char>{}, ec);
319
    }
320
321
    template <typename T,typename Allocator,typename CharT_ = CharT>
322
    typename std::enable_if<ext_traits::is_string<T>::value && std::is_same<typename T::value_type, CharT_>::value, T>::type
323
    get_(Allocator alloc,std::error_code& ec) const
324
    {
325
        constexpr const char_type* true_literal = JSONCONS_CSTRING_CONSTANT(char_type,"true"); 
326
        constexpr const char_type* false_literal = JSONCONS_CSTRING_CONSTANT(char_type,"false"); 
327
        constexpr const char_type* null_literal = JSONCONS_CSTRING_CONSTANT(char_type,"null"); 
328
329
        switch (storage_tag())
330
        {
331
            case staj_events::string_value:
332
            {
333
                return jsoncons::make_obj_using_allocator<T>(alloc, value_.string_data_, length_);
334
            }
335
            case staj_events::byte_string_value:
336
            {
337
                auto s = jsoncons::make_obj_using_allocator<T>(alloc);
338
                bytes_to_string(value_.byte_string_data_, value_.byte_string_data_+length_, tag(), s);
339
                return s;
340
            }
341
            case staj_events::uint64_value:
342
            {
343
                auto s = jsoncons::make_obj_using_allocator<T>(alloc);
344
                jsoncons::from_integer(value_.uint64_value_, s);
345
                return s;
346
            }
347
            case staj_events::int64_value:
348
            {
349
                auto s = jsoncons::make_obj_using_allocator<T>(alloc);
350
                jsoncons::from_integer(value_.int64_value_, s);
351
                return s;
352
            }
353
            case staj_events::half_value:
354
            {
355
                auto s = jsoncons::make_obj_using_allocator<T>(alloc);
356
                jsoncons::write_double f{float_chars_format::general,0};
357
                double x = binary::decode_half(value_.half_value_);
358
                f(x, s);
359
                return s;
360
            }
361
            case staj_events::double_value:
362
            {
363
                auto s = jsoncons::make_obj_using_allocator<T>(alloc);
364
                jsoncons::write_double f{float_chars_format::general,0};
365
                f(value_.double_value_, s);
366
                return s;
367
            }
368
            case staj_events::bool_value:
369
            {
370
                return jsoncons::make_obj_using_allocator<T>(alloc, value_.bool_value_ ? true_literal : false_literal);
371
            }
372
            case staj_events::null_value:
373
            {
374
                return jsoncons::make_obj_using_allocator<T>(alloc, null_literal);
375
            }
376
            default:
377
            {
378
                ec = conv_errc::not_string;
379
                return T{};
380
            }
381
        }
382
    }
383
384
    template <typename T,typename Allocator,typename CharT_ = CharT>
385
    typename std::enable_if<ext_traits::is_string_view<T>::value && std::is_same<typename T::value_type, CharT_>::value, T>::type
386
        get_(Allocator, std::error_code& ec) const
387
    {
388
        T s;
389
        switch (storage_tag())
390
        {
391
            case staj_events::string_value:
392
                s = T(value_.string_data_, length_);
393
                break;
394
            default:
395
                ec = conv_errc::not_string_view;
396
                break;        
397
        }
398
        return s;
399
    }
400
401
    template <typename T,typename Allocator>
402
    typename std::enable_if<std::is_same<T, byte_string_view>::value, T>::type
403
        get_(Allocator, std::error_code& ec) const
404
    {
405
        T s;
406
        switch (storage_tag())
407
        {
408
            case staj_events::byte_string_value:
409
                s = T(value_.byte_string_data_, length_);
410
                break;
411
            default:
412
                ec = conv_errc::not_byte_string_view;
413
                break;
414
        }
415
        return s;
416
    }
417
418
    template <typename T,typename Allocator>
419
    typename std::enable_if<ext_traits::is_array_like<T>::value &&
420
                            std::is_same<typename T::value_type,uint8_t>::value,T>::type
421
    get_(Allocator alloc, std::error_code& ec) const
422
    {
423
        switch (storage_tag())
424
        {
425
            case staj_events::byte_string_value:
426
            {
427
                auto v = jsoncons::make_obj_using_allocator<T>(alloc, 
428
                    value_.byte_string_data_, 
429
                    value_.byte_string_data_+length_);
430
                return v;
431
            }
432
            case staj_events::string_value:
433
            {
434
                auto v = jsoncons::make_obj_using_allocator<T>(alloc);
435
                auto r = string_to_bytes(value_.string_data_, value_.string_data_+length_, tag(), v);
436
                if (r.ec != conv_errc{})
437
                {
438
                    ec = conv_errc::not_byte_string;
439
                }
440
                return v;
441
            }
442
            default:
443
                ec = conv_errc::not_byte_string;
444
                return T{};
445
        }
446
    }
447
448
    template <typename IntegerType,typename Allocator>
449
    typename std::enable_if<ext_traits::is_integer<IntegerType>::value, IntegerType>::type
450
    get_(Allocator, std::error_code& ec) const
451
    {
452
        switch (storage_tag())
453
        {
454
            case staj_events::string_value:
455
            {
456
                IntegerType val;
457
                auto result = jsoncons::to_integer(value_.string_data_, length_, val);
458
                if (!result)
459
                {
460
                    ec = conv_errc::not_integer;
461
                    return IntegerType();
462
                }
463
                return val;
464
            }
465
            case staj_events::half_value:
466
                return static_cast<IntegerType>(value_.half_value_);
467
            case staj_events::double_value:
468
                return static_cast<IntegerType>(value_.double_value_);
469
            case staj_events::int64_value:
470
                return static_cast<IntegerType>(value_.int64_value_);
471
            case staj_events::uint64_value:
472
                return static_cast<IntegerType>(value_.uint64_value_);
473
            case staj_events::bool_value:
474
                return static_cast<IntegerType>(value_.bool_value_ ? 1 : 0);
475
            default:
476
                ec = conv_errc::not_integer;
477
                return IntegerType();
478
        }
479
    }
480
481
    template <typename T,typename Allocator>
482
    typename std::enable_if<std::is_floating_point<T>::value, T>::type
483
        get_(Allocator, std::error_code& ec) const
484
    {
485
        return static_cast<T>(as_double(ec));
486
    }
487
488
    template <typename T,typename Allocator>
489
    typename std::enable_if<ext_traits::is_bool<T>::value, T>::type
490
        get_(Allocator, std::error_code& ec) const
491
    {
492
        return as_bool(ec);
493
    }
494
495
    staj_events event_type() const noexcept { return event_flags_; }
496
497
    semantic_tag tag() const noexcept { return tag_; }
498
499
    uint64_t ext_tag() const noexcept { return raw_tag_; }
500
501
private:
502
503
    double as_double(std::error_code& ec) const
504
    {
505
        switch (storage_tag())
506
        {
507
            case staj_events::string_value:
508
            {
509
                double val{0};
510
                if (length_ == 0)
511
                {
512
                    ec = conv_errc::not_double;
513
                    return val;
514
                }
515
                auto result = jsoncons::decstr_to_double(value_.string_data_, length_, val);
516
                if (!result)
517
                {
518
                    ec = conv_errc::not_double;
519
                }
520
                return val;
521
            }
522
            case staj_events::double_value:
523
                return value_.double_value_;
524
            case staj_events::int64_value:
525
                return static_cast<double>(value_.int64_value_);
526
            case staj_events::uint64_value:
527
                return static_cast<double>(value_.uint64_value_);
528
            case staj_events::half_value:
529
            {
530
                double x = binary::decode_half(value_.half_value_);
531
                return static_cast<double>(x);
532
            }
533
            default:
534
                ec = conv_errc::not_double;
535
                return double();
536
        }
537
    }
538
539
    bool as_bool(std::error_code& ec) const
540
    {
541
        switch (storage_tag())
542
        {
543
            case staj_events::bool_value:
544
                return value_.bool_value_;
545
            case staj_events::double_value:
546
                return value_.double_value_ != 0.0;
547
            case staj_events::int64_value:
548
                return value_.int64_value_ != 0;
549
            case staj_events::uint64_value:
550
                return value_.uint64_value_ != 0;
551
            default:
552
                ec = conv_errc::not_bool;
553
                return bool();
554
        }
555
    }
556
public:
557
    void send_event(basic_json_visitor<CharT>& visitor,
558
        const ser_context& context,
559
        std::error_code& ec) const
560
    {
561
        switch (storage_tag())
562
        {
563
            case staj_events::begin_array:
564
                visitor.begin_array(tag(), context);
565
                break;
566
            case staj_events::end_array:
567
                visitor.end_array(context);
568
                break;
569
            case staj_events::begin_object:
570
                visitor.begin_object(tag(), context, ec);
571
                break;
572
            case staj_events::end_object:
573
                visitor.end_object(context, ec);
574
                break;
575
            case staj_events::string_value:
576
                if ((event_flags_ & staj_events::key_flag) != staj_events{})
577
                {
578
                    visitor.key(string_view_type(value_.string_data_,length_), context);
579
                }
580
                else
581
                {
582
                    visitor.string_value(string_view_type(value_.string_data_,length_), tag(), context);
583
                }
584
                break;
585
            case staj_events::byte_string_value:
586
                visitor.byte_string_value(byte_string_view(value_.byte_string_data_,length_), tag(), context);
587
                break;
588
            case staj_events::null_value:
589
                visitor.null_value(tag(), context);
590
                break;
591
            case staj_events::bool_value:
592
                visitor.bool_value(value_.bool_value_, tag(), context);
593
                break;
594
            case staj_events::int64_value:
595
                visitor.int64_value(value_.int64_value_, tag(), context);
596
                break;
597
            case staj_events::uint64_value:
598
                visitor.uint64_value(value_.uint64_value_, tag(), context);
599
                break;
600
            case staj_events::half_value:
601
                visitor.half_value(value_.half_value_, tag(), context);
602
                break;
603
            case staj_events::double_value:
604
                visitor.double_value(value_.double_value_, tag(), context);
605
                break;
606
            default:
607
                break;
608
        }
609
    }
610
    
611
    void send_event(basic_generic_visitor<CharT>& visitor,
612
        const ser_context& context,
613
        std::error_code& ec) const
614
    {
615
        switch (storage_tag())
616
        {
617
            case staj_events::begin_array:
618
                visitor.begin_array(tag(), context);
619
                break;
620
            case staj_events::end_array:
621
                visitor.end_array(context);
622
                break;
623
            case staj_events::begin_object:
624
                visitor.begin_object(tag(), context, ec);
625
                break;
626
            case staj_events::end_object:
627
                visitor.end_object(context, ec);
628
                break;
629
            case staj_events::string_value:
630
                visitor.string_value(string_view_type(value_.string_data_,length_), tag(), context);
631
                break;
632
            case staj_events::byte_string_value:
633
                visitor.byte_string_value(byte_string_view(value_.byte_string_data_,length_), tag(), context);
634
                break;
635
            case staj_events::null_value:
636
                visitor.null_value(tag(), context);
637
                break;
638
            case staj_events::bool_value:
639
                visitor.bool_value(value_.bool_value_, tag(), context);
640
                break;
641
            case staj_events::int64_value:
642
                visitor.int64_value(value_.int64_value_, tag(), context);
643
                break;
644
            case staj_events::uint64_value:
645
                visitor.uint64_value(value_.uint64_value_, tag(), context);
646
                break;
647
            case staj_events::half_value:
648
                visitor.half_value(value_.half_value_, tag(), context);
649
                break;
650
            case staj_events::double_value:
651
                visitor.double_value(value_.double_value_, tag(), context);
652
                break;
653
            default:
654
                break;
655
        }
656
    }
657
658
};
659
660
using staj_event = basic_staj_event<char>;
661
using wstaj_event = basic_staj_event<wchar_t>;
662
663
} // namespace jsoncons
664
665
#endif // JSONCONS_STAJ_EVENT_HPP
666