← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Thu Dec 15 15:23:56 2022
Reported on Thu Dec 15 15:27:03 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/JSON/PP.pm
StatementsExecuted 1227 statements in 10.9ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
569441.07ms1.07msJSON::PP::::true JSON::PP::true
111837µs837µsJSON::PP::::BEGIN@68 JSON::PP::BEGIN@68
40533817µs817µsJSON::PP::::false JSON::PP::false
111595µs657µsJSON::PP::::BEGIN@12 JSON::PP::BEGIN@12
111125µs137µsJSON::PP::::BEGIN@697 JSON::PP::BEGIN@697
11176µs76µsJSON::PP::::BEGIN@1448 JSON::PP::BEGIN@1448
11121µs21µsJSON::PP::::BEGIN@5 JSON::PP::BEGIN@5
11121µs41µsJSON::PP::::BEGIN@53 JSON::PP::BEGIN@53
11120µs20µsJSON::PP::::BEGIN@1511 JSON::PP::BEGIN@1511
11119µs19µsJSON::PP::::CORE:regcomp JSON::PP::CORE:regcomp (opcode)
11113µs16µsJSON::PP::IncrParser::::BEGIN@1658JSON::PP::IncrParser::BEGIN@1658
171112µs12µsJSON::PP::::CORE:match JSON::PP::CORE:match (opcode)
11110µs12µsJSON::PP::::BEGIN@799 JSON::PP::BEGIN@799
11110µs43µsJSON::PP::IncrParser::::BEGIN@1603JSON::PP::IncrParser::BEGIN@1603
1118µs28µsJSON::PP::::BEGIN@1294 JSON::PP::BEGIN@1294
1118µs25µsJSON::PP::::BEGIN@502 JSON::PP::BEGIN@502
1117µs44µsJSON::PP::::BEGIN@24 JSON::PP::BEGIN@24
1117µs8µsJSON::PP::::BEGIN@6 JSON::PP::BEGIN@6
1117µs7µsJSON::PP::::BEGIN@9 JSON::PP::BEGIN@9
1117µs9µsJSON::PP::IncrParser::::BEGIN@1596JSON::PP::IncrParser::BEGIN@1596
1116µs24µsJSON::PP::IncrParser::::BEGIN@1601JSON::PP::IncrParser::BEGIN@1601
1116µs31µsJSON::PP::IncrParser::::BEGIN@1602JSON::PP::IncrParser::BEGIN@1602
1116µs42µsJSON::PP::IncrParser::::BEGIN@1605JSON::PP::IncrParser::BEGIN@1605
1115µs28µsJSON::PP::::BEGIN@1582 JSON::PP::BEGIN@1582
1115µs24µsJSON::PP::::BEGIN@217 JSON::PP::BEGIN@217
1115µs16µsJSON::PP::::BEGIN@39 JSON::PP::BEGIN@39
1115µs22µsJSON::PP::::BEGIN@40 JSON::PP::BEGIN@40
1115µs19µsJSON::PP::::BEGIN@48 JSON::PP::BEGIN@48
1115µs14µsJSON::PP::::BEGIN@524 JSON::PP::BEGIN@524
1115µs50µsJSON::PP::IncrParser::::BEGIN@1598JSON::PP::IncrParser::BEGIN@1598
1115µs18µsJSON::PP::IncrParser::::BEGIN@1599JSON::PP::IncrParser::BEGIN@1599
1114µs16µsJSON::PP::::BEGIN@27 JSON::PP::BEGIN@27
1114µs18µsJSON::PP::::BEGIN@31 JSON::PP::BEGIN@31
1114µs15µsJSON::PP::::BEGIN@32 JSON::PP::BEGIN@32
1114µs18µsJSON::PP::::BEGIN@35 JSON::PP::BEGIN@35
1114µs16µsJSON::PP::::BEGIN@37 JSON::PP::BEGIN@37
1114µs24µsJSON::PP::IncrParser::::BEGIN@1604JSON::PP::IncrParser::BEGIN@1604
1113µs21µsJSON::PP::::BEGIN@25 JSON::PP::BEGIN@25
1113µs21µsJSON::PP::::BEGIN@26 JSON::PP::BEGIN@26
1113µs16µsJSON::PP::::BEGIN@28 JSON::PP::BEGIN@28
1113µs14µsJSON::PP::::BEGIN@33 JSON::PP::BEGIN@33
1113µs15µsJSON::PP::::BEGIN@34 JSON::PP::BEGIN@34
1113µs12µsJSON::PP::::BEGIN@42 JSON::PP::BEGIN@42
1113µs13µsJSON::PP::::BEGIN@44 JSON::PP::BEGIN@44
1113µs16µsJSON::PP::::BEGIN@45 JSON::PP::BEGIN@45
1113µs19µsJSON::PP::::BEGIN@47 JSON::PP::BEGIN@47
1113µs16µsJSON::PP::IncrParser::::BEGIN@1600JSON::PP::IncrParser::BEGIN@1600
1112µs2µsJSON::PP::::BEGIN@11 JSON::PP::BEGIN@11
1112µs2µsJSON::PP::::BEGIN@14 JSON::PP::BEGIN@14
1112µs15µsJSON::PP::::BEGIN@30 JSON::PP::BEGIN@30
1112µs16µsJSON::PP::::BEGIN@41 JSON::PP::BEGIN@41
1112µs10µsJSON::PP::::BEGIN@49 JSON::PP::BEGIN@49
1112µs2µsJSON::PP::::BEGIN@62 JSON::PP::BEGIN@62
1112µs2µsJSON::PP::::BEGIN@8 JSON::PP::BEGIN@8
1111µs11µsJSON::PP::::BEGIN@29 JSON::PP::BEGIN@29
1111µs14µsJSON::PP::::BEGIN@38 JSON::PP::BEGIN@38
1111µs1µsJSON::PP::::CORE:qr JSON::PP::CORE:qr (opcode)
0000s0sJSON::PP::IncrParser::::_incr_parseJSON::PP::IncrParser::_incr_parse
0000s0sJSON::PP::IncrParser::::incr_parseJSON::PP::IncrParser::incr_parse
0000s0sJSON::PP::IncrParser::::incr_resetJSON::PP::IncrParser::incr_reset
0000s0sJSON::PP::IncrParser::::incr_skipJSON::PP::IncrParser::incr_skip
0000s0sJSON::PP::IncrParser::::incr_textJSON::PP::IncrParser::incr_text
0000s0sJSON::PP::IncrParser::::newJSON::PP::IncrParser::new
0000s0sJSON::PP::::PP_decode_box JSON::PP::PP_decode_box
0000s0sJSON::PP::::PP_decode_json JSON::PP::PP_decode_json
0000s0sJSON::PP::::PP_encode_box JSON::PP::PP_encode_box
0000s0sJSON::PP::::PP_encode_json JSON::PP::PP_encode_json
1110s0sJSON::PP::::__ANON__ JSON::PP::__ANON__ (xsub)
0000s0sJSON::PP::::__ANON__[:1524] JSON::PP::__ANON__[:1524]
0000s0sJSON::PP::::__ANON__[:1546] JSON::PP::__ANON__[:1546]
0000s0sJSON::PP::::__ANON__[:1563] JSON::PP::__ANON__[:1563]
0000s0sJSON::PP::::__ANON__[:367] JSON::PP::__ANON__[:367]
0000s0sJSON::PP::::__ANON__[:372] JSON::PP::__ANON__[:372]
0000s0sJSON::PP::::_decode_surrogates JSON::PP::_decode_surrogates
0000s0sJSON::PP::::_decode_unicode JSON::PP::_decode_unicode
0000s0sJSON::PP::::_detect_utf_encoding JSON::PP::_detect_utf_encoding
0000s0sJSON::PP::::_down_indent JSON::PP::_down_indent
0000s0sJSON::PP::::_encode_ascii JSON::PP::_encode_ascii
0000s0sJSON::PP::::_encode_latin1 JSON::PP::_encode_latin1
0000s0sJSON::PP::::_encode_surrogates JSON::PP::_encode_surrogates
0000s0sJSON::PP::::_is_bignum JSON::PP::_is_bignum
0000s0sJSON::PP::::_json_object_hook JSON::PP::_json_object_hook
0000s0sJSON::PP::::_looks_like_number JSON::PP::_looks_like_number
0000s0sJSON::PP::::_sort JSON::PP::_sort
0000s0sJSON::PP::::_up_indent JSON::PP::_up_indent
0000s0sJSON::PP::::allow_bigint JSON::PP::allow_bigint
0000s0sJSON::PP::::array JSON::PP::array
0000s0sJSON::PP::::array_to_json JSON::PP::array_to_json
0000s0sJSON::PP::::bareKey JSON::PP::bareKey
0000s0sJSON::PP::::blessed_to_json JSON::PP::blessed_to_json
0000s0sJSON::PP::::boolean_values JSON::PP::boolean_values
0000s0sJSON::PP::::core_bools JSON::PP::core_bools
0000s0sJSON::PP::::decode JSON::PP::decode
0000s0sJSON::PP::::decode_error JSON::PP::decode_error
0000s0sJSON::PP::::decode_json JSON::PP::decode_json
0000s0sJSON::PP::::decode_prefix JSON::PP::decode_prefix
0000s0sJSON::PP::::encode JSON::PP::encode
0000s0sJSON::PP::::encode_error JSON::PP::encode_error
0000s0sJSON::PP::::encode_json JSON::PP::encode_json
0000s0sJSON::PP::::filter_json_object JSON::PP::filter_json_object
0000s0sJSON::PP::::filter_json_single_key_object JSON::PP::filter_json_single_key_object
0000s0sJSON::PP::::from_json JSON::PP::from_json
0000s0sJSON::PP::::get_boolean_values JSON::PP::get_boolean_values
0000s0sJSON::PP::::get_core_bools JSON::PP::get_core_bools
0000s0sJSON::PP::::get_indent_length JSON::PP::get_indent_length
0000s0sJSON::PP::::get_max_depth JSON::PP::get_max_depth
0000s0sJSON::PP::::get_max_size JSON::PP::get_max_size
0000s0sJSON::PP::::get_unblessed_bool JSON::PP::get_unblessed_bool
0000s0sJSON::PP::::hash_to_json JSON::PP::hash_to_json
0000s0sJSON::PP::::incr_parse JSON::PP::incr_parse
0000s0sJSON::PP::::incr_reset JSON::PP::incr_reset
0000s0sJSON::PP::::incr_skip JSON::PP::incr_skip
0000s0sJSON::PP::::indent_length JSON::PP::indent_length
0000s0sJSON::PP::::is_bool JSON::PP::is_bool
0000s0sJSON::PP::::is_valid_utf8 JSON::PP::is_valid_utf8
0000s0sJSON::PP::::max_depth JSON::PP::max_depth
0000s0sJSON::PP::::max_size JSON::PP::max_size
0000s0sJSON::PP::::new JSON::PP::new
0000s0sJSON::PP::::next_chr JSON::PP::next_chr
0000s0sJSON::PP::::null JSON::PP::null
0000s0sJSON::PP::::number JSON::PP::number
0000s0sJSON::PP::::object JSON::PP::object
0000s0sJSON::PP::::object_to_json JSON::PP::object_to_json
0000s0sJSON::PP::::pretty JSON::PP::pretty
0000s0sJSON::PP::::sort_by JSON::PP::sort_by
0000s0sJSON::PP::::string JSON::PP::string
0000s0sJSON::PP::::string_to_json JSON::PP::string_to_json
0000s0sJSON::PP::::tag JSON::PP::tag
0000s0sJSON::PP::::to_json JSON::PP::to_json
0000s0sJSON::PP::::unblessed_bool JSON::PP::unblessed_bool
0000s0sJSON::PP::::value JSON::PP::value
0000s0sJSON::PP::::value_to_json JSON::PP::value_to_json
0000s0sJSON::PP::::white JSON::PP::white
0000s0sJSON::PP::::word JSON::PP::word
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package JSON::PP;
2
3# JSON-2.0
4
5235µs121µs
# spent 21µs within JSON::PP::BEGIN@5 which was called: # once (21µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 5
use 5.005;
# spent 21µs making 1 call to JSON::PP::BEGIN@5
6217µs29µs
# spent 8µs (7+1000ns) within JSON::PP::BEGIN@6 which was called: # once (7µs+1000ns) by JSON::Schema::Modern::Error::BEGIN@18 at line 6
use strict;
# spent 8µs making 1 call to JSON::PP::BEGIN@6 # spent 1µs making 1 call to strict::import
7
8221µs12µs
# spent 2µs within JSON::PP::BEGIN@8 which was called: # once (2µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 8
use Exporter ();
# spent 2µs making 1 call to JSON::PP::BEGIN@8
9118µs17µs
# spent 7µs within JSON::PP::BEGIN@9 which was called: # once (7µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 9
BEGIN { @JSON::PP::ISA = ('Exporter') }
# spent 7µs making 1 call to JSON::PP::BEGIN@9
10
11212µs12µs
# spent 2µs within JSON::PP::BEGIN@11 which was called: # once (2µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 11
use overload ();
# spent 2µs making 1 call to JSON::PP::BEGIN@11
122498µs2657µs
# spent 657µs (595+62) within JSON::PP::BEGIN@12 which was called: # once (595µs+62µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 12
use JSON::PP::Boolean;
# spent 657µs making 1 call to JSON::PP::BEGIN@12 # spent 0s making 1 call to JSON::PP::__ANON__
13
14225µs12µs
# spent 2µs within JSON::PP::BEGIN@14 which was called: # once (2µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 14
use Carp ();
# spent 2µs making 1 call to JSON::PP::BEGIN@14
15#use Devel::Peek;
16
1711µs$JSON::PP::VERSION = '4.12';
18
1912µs@JSON::PP::EXPORT = qw(encode_json decode_json from_json to_json);
20
21# instead of hash-access, i tried index-access for speed.
22# but this method is not faster than what i expected. so it will be changed.
23
24216µs281µs
# spent 44µs (7+37) within JSON::PP::BEGIN@24 which was called: # once (7µs+37µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 24
use constant P_ASCII => 0;
# spent 44µs making 1 call to JSON::PP::BEGIN@24 # spent 37µs making 1 call to constant::import
25213µs239µs
# spent 21µs (3+18) within JSON::PP::BEGIN@25 which was called: # once (3µs+18µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 25
use constant P_LATIN1 => 1;
# spent 21µs making 1 call to JSON::PP::BEGIN@25 # spent 18µs making 1 call to constant::import
26214µs239µs
# spent 21µs (3+18) within JSON::PP::BEGIN@26 which was called: # once (3µs+18µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 26
use constant P_UTF8 => 2;
# spent 21µs making 1 call to JSON::PP::BEGIN@26 # spent 18µs making 1 call to constant::import
27210µs228µs
# spent 16µs (4+12) within JSON::PP::BEGIN@27 which was called: # once (4µs+12µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 27
use constant P_INDENT => 3;
# spent 16µs making 1 call to JSON::PP::BEGIN@27 # spent 12µs making 1 call to constant::import
2829µs229µs
# spent 16µs (3+13) within JSON::PP::BEGIN@28 which was called: # once (3µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 28
use constant P_CANONICAL => 4;
# spent 16µs making 1 call to JSON::PP::BEGIN@28 # spent 13µs making 1 call to constant::import
29210µs221µs
# spent 11µs (1+10) within JSON::PP::BEGIN@29 which was called: # once (1µs+10µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 29
use constant P_SPACE_BEFORE => 5;
# spent 11µs making 1 call to JSON::PP::BEGIN@29 # spent 10µs making 1 call to constant::import
30213µs228µs
# spent 15µs (2+13) within JSON::PP::BEGIN@30 which was called: # once (2µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 30
use constant P_SPACE_AFTER => 6;
# spent 15µs making 1 call to JSON::PP::BEGIN@30 # spent 13µs making 1 call to constant::import
31213µs232µs
# spent 18µs (4+14) within JSON::PP::BEGIN@31 which was called: # once (4µs+14µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 31
use constant P_ALLOW_NONREF => 7;
# spent 18µs making 1 call to JSON::PP::BEGIN@31 # spent 14µs making 1 call to constant::import
32210µs226µs
# spent 15µs (4+11) within JSON::PP::BEGIN@32 which was called: # once (4µs+11µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 32
use constant P_SHRINK => 8;
# spent 15µs making 1 call to JSON::PP::BEGIN@32 # spent 11µs making 1 call to constant::import
3328µs225µs
# spent 14µs (3+11) within JSON::PP::BEGIN@33 which was called: # once (3µs+11µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 33
use constant P_ALLOW_BLESSED => 9;
# spent 14µs making 1 call to JSON::PP::BEGIN@33 # spent 11µs making 1 call to constant::import
34211µs227µs
# spent 15µs (3+12) within JSON::PP::BEGIN@34 which was called: # once (3µs+12µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 34
use constant P_CONVERT_BLESSED => 10;
# spent 15µs making 1 call to JSON::PP::BEGIN@34 # spent 12µs making 1 call to constant::import
3529µs232µs
# spent 18µs (4+14) within JSON::PP::BEGIN@35 which was called: # once (4µs+14µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 35
use constant P_RELAXED => 11;
# spent 18µs making 1 call to JSON::PP::BEGIN@35 # spent 14µs making 1 call to constant::import
36
37210µs228µs
# spent 16µs (4+12) within JSON::PP::BEGIN@37 which was called: # once (4µs+12µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 37
use constant P_LOOSE => 12;
# spent 16µs making 1 call to JSON::PP::BEGIN@37 # spent 12µs making 1 call to constant::import
38212µs227µs
# spent 14µs (1+13) within JSON::PP::BEGIN@38 which was called: # once (1µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 38
use constant P_ALLOW_BIGNUM => 13;
# spent 14µs making 1 call to JSON::PP::BEGIN@38 # spent 13µs making 1 call to constant::import
39285µs227µs
# spent 16µs (5+11) within JSON::PP::BEGIN@39 which was called: # once (5µs+11µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 39
use constant P_ALLOW_BAREKEY => 14;
# spent 16µs making 1 call to JSON::PP::BEGIN@39 # spent 11µs making 1 call to constant::import
40215µs239µs
# spent 22µs (5+17) within JSON::PP::BEGIN@40 which was called: # once (5µs+17µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 40
use constant P_ALLOW_SINGLEQUOTE => 15;
# spent 22µs making 1 call to JSON::PP::BEGIN@40 # spent 17µs making 1 call to constant::import
41211µs230µs
# spent 16µs (2+14) within JSON::PP::BEGIN@41 which was called: # once (2µs+14µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 41
use constant P_ESCAPE_SLASH => 16;
# spent 16µs making 1 call to JSON::PP::BEGIN@41 # spent 14µs making 1 call to constant::import
42211µs221µs
# spent 12µs (3+9) within JSON::PP::BEGIN@42 which was called: # once (3µs+9µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 42
use constant P_AS_NONBLESSED => 17;
# spent 12µs making 1 call to JSON::PP::BEGIN@42 # spent 9µs making 1 call to constant::import
43
44210µs223µs
# spent 13µs (3+10) within JSON::PP::BEGIN@44 which was called: # once (3µs+10µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 44
use constant P_ALLOW_UNKNOWN => 18;
# spent 13µs making 1 call to JSON::PP::BEGIN@44 # spent 10µs making 1 call to constant::import
45220µs229µs
# spent 16µs (3+13) within JSON::PP::BEGIN@45 which was called: # once (3µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 45
use constant P_ALLOW_TAGS => 19;
# spent 16µs making 1 call to JSON::PP::BEGIN@45 # spent 13µs making 1 call to constant::import
46
47220µs235µs
# spent 19µs (3+16) within JSON::PP::BEGIN@47 which was called: # once (3µs+16µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 47
use constant OLD_PERL => $] < 5.008 ? 1 : 0;
# spent 19µs making 1 call to JSON::PP::BEGIN@47 # spent 16µs making 1 call to constant::import
48217µs233µs
# spent 19µs (5+14) within JSON::PP::BEGIN@48 which was called: # once (5µs+14µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 48
use constant USE_B => $ENV{PERL_JSON_PP_USE_B} || 0;
# spent 19µs making 1 call to JSON::PP::BEGIN@48 # spent 14µs making 1 call to constant::import
49252µs218µs
# spent 10µs (2+8) within JSON::PP::BEGIN@49 which was called: # once (2µs+8µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 49
use constant CORE_BOOL => defined &builtin::is_bool;
# spent 10µs making 1 call to JSON::PP::BEGIN@49 # spent 8µs making 1 call to constant::import
50
5110smy $invalid_char_re;
52
53
# spent 41µs (21+20) within JSON::PP::BEGIN@53 which was called: # once (21µs+20µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 60
BEGIN {
5410s $invalid_char_re = "[";
5510s for my $i (0 .. 0x01F, 0x22, 0x5c) { # '/' is ok
563411µs $invalid_char_re .= quotemeta chr utf8::unicode_to_native($i);
57 }
58
59129µs220µs $invalid_char_re = qr/$invalid_char_re]/;
# spent 19µs making 1 call to JSON::PP::CORE:regcomp # spent 1µs making 1 call to JSON::PP::CORE:qr
60120µs141µs}
# spent 41µs making 1 call to JSON::PP::BEGIN@53
61
62
# spent 2µs within JSON::PP::BEGIN@62 which was called: # once (2µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 66
BEGIN {
6312µs if (USE_B) {
64 require B;
65 }
66190µs12µs}
# spent 2µs making 1 call to JSON::PP::BEGIN@62
67
68
# spent 837µs within JSON::PP::BEGIN@68 which was called: # once (837µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 110
BEGIN {
6911µs my @xs_compati_bit_properties = qw(
70 latin1 ascii utf8 indent canonical space_before space_after allow_nonref shrink
71 allow_blessed convert_blessed relaxed allow_unknown
72 allow_tags
73 );
7413µs my @pp_bit_properties = qw(
75 allow_singlequote allow_bignum loose
76 allow_barekey escape_slash as_nonblessed
77 );
78
79 # Perl version check, Unicode handling is enabled?
80 # Helper module sets @JSON::PP::_properties.
81 if ( OLD_PERL ) {
82 my $helper = $] >= 5.006 ? 'JSON::PP::Compat5006' : 'JSON::PP::Compat5005';
83 eval qq| require $helper |;
84 if ($@) { Carp::croak $@; }
85 }
86
8714µs for my $name (@xs_compati_bit_properties, @pp_bit_properties) {
88206µs my $property_id = 'P_' . uc($name);
89
9020825µs eval qq/
91 sub $name {
92 my \$enable = defined \$_[1] ? \$_[1] : 1;
93
94 if (\$enable) {
95 \$_[0]->{PROPS}->[$property_id] = 1;
96 }
97 else {
98 \$_[0]->{PROPS}->[$property_id] = 0;
99 }
100
101 \$_[0];
102 }
103
104 sub get_$name {
105 \$_[0]->{PROPS}->[$property_id] ? 1 : '';
106 }
107 /;
108 }
109
1101238µs1837µs}
# spent 837µs making 1 call to JSON::PP::BEGIN@68
111
- -
114# Functions
115
116my $JSON; # cache
117
118sub encode_json ($) { # encode
119 ($JSON ||= __PACKAGE__->new->utf8)->encode(@_);
120}
121
122
123sub decode_json { # decode
124 ($JSON ||= __PACKAGE__->new->utf8)->decode(@_);
125}
126
127# Obsoleted
128
129sub to_json($) {
130 Carp::croak ("JSON::PP::to_json has been renamed to encode_json.");
131}
132
133
134sub from_json($) {
135 Carp::croak ("JSON::PP::from_json has been renamed to decode_json.");
136}
137
138
139# Methods
140
141sub new {
142 my $class = shift;
143 my $self = {
144 max_depth => 512,
145 max_size => 0,
146 indent_length => 3,
147 };
148
149 $self->{PROPS}[P_ALLOW_NONREF] = 1;
150
151 bless $self, $class;
152}
153
154
155sub encode {
156 return $_[0]->PP_encode_json($_[1]);
157}
158
159
160sub decode {
161 return $_[0]->PP_decode_json($_[1], 0x00000000);
162}
163
164
165sub decode_prefix {
166 return $_[0]->PP_decode_json($_[1], 0x00000001);
167}
168
169
170# accessor
171
172
173# pretty printing
174
175sub pretty {
176 my ($self, $v) = @_;
177 my $enable = defined $v ? $v : 1;
178
179 if ($enable) { # indent_length(3) for JSON::XS compatibility
180 $self->indent(1)->space_before(1)->space_after(1);
181 }
182 else {
183 $self->indent(0)->space_before(0)->space_after(0);
184 }
185
186 $self;
187}
188
189# etc
190
191sub max_depth {
192 my $max = defined $_[1] ? $_[1] : 0x80000000;
193 $_[0]->{max_depth} = $max;
194 $_[0];
195}
196
197
198sub get_max_depth { $_[0]->{max_depth}; }
199
200
201sub max_size {
202 my $max = defined $_[1] ? $_[1] : 0;
203 $_[0]->{max_size} = $max;
204 $_[0];
205}
206
207
208sub get_max_size { $_[0]->{max_size}; }
209
210sub boolean_values {
211 my $self = shift;
212 if (@_) {
213 my ($false, $true) = @_;
214 $self->{false} = $false;
215 $self->{true} = $true;
216 if (CORE_BOOL) {
21711.07ms243µs
# spent 24µs (5+19) within JSON::PP::BEGIN@217 which was called: # once (5µs+19µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 217
BEGIN { CORE_BOOL and warnings->unimport(qw(experimental::builtin)) }
# spent 24µs making 1 call to JSON::PP::BEGIN@217 # spent 19µs making 1 call to warnings::unimport
218 if (builtin::is_bool($true) && builtin::is_bool($false) && $true && !$false) {
219 $self->{core_bools} = !!1;
220 }
221 else {
222 delete $self->{core_bools};
223 }
224 }
225 } else {
226 delete $self->{false};
227 delete $self->{true};
228 delete $self->{core_bools};
229 }
230 return $self;
231}
232
233sub core_bools {
234 my $self = shift;
235 my $core_bools = defined $_[0] ? $_[0] : 1;
236 if ($core_bools) {
237 $self->{true} = !!1;
238 $self->{false} = !!0;
239 $self->{core_bools} = !!1;
240 }
241 else {
242 $self->{true} = $JSON::PP::true;
243 $self->{false} = $JSON::PP::false;
244 $self->{core_bools} = !!0;
245 }
246 return $self;
247}
248
249sub get_core_bools {
250 my $self = shift;
251 return !!$self->{core_bools};
252}
253
254sub unblessed_bool {
255 my $self = shift;
256 return $self->core_bools(@_);
257}
258
259sub get_unblessed_bool {
260 my $self = shift;
261 return $self->get_core_bools(@_);
262}
263
264sub get_boolean_values {
265 my $self = shift;
266 if (exists $self->{true} and exists $self->{false}) {
267 return @$self{qw/false true/};
268 }
269 return;
270}
271
272sub filter_json_object {
273 if (defined $_[1] and ref $_[1] eq 'CODE') {
274 $_[0]->{cb_object} = $_[1];
275 } else {
276 delete $_[0]->{cb_object};
277 }
278 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
279 $_[0];
280}
281
282sub filter_json_single_key_object {
283 if (@_ == 1 or @_ > 3) {
284 Carp::croak("Usage: JSON::PP::filter_json_single_key_object(self, key, callback = undef)");
285 }
286 if (defined $_[2] and ref $_[2] eq 'CODE') {
287 $_[0]->{cb_sk_object}->{$_[1]} = $_[2];
288 } else {
289 delete $_[0]->{cb_sk_object}->{$_[1]};
290 delete $_[0]->{cb_sk_object} unless %{$_[0]->{cb_sk_object} || {}};
291 }
292 $_[0]->{F_HOOK} = ($_[0]->{cb_object} or $_[0]->{cb_sk_object}) ? 1 : 0;
293 $_[0];
294}
295
296sub indent_length {
297 if (!defined $_[1] or $_[1] > 15 or $_[1] < 0) {
298 Carp::carp "The acceptable range of indent_length() is 0 to 15.";
299 }
300 else {
301 $_[0]->{indent_length} = $_[1];
302 }
303 $_[0];
304}
305
306sub get_indent_length {
307 $_[0]->{indent_length};
308}
309
310sub sort_by {
311 $_[0]->{sort_by} = defined $_[1] ? $_[1] : 1;
312 $_[0];
313}
314
315sub allow_bigint {
316 Carp::carp("allow_bigint() is obsoleted. use allow_bignum() instead.");
317 $_[0]->allow_bignum;
318}
319
320###############################
321
322###
323### Perl => JSON
324###
325
326
327{ # Convert
328
32910s my $max_depth;
330 my $indent;
331 my $ascii;
332 my $latin1;
333 my $utf8;
334 my $space_before;
335 my $space_after;
336 my $canonical;
337 my $allow_blessed;
338 my $convert_blessed;
339
340 my $indent_length;
341 my $escape_slash;
342 my $bignum;
343 my $as_nonblessed;
344 my $allow_tags;
345
346 my $depth;
347 my $indent_count;
348 my $keysort;
349
350
351 sub PP_encode_json {
352 my $self = shift;
353 my $obj = shift;
354
355 $indent_count = 0;
356 $depth = 0;
357
358 my $props = $self->{PROPS};
359
360 ($ascii, $latin1, $utf8, $indent, $canonical, $space_before, $space_after, $allow_blessed,
361 $convert_blessed, $escape_slash, $bignum, $as_nonblessed, $allow_tags)
362 = @{$props}[P_ASCII .. P_SPACE_AFTER, P_ALLOW_BLESSED, P_CONVERT_BLESSED,
363 P_ESCAPE_SLASH, P_ALLOW_BIGNUM, P_AS_NONBLESSED, P_ALLOW_TAGS];
364
365 ($max_depth, $indent_length) = @{$self}{qw/max_depth indent_length/};
366
367 $keysort = $canonical ? sub { $a cmp $b } : undef;
368
369 if ($self->{sort_by}) {
370 $keysort = ref($self->{sort_by}) eq 'CODE' ? $self->{sort_by}
371 : $self->{sort_by} =~ /\D+/ ? $self->{sort_by}
372 : sub { $a cmp $b };
373 }
374
375 encode_error("hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)")
376 if(!ref $obj and !$props->[ P_ALLOW_NONREF ]);
377
378 my $str = $self->object_to_json($obj);
379
380 $str .= "\n" if ( $indent ); # JSON::XS 2.26 compatible
381
382 return $str;
383 }
384
385
386 sub object_to_json {
387 my ($self, $obj) = @_;
388 my $type = ref($obj);
389
390 if($type eq 'HASH'){
391 return $self->hash_to_json($obj);
392 }
393 elsif($type eq 'ARRAY'){
394 return $self->array_to_json($obj);
395 }
396 elsif ($type) { # blessed object?
397 if (blessed($obj)) {
398
399 return $self->value_to_json($obj) if ( $obj->isa('JSON::PP::Boolean') );
400
401 if ( $allow_tags and $obj->can('FREEZE') ) {
402 my $obj_class = ref $obj || $obj;
403 $obj = bless $obj, $obj_class;
404 my @results = $obj->FREEZE('JSON');
405 if ( @results and ref $results[0] ) {
406 if ( refaddr( $obj ) eq refaddr( $results[0] ) ) {
407 encode_error( sprintf(
408 "%s::FREEZE method returned same object as was passed instead of a new one",
409 ref $obj
410 ) );
411 }
412 }
413 return '("'.$obj_class.'")['.join(',', @results).']';
414 }
415
416 if ( $convert_blessed and $obj->can('TO_JSON') ) {
417 my $result = $obj->TO_JSON();
418 if ( defined $result and ref( $result ) ) {
419 if ( refaddr( $obj ) eq refaddr( $result ) ) {
420 encode_error( sprintf(
421 "%s::TO_JSON method returned same object as was passed instead of a new one",
422 ref $obj
423 ) );
424 }
425 }
426
427 return $self->object_to_json( $result );
428 }
429
430 return "$obj" if ( $bignum and _is_bignum($obj) );
431
432 if ($allow_blessed) {
433 return $self->blessed_to_json($obj) if ($as_nonblessed); # will be removed.
434 return 'null';
435 }
436 encode_error( sprintf("encountered object '%s', but neither allow_blessed, convert_blessed nor allow_tags settings are enabled (or TO_JSON/FREEZE method missing)", $obj)
437 );
438 }
439 else {
440 return $self->value_to_json($obj);
441 }
442 }
443 else{
444 return $self->value_to_json($obj);
445 }
446 }
447
448
449 sub hash_to_json {
450 my ($self, $obj) = @_;
451 my @res;
452
453 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
454 if (++$depth > $max_depth);
455
456 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
457 my $del = ($space_before ? ' ' : '') . ':' . ($space_after ? ' ' : '');
458
459 for my $k ( _sort( $obj ) ) {
460 if ( OLD_PERL ) { utf8::decode($k) } # key for Perl 5.6 / be optimized
461 push @res, $self->string_to_json( $k )
462 . $del
463 . ( ref $obj->{$k} ? $self->object_to_json( $obj->{$k} ) : $self->value_to_json( $obj->{$k} ) );
464 }
465
466 --$depth;
467 $self->_down_indent() if ($indent);
468
469 return '{}' unless @res;
470 return '{' . $pre . join( ",$pre", @res ) . $post . '}';
471 }
472
473
474 sub array_to_json {
475 my ($self, $obj) = @_;
476 my @res;
477
478 encode_error("json text or perl structure exceeds maximum nesting level (max_depth set too low?)")
479 if (++$depth > $max_depth);
480
481 my ($pre, $post) = $indent ? $self->_up_indent() : ('', '');
482
483 for my $v (@$obj){
484 push @res, ref($v) ? $self->object_to_json($v) : $self->value_to_json($v);
485 }
486
487 --$depth;
488 $self->_down_indent() if ($indent);
489
490 return '[]' unless @res;
491 return '[' . $pre . join( ",$pre", @res ) . $post . ']';
492 }
493
494 sub _looks_like_number {
495 my $value = shift;
496 if (USE_B) {
497 my $b_obj = B::svref_2object(\$value);
498 my $flags = $b_obj->FLAGS;
499 return 1 if $flags & ( B::SVp_IOK() | B::SVp_NOK() ) and !( $flags & B::SVp_POK() );
500 return;
501 } else {
502271µs242µs
# spent 25µs (8+17) within JSON::PP::BEGIN@502 which was called: # once (8µs+17µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 502
no warnings 'numeric';
# spent 25µs making 1 call to JSON::PP::BEGIN@502 # spent 17µs making 1 call to warnings::unimport
503 # if the utf8 flag is on, it almost certainly started as a string
504 return if utf8::is_utf8($value);
505 # detect numbers
506 # string & "" -> ""
507 # number & "" -> 0 (with warning)
508 # nan and inf can detect as numbers, so check with * 0
509 return unless length((my $dummy = "") & $value);
510 return unless 0 + $value eq $value;
511 return 1 if $value * 0 == 0;
512 return -1; # inf/nan
513 }
514 }
515
516 sub value_to_json {
517 my ($self, $value) = @_;
518
519 return 'null' if(!defined $value);
520
521 my $type = ref($value);
522
523 if (!$type) {
5241643µs223µs
# spent 14µs (5+9) within JSON::PP::BEGIN@524 which was called: # once (5µs+9µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 524
BEGIN { CORE_BOOL and warnings->unimport('experimental::builtin') }
# spent 14µs making 1 call to JSON::PP::BEGIN@524 # spent 9µs making 1 call to warnings::unimport
525 if (CORE_BOOL && builtin::is_bool($value)) {
526 return $value ? 'true' : 'false';
527 }
528 elsif (_looks_like_number($value)) {
529 return $value;
530 }
531 return $self->string_to_json($value);
532 }
533 elsif( blessed($value) and $value->isa('JSON::PP::Boolean') ){
534 return $$value == 1 ? 'true' : 'false';
535 }
536 else {
537 if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
538 return $self->value_to_json("$value");
539 }
540
541 if ($type eq 'SCALAR' and defined $$value) {
542 return $$value eq '1' ? 'true'
543 : $$value eq '0' ? 'false'
544 : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
545 : encode_error("cannot encode reference to scalar");
546 }
547
548 if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
549 return 'null';
550 }
551 else {
552 if ( $type eq 'SCALAR' or $type eq 'REF' ) {
553 encode_error("cannot encode reference to scalar");
554 }
555 else {
556 encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
557 }
558 }
559
560 }
561 }
562
563
56414µs my %esc = (
565 "\n" => '\n',
566 "\r" => '\r',
567 "\t" => '\t',
568 "\f" => '\f',
569 "\b" => '\b',
570 "\"" => '\"',
571 "\\" => '\\\\',
572 "\'" => '\\\'',
573 );
574
575
576 sub string_to_json {
577 my ($self, $arg) = @_;
578
579 $arg =~ s/(["\\\n\r\t\f\b])/$esc{$1}/g;
580 $arg =~ s/\//\\\//g if ($escape_slash);
581
582 # On ASCII platforms, matches [\x00-\x08\x0b\x0e-\x1f]
583 $arg =~ s/([^\n\t\c?[:^cntrl:][:^ascii:]])/'\\u00' . unpack('H2', $1)/eg;
584
585 if ($ascii) {
586 $arg = JSON_PP_encode_ascii($arg);
587 }
588
589 if ($latin1) {
590 $arg = JSON_PP_encode_latin1($arg);
591 }
592
593 if ($utf8) {
594 utf8::encode($arg);
595 }
596
597 return '"' . $arg . '"';
598 }
599
600
601 sub blessed_to_json {
602 my $reftype = reftype($_[1]) || '';
603 if ($reftype eq 'HASH') {
604 return $_[0]->hash_to_json($_[1]);
605 }
606 elsif ($reftype eq 'ARRAY') {
607 return $_[0]->array_to_json($_[1]);
608 }
609 else {
610 return 'null';
611 }
612 }
613
614
615 sub encode_error {
616 my $error = shift;
617 Carp::croak "$error";
618 }
619
620
621 sub _sort {
622 defined $keysort ? (sort $keysort (keys %{$_[0]})) : keys %{$_[0]};
623 }
624
625
626 sub _up_indent {
627 my $self = shift;
628 my $space = ' ' x $indent_length;
629
630 my ($pre,$post) = ('','');
631
632 $post = "\n" . $space x $indent_count;
633
634 $indent_count++;
635
636 $pre = "\n" . $space x $indent_count;
637
638 return ($pre,$post);
639 }
640
641
642 sub _down_indent { $indent_count--; }
643
644
645 sub PP_encode_box {
646 {
647 depth => $depth,
648 indent_count => $indent_count,
649 };
650 }
651
652} # Convert
653
654
65511µssub _encode_ascii {
656 join('',
657 map {
658 chr($_) =~ /[[:ascii:]]/ ?
659 chr($_) :
660 $_ <= 65535 ?
661 sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
662 } unpack('U*', $_[0])
663 );
664}
665
666
667sub _encode_latin1 {
668 join('',
669 map {
670 $_ <= 255 ?
671 chr($_) :
672 $_ <= 65535 ?
673 sprintf('\u%04x', $_) : sprintf('\u%x\u%x', _encode_surrogates($_));
674 } unpack('U*', $_[0])
675 );
676}
677
678
679sub _encode_surrogates { # from perlunicode
680 my $uni = $_[0] - 0x10000;
681 return ($uni / 0x400 + 0xD800, $uni % 0x400 + 0xDC00);
682}
683
684
685sub _is_bignum {
686 $_[0]->isa('Math::BigInt') or $_[0]->isa('Math::BigFloat');
687}
688
- -
691#
692# JSON => Perl
693#
694
69510smy $max_intsize;
696
697
# spent 137µs (125+12) within JSON::PP::BEGIN@697 which was called: # once (125µs+12µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 707
BEGIN {
69811µs my $checkint = 1111;
69913µs for my $d (5..64) {
700172µs $checkint .= 1;
7011782µs my $int = eval qq| $checkint |;
# spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 1µs executing statements in string eval # spent 0s executing statements in string eval # spent 0s executing statements in string eval # spent 0s executing statements in string eval # spent 0s executing statements in string eval
7021732µs1712µs if ($int =~ /[eE]/) {
# spent 12µs making 17 calls to JSON::PP::CORE:match, avg 706ns/call
70310s $max_intsize = $d - 1;
70413µs last;
705 }
706 }
7071220µs1137µs}
# spent 137µs making 1 call to JSON::PP::BEGIN@697
708
709{ # PARSE
710
71113µs my %escapes = ( # by Jeremy Muhlich <jmuhlich [at] bitflood.org>
712 b => "\b",
713 t => "\t",
714 n => "\n",
715 f => "\f",
716 r => "\r",
717 '\\' => '\\',
718 '"' => '"',
719 '/' => '/',
720 );
721
72210s my $text; # json data
723 my $at; # offset
724 my $ch; # first character
725 my $len; # text length (changed according to UTF8 or NON UTF8)
726 # INTERNAL
727 my $depth; # nest counter
728 my $encoding; # json text encoding
729 my $is_valid_utf8; # temp variable
730 my $utf8_len; # utf8 byte length
731 # FLAGS
732 my $utf8; # must be utf8
733 my $max_depth; # max nest number of objects and arrays
734 my $max_size;
735 my $relaxed;
736 my $cb_object;
737 my $cb_sk_object;
738
739 my $F_HOOK;
740
741 my $allow_bignum; # using Math::BigInt/BigFloat
742 my $singlequote; # loosely quoting
743 my $loose; #
744 my $allow_barekey; # bareKey
745 my $allow_tags;
746
747 my $alt_true;
748 my $alt_false;
749
750 sub _detect_utf_encoding {
751 my $text = shift;
752 my @octets = unpack('C4', $text);
753 return 'unknown' unless defined $octets[3];
754 return ( $octets[0] and $octets[1]) ? 'UTF-8'
755 : (!$octets[0] and $octets[1]) ? 'UTF-16BE'
756 : (!$octets[0] and !$octets[1]) ? 'UTF-32BE'
757 : ( $octets[2] ) ? 'UTF-16LE'
758 : (!$octets[2] ) ? 'UTF-32LE'
759 : 'unknown';
760 }
761
762 sub PP_decode_json {
763 my ($self, $want_offset);
764
765 ($self, $text, $want_offset) = @_;
766
767 ($at, $ch, $depth) = (0, '', 0);
768
769 if ( !defined $text or ref $text ) {
770 decode_error("malformed JSON string, neither array, object, number, string or atom");
771 }
772
773 my $props = $self->{PROPS};
774
775 ($utf8, $relaxed, $loose, $allow_bignum, $allow_barekey, $singlequote, $allow_tags)
776 = @{$props}[P_UTF8, P_RELAXED, P_LOOSE .. P_ALLOW_SINGLEQUOTE, P_ALLOW_TAGS];
777
778 ($alt_true, $alt_false) = @$self{qw/true false/};
779
780 if ( $utf8 ) {
781 $encoding = _detect_utf_encoding($text);
782 if ($encoding ne 'UTF-8' and $encoding ne 'unknown') {
783 require Encode;
784 Encode::from_to($text, $encoding, 'utf-8');
785 } else {
786 utf8::downgrade( $text, 1 ) or Carp::croak("Wide character in subroutine entry");
787 }
788 }
789 else {
790 utf8::encode( $text );
791 }
792
793 $len = length $text;
794
795 ($max_depth, $max_size, $cb_object, $cb_sk_object, $F_HOOK)
796 = @{$self}{qw/max_depth max_size cb_object cb_sk_object F_HOOK/};
797
798 if ($max_size > 1) {
79921.42ms214µs
# spent 12µs (10+2) within JSON::PP::BEGIN@799 which was called: # once (10µs+2µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 799
use bytes;
# spent 12µs making 1 call to JSON::PP::BEGIN@799 # spent 2µs making 1 call to bytes::import
800 my $bytes = length $text;
801 decode_error(
802 sprintf("attempted decode of JSON text of %s bytes size, but max_size is set to %s"
803 , $bytes, $max_size), 1
804 ) if ($bytes > $max_size);
805 }
806
807 white(); # remove head white space
808
809 decode_error("malformed JSON string, neither array, object, number, string or atom") unless defined $ch; # Is there a first character for JSON structure?
810
811 my $result = value();
812
813 if ( !$props->[ P_ALLOW_NONREF ] and !ref $result ) {
814 decode_error(
815 'JSON text must be an object or array (but found number, string, true, false or null,'
816 . ' use allow_nonref to allow this)', 1);
817 }
818
819 Carp::croak('something wrong.') if $len < $at; # we won't arrive here.
820
821 my $consumed = defined $ch ? $at - 1 : $at; # consumed JSON text length
822
823 white(); # remove tail white space
824
825 return ( $result, $consumed ) if $want_offset; # all right if decode_prefix
826
827 decode_error("garbage after JSON object") if defined $ch;
828
829 $result;
830 }
831
832
833 sub next_chr {
834 return $ch = undef if($at >= $len);
835 $ch = substr($text, $at++, 1);
836 }
837
838
839 sub value {
840 white();
841 return if(!defined $ch);
842 return object() if($ch eq '{');
843 return array() if($ch eq '[');
844 return tag() if($ch eq '(');
845 return string() if($ch eq '"' or ($singlequote and $ch eq "'"));
846 return number() if($ch =~ /[0-9]/ or $ch eq '-');
847 return word();
848 }
849
850 sub string {
851 my $utf16;
852 my $is_utf8;
853
854 ($is_valid_utf8, $utf8_len) = ('', 0);
855
856 my $s = ''; # basically UTF8 flag on
857
858 if($ch eq '"' or ($singlequote and $ch eq "'")){
859 my $boundChar = $ch;
860
861 OUTER: while( defined(next_chr()) ){
862
863 if($ch eq $boundChar){
864 next_chr();
865
866 if ($utf16) {
867 decode_error("missing low surrogate character in surrogate pair");
868 }
869
870 utf8::decode($s) if($is_utf8);
871
872 return $s;
873 }
874 elsif($ch eq '\\'){
875 next_chr();
876 if(exists $escapes{$ch}){
877 $s .= $escapes{$ch};
878 }
879 elsif($ch eq 'u'){ # UNICODE handling
880 my $u = '';
881
882 for(1..4){
883 $ch = next_chr();
884 last OUTER if($ch !~ /[0-9a-fA-F]/);
885 $u .= $ch;
886 }
887
888 # U+D800 - U+DBFF
889 if ($u =~ /^[dD][89abAB][0-9a-fA-F]{2}/) { # UTF-16 high surrogate?
890 $utf16 = $u;
891 }
892 # U+DC00 - U+DFFF
893 elsif ($u =~ /^[dD][c-fC-F][0-9a-fA-F]{2}/) { # UTF-16 low surrogate?
894 unless (defined $utf16) {
895 decode_error("missing high surrogate character in surrogate pair");
896 }
897 $is_utf8 = 1;
898 $s .= JSON_PP_decode_surrogates($utf16, $u) || next;
899 $utf16 = undef;
900 }
901 else {
902 if (defined $utf16) {
903 decode_error("surrogate pair expected");
904 }
905
906 my $hex = hex( $u );
907 if ( chr $u =~ /[[:^ascii:]]/ ) {
908 $is_utf8 = 1;
909 $s .= JSON_PP_decode_unicode($u) || next;
910 }
911 else {
912 $s .= chr $hex;
913 }
914 }
915
916 }
917 else{
918 unless ($loose) {
919 $at -= 2;
920 decode_error('illegal backslash escape sequence in string');
921 }
922 $s .= $ch;
923 }
924 }
925 else{
926
927 if ( $ch =~ /[[:^ascii:]]/ ) {
928 unless( $ch = is_valid_utf8($ch) ) {
929 $at -= 1;
930 decode_error("malformed UTF-8 character in JSON string");
931 }
932 else {
933 $at += $utf8_len - 1;
934 }
935
936 $is_utf8 = 1;
937 }
938
939 if (!$loose) {
940 if ($ch =~ $invalid_char_re) { # '/' ok
941 if (!$relaxed or $ch ne "\t") {
942 $at--;
943 decode_error(sprintf "invalid character 0x%X"
944 . " encountered while parsing JSON string",
945 ord $ch);
946 }
947 }
948 }
949
950 $s .= $ch;
951 }
952 }
953 }
954
955 decode_error("unexpected end of string while parsing JSON string");
956 }
957
958
959 sub white {
960 while( defined $ch ){
961 if($ch eq '' or $ch =~ /\A[ \t\r\n]\z/){
962 next_chr();
963 }
964 elsif($relaxed and $ch eq '/'){
965 next_chr();
966 if(defined $ch and $ch eq '/'){
967 1 while(defined(next_chr()) and $ch ne "\n" and $ch ne "\r");
968 }
969 elsif(defined $ch and $ch eq '*'){
970 next_chr();
971 while(1){
972 if(defined $ch){
973 if($ch eq '*'){
974 if(defined(next_chr()) and $ch eq '/'){
975 next_chr();
976 last;
977 }
978 }
979 else{
980 next_chr();
981 }
982 }
983 else{
984 decode_error("Unterminated comment");
985 }
986 }
987 next;
988 }
989 else{
990 $at--;
991 decode_error("malformed JSON string, neither array, object, number, string or atom");
992 }
993 }
994 else{
995 if ($relaxed and $ch eq '#') { # correctly?
996 pos($text) = $at;
997 $text =~ /\G([^\n]*(?:\r\n|\r|\n|$))/g;
998 $at = pos($text);
999 next_chr;
1000 next;
1001 }
1002
1003 last;
1004 }
1005 }
1006 }
1007
1008
1009 sub array {
1010 my $a = $_[0] || []; # you can use this code to use another array ref object.
1011
1012 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1013 if (++$depth > $max_depth);
1014
1015 next_chr();
1016 white();
1017
1018 if(defined $ch and $ch eq ']'){
1019 --$depth;
1020 next_chr();
1021 return $a;
1022 }
1023 else {
1024 while(defined($ch)){
1025 push @$a, value();
1026
1027 white();
1028
1029 if (!defined $ch) {
1030 last;
1031 }
1032
1033 if($ch eq ']'){
1034 --$depth;
1035 next_chr();
1036 return $a;
1037 }
1038
1039 if($ch ne ','){
1040 last;
1041 }
1042
1043 next_chr();
1044 white();
1045
1046 if ($relaxed and $ch eq ']') {
1047 --$depth;
1048 next_chr();
1049 return $a;
1050 }
1051
1052 }
1053 }
1054
1055 $at-- if defined $ch and $ch ne '';
1056 decode_error(", or ] expected while parsing array");
1057 }
1058
1059 sub tag {
1060 decode_error('malformed JSON string, neither array, object, number, string or atom') unless $allow_tags;
1061
1062 next_chr();
1063 white();
1064
1065 my $tag = value();
1066 return unless defined $tag;
1067 decode_error('malformed JSON string, (tag) must be a string') if ref $tag;
1068
1069 white();
1070
1071 if (!defined $ch or $ch ne ')') {
1072 decode_error(') expected after tag');
1073 }
1074
1075 next_chr();
1076 white();
1077
1078 my $val = value();
1079 return unless defined $val;
1080 decode_error('malformed JSON string, tag value must be an array') unless ref $val eq 'ARRAY';
1081
1082 if (!eval { $tag->can('THAW') }) {
1083 decode_error('cannot decode perl-object (package does not exist)') if $@;
1084 decode_error('cannot decode perl-object (package does not have a THAW method)');
1085 }
1086 $tag->THAW('JSON', @$val);
1087 }
1088
1089 sub object {
1090 my $o = $_[0] || {}; # you can use this code to use another hash ref object.
1091 my $k;
1092
1093 decode_error('json text or perl structure exceeds maximum nesting level (max_depth set too low?)')
1094 if (++$depth > $max_depth);
1095 next_chr();
1096 white();
1097
1098 if(defined $ch and $ch eq '}'){
1099 --$depth;
1100 next_chr();
1101 if ($F_HOOK) {
1102 return _json_object_hook($o);
1103 }
1104 return $o;
1105 }
1106 else {
1107 while (defined $ch) {
1108 $k = ($allow_barekey and $ch ne '"' and $ch ne "'") ? bareKey() : string();
1109 white();
1110
1111 if(!defined $ch or $ch ne ':'){
1112 $at--;
1113 decode_error("':' expected");
1114 }
1115
1116 next_chr();
1117 $o->{$k} = value();
1118 white();
1119
1120 last if (!defined $ch);
1121
1122 if($ch eq '}'){
1123 --$depth;
1124 next_chr();
1125 if ($F_HOOK) {
1126 return _json_object_hook($o);
1127 }
1128 return $o;
1129 }
1130
1131 if($ch ne ','){
1132 last;
1133 }
1134
1135 next_chr();
1136 white();
1137
1138 if ($relaxed and $ch eq '}') {
1139 --$depth;
1140 next_chr();
1141 if ($F_HOOK) {
1142 return _json_object_hook($o);
1143 }
1144 return $o;
1145 }
1146
1147 }
1148
1149 }
1150
1151 $at-- if defined $ch and $ch ne '';
1152 decode_error(", or } expected while parsing object/hash");
1153 }
1154
1155
1156 sub bareKey { # doesn't strictly follow Standard ECMA-262 3rd Edition
1157 my $key;
1158 while($ch =~ /[\$\w[:^ascii:]]/){
1159 $key .= $ch;
1160 next_chr();
1161 }
1162 return $key;
1163 }
1164
1165
1166 sub word {
1167 my $word = substr($text,$at-1,4);
1168
1169 if($word eq 'true'){
1170 $at += 3;
1171 next_chr;
1172 return defined $alt_true ? $alt_true : $JSON::PP::true;
1173 }
1174 elsif($word eq 'null'){
1175 $at += 3;
1176 next_chr;
1177 return undef;
1178 }
1179 elsif($word eq 'fals'){
1180 $at += 3;
1181 if(substr($text,$at,1) eq 'e'){
1182 $at++;
1183 next_chr;
1184 return defined $alt_false ? $alt_false : $JSON::PP::false;
1185 }
1186 }
1187
1188 $at--; # for decode_error report
1189
1190 decode_error("'null' expected") if ($word =~ /^n/);
1191 decode_error("'true' expected") if ($word =~ /^t/);
1192 decode_error("'false' expected") if ($word =~ /^f/);
1193 decode_error("malformed JSON string, neither array, object, number, string or atom");
1194 }
1195
1196
1197 sub number {
1198 my $n = '';
1199 my $v;
1200 my $is_dec;
1201 my $is_exp;
1202
1203 if($ch eq '-'){
1204 $n = '-';
1205 next_chr;
1206 if (!defined $ch or $ch !~ /\d/) {
1207 decode_error("malformed number (no digits after initial minus)");
1208 }
1209 }
1210
1211 # According to RFC4627, hex or oct digits are invalid.
1212 if($ch eq '0'){
1213 my $peek = substr($text,$at,1);
1214 if($peek =~ /^[0-9a-dfA-DF]/){ # e may be valid (exponential)
1215 decode_error("malformed number (leading zero must not be followed by another digit)");
1216 }
1217 $n .= $ch;
1218 next_chr;
1219 }
1220
1221 while(defined $ch and $ch =~ /\d/){
1222 $n .= $ch;
1223 next_chr;
1224 }
1225
1226 if(defined $ch and $ch eq '.'){
1227 $n .= '.';
1228 $is_dec = 1;
1229
1230 next_chr;
1231 if (!defined $ch or $ch !~ /\d/) {
1232 decode_error("malformed number (no digits after decimal point)");
1233 }
1234 else {
1235 $n .= $ch;
1236 }
1237
1238 while(defined(next_chr) and $ch =~ /\d/){
1239 $n .= $ch;
1240 }
1241 }
1242
1243 if(defined $ch and ($ch eq 'e' or $ch eq 'E')){
1244 $n .= $ch;
1245 $is_exp = 1;
1246 next_chr;
1247
1248 if(defined($ch) and ($ch eq '+' or $ch eq '-')){
1249 $n .= $ch;
1250 next_chr;
1251 if (!defined $ch or $ch =~ /\D/) {
1252 decode_error("malformed number (no digits after exp sign)");
1253 }
1254 $n .= $ch;
1255 }
1256 elsif(defined($ch) and $ch =~ /\d/){
1257 $n .= $ch;
1258 }
1259 else {
1260 decode_error("malformed number (no digits after exp sign)");
1261 }
1262
1263 while(defined(next_chr) and $ch =~ /\d/){
1264 $n .= $ch;
1265 }
1266
1267 }
1268
1269 $v .= $n;
1270
1271 if ($is_dec or $is_exp) {
1272 if ($allow_bignum) {
1273 require Math::BigFloat;
1274 return Math::BigFloat->new($v);
1275 }
1276 } else {
1277 if (length $v > $max_intsize) {
1278 if ($allow_bignum) { # from Adam Sussman
1279 require Math::BigInt;
1280 return Math::BigInt->new($v);
1281 }
1282 else {
1283 return "$v";
1284 }
1285 }
1286 }
1287
1288 return $is_dec ? $v/1.0 : 0+$v;
1289 }
1290
1291 # Compute how many bytes are in the longest legal official Unicode
1292 # character
129311µs my $max_unicode_length = do {
12941648µs248µs
# spent 28µs (8+20) within JSON::PP::BEGIN@1294 which was called: # once (8µs+20µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1294
BEGIN { $] >= 5.006 and require warnings and warnings->unimport('utf8') }
# spent 28µs making 1 call to JSON::PP::BEGIN@1294 # spent 20µs making 1 call to warnings::unimport
1295 chr 0x10FFFF;
1296 };
1297110µs12µs utf8::encode($max_unicode_length);
# spent 2µs making 1 call to utf8::encode
129811µs $max_unicode_length = length $max_unicode_length;
1299
1300 sub is_valid_utf8 {
1301
1302 # Returns undef (setting $utf8_len to 0) unless the next bytes in $text
1303 # comprise a well-formed UTF-8 encoded character, in which case,
1304 # return those bytes, setting $utf8_len to their count.
1305
1306 my $start_point = substr($text, $at - 1);
1307
1308 # Look no further than the maximum number of bytes in a single
1309 # character
1310 my $limit = $max_unicode_length;
1311 $limit = length($start_point) if $limit > length($start_point);
1312
1313 # Find the number of bytes comprising the first character in $text
1314 # (without having to know the details of its internal representation).
1315 # This loop will iterate just once on well-formed input.
1316 while ($limit > 0) { # Until we succeed or exhaust the input
1317 my $copy = substr($start_point, 0, $limit);
1318
1319 # decode() will return true if all bytes are valid; false
1320 # if any aren't.
1321 if (utf8::decode($copy)) {
1322
1323 # Is valid: get the first character, convert back to bytes,
1324 # and return those bytes.
1325 $copy = substr($copy, 0, 1);
1326 utf8::encode($copy);
1327 $utf8_len = length $copy;
1328 return substr($start_point, 0, $utf8_len);
1329 }
1330
1331 # If it didn't work, it could be that there is a full legal character
1332 # followed by a partial or malformed one. Narrow the window and
1333 # try again.
1334 $limit--;
1335 }
1336
1337 # Failed to find a legal UTF-8 character.
1338 $utf8_len = 0;
1339 return;
1340 }
1341
1342
1343 sub decode_error {
1344 my $error = shift;
1345 my $no_rep = shift;
1346 my $str = defined $text ? substr($text, $at) : '';
1347 my $mess = '';
1348 my $type = 'U*';
1349
1350 if ( OLD_PERL ) {
1351 my $type = $] < 5.006 ? 'C*'
1352 : utf8::is_utf8( $str ) ? 'U*' # 5.6
1353 : 'C*'
1354 ;
1355 }
1356
1357 for my $c ( unpack( $type, $str ) ) { # emulate pv_uni_display() ?
1358 my $chr_c = chr($c);
1359 $mess .= $chr_c eq '\\' ? '\\\\'
1360 : $chr_c =~ /[[:print:]]/ ? $chr_c
1361 : $chr_c eq '\a' ? '\a'
1362 : $chr_c eq '\t' ? '\t'
1363 : $chr_c eq '\n' ? '\n'
1364 : $chr_c eq '\r' ? '\r'
1365 : $chr_c eq '\f' ? '\f'
1366 : sprintf('\x{%x}', $c)
1367 ;
1368 if ( length $mess >= 20 ) {
1369 $mess .= '...';
1370 last;
1371 }
1372 }
1373
1374 unless ( length $mess ) {
1375 $mess = '(end of string)';
1376 }
1377
1378 Carp::croak (
1379 $no_rep ? "$error" : "$error, at character offset $at (before \"$mess\")"
1380 );
1381
1382 }
1383
1384
1385 sub _json_object_hook {
1386 my $o = $_[0];
1387 my @ks = keys %{$o};
1388
1389 if ( $cb_sk_object and @ks == 1 and exists $cb_sk_object->{ $ks[0] } and ref $cb_sk_object->{ $ks[0] } ) {
1390 my @val = $cb_sk_object->{ $ks[0] }->( $o->{$ks[0]} );
1391 if (@val == 0) {
1392 return $o;
1393 }
1394 elsif (@val == 1) {
1395 return $val[0];
1396 }
1397 else {
1398 Carp::croak("filter_json_single_key_object callbacks must not return more than one scalar");
1399 }
1400 }
1401
1402 my @val = $cb_object->($o) if ($cb_object);
1403 if (@val == 0) {
1404 return $o;
1405 }
1406 elsif (@val == 1) {
1407 return $val[0];
1408 }
1409 else {
1410 Carp::croak("filter_json_object callbacks must not return more than one scalar");
1411 }
1412 }
1413
1414
1415 sub PP_decode_box {
1416 {
1417 text => $text,
1418 at => $at,
1419 ch => $ch,
1420 len => $len,
1421 depth => $depth,
1422 encoding => $encoding,
1423 is_valid_utf8 => $is_valid_utf8,
1424 };
1425 }
1426
1427} # PARSE
1428
1429
143010ssub _decode_surrogates { # from perlunicode
1431 my $uni = 0x10000 + (hex($_[0]) - 0xD800) * 0x400 + (hex($_[1]) - 0xDC00);
1432 my $un = pack('U*', $uni);
1433 utf8::encode( $un );
1434 return $un;
1435}
1436
1437
1438sub _decode_unicode {
1439 my $un = pack('U', hex shift);
1440 utf8::encode( $un );
1441 return $un;
1442}
1443
1444#
1445# Setup for various Perl versions (the code from JSON::PP58)
1446#
1447
1448
# spent 76µs within JSON::PP::BEGIN@1448 which was called: # once (76µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 1504
BEGIN {
1449
145011µs unless ( defined &utf8::is_utf8 ) {
1451 require Encode;
1452 *utf8::is_utf8 = *Encode::is_utf8;
1453 }
1454
145511µs if ( !OLD_PERL ) {
145612µs *JSON::PP::JSON_PP_encode_ascii = \&_encode_ascii;
145711µs *JSON::PP::JSON_PP_encode_latin1 = \&_encode_latin1;
145811µs *JSON::PP::JSON_PP_decode_surrogates = \&_decode_surrogates;
145910s *JSON::PP::JSON_PP_decode_unicode = \&_decode_unicode;
1460
146113µs if ($] < 5.008003) { # join() in 5.8.0 - 5.8.2 is broken.
1462 package JSON::PP;
1463 require subs;
1464 subs->import('join');
1465 eval q|
1466 sub join {
1467 return '' if (@_ < 2);
1468 my $j = shift;
1469 my $str = shift;
1470 for (@_) { $str .= $j . $_; }
1471 return $str;
1472 }
1473 |;
1474 }
1475 }
1476
1477
1478 sub JSON::PP::incr_parse {
1479 local $Carp::CarpLevel = 1;
1480 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_parse( @_ );
1481 }
1482
1483
1484 sub JSON::PP::incr_skip {
1485 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_skip;
1486 }
1487
1488
1489 sub JSON::PP::incr_reset {
1490 ( $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new )->incr_reset;
1491 }
1492
1493167µs eval q{
1494 sub JSON::PP::incr_text : lvalue {
1495 $_[0]->{_incr_parser} ||= JSON::PP::IncrParser->new;
1496
1497 if ( $_[0]->{_incr_parser}->{incr_pos} ) {
1498 Carp::croak("incr_text cannot be called when the incremental parser already started parsing");
1499 }
1500 $_[0]->{_incr_parser}->{incr_text};
1501 }
1502 } if ( $] >= 5.006 );
1503
15041219µs176µs} # Setup for various Perl versions (the code from JSON::PP58)
# spent 76µs making 1 call to JSON::PP::BEGIN@1448
1505
1506
1507###############################
1508# Utilities
1509#
1510
1511
# spent 20µs within JSON::PP::BEGIN@1511 which was called: # once (20µs+0s) by JSON::Schema::Modern::Error::BEGIN@18 at line 1565
BEGIN {
1512114µs eval 'require Scalar::Util';
# spent 3µs executing statements in string eval
151314µs unless($@){
151411µs *JSON::PP::blessed = \&Scalar::Util::blessed;
151510s *JSON::PP::reftype = \&Scalar::Util::reftype;
151610s *JSON::PP::refaddr = \&Scalar::Util::refaddr;
1517 }
1518 else{ # This code is from Scalar::Util.
1519 # warn $@;
1520 eval 'sub UNIVERSAL::a_sub_not_likely_to_be_here { ref($_[0]) }';
1521 *JSON::PP::blessed = sub {
1522 local($@, $SIG{__DIE__}, $SIG{__WARN__});
1523 ref($_[0]) ? eval { $_[0]->a_sub_not_likely_to_be_here } : undef;
1524 };
1525 require B;
1526 my %tmap = qw(
1527 B::NULL SCALAR
1528 B::HV HASH
1529 B::AV ARRAY
1530 B::CV CODE
1531 B::IO IO
1532 B::GV GLOB
1533 B::REGEXP REGEXP
1534 );
1535 *JSON::PP::reftype = sub {
1536 my $r = shift;
1537
1538 return undef unless length(ref($r));
1539
1540 my $t = ref(B::svref_2object($r));
1541
1542 return
1543 exists $tmap{$t} ? $tmap{$t}
1544 : length(ref($$r)) ? 'REF'
1545 : 'SCALAR';
1546 };
1547 *JSON::PP::refaddr = sub {
1548 return undef unless length(ref($_[0]));
1549
1550 my $addr;
1551 if(defined(my $pkg = blessed($_[0]))) {
1552 $addr .= bless $_[0], 'Scalar::Util::Fake';
1553 bless $_[0], $pkg;
1554 }
1555 else {
1556 $addr .= $_[0]
1557 }
1558
1559 $addr =~ /0x(\w+)/;
1560 local $^W;
1561 #no warnings 'portable';
1562 hex($1);
1563 }
1564 }
1565179µs120µs}
# spent 20µs making 1 call to JSON::PP::BEGIN@1511
1566
1567
1568# shamelessly copied and modified from JSON::XS code.
1569
157012µs$JSON::PP::true = do { bless \(my $dummy = 1), "JSON::PP::Boolean" };
157111µs$JSON::PP::false = do { bless \(my $dummy = 0), "JSON::PP::Boolean" };
1572
1573sub is_bool {
1574 if (blessed $_[0]) {
1575 return (
1576 $_[0]->isa("JSON::PP::Boolean")
1577 or $_[0]->isa("Types::Serialiser::BooleanBase")
1578 or $_[0]->isa("JSON::XS::Boolean")
1579 );
1580 }
1581 elsif (CORE_BOOL) {
1582166µs251µs
# spent 28µs (5+23) within JSON::PP::BEGIN@1582 which was called: # once (5µs+23µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1582
BEGIN { CORE_BOOL and warnings->unimport('experimental::builtin') }
# spent 28µs making 1 call to JSON::PP::BEGIN@1582 # spent 23µs making 1 call to warnings::unimport
1583 return builtin::is_bool($_[0]);
1584 }
1585 return !!0;
1586}
1587
15885691.24ms
# spent 1.07ms within JSON::PP::true which was called 569 times, avg 2µs/call: # 566 times (1.06ms+0s) by YAML::PP::Schema::_bool_jsonpp_true at line 416 of YAML/PP/Schema.pm, avg 2µs/call # once (9µs+0s) by JSON::Schema::Modern::Result::__ANON__[/Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm:38] at line 38 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Result.pm # once (2µs+0s) by OpenAPI::Modern::BEGIN@32 at line 32 of OpenAPI/Modern.pm # once (2µs+0s) by JSON::Schema::Modern::Utilities::BEGIN@53 at line 53 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Utilities.pm
sub true { $JSON::PP::true }
15894051.12ms
# spent 817µs within JSON::PP::false which was called 405 times, avg 2µs/call: # 403 times (815µs+0s) by YAML::PP::Schema::_bool_jsonpp_false at line 422 of YAML/PP/Schema.pm, avg 2µs/call # once (1µs+0s) by JSON::Schema::Modern::Utilities::BEGIN@53 at line 53 of /Users/ether/git/JSON-Schema-Modern/lib/JSON/Schema/Modern/Utilities.pm # once (1µs+0s) by OpenAPI::Modern::BEGIN@32 at line 32 of OpenAPI/Modern.pm
sub false { $JSON::PP::false }
1590sub null { undef; }
1591
1592###############################
1593
1594package JSON::PP::IncrParser;
1595
1596221µs211µs
# spent 9µs (7+2) within JSON::PP::IncrParser::BEGIN@1596 which was called: # once (7µs+2µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1596
use strict;
# spent 9µs making 1 call to JSON::PP::IncrParser::BEGIN@1596 # spent 2µs making 1 call to strict::import
1597
1598224µs295µs
# spent 50µs (5+45) within JSON::PP::IncrParser::BEGIN@1598 which was called: # once (5µs+45µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1598
use constant INCR_M_WS => 0; # initial whitespace skipping
# spent 50µs making 1 call to JSON::PP::IncrParser::BEGIN@1598 # spent 45µs making 1 call to constant::import
1599214µs231µs
# spent 18µs (5+13) within JSON::PP::IncrParser::BEGIN@1599 which was called: # once (5µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1599
use constant INCR_M_STR => 1; # inside string
# spent 18µs making 1 call to JSON::PP::IncrParser::BEGIN@1599 # spent 13µs making 1 call to constant::import
1600219µs229µs
# spent 16µs (3+13) within JSON::PP::IncrParser::BEGIN@1600 which was called: # once (3µs+13µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1600
use constant INCR_M_BS => 2; # inside backslash
# spent 16µs making 1 call to JSON::PP::IncrParser::BEGIN@1600 # spent 13µs making 1 call to constant::import
1601223µs242µs
# spent 24µs (6+18) within JSON::PP::IncrParser::BEGIN@1601 which was called: # once (6µs+18µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1601
use constant INCR_M_JSON => 3; # outside anything, count nesting
# spent 24µs making 1 call to JSON::PP::IncrParser::BEGIN@1601 # spent 18µs making 1 call to constant::import
1602262µs256µs
# spent 31µs (6+25) within JSON::PP::IncrParser::BEGIN@1602 which was called: # once (6µs+25µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1602
use constant INCR_M_C0 => 4;
# spent 31µs making 1 call to JSON::PP::IncrParser::BEGIN@1602 # spent 25µs making 1 call to constant::import
1603230µs276µs
# spent 43µs (10+33) within JSON::PP::IncrParser::BEGIN@1603 which was called: # once (10µs+33µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1603
use constant INCR_M_C1 => 5;
# spent 43µs making 1 call to JSON::PP::IncrParser::BEGIN@1603 # spent 33µs making 1 call to constant::import
1604221µs244µs
# spent 24µs (4+20) within JSON::PP::IncrParser::BEGIN@1604 which was called: # once (4µs+20µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1604
use constant INCR_M_TFN => 6;
# spent 24µs making 1 call to JSON::PP::IncrParser::BEGIN@1604 # spent 20µs making 1 call to constant::import
16052192µs278µs
# spent 42µs (6+36) within JSON::PP::IncrParser::BEGIN@1605 which was called: # once (6µs+36µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1605
use constant INCR_M_NUM => 7;
# spent 42µs making 1 call to JSON::PP::IncrParser::BEGIN@1605 # spent 36µs making 1 call to constant::import
1606
160710s$JSON::PP::IncrParser::VERSION = '1.01';
1608
1609sub new {
1610 my ( $class ) = @_;
1611
1612 bless {
1613 incr_nest => 0,
1614 incr_text => undef,
1615 incr_pos => 0,
1616 incr_mode => 0,
1617 }, $class;
1618}
1619
1620
1621sub incr_parse {
1622 my ( $self, $coder, $text ) = @_;
1623
1624 $self->{incr_text} = '' unless ( defined $self->{incr_text} );
1625
1626 if ( defined $text ) {
1627 $self->{incr_text} .= $text;
1628 }
1629
1630 if ( defined wantarray ) {
1631 my $max_size = $coder->get_max_size;
1632 my $p = $self->{incr_pos};
1633 my @ret;
1634 {
1635 do {
1636 unless ( $self->{incr_nest} <= 0 and $self->{incr_mode} == INCR_M_JSON ) {
1637 $self->_incr_parse( $coder );
1638
1639 if ( $max_size and $self->{incr_pos} > $max_size ) {
1640 Carp::croak("attempted decode of JSON text of $self->{incr_pos} bytes size, but max_size is set to $max_size");
1641 }
1642 unless ( $self->{incr_nest} <= 0 and $self->{incr_mode} == INCR_M_JSON ) {
1643 # as an optimisation, do not accumulate white space in the incr buffer
1644 if ( $self->{incr_mode} == INCR_M_WS and $self->{incr_pos} ) {
1645 $self->{incr_pos} = 0;
1646 $self->{incr_text} = '';
1647 }
1648 last;
1649 }
1650 }
1651
1652 unless ( $coder->get_utf8 ) {
1653 utf8::decode( $self->{incr_text} );
1654 }
1655
1656 my ($obj, $offset) = $coder->PP_decode_json( $self->{incr_text}, 0x00000001 );
1657 push @ret, $obj;
165821.15ms219µs
# spent 16µs (13+3) within JSON::PP::IncrParser::BEGIN@1658 which was called: # once (13µs+3µs) by JSON::Schema::Modern::Error::BEGIN@18 at line 1658
use bytes;
# spent 16µs making 1 call to JSON::PP::IncrParser::BEGIN@1658 # spent 3µs making 1 call to bytes::import
1659 $self->{incr_text} = substr( $self->{incr_text}, $offset || 0 );
1660 $self->{incr_pos} = 0;
1661 $self->{incr_nest} = 0;
1662 $self->{incr_mode} = 0;
1663 last unless wantarray;
1664 } while ( wantarray );
1665 }
1666
1667 if ( wantarray ) {
1668 return @ret;
1669 }
1670 else { # in scalar context
1671 return defined $ret[0] ? $ret[0] : undef;
1672 }
1673 }
1674}
1675
1676
1677sub _incr_parse {
1678 my ($self, $coder) = @_;
1679 my $text = $self->{incr_text};
1680 my $len = length $text;
1681 my $p = $self->{incr_pos};
1682
1683INCR_PARSE:
1684 while ( $len > $p ) {
1685 my $s = substr( $text, $p, 1 );
1686 last INCR_PARSE unless defined $s;
1687 my $mode = $self->{incr_mode};
1688
1689 if ( $mode == INCR_M_WS ) {
1690 while ( $len > $p ) {
1691 $s = substr( $text, $p, 1 );
1692 last INCR_PARSE unless defined $s;
1693 if ( ord($s) > ord " " ) {
1694 if ( $s eq '#' ) {
1695 $self->{incr_mode} = INCR_M_C0;
1696 redo INCR_PARSE;
1697 } else {
1698 $self->{incr_mode} = INCR_M_JSON;
1699 redo INCR_PARSE;
1700 }
1701 }
1702 $p++;
1703 }
1704 } elsif ( $mode == INCR_M_BS ) {
1705 $p++;
1706 $self->{incr_mode} = INCR_M_STR;
1707 redo INCR_PARSE;
1708 } elsif ( $mode == INCR_M_C0 or $mode == INCR_M_C1 ) {
1709 while ( $len > $p ) {
1710 $s = substr( $text, $p, 1 );
1711 last INCR_PARSE unless defined $s;
1712 if ( $s eq "\n" ) {
1713 $self->{incr_mode} = $self->{incr_mode} == INCR_M_C0 ? INCR_M_WS : INCR_M_JSON;
1714 last;
1715 }
1716 $p++;
1717 }
1718 next;
1719 } elsif ( $mode == INCR_M_TFN ) {
1720 last INCR_PARSE if $p >= $len && $self->{incr_nest};
1721 while ( $len > $p ) {
1722 $s = substr( $text, $p++, 1 );
1723 next if defined $s and $s =~ /[rueals]/;
1724 last;
1725 }
1726 $p--;
1727 $self->{incr_mode} = INCR_M_JSON;
1728
1729 last INCR_PARSE unless $self->{incr_nest};
1730 redo INCR_PARSE;
1731 } elsif ( $mode == INCR_M_NUM ) {
1732 last INCR_PARSE if $p >= $len && $self->{incr_nest};
1733 while ( $len > $p ) {
1734 $s = substr( $text, $p++, 1 );
1735 next if defined $s and $s =~ /[0-9eE.+\-]/;
1736 last;
1737 }
1738 $p--;
1739 $self->{incr_mode} = INCR_M_JSON;
1740
1741 last INCR_PARSE unless $self->{incr_nest};
1742 redo INCR_PARSE;
1743 } elsif ( $mode == INCR_M_STR ) {
1744 while ( $len > $p ) {
1745 $s = substr( $text, $p, 1 );
1746 last INCR_PARSE unless defined $s;
1747 if ( $s eq '"' ) {
1748 $p++;
1749 $self->{incr_mode} = INCR_M_JSON;
1750
1751 last INCR_PARSE unless $self->{incr_nest};
1752 redo INCR_PARSE;
1753 }
1754 elsif ( $s eq '\\' ) {
1755 $p++;
1756 if ( !defined substr($text, $p, 1) ) {
1757 $self->{incr_mode} = INCR_M_BS;
1758 last INCR_PARSE;
1759 }
1760 }
1761 $p++;
1762 }
1763 } elsif ( $mode == INCR_M_JSON ) {
1764 while ( $len > $p ) {
1765 $s = substr( $text, $p++, 1 );
1766 if ( $s eq "\x00" ) {
1767 $p--;
1768 last INCR_PARSE;
1769 } elsif ( $s =~ /^[\t\n\r ]$/) {
1770 if ( !$self->{incr_nest} ) {
1771 $p--; # do not eat the whitespace, let the next round do it
1772 last INCR_PARSE;
1773 }
1774 next;
1775 } elsif ( $s eq 't' or $s eq 'f' or $s eq 'n' ) {
1776 $self->{incr_mode} = INCR_M_TFN;
1777 redo INCR_PARSE;
1778 } elsif ( $s =~ /^[0-9\-]$/ ) {
1779 $self->{incr_mode} = INCR_M_NUM;
1780 redo INCR_PARSE;
1781 } elsif ( $s eq '"' ) {
1782 $self->{incr_mode} = INCR_M_STR;
1783 redo INCR_PARSE;
1784 } elsif ( $s eq '[' or $s eq '{' ) {
1785 if ( ++$self->{incr_nest} > $coder->get_max_depth ) {
1786 Carp::croak('json text or perl structure exceeds maximum nesting level (max_depth set too low?)');
1787 }
1788 next;
1789 } elsif ( $s eq ']' or $s eq '}' ) {
1790 if ( --$self->{incr_nest} <= 0 ) {
1791 last INCR_PARSE;
1792 }
1793 } elsif ( $s eq '#' ) {
1794 $self->{incr_mode} = INCR_M_C1;
1795 redo INCR_PARSE;
1796 }
1797 }
1798 }
1799 }
1800
1801 $self->{incr_pos} = $p;
1802 $self->{incr_parsing} = $p ? 1 : 0; # for backward compatibility
1803}
1804
1805
1806sub incr_text {
1807 if ( $_[0]->{incr_pos} ) {
1808 Carp::croak("incr_text cannot be called when the incremental parser already started parsing");
1809 }
1810 $_[0]->{incr_text};
1811}
1812
1813
1814sub incr_skip {
1815 my $self = shift;
1816 $self->{incr_text} = substr( $self->{incr_text}, $self->{incr_pos} );
1817 $self->{incr_pos} = 0;
1818 $self->{incr_mode} = 0;
1819 $self->{incr_nest} = 0;
1820}
1821
1822
1823sub incr_reset {
1824 my $self = shift;
1825 $self->{incr_text} = undef;
1826 $self->{incr_pos} = 0;
1827 $self->{incr_mode} = 0;
1828 $self->{incr_nest} = 0;
1829}
1830
1831###############################
1832
1833
1834112µs1;
1835__END__
 
# spent 12µs within JSON::PP::CORE:match which was called 17 times, avg 706ns/call: # 17 times (12µs+0s) by JSON::PP::BEGIN@697 at line 702, avg 706ns/call
sub JSON::PP::CORE:match; # opcode
# spent 1µs within JSON::PP::CORE:qr which was called: # once (1µs+0s) by JSON::PP::BEGIN@53 at line 59
sub JSON::PP::CORE:qr; # opcode
# spent 19µs within JSON::PP::CORE:regcomp which was called: # once (19µs+0s) by JSON::PP::BEGIN@53 at line 59
sub JSON::PP::CORE:regcomp; # opcode
# spent 0s within JSON::PP::__ANON__ which was called: # once (0s+0s) by JSON::PP::BEGIN@12 at line 12
sub JSON::PP::__ANON__; # xsub