Skip to content

Commit 2505a4c

Browse files
committed
decoder: Use faster ondemand parser for validating documents
1 parent 1a9102c commit 2505a4c

File tree

4 files changed

+121
-36
lines changed

4 files changed

+121
-36
lines changed

src/simdjson_decoder.cpp

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ extern "C" {
2525
#include "simdjson_compatibility.h"
2626

2727
#define SIMDJSON_PHP_TRY(EXPR) { auto _err = (EXPR); if (UNEXPECTED(_err)) { return _err; } }
28+
#define SIMDJSON_PHP_CHECK_ERROR(EXPR) { auto _err = (EXPR).error(); if (UNEXPECTED(_err)) { return _err; } }
29+
#define SIMDJSON_PHP_VALUE(EXPR) ({ auto _res = EXPR; auto _err = _res.error(); if (UNEXPECTED(_err)) { return _err; } _res.value_unsafe(); })
2830

2931
#define SIMDJSON_DEPTH_CHECK_THRESHOLD 100000
3032

@@ -626,13 +628,62 @@ static simdjson_php_error_code simdjson_convert_element(simdjson::dom::element e
626628
return resp;
627629
}
628630

629-
PHP_SIMDJSON_API simdjson_php_error_code php_simdjson_validate(simdjson_php_parser* parser, const zend_string *json, size_t depth) /* {{{ */ {
630-
simdjson::dom::element doc;
631-
/* The depth is passed in to ensure this behaves the same way for the same arguments */
632-
return build_parsed_json_cust(parser, doc, ZSTR_VAL(json), ZSTR_LEN(json), simdjson_realloc_needed(json), depth);
631+
static simdjson_php_error_code simdjson_ondemand_validate(simdjson::ondemand::value element, size_t max_depth) {
632+
if (UNEXPECTED(element.current_depth() > max_depth)) {
633+
return simdjson::DEPTH_ERROR;
634+
}
635+
636+
switch (SIMDJSON_PHP_VALUE(element.type())) {
637+
case simdjson::ondemand::json_type::array:
638+
for (auto child : element.get_array()) {
639+
SIMDJSON_PHP_TRY(simdjson_ondemand_validate(SIMDJSON_PHP_VALUE(child), max_depth));
640+
}
641+
break;
642+
case simdjson::ondemand::json_type::object:
643+
for (auto field : element.get_object()) {
644+
SIMDJSON_PHP_TRY(simdjson_ondemand_validate(SIMDJSON_PHP_VALUE(field).value(), max_depth));
645+
}
646+
break;
647+
case simdjson::ondemand::json_type::number:
648+
return element.get_number().error();
649+
case simdjson::ondemand::json_type::string:
650+
return element.get_raw_json_string().error();
651+
case simdjson::ondemand::json_type::boolean:
652+
return element.get_bool().error();
653+
case simdjson::ondemand::json_type::null:
654+
return element.is_null().error();
655+
EMPTY_SWITCH_DEFAULT_CASE();
656+
}
657+
return simdjson::SUCCESS;
633658
}
634659

635-
/* }}} */
660+
static inline simdjson_php_error_code simdjson_ondemand_validate_scalar(simdjson::ondemand::document *element) {
661+
switch (SIMDJSON_PHP_VALUE(element->type())) {
662+
case simdjson::ondemand::json_type::number:
663+
return element->get_number().error();
664+
case simdjson::ondemand::json_type::string:
665+
return element->get_raw_json_string().error();
666+
case simdjson::ondemand::json_type::boolean:
667+
return element->get_bool().error();
668+
case simdjson::ondemand::json_type::null:
669+
return element->is_null().error();
670+
EMPTY_SWITCH_DEFAULT_CASE();
671+
}
672+
}
673+
674+
PHP_SIMDJSON_API simdjson_php_error_code php_simdjson_validate(simdjson_php_parser* parser, const zend_string *json, size_t depth) {
675+
simdjson::padded_string jsonbuffer;
676+
simdjson::ondemand::document doc;
677+
simdjson::ondemand::value value;
678+
679+
SIMDJSON_PHP_TRY(parser->ondemand_parser.iterate(simdjson_padded_string_view(json, jsonbuffer)).get(doc));
680+
if (SIMDJSON_PHP_VALUE(doc.is_scalar())) {
681+
return simdjson_ondemand_validate_scalar(&doc);
682+
}
683+
684+
SIMDJSON_PHP_TRY(doc.get(value));
685+
return simdjson_ondemand_validate(value, depth);
686+
}
636687

637688
PHP_SIMDJSON_API simdjson_php_error_code php_simdjson_parse(simdjson_php_parser* parser, const zend_string *json, zval *return_value, bool associative, size_t depth) /* {{{ */ {
638689
simdjson::dom::element doc;

tests/decode_integer_overflow.phpt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function dump_result(string $x) {
1616
echo "Testing " . var_export($x, true) . "\n";
1717
try {
1818
var_dump(simdjson_decode($x));
19+
var_dump(simdjson_validate($x));
1920
} catch (Exception $e) {
2021
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
2122
}
@@ -54,61 +55,91 @@ dump_result('-0.0');
5455
--EXPECT--
5556
Testing '18446744073709551615'
5657
float(18446744073709551616)
58+
bool(true)
5759
Testing '18446744073709551615.0'
5860
float(18446744073709551616)
61+
bool(true)
5962
Testing '18446744073709551615E0'
6063
float(18446744073709551616)
64+
bool(true)
6165
Testing '18446744073709551616'
6266
float(18446744073709551616)
67+
bool(true)
6368
Testing '18446744073709551616.0'
6469
float(18446744073709551616)
70+
bool(true)
6571
Testing '-9223372036854775808'
6672
int(-9223372036854775808)
73+
bool(true)
6774
Testing '-9223372036854775809'
6875
float(-9223372036854775808)
76+
bool(true)
6977
Testing '-9223372036854775809.0'
7078
float(-9223372036854775808)
79+
bool(true)
7180
Testing '4000000000000000000000000000000000000000000000000000000'
7281
float(4.0000000000000003132E+54)
82+
bool(true)
7383
Testing '4000000000000000000000000000000000000000000000000000000.1'
7484
float(4.0000000000000003132E+54)
85+
bool(true)
7586
Testing '4000000000000000000000000000000000000000000000000000000E1'
7687
float(4.0000000000000000409E+55)
88+
bool(true)
7789
Testing '400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
7890
float(3.999999999999999757E+305)
91+
bool(true)
7992
Testing '4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
8093
float(INF)
94+
bool(true)
8195
Testing '1e307'
8296
float(9.9999999999999998603E+306)
97+
bool(true)
8398
Testing '1e309'
8499
float(INF)
100+
bool(true)
85101
Testing '1e309'
86102
float(INF)
103+
bool(true)
87104
Testing '1e999999999999'
88105
float(INF)
106+
bool(true)
89107
Testing '-1e307'
90108
float(-9.9999999999999998603E+306)
109+
bool(true)
91110
Testing '-1e309'
92111
float(-INF)
112+
bool(true)
93113
Testing '-1e999999999999'
94114
float(-INF)
115+
bool(true)
95116
Testing '1e-307'
96117
float(9.9999999999999990933E-308)
118+
bool(true)
97119
Testing '1e-999'
98120
float(0)
121+
bool(true)
99122
Testing '1e999999'
100123
float(INF)
124+
bool(true)
101125
Testing '1e-999999'
102126
float(0)
127+
bool(true)
103128
Testing '0e-999'
104129
float(0)
130+
bool(true)
105131
Testing '0.0'
106132
float(0)
133+
bool(true)
107134
Testing '-1e-307'
108135
float(-9.9999999999999990933E-308)
136+
bool(true)
109137
Testing '-1e-999'
110138
float(-0)
139+
bool(true)
111140
Testing '-0e-999'
112141
float(-0)
142+
bool(true)
113143
Testing '-0.0'
114-
float(-0)
144+
float(-0)
145+
bool(true)

tests/is_valid.phpt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@ $json = file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_S
66
$value = \simdjson_is_valid($json);
77
var_dump($value);
88

9+
$value = \simdjson_is_valid("true");
10+
var_dump($value);
11+
12+
$value = \simdjson_is_valid("false");
13+
var_dump($value);
14+
15+
$value = \simdjson_is_valid("null");
16+
var_dump($value);
17+
18+
$value = \simdjson_is_valid("[]");
19+
var_dump($value);
20+
21+
$value = \simdjson_is_valid("{}");
22+
var_dump($value);
23+
24+
$value = \simdjson_is_valid("1");
25+
var_dump($value);
26+
27+
$value = \simdjson_is_valid("1.1");
28+
var_dump($value);
29+
930
$value = \simdjson_is_valid('{"corrupt": true,');
1031
var_dump($value);
1132

@@ -15,9 +36,20 @@ var_dump($value);
1536
$value = \simdjson_is_valid('Invalid JSON string');
1637
var_dump($value);
1738

39+
$value = \simdjson_is_valid('{"value": true} ');
40+
var_dump($value);
41+
1842
?>
1943
--EXPECTF--
2044
bool(true)
45+
bool(true)
46+
bool(true)
47+
bool(true)
48+
bool(true)
49+
bool(true)
50+
bool(true)
51+
bool(true)
52+
bool(false)
2153
bool(false)
2254
bool(false)
23-
bool(false)
55+
bool(true)

tests/is_valid_edge_cases.phpt

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)