Merge pull request #1414 from simdjson/jkeiser/array-assert

Fix #1409 (assert when trying to get one value as multiple types)
This commit is contained in:
John Keiser 2021-02-05 09:45:49 -08:00 committed by GitHub
commit 3f2639a655
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1022 additions and 860 deletions

View File

@ -423,7 +423,7 @@ simdjson_really_inline error_code parse_exponent(simdjson_unused const uint8_t *
return SUCCESS;
}
simdjson_really_inline int significant_digits(const uint8_t * start_digits, int digit_count) {
simdjson_really_inline size_t significant_digits(const uint8_t * start_digits, size_t digit_count) {
// It is possible that the integer had an overflow.
// We have to handle the case where we have 0.0000somenumber.
const uint8_t *start = start_digits;
@ -431,11 +431,11 @@ simdjson_really_inline int significant_digits(const uint8_t * start_digits, int
start++;
}
// we over-decrement by one when there is a '.'
return digit_count - int(start - start_digits);
return digit_count - size_t(start - start_digits);
}
template<typename W>
simdjson_really_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, int digit_count, int64_t exponent, W &writer) {
simdjson_really_inline error_code write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer) {
// If we frequently had to deal with long strings of digits,
// we could extend our code by using a 128-bit integer instead
// of a 64-bit integer. However, this is uncommon in practice.
@ -529,7 +529,8 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
while (parse_digit(*p, i)) { p++; }
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
int digit_count = int(p - start_digits);
// Optimization note: size_t is expected to be unsigned.
size_t digit_count = size_t(p - start_digits);
if (digit_count == 0 || ('0' == *start_digits && digit_count > 1)) { return INVALID_NUMBER(src); }
//
@ -549,23 +550,23 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
SIMDJSON_TRY( parse_exponent(src, p, exponent) );
}
if (is_float) {
const bool clean_end = jsoncharutils::is_structural_or_whitespace(*p);
const bool dirty_end = jsoncharutils::is_not_structural_or_whitespace(*p);
SIMDJSON_TRY( write_float(src, negative, i, start_digits, digit_count, exponent, writer) );
if (!clean_end) { return INVALID_NUMBER(src); }
if (dirty_end) { return INVALID_NUMBER(src); }
return SUCCESS;
}
// The longest negative 64-bit number is 19 digits.
// The longest positive 64-bit number is 20 digits.
// We do it this way so we don't trigger this branch unless we must.
int longest_digit_count = negative ? 19 : 20;
size_t longest_digit_count = negative ? 19 : 20;
if (digit_count > longest_digit_count) { return INVALID_NUMBER(src); }
if (digit_count == longest_digit_count) {
if (negative) {
// Anything negative above INT64_MAX+1 is invalid
if (i > uint64_t(INT64_MAX)+1) { return INVALID_NUMBER(src); }
WRITE_INTEGER(~i+1, src, writer);
if (!jsoncharutils::is_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
return SUCCESS;
// Positive overflow check:
// - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the
@ -588,16 +589,81 @@ simdjson_really_inline error_code parse_number(const uint8_t *const src, W &writ
} else {
WRITE_INTEGER(negative ? (~i+1) : i, src, writer);
}
if (!jsoncharutils::is_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
if (jsoncharutils::is_not_structural_or_whitespace(*p)) { return INVALID_NUMBER(src); }
return SUCCESS;
}
// SAX functions
// Inlineable functions
namespace {
// This table can be used to characterize the final character of an integer
// string. For JSON structural character and allowable white space characters,
// we return SUCCESS. For 'e', '.' and 'E', we return INCORRECT_TYPE. Otherwise
// we return NUMBER_ERROR.
// Optimization note: we could easily reduce the size of the table by half (to 128)
// at the cost of an extra branch.
// Optimization note: we want the values to use at most 8 bits (not, e.g., 32 bits):
static_assert(error_code(uint8_t(NUMBER_ERROR))== NUMBER_ERROR, "bad NUMBER_ERROR cast");
static_assert(error_code(uint8_t(SUCCESS))== SUCCESS, "bad NUMBER_ERROR cast");
static_assert(error_code(uint8_t(INCORRECT_TYPE))== INCORRECT_TYPE, "bad NUMBER_ERROR cast");
const uint8_t integer_string_finisher[256] = {
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS,
SUCCESS, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS,
NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, INCORRECT_TYPE,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, SUCCESS, NUMBER_ERROR, SUCCESS, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, INCORRECT_TYPE, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, SUCCESS, NUMBER_ERROR,
SUCCESS, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR, NUMBER_ERROR,
NUMBER_ERROR};
// Parse any number from 0 to 18,446,744,073,709,551,615
simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(const uint8_t * const src) noexcept {
const uint8_t *p = src;
//
// Parse the integer part.
//
@ -607,13 +673,23 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
while (parse_digit(*p, i)) { p++; }
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
int digit_count = int(p - start_digits);
if (digit_count == 0 || ('0' == *start_digits && digit_count > 1)) { return NUMBER_ERROR; }
if (!jsoncharutils::is_structural_or_whitespace(*p)) { return NUMBER_ERROR; }
// Optimization note: size_t is expected to be unsigned.
size_t digit_count = size_t(p - start_digits);
// The longest positive 64-bit number is 20 digits.
// We do it this way so we don't trigger this branch unless we must.
if (digit_count > 20) { return NUMBER_ERROR; }
// Optimization note: the compiler can probably merge
// ((digit_count == 0) || (digit_count > 20))
// into a single branch since digit_count is unsigned.
if ((digit_count == 0) || (digit_count > 20)) { return INCORRECT_TYPE; }
// Here digit_count > 0.
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
// We can do the following...
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
// }
// as a single table lookup:
if (integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); }
if (digit_count == 20) {
// Positive overflow check:
// - A 20 digit number starting with 2-9 is overflow, because 18,446,744,073,709,551,615 is the
@ -627,7 +703,7 @@ simdjson_unused simdjson_really_inline simdjson_result<uint64_t> parse_unsigned(
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
//
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return NUMBER_ERROR; }
if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return i;
@ -650,19 +726,28 @@ simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer(co
while (parse_digit(*p, i)) { p++; }
// If there were no digits, or if the integer starts with 0 and has more than one digit, it's an error.
int digit_count = int(p - start_digits);
if (digit_count == 0 || ('0' == *start_digits && digit_count > 1)) { return NUMBER_ERROR; }
if (!jsoncharutils::is_structural_or_whitespace(*p)) { return NUMBER_ERROR; }
// Optimization note: size_t is expected to be unsigned.
size_t digit_count = size_t(p - start_digits);
// The longest negative 64-bit number is 19 digits.
// The longest positive 64-bit number is 20 digits.
// We do it this way so we don't trigger this branch unless we must.
int longest_digit_count = negative ? 19 : 20;
if (digit_count > longest_digit_count) { return NUMBER_ERROR; }
size_t longest_digit_count = negative ? 19 : 20;
// Optimization note: the compiler can probably merge
// ((digit_count == 0) || (digit_count > longest_digit_count))
// into a single branch since digit_count is unsigned.
if ((digit_count == 0) || (digit_count > longest_digit_count)) { return INCORRECT_TYPE; }
// Here digit_count > 0.
if (('0' == *start_digits) && (digit_count > 1)) { return NUMBER_ERROR; }
// We can do the following...
// if (!jsoncharutils::is_structural_or_whitespace(*p)) {
// return (*p == '.' || *p == 'e' || *p == 'E') ? INCORRECT_TYPE : NUMBER_ERROR;
// }
// as a single table lookup:
if(integer_string_finisher[*p] != SUCCESS) { return error_code(integer_string_finisher[*p]); }
if (digit_count == longest_digit_count) {
if(negative) {
if (negative) {
// Anything negative above INT64_MAX+1 is invalid
if (i > uint64_t(INT64_MAX)+1) { return NUMBER_ERROR; }
if (i > uint64_t(INT64_MAX)+1) { return INCORRECT_TYPE; }
return ~i+1;
// Positive overflow check:
@ -677,7 +762,7 @@ simdjson_unused simdjson_really_inline simdjson_result<int64_t> parse_integer(co
// - Therefore, if the number is positive and lower than that, it's overflow.
// - The value we are looking at is less than or equal to 9,223,372,036,854,775,808 (INT64_MAX).
//
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return NUMBER_ERROR; }
} else if (src[0] != uint8_t('1') || i <= uint64_t(INT64_MAX)) { return INCORRECT_TYPE; }
}
return negative ? (~i+1) : i;
@ -699,7 +784,8 @@ simdjson_unused simdjson_really_inline simdjson_result<double> parse_double(cons
bool leading_zero = (i == 0);
while (parse_digit(*p, i)) { p++; }
// no integer digits, or 0123 (zero must be solo)
if ( p == src || (leading_zero && p != src+1)) { return NUMBER_ERROR; }
if ( p == src ) { return INCORRECT_TYPE; }
if ( (leading_zero && p != src+1)) { return NUMBER_ERROR; }
//
// Parse the decimal part.

View File

@ -50,11 +50,6 @@ simdjson_really_inline simdjson_result<array> array::start(value_iterator &iter)
SIMDJSON_TRY( iter.start_array().get(has_value) );
return array(iter);
}
simdjson_really_inline simdjson_result<array> array::try_start(value_iterator &iter) noexcept {
simdjson_unused bool has_value;
SIMDJSON_TRY( iter.try_start_array().get(has_value) );
return array(iter);
}
simdjson_really_inline array array::started(value_iterator &iter) noexcept {
simdjson_unused bool has_value = iter.started_array();
return array(iter);

View File

@ -41,14 +41,6 @@ protected:
* @error INCORRECT_TYPE if the iterator is not at [.
*/
static simdjson_really_inline simdjson_result<array> start(value_iterator &iter) noexcept;
/**
* Begin array iteration.
*
* @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
* resulting array.
* @error INCORRECT_TYPE if the iterator is not at [.
*/
static simdjson_really_inline simdjson_result<array> try_start(value_iterator &iter) noexcept;
/**
* Begin array iteration.
*

View File

@ -21,20 +21,28 @@ static simdjson_really_inline char printable_char(char c) {
simdjson_really_inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
log_line(iter, "", type, detail, delta, depth_delta);
}
simdjson_really_inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
log_line(iter, "", type, detail, delta, depth_delta);
}
simdjson_really_inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
log_line(iter, index, depth, "", type, detail);
}
simdjson_really_inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
log_line(iter, "", type, detail, delta, depth_delta);
}
simdjson_really_inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
log_line(iter, index, depth, "+", type, detail);
if (LOG_ENABLED) { log_depth++; }
}
simdjson_really_inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
log_line(iter, "+", type, "", delta, depth_delta);
log_depth++;
if (LOG_ENABLED) { log_depth++; }
}
simdjson_really_inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
log_depth--;
if (LOG_ENABLED) { log_depth--; }
log_line(iter, "-", type, "", delta, depth_delta);
}
simdjson_really_inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
log_line(iter, "ERROR: ", error, detail, delta, depth_delta);
}
@ -45,22 +53,26 @@ simdjson_really_inline void log_error(const json_iterator &iter, token_position
simdjson_really_inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
log_event(iter.json_iter(), type, detail, delta, depth_delta);
}
simdjson_really_inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
log_value(iter.json_iter(), type, detail, delta, depth_delta);
}
simdjson_really_inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
log_start_value(iter.json_iter(), type, delta, depth_delta);
}
simdjson_really_inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
log_end_value(iter.json_iter(), type, delta, depth_delta);
}
simdjson_really_inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
log_error(iter.json_iter(), error, detail, delta, depth_delta);
}
simdjson_really_inline void log_headers() noexcept {
log_depth = 0;
if (LOG_ENABLED) {
log_depth = 0;
printf("\n");
printf("| %-*s ", LOG_EVENT_LEN, "Event");
printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");

View File

@ -14,15 +14,16 @@ namespace logger {
#endif
static simdjson_really_inline void log_headers() noexcept;
static simdjson_really_inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept;
static simdjson_really_inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail) noexcept;
static simdjson_really_inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept;
static simdjson_really_inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
static simdjson_really_inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
static simdjson_really_inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
static simdjson_really_inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
static simdjson_really_inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
static simdjson_really_inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
static simdjson_really_inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;

View File

@ -38,11 +38,6 @@ simdjson_really_inline simdjson_result<object> object::start(value_iterator &ite
SIMDJSON_TRY( iter.start_object().get(has_value) );
return object(iter);
}
simdjson_really_inline simdjson_result<object> object::try_start(value_iterator &iter) noexcept {
simdjson_unused bool has_value;
SIMDJSON_TRY( iter.try_start_object().get(has_value) );
return object(iter);
}
simdjson_really_inline object object::started(value_iterator &iter) noexcept {
simdjson_unused bool has_value = iter.started_object();
return iter;

View File

@ -72,7 +72,6 @@ public:
protected:
static simdjson_really_inline simdjson_result<object> start(value_iterator &iter) noexcept;
static simdjson_really_inline simdjson_result<object> try_start(value_iterator &iter) noexcept;
static simdjson_really_inline object started(value_iterator &iter) noexcept;
static simdjson_really_inline object resume(const value_iterator &iter) noexcept;
simdjson_really_inline object(const value_iterator &iter) noexcept;

View File

@ -13,26 +13,13 @@ simdjson_really_inline value value::resume(const value_iterator &iter) noexcept
return iter;
}
simdjson_really_inline simdjson_result<array> value::get_array() && noexcept {
simdjson_really_inline simdjson_result<array> value::get_array() noexcept {
return array::start(iter);
}
simdjson_really_inline simdjson_result<array> value::get_array() & noexcept {
return array::try_start(iter);
}
simdjson_really_inline simdjson_result<object> value::get_object() && noexcept {
simdjson_really_inline simdjson_result<object> value::get_object() noexcept {
return object::start(iter);
}
simdjson_really_inline simdjson_result<object> value::get_object() & noexcept {
return object::try_start(iter);
}
simdjson_really_inline simdjson_result<object> value::start_or_resume_object() & noexcept {
if (iter.at_start()) {
return get_object();
} else {
return object::resume(iter);
}
}
simdjson_really_inline simdjson_result<object> value::start_or_resume_object() && noexcept {
simdjson_really_inline simdjson_result<object> value::start_or_resume_object() noexcept {
if (iter.at_start()) {
return get_object();
} else {
@ -62,44 +49,25 @@ simdjson_really_inline bool value::is_null() noexcept {
return iter.is_null();
}
template<> simdjson_really_inline simdjson_result<array> value::get() & noexcept { return get_array(); }
template<> simdjson_really_inline simdjson_result<object> value::get() & noexcept { return get_object(); }
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() & noexcept { return get_raw_json_string(); }
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() & noexcept { return get_string(); }
template<> simdjson_really_inline simdjson_result<double> value::get() & noexcept { return get_double(); }
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() & noexcept { return get_uint64(); }
template<> simdjson_really_inline simdjson_result<int64_t> value::get() & noexcept { return get_int64(); }
template<> simdjson_really_inline simdjson_result<bool> value::get() & noexcept { return get_bool(); }
template<> simdjson_really_inline simdjson_result<array> value::get() noexcept { return get_array(); }
template<> simdjson_really_inline simdjson_result<object> value::get() noexcept { return get_object(); }
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(); }
template<> simdjson_really_inline simdjson_result<double> value::get() noexcept { return get_double(); }
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
template<> simdjson_really_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
template<> simdjson_really_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
template<> simdjson_really_inline simdjson_result<value> value::get() && noexcept { return std::forward<value>(*this); }
template<> simdjson_really_inline simdjson_result<array> value::get() && noexcept { return std::forward<value>(*this).get_array(); }
template<> simdjson_really_inline simdjson_result<object> value::get() && noexcept { return std::forward<value>(*this).get_object(); }
template<> simdjson_really_inline simdjson_result<raw_json_string> value::get() && noexcept { return std::forward<value>(*this).get_raw_json_string(); }
template<> simdjson_really_inline simdjson_result<std::string_view> value::get() && noexcept { return std::forward<value>(*this).get_string(); }
template<> simdjson_really_inline simdjson_result<double> value::get() && noexcept { return std::forward<value>(*this).get_double(); }
template<> simdjson_really_inline simdjson_result<uint64_t> value::get() && noexcept { return std::forward<value>(*this).get_uint64(); }
template<> simdjson_really_inline simdjson_result<int64_t> value::get() && noexcept { return std::forward<value>(*this).get_int64(); }
template<> simdjson_really_inline simdjson_result<bool> value::get() && noexcept { return std::forward<value>(*this).get_bool(); }
template<typename T> simdjson_really_inline error_code value::get(T &out) & noexcept {
template<typename T> simdjson_really_inline error_code value::get(T &out) noexcept {
return get<T>().get(out);
}
template<typename T> simdjson_really_inline error_code value::get(T &out) && noexcept {
return std::forward<value>(*this).get<T>().get(out);
}
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline value::operator array() && noexcept(false) {
return std::forward<value>(*this).get_array();
simdjson_really_inline value::operator array() noexcept(false) {
return get_array();
}
simdjson_really_inline value::operator array() & noexcept(false) {
return std::forward<value>(*this).get_array();
}
simdjson_really_inline value::operator object() && noexcept(false) {
return std::forward<value>(*this).get_object();
}
simdjson_really_inline value::operator object() & noexcept(false) {
return std::forward<value>(*this).get_object();
simdjson_really_inline value::operator object() noexcept(false) {
return get_object();
}
simdjson_really_inline value::operator uint64_t() noexcept(false) {
return get_uint64();
@ -128,44 +96,26 @@ simdjson_really_inline simdjson_result<array_iterator> value::end() & noexcept {
return {};
}
simdjson_really_inline simdjson_result<value> value::find_field(std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
return start_or_resume_object().find_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_field(std::string_view key) && noexcept {
return std::forward<value>(*this).start_or_resume_object().find_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_field(const char *key) & noexcept {
simdjson_really_inline simdjson_result<value> value::find_field(const char *key) noexcept {
return start_or_resume_object().find_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_field(const char *key) && noexcept {
return std::forward<value>(*this).start_or_resume_object().find_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_field_unordered(std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
return start_or_resume_object().find_field_unordered(key);
}
simdjson_really_inline simdjson_result<value> value::find_field_unordered(std::string_view key) && noexcept {
return std::forward<value>(*this).start_or_resume_object().find_field_unordered(key);
}
simdjson_really_inline simdjson_result<value> value::find_field_unordered(const char *key) & noexcept {
simdjson_really_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
return start_or_resume_object().find_field_unordered(key);
}
simdjson_really_inline simdjson_result<value> value::find_field_unordered(const char *key) && noexcept {
return std::forward<value>(*this).start_or_resume_object().find_field_unordered(key);
}
simdjson_really_inline simdjson_result<value> value::operator[](std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
return start_or_resume_object()[key];
}
simdjson_really_inline simdjson_result<value> value::operator[](std::string_view key) && noexcept {
return std::forward<value>(*this).start_or_resume_object()[key];
}
simdjson_really_inline simdjson_result<value> value::operator[](const char *key) & noexcept {
simdjson_really_inline simdjson_result<value> value::operator[](const char *key) noexcept {
return start_or_resume_object()[key];
}
simdjson_really_inline simdjson_result<value> value::operator[](const char *key) && noexcept {
return std::forward<value>(*this).start_or_resume_object()[key];
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
@ -197,73 +147,41 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_
return {};
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(std::string_view key) noexcept {
if (error()) { return error(); }
return first.find_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(std::string_view key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).find_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(const char *key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(const char *key) noexcept {
if (error()) { return error(); }
return first.find_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field(const char *key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).find_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
if (error()) { return error(); }
return first.find_field_unordered(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(std::string_view key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).find_field_unordered(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(const char *key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(const char *key) noexcept {
if (error()) { return error(); }
return first.find_field_unordered(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(const char *key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).find_field_unordered(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](std::string_view key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](std::string_view key) noexcept {
if (error()) { return error(); }
return first[key];
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](std::string_view key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first)[key];
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](const char *key) & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](const char *key) noexcept {
if (error()) { return error(); }
return first[key];
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](const char *key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first)[key];
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_array() & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_array() noexcept {
if (error()) { return error(); }
return first.get_array();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_array() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).get_array();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_object() & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_object() noexcept {
if (error()) { return error(); }
return first.get_object();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_object() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).get_object();
}
simdjson_really_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_uint64() noexcept {
if (error()) { return error(); }
return first.get_uint64();
@ -293,59 +211,34 @@ simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::v
return first.is_null();
}
template<typename T> simdjson_really_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() & noexcept {
template<typename T> simdjson_really_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() noexcept {
if (error()) { return error(); }
return first.get<T>();
}
template<typename T> simdjson_really_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).get<T>();
}
template<typename T> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get(T &out) & noexcept {
template<typename T> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get(T &out) noexcept {
if (error()) { return error(); }
return first.get<T>(out);
}
template<typename T> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get(T &out) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first).get<T>(out);
}
template<> simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>() & noexcept {
template<> simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>() noexcept {
if (error()) { return error(); }
return std::move(first);
}
template<> simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>() && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first);
}
template<> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) & noexcept {
template<> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept {
if (error()) { return error(); }
out = first;
return SUCCESS;
}
template<> simdjson_really_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get<SIMDJSON_IMPLEMENTATION::ondemand::value>(SIMDJSON_IMPLEMENTATION::ondemand::value &out) && noexcept {
if (error()) { return error(); }
out = std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first);
return SUCCESS;
}
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::array() && noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false) {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::object() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator SIMDJSON_IMPLEMENTATION::ondemand::object() && noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator uint64_t() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first;

View File

@ -30,9 +30,7 @@ public:
* @returns A value of the given type, parsed from the JSON.
* @returns INCORRECT_TYPE If the JSON value is not the given type.
*/
template<typename T> simdjson_really_inline simdjson_result<T> get() & noexcept;
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
template<typename T> simdjson_really_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_really_inline simdjson_result<T> get() noexcept;
/**
* Get this value as the given type.
@ -43,9 +41,7 @@ public:
* @returns INCORRECT_TYPE If the JSON value is not an object.
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
*/
template<typename T> simdjson_really_inline error_code get(T &out) & noexcept;
/** @overload template<typename T> error_code get(T &out) & noexcept */
template<typename T> simdjson_really_inline error_code get(T &out) && noexcept;
template<typename T> simdjson_really_inline error_code get(T &out) noexcept;
/**
* Cast this JSON value to an array.
@ -53,9 +49,7 @@ public:
* @returns An object that can be used to iterate the array.
* @returns INCORRECT_TYPE If the JSON value is not an array.
*/
simdjson_really_inline simdjson_result<array> get_array() && noexcept;
/** @overload simdjson_really_inline operator get_array() && noexcept(false); */
simdjson_really_inline simdjson_result<array> get_array() & noexcept;
simdjson_really_inline simdjson_result<array> get_array() noexcept;
/**
* Cast this JSON value to an object.
@ -63,9 +57,7 @@ public:
* @returns An object that can be used to look up or iterate fields.
* @returns INCORRECT_TYPE If the JSON value is not an object.
*/
simdjson_really_inline simdjson_result<object> get_object() && noexcept;
/** @overload simdjson_really_inline operator object() && noexcept(false); */
simdjson_really_inline simdjson_result<object> get_object() & noexcept;
simdjson_really_inline simdjson_result<object> get_object() noexcept;
/**
* Cast this JSON value to an unsigned integer.
@ -136,18 +128,14 @@ public:
* @returns An object that can be used to iterate the array.
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
*/
simdjson_really_inline operator array() && noexcept(false);
/** @overload simdjson_really_inline operator array() && noexcept(false); */
simdjson_really_inline operator array() & noexcept(false);
simdjson_really_inline operator array() noexcept(false);
/**
* Cast this JSON value to an object.
*
* @returns An object that can be used to look up or iterate fields.
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
*/
simdjson_really_inline operator object() && noexcept(false);
/** @overload simdjson_really_inline operator object() && noexcept(false); */
simdjson_really_inline operator object() & noexcept(false);
simdjson_really_inline operator object() noexcept(false);
/**
* Cast this JSON value to an unsigned integer.
*
@ -234,13 +222,9 @@ public:
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field(const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field(const char *key) && noexcept;
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> find_field(const char *key) noexcept;
/**
* Look up a field by name on an object, without regard to key order.
@ -261,21 +245,13 @@ public:
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field_unordered(const char *key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> operator[](const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> operator[](const char *key) && noexcept;
simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> operator[](std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> operator[](const char *key) noexcept;
protected:
/**
@ -303,9 +279,7 @@ protected:
/**
* Get the object, starting or resuming it as necessary
*/
simdjson_really_inline simdjson_result<object> start_or_resume_object() & noexcept;
/** @overload simdjson_really_inline simdjson_result<object> start_or_resume_object() & noexcept; */
simdjson_really_inline simdjson_result<object> start_or_resume_object() && noexcept;
simdjson_really_inline simdjson_result<object> start_or_resume_object() noexcept;
// simdjson_really_inline void log_value(const char *type) const noexcept;
// simdjson_really_inline void log_error(const char *message) const noexcept;
@ -334,11 +308,8 @@ public:
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result() noexcept = default;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array> get_array() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> get_object() noexcept;
simdjson_really_inline simdjson_result<uint64_t> get_uint64() noexcept;
simdjson_really_inline simdjson_result<int64_t> get_int64() noexcept;
@ -348,17 +319,13 @@ public:
simdjson_really_inline simdjson_result<bool> get_bool() noexcept;
simdjson_really_inline bool is_null() noexcept;
template<typename T> simdjson_really_inline simdjson_result<T> get() & noexcept;
template<typename T> simdjson_really_inline simdjson_result<T> get() && noexcept;
template<typename T> simdjson_really_inline simdjson_result<T> get() noexcept;
template<typename T> simdjson_really_inline error_code get(T &out) & noexcept;
template<typename T> simdjson_really_inline error_code get(T &out) && noexcept;
template<typename T> simdjson_really_inline error_code get(T &out) noexcept;
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() && noexcept(false);
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false);
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() && noexcept(false);
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false);
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false);
simdjson_really_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() noexcept(false);
simdjson_really_inline operator uint64_t() noexcept(false);
simdjson_really_inline operator int64_t() noexcept(false);
simdjson_really_inline operator double() noexcept(false);
@ -390,13 +357,9 @@ public:
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) noexcept;
/**
* Look up a field by name on an object, without regard to key order.
@ -417,21 +380,13 @@ public:
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
*/
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) && noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) noexcept;
};
} // namespace simdjson

View File

@ -10,20 +10,12 @@ simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter,
}
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_object() noexcept {
assert_at_start();
if (*_json_iter->advance() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; }
return started_object();
}
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_object() noexcept {
assert_at_start();
if (*_json_iter->peek() != '{') { logger::log_error(*_json_iter, "Not an object"); return INCORRECT_TYPE; }
_json_iter->advance();
if (*advance_container_start("object") != '{') { return incorrect_type_error("Not an object"); }
return started_object();
}
simdjson_warn_unused simdjson_really_inline bool value_iterator::started_object() noexcept {
assert_at_container_start();
if (*_json_iter->peek() == '}') {
logger::log_value(*_json_iter, "empty object");
_json_iter->advance();
@ -256,21 +248,12 @@ simdjson_warn_unused simdjson_really_inline error_code value_iterator::field_val
}
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::start_array() noexcept {
assert_at_start();
if (*_json_iter->advance() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; }
return started_array();
}
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::try_start_array() noexcept {
assert_at_start();
if (*_json_iter->peek() != '[') { logger::log_error(*_json_iter, "Not an array"); return INCORRECT_TYPE; }
_json_iter->advance();
if (*advance_container_start("array") != '[') { return incorrect_type_error("Not an array"); }
return started_array();
}
simdjson_warn_unused simdjson_really_inline bool value_iterator::started_array() noexcept {
assert_at_container_start();
if (*_json_iter->peek() == ']') {
logger::log_value(*_json_iter, "empty array");
_json_iter->advance();
@ -313,7 +296,7 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> va
return get_raw_json_string().unescape(_json_iter->string_buf_loc());
}
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
auto json = advance_scalar("string");
auto json = advance_start("string");
if (*json != '"') { return incorrect_type_error("Not a string"); }
return raw_json_string(json+1);
}
@ -342,21 +325,21 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> val
return get_raw_json_string();
}
simdjson_warn_unused simdjson_really_inline simdjson_result<uint64_t> value_iterator::get_root_uint64() noexcept {
auto max_len = peek_scalar_length();
auto max_len = peek_start_length();
auto json = advance_root_scalar("uint64");
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, _start_position, depth(), "Root number more than 20 characters"); return NUMBER_ERROR; }
return numberparsing::parse_unsigned(tmpbuf);
}
simdjson_warn_unused simdjson_really_inline simdjson_result<int64_t> value_iterator::get_root_int64() noexcept {
auto max_len = peek_scalar_length();
auto max_len = peek_start_length();
auto json = advance_root_scalar("int64");
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { logger::log_error(*_json_iter, _start_position, depth(), "Root number more than 20 characters"); return NUMBER_ERROR; }
return numberparsing::parse_integer(tmpbuf);
}
simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterator::get_root_double() noexcept {
auto max_len = peek_scalar_length();
auto max_len = peek_start_length();
auto json = advance_root_scalar("double");
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest number: -0.<fraction>e-308.
uint8_t tmpbuf[1074+8+1];
@ -364,14 +347,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<double> value_iterat
return numberparsing::parse_double(tmpbuf);
}
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::get_root_bool() noexcept {
auto max_len = peek_scalar_length();
auto max_len = peek_start_length();
auto json = advance_root_scalar("bool");
uint8_t tmpbuf[5+1];
if (!_json_iter->copy_to_buffer(json, max_len, tmpbuf)) { return incorrect_type_error("Not a boolean"); }
return parse_bool(tmpbuf);
}
simdjson_really_inline bool value_iterator::is_root_null() noexcept {
auto max_len = peek_scalar_length();
auto max_len = peek_start_length();
auto json = advance_root_scalar("null");
return max_len >= 4 && !atomparsing::str4ncmp(json, "null") &&
(max_len == 4 || jsoncharutils::is_structural_or_whitespace(json[5]));
@ -427,17 +410,17 @@ simdjson_warn_unused simdjson_really_inline json_iterator &value_iterator::json_
return *_json_iter;
}
simdjson_really_inline const uint8_t *value_iterator::peek_scalar() const noexcept {
simdjson_really_inline const uint8_t *value_iterator::peek_start() const noexcept {
return _json_iter->peek(_start_position);
}
simdjson_really_inline uint32_t value_iterator::peek_scalar_length() const noexcept {
simdjson_really_inline uint32_t value_iterator::peek_start_length() const noexcept {
return _json_iter->peek_length(_start_position);
}
simdjson_really_inline const uint8_t *value_iterator::advance_scalar(const char *type) const noexcept {
simdjson_really_inline const uint8_t *value_iterator::advance_start(const char *type) const noexcept {
logger::log_value(*_json_iter, _start_position, depth(), type);
// If we're not at the position anymore, we don't want to advance the cursor.
if (!is_at_start()) { return peek_scalar(); }
if (!is_at_start()) { return peek_start(); }
// Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
assert_at_start();
@ -445,9 +428,19 @@ simdjson_really_inline const uint8_t *value_iterator::advance_scalar(const char
_json_iter->ascend_to(depth()-1);
return result;
}
simdjson_really_inline const uint8_t *value_iterator::advance_container_start(const char *type) const noexcept {
// If we're not at the position anymore, we don't want to advance the cursor.
if (is_at_container_start()) { return peek_start(); }
logger::log_start_value(*_json_iter, _start_position, depth(), type);
// Get the JSON and advance the cursor, decreasing depth to signify that we have retrieved the value.
assert_at_start();
return _json_iter->advance();
}
simdjson_really_inline const uint8_t *value_iterator::advance_root_scalar(const char *type) const noexcept {
logger::log_value(*_json_iter, _start_position, depth(), type);
if (!is_at_start()) { return peek_scalar(); }
if (!is_at_start()) { return peek_start(); }
assert_at_root();
auto result = _json_iter->advance();
@ -456,7 +449,7 @@ simdjson_really_inline const uint8_t *value_iterator::advance_root_scalar(const
}
simdjson_really_inline const uint8_t *value_iterator::advance_non_root_scalar(const char *type) const noexcept {
logger::log_value(*_json_iter, _start_position, depth(), type);
if (!is_at_start()) { return peek_scalar(); }
if (!is_at_start()) { return peek_start(); }
assert_at_non_root_start();
auto result = _json_iter->advance();
@ -472,6 +465,9 @@ simdjson_really_inline error_code value_iterator::incorrect_type_error(const cha
simdjson_really_inline bool value_iterator::is_at_start() const noexcept {
return _json_iter->token.index == _start_position;
}
simdjson_really_inline bool value_iterator::is_at_container_start() const noexcept {
return _json_iter->token.index == _start_position + 1;
}
simdjson_really_inline void value_iterator::assert_at_start() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index == _start_position );
@ -479,6 +475,12 @@ simdjson_really_inline void value_iterator::assert_at_start() const noexcept {
SIMDJSON_ASSUME( _depth > 0 );
}
simdjson_really_inline void value_iterator::assert_at_container_start() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index == _start_position + 1 );
SIMDJSON_ASSUME( _json_iter->_depth == _depth );
SIMDJSON_ASSUME( _depth > 0 );
}
simdjson_really_inline void value_iterator::assert_at_next() const noexcept {
SIMDJSON_ASSUME( _json_iter->token.index > _start_position );
SIMDJSON_ASSUME( _json_iter->_depth == _depth );

View File

@ -208,13 +208,6 @@ public:
* @error INCORRECT_TYPE If there is no [.
*/
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> start_array() noexcept;
/**
* Check for an opening [ and start an array iteration.
*
* @returns Whether the array had any elements (returns false for empty).
* @error INCORRECT_TYPE If there is no [.
*/
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> try_start_array() noexcept;
/**
* Start an array iteration after the user has already checked and moved past the [.
@ -278,16 +271,19 @@ protected:
simdjson_really_inline bool parse_null(const uint8_t *json) const noexcept;
simdjson_really_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
simdjson_really_inline const uint8_t *peek_scalar() const noexcept;
simdjson_really_inline uint32_t peek_scalar_length() const noexcept;
simdjson_really_inline const uint8_t *advance_scalar(const char *type) const noexcept;
simdjson_really_inline const uint8_t *peek_start() const noexcept;
simdjson_really_inline uint32_t peek_start_length() const noexcept;
simdjson_really_inline const uint8_t *advance_start(const char *type) const noexcept;
simdjson_really_inline const uint8_t *advance_container_start(const char *type) const noexcept;
simdjson_really_inline const uint8_t *advance_root_scalar(const char *type) const noexcept;
simdjson_really_inline const uint8_t *advance_non_root_scalar(const char *type) const noexcept;
simdjson_really_inline error_code incorrect_type_error(const char *message) const noexcept;
simdjson_really_inline bool is_at_start() const noexcept;
simdjson_really_inline bool is_at_container_start() const noexcept;
simdjson_really_inline void assert_at_start() const noexcept;
simdjson_really_inline void assert_at_container_start() const noexcept;
simdjson_really_inline void assert_at_root() const noexcept;
simdjson_really_inline void assert_at_child() const noexcept;
simdjson_really_inline void assert_at_next() const noexcept;

View File

@ -4,14 +4,16 @@ include_directories(..)
add_subdirectory(compilation_failure_tests)
add_cpp_test(ondemand_active_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_array_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_compilation_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_dom_api_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_error_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_key_string_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_number_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_object_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_ordering_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_parse_api_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_readme_examples LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_scalar_tests LABELS ondemand acceptance per_implementation)
add_cpp_test(ondemand_twitter_tests LABELS ondemand acceptance per_implementation)
if(HAVE_POSIX_FORK AND HAVE_POSIX_WAIT) # assert tests use fork and wait, which aren't on MSVC
@ -20,8 +22,8 @@ endif()
# Copy the simdjson dll into the tests directory
if(MSVC)
add_custom_command(TARGET ondemand_dom_api_tests POST_BUILD # Adds a post-build event
add_custom_command(TARGET ondemand_parse_api_tests POST_BUILD # Adds a post-build event
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
"$<TARGET_FILE:simdjson>" # <--this is in-file
"$<TARGET_FILE_DIR:ondemand_dom_api_tests>") # <--this is out-file path
"$<TARGET_FILE_DIR:ondemand_parse_api_tests>") # <--this is out-file path
endif(MSVC)

View File

@ -0,0 +1,275 @@
#include "simdjson.h"
#include "test_ondemand.h"
using namespace simdjson;
namespace array_tests {
using namespace std;
bool iterate_array() {
TEST_START();
const auto json = R"([ 1, 10, 100 ])"_padded;
const uint64_t expected_value[] = { 1, 10, 100 };
SUBTEST("ondemand::array", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::array array;
ASSERT_SUCCESS( doc_result.get(array) );
size_t i=0;
for (auto value : array) {
int64_t actual;
ASSERT_SUCCESS( value.get(actual) );
ASSERT_EQUAL(actual, expected_value[i]);
i++;
}
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("simdjson_result<ondemand::array>", test_ondemand_doc(json, [&](auto doc_result) {
simdjson_result<ondemand::array> array = doc_result.get_array();
size_t i=0;
for (simdjson_unused auto value : array) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
size_t i=0;
for (simdjson_unused auto value : doc) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
size_t i=0;
for (simdjson_unused auto value : doc_result) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
TEST_SUCCEED();
}
bool iterate_array_partial_children() {
TEST_START();
auto json = R"(
[
0,
[],
{},
{ "x": 3, "y": 33 },
{ "x": 4, "y": 44 },
{ "x": 5, "y": 55 },
{ "x": 6, "y": 66 },
[ 7, 77, 777 ],
[ 8, 88, 888 ],
{ "a": [ { "b": [ 9, 99 ], "c": 999 }, 9999 ], "d": 99999 },
10
]
)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
size_t i = 0;
for (auto value : doc_result) {
ASSERT_SUCCESS(value);
switch (i) {
case 0: {
std::cout << " - After ignoring empty scalar ..." << std::endl;
break;
}
case 1: {
std::cout << " - After ignoring empty array ..." << std::endl;
break;
}
case 2: {
std::cout << " - After ignoring empty object ..." << std::endl;
break;
}
// Break after using first value in child object
case 3: {
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
uint64_t x;
ASSERT_SUCCESS( child_field.value().get(x) );
ASSERT_EQUAL(x, 3);
break; // Break after the first value
}
std::cout << " - After using first value in child object ..." << std::endl;
break;
}
// Break without using first value in child object
case 4: {
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
break;
}
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
break;
}
// Only look up one field in child object
case 5: {
uint64_t x;
ASSERT_SUCCESS( value["x"].get(x) );
ASSERT_EQUAL( x, 5 );
std::cout << " - After looking up one field in child object ..." << std::endl;
break;
}
// Only look up one field in child object, but don't use it
case 6: {
ASSERT_SUCCESS( value["x"] );
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
break;
}
// Break after first value in child array
case 7: {
for (auto [ child_value, error ] : value) {
ASSERT_SUCCESS(error);
uint64_t x;
ASSERT_SUCCESS( child_value.get(x) );
ASSERT_EQUAL( x, 7 );
break;
}
std::cout << " - After using first value in child array ..." << std::endl;
break;
}
// Break without using first value in child array
case 8: {
for (auto child_value : value) {
ASSERT_SUCCESS(child_value);
break;
}
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
break;
}
// Break out of multiple child loops
case 9: {
for (auto child1 : value.get_object()) {
for (auto child2 : child1.value().get_array()) {
for (auto child3 : child2.get_object()) {
for (auto child4 : child3.value().get_array()) {
uint64_t x;
ASSERT_SUCCESS( child4.get(x) );
ASSERT_EQUAL( x, 9 );
break;
}
break;
}
break;
}
break;
}
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
break;
}
// Test the actual value
case 10: {
uint64_t actual_value;
ASSERT_SUCCESS( value.get(actual_value) );
ASSERT_EQUAL( actual_value, 10 );
break;
}
}
i++;
}
ASSERT_EQUAL( i, 11 ); // Make sure we found all the keys we expected
return true;
}));
return true;
}
bool iterate_empty_array() {
TEST_START();
auto json = "[]"_padded;
SUBTEST("ondemand::array", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::array array;
ASSERT_SUCCESS( doc_result.get(array) );
for (simdjson_unused auto value : array) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("simdjson_result<ondemand::array>", test_ondemand_doc(json, [&](auto doc_result) {
simdjson_result<ondemand::array> array_result = doc_result.get_array();
for (simdjson_unused auto value : array_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
for (simdjson_unused auto value : doc) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
for (simdjson_unused auto value : doc_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
TEST_SUCCEED();
}
#if SIMDJSON_EXCEPTIONS
bool iterate_array_exception() {
TEST_START();
auto json = R"([ 1, 10, 100 ])"_padded;
const uint64_t expected_value[] = { 1, 10, 100 };
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
size_t i=0;
for (int64_t actual : doc_result) { ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
TEST_SUCCEED();
}
bool iterate_empty_object_exception() {
TEST_START();
auto json = R"({})"_padded;
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
for (simdjson_unused ondemand::field field : doc_result.get_object()) {
TEST_FAIL("Unexpected field");
}
return true;
}));
TEST_SUCCEED();
}
bool iterate_empty_array_exception() {
TEST_START();
auto json = "[]"_padded;
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
for (simdjson_unused ondemand::value value : doc_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
TEST_SUCCEED();
}
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return
iterate_array() &&
iterate_empty_array() &&
iterate_array_partial_children() &&
#if SIMDJSON_EXCEPTIONS
iterate_array_exception() &&
#endif // SIMDJSON_EXCEPTIONS
true;
}
} // namespace dom_api_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, array_tests::run);
}

View File

@ -39,9 +39,9 @@ namespace error_tests {
TEST_START();
TEST_CAST_ERROR("[]", object, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", int64, NUMBER_ERROR);
TEST_CAST_ERROR("[]", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("[]", double, NUMBER_ERROR);
TEST_CAST_ERROR("[]", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", double, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", string, INCORRECT_TYPE);
TEST_CAST_ERROR("[]", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -51,9 +51,9 @@ namespace error_tests {
TEST_START();
TEST_CAST_ERROR("{}", array, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", int64, NUMBER_ERROR);
TEST_CAST_ERROR("{}", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("{}", double, NUMBER_ERROR);
TEST_CAST_ERROR("{}", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", double, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", string, INCORRECT_TYPE);
TEST_CAST_ERROR("{}", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -63,9 +63,9 @@ namespace error_tests {
TEST_START();
TEST_CAST_ERROR("true", array, INCORRECT_TYPE);
TEST_CAST_ERROR("true", object, INCORRECT_TYPE);
TEST_CAST_ERROR("true", int64, NUMBER_ERROR);
TEST_CAST_ERROR("true", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("true", double, NUMBER_ERROR);
TEST_CAST_ERROR("true", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("true", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("true", double, INCORRECT_TYPE);
TEST_CAST_ERROR("true", string, INCORRECT_TYPE);
TEST_CAST_ERROR("true", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -75,9 +75,9 @@ namespace error_tests {
TEST_START();
TEST_CAST_ERROR("false", array, INCORRECT_TYPE);
TEST_CAST_ERROR("false", object, INCORRECT_TYPE);
TEST_CAST_ERROR("false", int64, NUMBER_ERROR);
TEST_CAST_ERROR("false", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("false", double, NUMBER_ERROR);
TEST_CAST_ERROR("false", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("false", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("false", double, INCORRECT_TYPE);
TEST_CAST_ERROR("false", string, INCORRECT_TYPE);
TEST_CAST_ERROR("false", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -87,9 +87,9 @@ namespace error_tests {
TEST_START();
TEST_CAST_ERROR("null", array, INCORRECT_TYPE);
TEST_CAST_ERROR("null", object, INCORRECT_TYPE);
TEST_CAST_ERROR("null", int64, NUMBER_ERROR);
TEST_CAST_ERROR("null", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("null", double, NUMBER_ERROR);
TEST_CAST_ERROR("null", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("null", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("null", double, INCORRECT_TYPE);
TEST_CAST_ERROR("null", string, INCORRECT_TYPE);
TEST_CAST_ERROR("null", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -110,7 +110,7 @@ namespace error_tests {
TEST_CAST_ERROR("-1", array, INCORRECT_TYPE);
TEST_CAST_ERROR("-1", object, INCORRECT_TYPE);
TEST_CAST_ERROR("-1", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("-1", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("-1", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("-1", string, INCORRECT_TYPE);
TEST_CAST_ERROR("-1", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -121,8 +121,8 @@ namespace error_tests {
TEST_CAST_ERROR("1.1", array, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", object, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", int64, NUMBER_ERROR);
TEST_CAST_ERROR("1.1", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("1.1", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", string, INCORRECT_TYPE);
TEST_CAST_ERROR("1.1", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -133,8 +133,8 @@ namespace error_tests {
TEST_CAST_ERROR("-9223372036854775809", array, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", object, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", int64, NUMBER_ERROR);
TEST_CAST_ERROR("-9223372036854775809", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("-9223372036854775809", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", string, INCORRECT_TYPE);
TEST_CAST_ERROR("-9223372036854775809", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -146,7 +146,7 @@ namespace error_tests {
TEST_CAST_ERROR("9223372036854775808", object, INCORRECT_TYPE);
TEST_CAST_ERROR("9223372036854775808", bool, INCORRECT_TYPE);
// TODO BUG: this should be an error but is presently not
// TEST_CAST_ERROR("9223372036854775808", int64, NUMBER_ERROR);
// TEST_CAST_ERROR("9223372036854775808", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("9223372036854775808", string, INCORRECT_TYPE);
TEST_CAST_ERROR("9223372036854775808", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -157,9 +157,8 @@ namespace error_tests {
TEST_CAST_ERROR("18446744073709551616", array, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", object, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", bool, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", int64, NUMBER_ERROR);
// TODO BUG: this should be an error but is presently not
// TEST_CAST_ERROR("18446744073709551616", uint64, NUMBER_ERROR);
TEST_CAST_ERROR("18446744073709551616", int64, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", uint64, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", string, INCORRECT_TYPE);
TEST_CAST_ERROR("18446744073709551616", raw_json_string, INCORRECT_TYPE);
TEST_SUCCEED();
@ -238,43 +237,43 @@ namespace error_tests {
bool top_level_array_iterate_error() {
TEST_START();
ONDEMAND_SUBTEST("missing comma", "[1 1]", assert_iterate(doc, { int64_t(1) }, { TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", "[1,,1]", assert_iterate(doc, { int64_t(1) }, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", "[,]", assert_iterate(doc, { NUMBER_ERROR }));
ONDEMAND_SUBTEST("extra comma ", "[,,]", assert_iterate(doc, { NUMBER_ERROR, NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", "[1,,1]", assert_iterate(doc, { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", "[,]", assert_iterate(doc, { INCORRECT_TYPE }));
ONDEMAND_SUBTEST("extra comma ", "[,,]", assert_iterate(doc, { INCORRECT_TYPE, INCORRECT_TYPE, TAPE_ERROR }));
TEST_SUCCEED();
}
bool top_level_array_iterate_unclosed_error() {
TEST_START();
ONDEMAND_SUBTEST("unclosed extra comma", "[,", assert_iterate(doc, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1 ", assert_iterate(doc, { int64_t(1) }, { TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed extra comma", "[,", assert_iterate(doc, { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1 ", assert_iterate(doc, { int64_t(1) }, { TAPE_ERROR }));
// TODO These pass the user values that may run past the end of the buffer if they aren't careful
// In particular, if the padding is decorated with the wrong values, we could cause overrun!
ONDEMAND_SUBTEST("unclosed extra comma", "[,,", assert_iterate(doc, { NUMBER_ERROR, NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1,", assert_iterate(doc, { int64_t(1) }, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1", assert_iterate(doc, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[", assert_iterate(doc, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed extra comma", "[,,", assert_iterate(doc, { INCORRECT_TYPE, INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1,", assert_iterate(doc, { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[1", assert_iterate(doc, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", "[", assert_iterate(doc, { INCORRECT_TYPE, TAPE_ERROR }));
TEST_SUCCEED();
}
bool array_iterate_error() {
TEST_START();
ONDEMAND_SUBTEST("missing comma", R"({ "a": [1 1] })", assert_iterate(doc["a"], { int64_t(1) }, { TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [1,,1] })", assert_iterate(doc["a"], { int64_t(1) }, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [1,,] })", assert_iterate(doc["a"], { int64_t(1) }, { NUMBER_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [,] })", assert_iterate(doc["a"], { NUMBER_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [,,] })", assert_iterate(doc["a"], { NUMBER_ERROR, NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [1,,1] })", assert_iterate(doc["a"], { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [1,,] })", assert_iterate(doc["a"], { int64_t(1) }, { INCORRECT_TYPE }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [,] })", assert_iterate(doc["a"], { INCORRECT_TYPE }));
ONDEMAND_SUBTEST("extra comma ", R"({ "a": [,,] })", assert_iterate(doc["a"], { INCORRECT_TYPE, INCORRECT_TYPE, TAPE_ERROR }));
TEST_SUCCEED();
}
bool array_iterate_unclosed_error() {
TEST_START();
ONDEMAND_SUBTEST("unclosed extra comma", R"({ "a": [,)", assert_iterate(doc["a"], { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed extra comma", R"({ "a": [,,)", assert_iterate(doc["a"], { NUMBER_ERROR, NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed extra comma", R"({ "a": [,)", assert_iterate(doc["a"], { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed extra comma", R"({ "a": [,,)", assert_iterate(doc["a"], { INCORRECT_TYPE, INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [1 )", assert_iterate(doc["a"], { int64_t(1) }, { TAPE_ERROR }));
// TODO These pass the user values that may run past the end of the buffer if they aren't careful
// In particular, if the padding is decorated with the wrong values, we could cause overrun!
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [1,)", assert_iterate(doc["a"], { int64_t(1) }, { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [1,)", assert_iterate(doc["a"], { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [1)", assert_iterate(doc["a"], { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [)", assert_iterate(doc["a"], { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed ", R"({ "a": [)", assert_iterate(doc["a"], { INCORRECT_TYPE, TAPE_ERROR }));
TEST_SUCCEED();
}
@ -317,7 +316,7 @@ namespace error_tests {
TEST_START();
ONDEMAND_SUBTEST("missing colon", R"({ "a" 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
ONDEMAND_SUBTEST("missing key ", R"({ : 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
ONDEMAND_SUBTEST("missing value", R"({ "a": , "b": 2 })", assert_iterate_object(doc.get_object(), { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("missing value", R"({ "a": , "b": 2 })", assert_iterate_object(doc.get_object(), { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("missing comma", R"({ "a": 1 "b": 2 })", assert_iterate_object(doc.get_object(), { "a" }, { int64_t(1) }, { TAPE_ERROR }));
TEST_SUCCEED();
}
@ -337,7 +336,7 @@ namespace error_tests {
// TODO These next two pass the user a value that may run past the end of the buffer if they aren't careful.
// In particular, if the padding is decorated with the wrong values, we could cause overrun!
ONDEMAND_SUBTEST("unclosed", R"({ "a": 1 )", assert_iterate_object(doc.get_object(), { "a" }, { int64_t(1) }, { TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed", R"({ "a": )", assert_iterate_object(doc.get_object(), { NUMBER_ERROR, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed", R"({ "a": )", assert_iterate_object(doc.get_object(), { INCORRECT_TYPE, TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed", R"({ "a" )", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
ONDEMAND_SUBTEST("unclosed", R"({ )", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
TEST_SUCCEED();
@ -399,6 +398,177 @@ namespace error_tests {
TEST_SUCCEED();
}
bool get_fail_then_succeed_bool() {
TEST_START();
auto json = R"({ "val" : true })"_padded;
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
simdjson_result<ondemand::value> val = doc["val"];
// Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() );
TEST_SUCCEED();
}));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() );
TEST_SUCCEED();
}));
json = R"(true)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) {
// Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool());
TEST_SUCCEED();
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
ondemand::document val;
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
ASSERT_EQUAL( val.is_null(), false );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), false );
ASSERT_SUCCESS( val.get_bool() );
TEST_SUCCEED();
}));
TEST_SUCCEED();
}
bool get_fail_then_succeed_null() {
TEST_START();
auto json = R"({ "val" : null })"_padded;
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc) {
simdjson_result<ondemand::value> val = doc["val"];
// Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true );
TEST_SUCCEED();
}));
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc) {
ondemand::value val;
ASSERT_SUCCESS( doc["val"].get(val) );
// Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true );
TEST_SUCCEED();
}));
json = R"(null)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](simdjson_result<ondemand::document> val) {
// Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true );
TEST_SUCCEED();
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc) {
ondemand::document val;
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
ASSERT_EQUAL( val.is_null(), true );
TEST_SUCCEED();
}));
//
// Do it again for bool
//
TEST_SUCCEED();
}
bool run() {
return
empty_document_error() &&
@ -416,6 +586,8 @@ namespace error_tests {
object_lookup_miss_unclosed_error() &&
object_lookup_miss_wrong_key_type_error() &&
object_lookup_miss_next_error() &&
get_fail_then_succeed_bool() &&
get_fail_then_succeed_null() &&
true;
}
}

View File

@ -3,7 +3,7 @@
using namespace simdjson;
namespace dom_api_tests {
namespace object_tests {
using namespace std;
bool iterate_object() {
@ -39,48 +39,6 @@ namespace dom_api_tests {
TEST_SUCCEED();
}
bool iterate_array() {
TEST_START();
const auto json = R"([ 1, 10, 100 ])"_padded;
const uint64_t expected_value[] = { 1, 10, 100 };
SUBTEST("ondemand::array", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::array array;
ASSERT_SUCCESS( doc_result.get(array) );
size_t i=0;
for (auto value : array) {
int64_t actual;
ASSERT_SUCCESS( value.get(actual) );
ASSERT_EQUAL(actual, expected_value[i]);
i++;
}
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("simdjson_result<ondemand::array>", test_ondemand_doc(json, [&](auto doc_result) {
simdjson_result<ondemand::array> array = doc_result.get_array();
size_t i=0;
for (simdjson_unused auto value : array) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
size_t i=0;
for (simdjson_unused auto value : doc) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
size_t i=0;
for (simdjson_unused auto value : doc_result) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
TEST_SUCCEED();
}
bool iterate_object_partial_children() {
TEST_START();
auto json = R"(
@ -235,143 +193,6 @@ namespace dom_api_tests {
return true;
}
bool iterate_array_partial_children() {
TEST_START();
auto json = R"(
[
0,
[],
{},
{ "x": 3, "y": 33 },
{ "x": 4, "y": 44 },
{ "x": 5, "y": 55 },
{ "x": 6, "y": 66 },
[ 7, 77, 777 ],
[ 8, 88, 888 ],
{ "a": [ { "b": [ 9, 99 ], "c": 999 }, 9999 ], "d": 99999 },
10
]
)"_padded;
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
size_t i = 0;
for (auto value : doc_result) {
ASSERT_SUCCESS(value);
switch (i) {
case 0: {
std::cout << " - After ignoring empty scalar ..." << std::endl;
break;
}
case 1: {
std::cout << " - After ignoring empty array ..." << std::endl;
break;
}
case 2: {
std::cout << " - After ignoring empty object ..." << std::endl;
break;
}
// Break after using first value in child object
case 3: {
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
uint64_t x;
ASSERT_SUCCESS( child_field.value().get(x) );
ASSERT_EQUAL(x, 3);
break; // Break after the first value
}
std::cout << " - After using first value in child object ..." << std::endl;
break;
}
// Break without using first value in child object
case 4: {
for (auto [ child_field, error ] : value.get_object()) {
ASSERT_SUCCESS(error);
ASSERT_EQUAL(child_field.key(), "x");
break;
}
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
break;
}
// Only look up one field in child object
case 5: {
uint64_t x;
ASSERT_SUCCESS( value["x"].get(x) );
ASSERT_EQUAL( x, 5 );
std::cout << " - After looking up one field in child object ..." << std::endl;
break;
}
// Only look up one field in child object, but don't use it
case 6: {
ASSERT_SUCCESS( value["x"] );
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
break;
}
// Break after first value in child array
case 7: {
for (auto [ child_value, error ] : value) {
ASSERT_SUCCESS(error);
uint64_t x;
ASSERT_SUCCESS( child_value.get(x) );
ASSERT_EQUAL( x, 7 );
break;
}
std::cout << " - After using first value in child array ..." << std::endl;
break;
}
// Break without using first value in child array
case 8: {
for (auto child_value : value) {
ASSERT_SUCCESS(child_value);
break;
}
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
break;
}
// Break out of multiple child loops
case 9: {
for (auto child1 : value.get_object()) {
for (auto child2 : child1.value().get_array()) {
for (auto child3 : child2.get_object()) {
for (auto child4 : child3.value().get_array()) {
uint64_t x;
ASSERT_SUCCESS( child4.get(x) );
ASSERT_EQUAL( x, 9 );
break;
}
break;
}
break;
}
break;
}
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
break;
}
// Test the actual value
case 10: {
uint64_t actual_value;
ASSERT_SUCCESS( value.get(actual_value) );
ASSERT_EQUAL( actual_value, 10 );
break;
}
}
i++;
}
ASSERT_EQUAL( i, 11 ); // Make sure we found all the keys we expected
return true;
}));
return true;
}
bool object_index_partial_children() {
TEST_START();
auto json = R"(
@ -635,234 +456,6 @@ namespace dom_api_tests {
TEST_SUCCEED();
}
bool iterate_empty_array() {
TEST_START();
auto json = "[]"_padded;
SUBTEST("ondemand::array", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::array array;
ASSERT_SUCCESS( doc_result.get(array) );
for (simdjson_unused auto value : array) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("simdjson_result<ondemand::array>", test_ondemand_doc(json, [&](auto doc_result) {
simdjson_result<ondemand::array> array_result = doc_result.get_array();
for (simdjson_unused auto value : array_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
for (simdjson_unused auto value : doc) { TEST_FAIL("Unexpected value"); }
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
for (simdjson_unused auto value : doc_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
TEST_SUCCEED();
}
template<typename T>
bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) {
std::cout << "- JSON: " << json << endl;
SUBTEST( "simdjson_result<document>", test_ondemand_doc(json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
SUBTEST( "document", test_ondemand_doc(json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
{
padded_string whitespace_json = std::string(json) + " ";
std::cout << "- JSON: " << whitespace_json << endl;
SUBTEST( "simdjson_result<document>", test_ondemand_doc(whitespace_json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
SUBTEST( "document", test_ondemand_doc(whitespace_json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
}
{
padded_string array_json = std::string("[") + std::string(json) + "]";
std::cout << "- JSON: " << array_json << endl;
SUBTEST( "simdjson_result<value>", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
T actual;
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
SUBTEST( "value", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
ondemand::value val;
ASSERT_SUCCESS( val_result.get(val) );
T actual;
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
}
{
padded_string whitespace_array_json = std::string("[") + std::string(json) + " ]";
std::cout << "- JSON: " << whitespace_array_json << endl;
SUBTEST( "simdjson_result<value>", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
T actual;
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
SUBTEST( "value", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
ondemand::value val;
ASSERT_SUCCESS( val_result.get(val) );
T actual;
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
}
TEST_SUCCEED();
}
bool string_value() {
TEST_START();
// We can't retrieve a small string twice because it will blow out the string buffer
if (!test_scalar_value(R"("hi")"_padded, std::string_view("hi"), false)) { return false; }
// ... unless the document is big enough to have a big string buffer :)
if (!test_scalar_value(R"("hi" )"_padded, std::string_view("hi"))) { return false; }
TEST_SUCCEED();
}
bool numeric_values() {
TEST_START();
if (!test_scalar_value<int64_t> ("0"_padded, 0)) { return false; }
if (!test_scalar_value<uint64_t>("0"_padded, 0)) { return false; }
if (!test_scalar_value<double> ("0"_padded, 0)) { return false; }
if (!test_scalar_value<int64_t> ("1"_padded, 1)) { return false; }
if (!test_scalar_value<uint64_t>("1"_padded, 1)) { return false; }
if (!test_scalar_value<double> ("1"_padded, 1)) { return false; }
if (!test_scalar_value<int64_t> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value<double> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value<double> ("1.1"_padded, 1.1)) { return false; }
TEST_SUCCEED();
}
bool boolean_values() {
TEST_START();
if (!test_scalar_value<bool> ("true"_padded, true)) { return false; }
if (!test_scalar_value<bool> ("false"_padded, false)) { return false; }
TEST_SUCCEED();
}
bool null_value() {
TEST_START();
auto json = "null"_padded;
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
ASSERT_EQUAL( doc.is_null(), true );
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( doc_result.is_null(), true );
return true;
}));
json = "[null]"_padded;
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0;
for (auto value_result : doc_result) {
ondemand::value value;
ASSERT_SUCCESS( value_result.get(value) );
ASSERT_EQUAL( value.is_null(), true );
count++;
}
ASSERT_EQUAL( count, 1 );
return true;
}));
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0;
for (auto value_result : doc_result) {
ASSERT_EQUAL( value_result.is_null(), true );
count++;
}
ASSERT_EQUAL( count, 1 );
return true;
}));
return true;
}
bool object_index() {
TEST_START();
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
@ -1140,20 +733,6 @@ namespace dom_api_tests {
TEST_SUCCEED();
}
bool iterate_array_exception() {
TEST_START();
auto json = R"([ 1, 10, 100 ])"_padded;
const uint64_t expected_value[] = { 1, 10, 100 };
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
size_t i=0;
for (int64_t actual : doc_result) { ASSERT_EQUAL(actual, expected_value[i]); i++; }
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
return true;
}));
TEST_SUCCEED();
}
bool iterate_empty_object_exception() {
TEST_START();
auto json = R"({})"_padded;
@ -1168,65 +747,6 @@ namespace dom_api_tests {
TEST_SUCCEED();
}
bool iterate_empty_array_exception() {
TEST_START();
auto json = "[]"_padded;
ASSERT_TRUE(test_ondemand_doc(json, [&](auto doc_result) {
for (simdjson_unused ondemand::value value : doc_result) { TEST_FAIL("Unexpected value"); }
return true;
}));
TEST_SUCCEED();
}
template<typename T>
bool test_scalar_value_exception(const padded_string &json, const T &expected) {
std::cout << "- JSON: " << json << endl;
SUBTEST( "document", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( expected, T(doc_result) );
return true;
}));
padded_string array_json = std::string("[") + std::string(json) + "]";
std::cout << "- JSON: " << array_json << endl;
SUBTEST( "value", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (T actual : doc_result) {
ASSERT_EQUAL( expected, actual );
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
TEST_SUCCEED();
}
bool string_value_exception() {
TEST_START();
return test_scalar_value_exception(R"("hi")"_padded, std::string_view("hi"));
}
bool numeric_values_exception() {
TEST_START();
if (!test_scalar_value_exception<int64_t> ("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<uint64_t>("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<double> ("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<int64_t> ("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<uint64_t>("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<double> ("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<int64_t> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value_exception<double> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value_exception<double> ("1.1"_padded, 1.1)) { return false; }
TEST_SUCCEED();
}
bool boolean_values_exception() {
TEST_START();
if (!test_scalar_value_exception<bool> ("true"_padded, true)) { return false; }
if (!test_scalar_value_exception<bool> ("false"_padded, false)) { return false; }
TEST_SUCCEED();
}
bool object_index_exception() {
TEST_START();
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
@ -1255,35 +775,24 @@ namespace dom_api_tests {
bool run() {
return
iterate_array() &&
iterate_empty_array() &&
iterate_object() &&
iterate_empty_object() &&
string_value() &&
numeric_values() &&
boolean_values() &&
null_value() &&
object_index() &&
object_find_field_unordered() &&
object_find_field() &&
nested_object_index() &&
iterate_object_partial_children() &&
iterate_array_partial_children() &&
object_index_partial_children() &&
#if SIMDJSON_EXCEPTIONS
iterate_object_exception() &&
iterate_array_exception() &&
string_value_exception() &&
numeric_values_exception() &&
boolean_values_exception() &&
object_index_exception() &&
nested_object_index_exception() &&
#endif // SIMDJSON_EXCEPTIONS
true;
}
} // namespace dom_api_tests
} // namespace object_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, dom_api_tests::run);
return test_main(argc, argv, object_tests::run);
}

View File

@ -0,0 +1,278 @@
#include "simdjson.h"
#include "test_ondemand.h"
using namespace simdjson;
namespace scalar_tests {
using namespace std;
template<typename T>
bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) {
std::cout << "- JSON: " << json << endl;
SUBTEST( "simdjson_result<document>", test_ondemand_doc(json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
SUBTEST( "document", test_ondemand_doc(json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
{
padded_string whitespace_json = std::string(json) + " ";
std::cout << "- JSON: " << whitespace_json << endl;
SUBTEST( "simdjson_result<document>", test_ondemand_doc(whitespace_json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
SUBTEST( "document", test_ondemand_doc(whitespace_json, [&](auto doc_result) {
T actual;
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( doc_result.get(actual) );
ASSERT_EQUAL( expected, actual );
}
return true;
}));
}
{
padded_string array_json = std::string("[") + std::string(json) + "]";
std::cout << "- JSON: " << array_json << endl;
SUBTEST( "simdjson_result<value>", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
T actual;
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
SUBTEST( "value", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
ondemand::value val;
ASSERT_SUCCESS( val_result.get(val) );
T actual;
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
}
{
padded_string whitespace_array_json = std::string("[") + std::string(json) + " ]";
std::cout << "- JSON: " << whitespace_array_json << endl;
SUBTEST( "simdjson_result<value>", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
T actual;
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val_result.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
SUBTEST( "value", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) {
int count = 0;
for (simdjson_result<ondemand::value> val_result : doc_result) {
ondemand::value val;
ASSERT_SUCCESS( val_result.get(val) );
T actual;
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
// Test it twice (scalars can be retrieved more than once)
if (test_twice) {
ASSERT_SUCCESS( val.get(actual) );
ASSERT_EQUAL(expected, actual);
}
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
}
TEST_SUCCEED();
}
bool string_value() {
TEST_START();
// We can't retrieve a small string twice because it will blow out the string buffer
if (!test_scalar_value(R"("hi")"_padded, std::string_view("hi"), false)) { return false; }
// ... unless the document is big enough to have a big string buffer :)
if (!test_scalar_value(R"("hi" )"_padded, std::string_view("hi"))) { return false; }
TEST_SUCCEED();
}
bool numeric_values() {
TEST_START();
if (!test_scalar_value<int64_t> ("0"_padded, 0)) { return false; }
if (!test_scalar_value<uint64_t>("0"_padded, 0)) { return false; }
if (!test_scalar_value<double> ("0"_padded, 0)) { return false; }
if (!test_scalar_value<int64_t> ("1"_padded, 1)) { return false; }
if (!test_scalar_value<uint64_t>("1"_padded, 1)) { return false; }
if (!test_scalar_value<double> ("1"_padded, 1)) { return false; }
if (!test_scalar_value<int64_t> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value<double> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value<double> ("1.1"_padded, 1.1)) { return false; }
TEST_SUCCEED();
}
bool boolean_values() {
TEST_START();
if (!test_scalar_value<bool> ("true"_padded, true)) { return false; }
if (!test_scalar_value<bool> ("false"_padded, false)) { return false; }
TEST_SUCCEED();
}
bool null_value() {
TEST_START();
auto json = "null"_padded;
SUBTEST("ondemand::document", test_ondemand_doc(json, [&](auto doc_result) {
ondemand::document doc;
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
ASSERT_EQUAL( doc.is_null(), true );
return true;
}));
SUBTEST("simdjson_result<ondemand::document>", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( doc_result.is_null(), true );
return true;
}));
json = "[null]"_padded;
SUBTEST("ondemand::value", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0;
for (auto value_result : doc_result) {
ondemand::value value;
ASSERT_SUCCESS( value_result.get(value) );
ASSERT_EQUAL( value.is_null(), true );
count++;
}
ASSERT_EQUAL( count, 1 );
return true;
}));
SUBTEST("simdjson_result<ondemand::value>", test_ondemand_doc(json, [&](auto doc_result) {
int count = 0;
for (auto value_result : doc_result) {
ASSERT_EQUAL( value_result.is_null(), true );
count++;
}
ASSERT_EQUAL( count, 1 );
return true;
}));
return true;
}
#if SIMDJSON_EXCEPTIONS
template<typename T>
bool test_scalar_value_exception(const padded_string &json, const T &expected) {
std::cout << "- JSON: " << json << endl;
SUBTEST( "document", test_ondemand_doc(json, [&](auto doc_result) {
ASSERT_EQUAL( expected, T(doc_result) );
return true;
}));
padded_string array_json = std::string("[") + std::string(json) + "]";
std::cout << "- JSON: " << array_json << endl;
SUBTEST( "value", test_ondemand_doc(array_json, [&](auto doc_result) {
int count = 0;
for (T actual : doc_result) {
ASSERT_EQUAL( expected, actual );
count++;
}
ASSERT_EQUAL(count, 1);
return true;
}));
TEST_SUCCEED();
}
bool string_value_exception() {
TEST_START();
return test_scalar_value_exception(R"("hi")"_padded, std::string_view("hi"));
}
bool numeric_values_exception() {
TEST_START();
if (!test_scalar_value_exception<int64_t> ("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<uint64_t>("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<double> ("0"_padded, 0)) { return false; }
if (!test_scalar_value_exception<int64_t> ("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<uint64_t>("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<double> ("1"_padded, 1)) { return false; }
if (!test_scalar_value_exception<int64_t> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value_exception<double> ("-1"_padded, -1)) { return false; }
if (!test_scalar_value_exception<double> ("1.1"_padded, 1.1)) { return false; }
TEST_SUCCEED();
}
bool boolean_values_exception() {
TEST_START();
if (!test_scalar_value_exception<bool> ("true"_padded, true)) { return false; }
if (!test_scalar_value_exception<bool> ("false"_padded, false)) { return false; }
TEST_SUCCEED();
}
#endif // SIMDJSON_EXCEPTIONS
bool run() {
return
string_value() &&
numeric_values() &&
boolean_values() &&
null_value() &&
#if SIMDJSON_EXCEPTIONS
string_value_exception() &&
numeric_values_exception() &&
boolean_values_exception() &&
#endif // SIMDJSON_EXCEPTIONS
true;
}
} // namespace scalar_tests
int main(int argc, char *argv[]) {
return test_main(argc, argv, scalar_tests::run);
}

View File

@ -48,7 +48,7 @@ template<typename T>
simdjson_really_inline bool assert_success(const T &actual, const char *operation = "result") {
simdjson::error_code error = to_error_code(actual);
if (error) {
std::cerr << "FAIL: " << operation << " returned error: " << error << std::endl;
std::cerr << "FAIL: " << operation << " returned error: " << error << " (" << int(error) << ")" << std::endl;
return false;
}
return true;