Compare commits

...

3 Commits

Author SHA1 Message Date
Daniel Lemire 8c1bfe782b Adds 'current_depth()'. (#1824) 2022-05-17 18:06:42 -04:00
Daniel Lemire 730939f01c Better documentation regarding the direct get_number_type() method. (#1821) 2022-05-13 15:31:09 -04:00
Daniel Lemire b169dc2ea7 Fixing get_number_type() (#1819) 2022-05-12 12:15:38 -04:00
9 changed files with 157 additions and 17 deletions
+1 -7
View File
@@ -1401,10 +1401,6 @@ You must check the type before accessing the value: it is an error to call `get_
The `get_number()` function is designed with performance in mind. When calling `get_number()`, you scan the number string only once, determining efficiently the type and storing it in an efficient manner.
If you only need to compute `v.get_number().get_number_type()` on
a `document` or `value` instance, you should call directly the faster method
`v.get_number_type()` which does not generate an
intermediate `number` instance.
Consider the following example:
```C++
@@ -1417,9 +1413,7 @@ Consider the following example:
std::cout << "negative: " << val.is_negative() << " ";
std::cout << "is_integer: " << val.is_integer() << " ";
ondemand::number num = val.get_number();
// direct computation without materializing the number:
ondemand::number_type dt = val.get_number_type();
if(t != dt) { throw std::runtime_error("bug"); }
ondemand::number_type t = num.get_number_type();
switch(t) {
case ondemand::number_type::signed_integer:
std::cout << "integer: " << int64_t(num) << " ";
+6
View File
@@ -1067,6 +1067,11 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
while(static_cast<uint8_t>(*p - '0') <= 9) { p++; }
if ( p == src ) { return NUMBER_ERROR; }
if (jsoncharutils::is_structural_or_whitespace(*p)) {
// We have an integer.
// If the number is negative and valid, it must be a signed integer.
if(negative) { return ondemand::number_type::signed_integer; }
// We want values larger or equal to 9223372036854775808 to be unsigned
// integers, and the other values to be signed integers.
int digit_count = int(p - src);
if(digit_count >= 19) {
const uint8_t * smaller_big_integer = reinterpret_cast<const uint8_t *>("9223372036854775808");
@@ -1076,6 +1081,7 @@ simdjson_unused simdjson_really_inline simdjson_result<ondemand::number_type> ge
}
return ondemand::number_type::signed_integer;
}
// Hopefully, we have 'e' or 'E' or '.'.
return ondemand::number_type::floating_point_number;
}
@@ -24,6 +24,10 @@ inline simdjson_result<const char *> document::current_location() noexcept {
return iter.current_location();
}
inline int32_t document::current_depth() const noexcept {
return iter.depth();
}
inline bool document::is_alive() noexcept {
return iter.is_alive();
}
@@ -471,6 +475,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
return first.current_location();
}
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::current_depth() const noexcept {
if (error()) { return error(); }
return first.current_depth();
}
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::raw_json_token() noexcept {
if (error()) { return error(); }
return first.raw_json_token();
@@ -528,6 +537,7 @@ simdjson_really_inline simdjson_result<value> document_reference::find_field_uno
simdjson_really_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
simdjson_really_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
simdjson_really_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
simdjson_really_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
simdjson_really_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->is_integer(); }
simdjson_really_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_number_type(); }
+23 -3
View File
@@ -399,7 +399,14 @@ public:
*/
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
/**
* Determine the number type (integer or floating-point number).
* Determine the number type (integer or floating-point number) as quickly
* as possible. This function does not fully validate the input. It is
* useful when you only need to classify the numbers, without parsing them.
*
* If you are planning to retrieve the value or you need full validation,
* consider using the get_number() method instead: it will fully parse
* and validate the input, and give you access to the type:
* get_number().get_number_type().
*
* get_number_type() is number_type::unsigned_integer if we have
* an integer greater or equal to 9223372036854775808
@@ -407,8 +414,7 @@ public:
* integer that is less than 9223372036854775808
* Otherwise, get_number_type() has value number_type::floating_point_number
*
* This function req
* uires processing the number string, but it is expected
* This function requires processing the number string, but it is expected
* to be faster than get_number().get_number_type() because it is does not
* parse the number value.
*
@@ -489,6 +495,17 @@ public:
*/
inline simdjson_result<const char *> current_location() noexcept;
/**
* Returns the current depth in the document if in bounds.
*
* E.g.,
* 0 = finished with document
* 1 = document root value (could be [ or {, not yet known)
* 2 = , or } inside root array/object
* 3 = key or value inside root array/object.
*/
simdjson_really_inline int32_t current_depth() const noexcept;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
* https://tools.ietf.org/html/rfc6901 standard.
@@ -609,6 +626,7 @@ public:
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<number_type> get_number_type() noexcept;
@@ -675,6 +693,7 @@ public:
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
@@ -735,6 +754,7 @@ public:
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::json_type> type() noexcept;
simdjson_really_inline simdjson_result<bool> is_scalar() noexcept;
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline bool is_negative() noexcept;
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::number_type> get_number_type() noexcept;
@@ -181,6 +181,10 @@ simdjson_really_inline simdjson_result<const char *> value::current_location() n
return iter.json_iter().current_location();
}
simdjson_really_inline int32_t value::current_depth() const noexcept{
return iter.json_iter().depth();
}
simdjson_really_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
json_type t;
SIMDJSON_TRY(type().get(t));
@@ -400,6 +404,11 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
return first.current_location();
}
simdjson_really_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_depth() const noexcept {
if (error()) { return error(); }
return first.current_depth();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::at_pointer(std::string_view json_pointer) noexcept {
if (error()) { return error(); }
return first.at_pointer(json_pointer);
+21 -2
View File
@@ -369,7 +369,14 @@ public:
*/
simdjson_really_inline simdjson_result<bool> is_integer() noexcept;
/**
* Determine the number type (integer or floating-point number).
* Determine the number type (integer or floating-point number) as quickly
* as possible. This function does not fully validate the input. It is
* useful when you only need to classify the numbers, without parsing them.
*
* If you are planning to retrieve the value or you need full validation,
* consider using the get_number() method instead: it will fully parse
* and validate the input, and give you access to the type:
* get_number().get_number_type().
*
* get_number_type() is number_type::unsigned_integer if we have
* an integer greater or equal to 9223372036854775808
@@ -448,6 +455,17 @@ public:
*/
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
/**
* Returns the current depth in the document if in bounds.
*
* E.g.,
* 0 = finished with document
* 1 = document root value (could be [ or {, not yet known)
* 2 = , or } inside root array/object
* 3 = key or value inside root array/object.
*/
simdjson_really_inline int32_t current_depth() const noexcept;
/**
* Get the value associated with the given JSON pointer. We use the RFC 6901
* https://tools.ietf.org/html/rfc6901 standard.
@@ -650,7 +668,8 @@ public:
/** @copydoc simdjson_really_inline simdjson_result<const char *> current_location() noexcept */
simdjson_really_inline simdjson_result<const char *> current_location() noexcept;
/** @copydoc simdjson_really_inline int32_t current_depth() const noexcept */
simdjson_really_inline int32_t current_depth() const noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> at_pointer(std::string_view json_pointer) noexcept;
};
@@ -76,7 +76,7 @@ public:
/**
* Get the depth of this value.
*/
simdjson_really_inline depth_t depth() const noexcept;
simdjson_really_inline int32_t depth() const noexcept;
/**
* Get the JSON type of this value.
+6 -4
View File
@@ -197,16 +197,18 @@ namespace number_tests {
bool get_number_tests() {
TEST_START();
ondemand::parser parser;
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999])"_padded;
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999,-9223372036854775807,-9223372036854775808])"_padded;
ondemand::number_type expectedtypes[] = {ondemand::number_type::floating_point_number,
ondemand::number_type::signed_integer,
ondemand::number_type::signed_integer,
ondemand::number_type::floating_point_number,
ondemand::number_type::signed_integer,
ondemand::number_type::unsigned_integer
ondemand::number_type::unsigned_integer,
ondemand::number_type::signed_integer,
ondemand::number_type::signed_integer
};
bool is_negative[] = {false, false, false, false, true, false};
bool is_integer[] = {false, true, true, false, true, true};
bool is_negative[] = {false, false, false, false, true, false, true, true};
bool is_integer[] = {false, true, true, false, true, true, true, true};
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
@@ -109,6 +109,85 @@ bool basics_treewalk() {
return true;
}
void print_depth_space(ondemand::value element) {
for(auto i = 0; i < element.current_depth(); i++) {
cout << " ";
}
}
void recursive_print_json_breakline(ondemand::value element) {
bool add_comma;
switch (element.type()) {
case ondemand::json_type::array:
cout << endl;
print_depth_space(element);
cout << "[";
add_comma = false;
for (auto child : element.get_array()) {
if (add_comma) {
print_depth_space(element);
cout << ",";
}
// We need the call to value() to get
// an ondemand::value type.
recursive_print_json_breakline(child.value());
add_comma = true;
}
cout << "]";
break;
case ondemand::json_type::object:
cout << endl;
print_depth_space(element);
cout << "{";
add_comma = false;
for (auto field : element.get_object()) {
if (add_comma) {
print_depth_space(element);
cout << ",";
}
// key() returns the key as it appears in the raw
// JSON document, if we want the unescaped key,
// we should do field.unescaped_key().
cout << "\"" << field.key() << "\": ";
recursive_print_json_breakline(field.value());
add_comma = true;
}
cout << "}\n";
break;
case ondemand::json_type::number:
// assume it fits in a double
cout << element.get_double();
break;
case ondemand::json_type::string:
// get_string() would return escaped string, but
// we are happy with unescaped string.
cout << "\"" << element.get_raw_json_string() << "\"";
break;
case ondemand::json_type::boolean:
cout << element.get_bool();
break;
case ondemand::json_type::null:
cout << "null";
break;
}
}
bool basics_treewalk_breakline() {
padded_string json[3] = {R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded, R"( {"key":"value"} )"_padded, "[12,3]"_padded};
ondemand::parser parser;
for(size_t i = 0 ; i < 3; i++) {
ondemand::document doc = parser.iterate(json[i]);
ondemand::value val = doc;
recursive_print_json_breakline(val);
std::cout << std::endl;
}
return true;
}
bool basics_1() {
TEST_START();
@@ -882,6 +961,7 @@ bool current_location_no_error() {
int main() {
#if SIMDJSON_EXCEPTIONS
basics_treewalk();
basics_treewalk_breakline();
#endif
if (
true