diff --git a/include/simdjson/generic/numberparsing.h b/include/simdjson/generic/numberparsing.h index 8779ea87..f2cf5df0 100644 --- a/include/simdjson/generic/numberparsing.h +++ b/include/simdjson/generic/numberparsing.h @@ -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 -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 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 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 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 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 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 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. diff --git a/include/simdjson/generic/ondemand/array-inl.h b/include/simdjson/generic/ondemand/array-inl.h index 3cd2fb87..f366e3bd 100644 --- a/include/simdjson/generic/ondemand/array-inl.h +++ b/include/simdjson/generic/ondemand/array-inl.h @@ -50,11 +50,6 @@ simdjson_really_inline simdjson_result array::start(value_iterator &iter) SIMDJSON_TRY( iter.start_array().get(has_value) ); return array(iter); } -simdjson_really_inline simdjson_result 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); diff --git a/include/simdjson/generic/ondemand/array.h b/include/simdjson/generic/ondemand/array.h index 739ebf9a..60f39852 100644 --- a/include/simdjson/generic/ondemand/array.h +++ b/include/simdjson/generic/ondemand/array.h @@ -41,14 +41,6 @@ protected: * @error INCORRECT_TYPE if the iterator is not at [. */ static simdjson_really_inline simdjson_result 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 try_start(value_iterator &iter) noexcept; /** * Begin array iteration. * diff --git a/include/simdjson/generic/ondemand/logger-inl.h b/include/simdjson/generic/ondemand/logger-inl.h index a7107d76..5466e15a 100644 --- a/include/simdjson/generic/ondemand/logger-inl.h +++ b/include/simdjson/generic/ondemand/logger-inl.h @@ -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"); diff --git a/include/simdjson/generic/ondemand/logger.h b/include/simdjson/generic/ondemand/logger.h index 4d657df3..8cb0cb77 100644 --- a/include/simdjson/generic/ondemand/logger.h +++ b/include/simdjson/generic/ondemand/logger.h @@ -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; diff --git a/include/simdjson/generic/ondemand/object-inl.h b/include/simdjson/generic/ondemand/object-inl.h index 83203001..8e5785ba 100644 --- a/include/simdjson/generic/ondemand/object-inl.h +++ b/include/simdjson/generic/ondemand/object-inl.h @@ -38,11 +38,6 @@ simdjson_really_inline simdjson_result object::start(value_iterator &ite SIMDJSON_TRY( iter.start_object().get(has_value) ); return object(iter); } -simdjson_really_inline simdjson_result 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; diff --git a/include/simdjson/generic/ondemand/object.h b/include/simdjson/generic/ondemand/object.h index f484b21b..f4a57db3 100644 --- a/include/simdjson/generic/ondemand/object.h +++ b/include/simdjson/generic/ondemand/object.h @@ -72,7 +72,6 @@ public: protected: static simdjson_really_inline simdjson_result start(value_iterator &iter) noexcept; - static simdjson_really_inline simdjson_result 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; diff --git a/include/simdjson/generic/ondemand/value-inl.h b/include/simdjson/generic/ondemand/value-inl.h index af2cfcc0..df5a5d12 100644 --- a/include/simdjson/generic/ondemand/value-inl.h +++ b/include/simdjson/generic/ondemand/value-inl.h @@ -13,26 +13,13 @@ simdjson_really_inline value value::resume(const value_iterator &iter) noexcept return iter; } -simdjson_really_inline simdjson_result value::get_array() && noexcept { +simdjson_really_inline simdjson_result value::get_array() noexcept { return array::start(iter); } -simdjson_really_inline simdjson_result value::get_array() & noexcept { - return array::try_start(iter); -} -simdjson_really_inline simdjson_result value::get_object() && noexcept { +simdjson_really_inline simdjson_result value::get_object() noexcept { return object::start(iter); } -simdjson_really_inline simdjson_result value::get_object() & noexcept { - return object::try_start(iter); -} -simdjson_really_inline simdjson_result value::start_or_resume_object() & noexcept { - if (iter.at_start()) { - return get_object(); - } else { - return object::resume(iter); - } -} -simdjson_really_inline simdjson_result value::start_or_resume_object() && noexcept { +simdjson_really_inline simdjson_result 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 value::get() & noexcept { return get_array(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_object(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_raw_json_string(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_string(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_double(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_uint64(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_int64(); } -template<> simdjson_really_inline simdjson_result value::get() & noexcept { return get_bool(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_array(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_object(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_raw_json_string(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_string(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_double(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_uint64(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_int64(); } +template<> simdjson_really_inline simdjson_result value::get() noexcept { return get_bool(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_array(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_object(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_raw_json_string(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_string(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_double(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_uint64(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_int64(); } -template<> simdjson_really_inline simdjson_result value::get() && noexcept { return std::forward(*this).get_bool(); } - -template simdjson_really_inline error_code value::get(T &out) & noexcept { +template simdjson_really_inline error_code value::get(T &out) noexcept { return get().get(out); } -template simdjson_really_inline error_code value::get(T &out) && noexcept { - return std::forward(*this).get().get(out); -} #if SIMDJSON_EXCEPTIONS -simdjson_really_inline value::operator array() && noexcept(false) { - return std::forward(*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(*this).get_array(); -} -simdjson_really_inline value::operator object() && noexcept(false) { - return std::forward(*this).get_object(); -} -simdjson_really_inline value::operator object() & noexcept(false) { - return std::forward(*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 value::end() & noexcept { return {}; } -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 { return start_or_resume_object().find_field(key); } -simdjson_really_inline simdjson_result value::find_field(std::string_view key) && noexcept { - return std::forward(*this).start_or_resume_object().find_field(key); -} -simdjson_really_inline simdjson_result value::find_field(const char *key) & noexcept { +simdjson_really_inline simdjson_result value::find_field(const char *key) noexcept { return start_or_resume_object().find_field(key); } -simdjson_really_inline simdjson_result value::find_field(const char *key) && noexcept { - return std::forward(*this).start_or_resume_object().find_field(key); -} -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 { return start_or_resume_object().find_field_unordered(key); } -simdjson_really_inline simdjson_result value::find_field_unordered(std::string_view key) && noexcept { - return std::forward(*this).start_or_resume_object().find_field_unordered(key); -} -simdjson_really_inline simdjson_result value::find_field_unordered(const char *key) & noexcept { +simdjson_really_inline simdjson_result value::find_field_unordered(const char *key) noexcept { return start_or_resume_object().find_field_unordered(key); } -simdjson_really_inline simdjson_result value::find_field_unordered(const char *key) && noexcept { - return std::forward(*this).start_or_resume_object().find_field_unordered(key); -} -simdjson_really_inline simdjson_result value::operator[](std::string_view key) & noexcept { +simdjson_really_inline simdjson_result value::operator[](std::string_view key) noexcept { return start_or_resume_object()[key]; } -simdjson_really_inline simdjson_result value::operator[](std::string_view key) && noexcept { - return std::forward(*this).start_or_resume_object()[key]; -} -simdjson_really_inline simdjson_result value::operator[](const char *key) & noexcept { +simdjson_really_inline simdjson_result value::operator[](const char *key) noexcept { return start_or_resume_object()[key]; } -simdjson_really_inline simdjson_result value::operator[](const char *key) && noexcept { - return std::forward(*this).start_or_resume_object()[key]; -} } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION @@ -197,73 +147,41 @@ simdjson_really_inline simdjson_result simdjson_result::find_field(std::string_view key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::find_field(std::string_view key) noexcept { if (error()) { return error(); } return first.find_field(key); } -simdjson_really_inline simdjson_result simdjson_result::find_field(std::string_view key) && noexcept { - if (error()) { return error(); } - return std::forward(first).find_field(key); -} -simdjson_really_inline simdjson_result simdjson_result::find_field(const char *key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::find_field(const char *key) noexcept { if (error()) { return error(); } return first.find_field(key); } -simdjson_really_inline simdjson_result simdjson_result::find_field(const char *key) && noexcept { - if (error()) { return error(); } - return std::forward(first).find_field(key); -} -simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) noexcept { if (error()) { return error(); } return first.find_field_unordered(key); } -simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(std::string_view key) && noexcept { - if (error()) { return error(); } - return std::forward(first).find_field_unordered(key); -} -simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(const char *key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(const char *key) noexcept { if (error()) { return error(); } return first.find_field_unordered(key); } -simdjson_really_inline simdjson_result simdjson_result::find_field_unordered(const char *key) && noexcept { - if (error()) { return error(); } - return std::forward(first).find_field_unordered(key); -} -simdjson_really_inline simdjson_result simdjson_result::operator[](std::string_view key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::operator[](std::string_view key) noexcept { if (error()) { return error(); } return first[key]; } -simdjson_really_inline simdjson_result simdjson_result::operator[](std::string_view key) && noexcept { - if (error()) { return error(); } - return std::forward(first)[key]; -} -simdjson_really_inline simdjson_result simdjson_result::operator[](const char *key) & noexcept { +simdjson_really_inline simdjson_result simdjson_result::operator[](const char *key) noexcept { if (error()) { return error(); } return first[key]; } -simdjson_really_inline simdjson_result simdjson_result::operator[](const char *key) && noexcept { - if (error()) { return error(); } - return std::forward(first)[key]; -} -simdjson_really_inline simdjson_result simdjson_result::get_array() & noexcept { +simdjson_really_inline simdjson_result simdjson_result::get_array() noexcept { if (error()) { return error(); } return first.get_array(); } -simdjson_really_inline simdjson_result simdjson_result::get_array() && noexcept { - if (error()) { return error(); } - return std::forward(first).get_array(); -} -simdjson_really_inline simdjson_result simdjson_result::get_object() & noexcept { +simdjson_really_inline simdjson_result simdjson_result::get_object() noexcept { if (error()) { return error(); } return first.get_object(); } -simdjson_really_inline simdjson_result simdjson_result::get_object() && noexcept { - if (error()) { return error(); } - return std::forward(first).get_object(); -} simdjson_really_inline simdjson_result simdjson_result::get_uint64() noexcept { if (error()) { return error(); } return first.get_uint64(); @@ -293,59 +211,34 @@ simdjson_really_inline bool simdjson_result simdjson_really_inline simdjson_result simdjson_result::get() & noexcept { +template simdjson_really_inline simdjson_result simdjson_result::get() noexcept { if (error()) { return error(); } return first.get(); } -template simdjson_really_inline simdjson_result simdjson_result::get() && noexcept { - if (error()) { return error(); } - return std::forward(first).get(); -} -template simdjson_really_inline error_code simdjson_result::get(T &out) & noexcept { +template simdjson_really_inline error_code simdjson_result::get(T &out) noexcept { if (error()) { return error(); } return first.get(out); } -template simdjson_really_inline error_code simdjson_result::get(T &out) && noexcept { - if (error()) { return error(); } - return std::forward(first).get(out); -} -template<> simdjson_really_inline simdjson_result simdjson_result::get() & noexcept { +template<> simdjson_really_inline simdjson_result simdjson_result::get() noexcept { if (error()) { return error(); } return std::move(first); } -template<> simdjson_really_inline simdjson_result simdjson_result::get() && noexcept { - if (error()) { return error(); } - return std::forward(first); -} -template<> simdjson_really_inline error_code simdjson_result::get(SIMDJSON_IMPLEMENTATION::ondemand::value &out) & noexcept { +template<> simdjson_really_inline error_code simdjson_result::get(SIMDJSON_IMPLEMENTATION::ondemand::value &out) noexcept { if (error()) { return error(); } out = first; return SUCCESS; } -template<> simdjson_really_inline error_code simdjson_result::get(SIMDJSON_IMPLEMENTATION::ondemand::value &out) && noexcept { - if (error()) { return error(); } - out = std::forward(first); - return SUCCESS; -} #if SIMDJSON_EXCEPTIONS -simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false) { +simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::array() noexcept(false) { if (error()) { throw simdjson_error(error()); } return first; } -simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::array() && noexcept(false) { - if (error()) { throw simdjson_error(error()); } - return std::forward(first); -} -simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false) { +simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::object() noexcept(false) { if (error()) { throw simdjson_error(error()); } return first; } -simdjson_really_inline simdjson_result::operator SIMDJSON_IMPLEMENTATION::ondemand::object() && noexcept(false) { - if (error()) { throw simdjson_error(error()); } - return std::forward(first); -} simdjson_really_inline simdjson_result::operator uint64_t() noexcept(false) { if (error()) { throw simdjson_error(error()); } return first; diff --git a/include/simdjson/generic/ondemand/value.h b/include/simdjson/generic/ondemand/value.h index 9b2dee87..fdeeafe1 100644 --- a/include/simdjson/generic/ondemand/value.h +++ b/include/simdjson/generic/ondemand/value.h @@ -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 simdjson_really_inline simdjson_result get() & noexcept; - /** @overload template simdjson_result get() & noexcept */ - template simdjson_really_inline simdjson_result get() && noexcept; + template simdjson_really_inline simdjson_result 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 simdjson_really_inline error_code get(T &out) & noexcept; - /** @overload template error_code get(T &out) & noexcept */ - template simdjson_really_inline error_code get(T &out) && noexcept; + template 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 get_array() && noexcept; - /** @overload simdjson_really_inline operator get_array() && noexcept(false); */ - simdjson_really_inline simdjson_result get_array() & noexcept; + simdjson_really_inline simdjson_result 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 get_object() && noexcept; - /** @overload simdjson_really_inline operator object() && noexcept(false); */ - simdjson_really_inline simdjson_result get_object() & noexcept; + simdjson_really_inline simdjson_result 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 find_field(std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(const char *key) && noexcept; + simdjson_really_inline simdjson_result find_field(std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result 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 find_field_unordered(std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(const char *key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](const char *key) && noexcept; + simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result find_field_unordered(const char *key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result operator[](std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result 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 start_or_resume_object() & noexcept; - /** @overload simdjson_really_inline simdjson_result start_or_resume_object() & noexcept; */ - simdjson_really_inline simdjson_result start_or_resume_object() && noexcept; + simdjson_really_inline simdjson_result 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 get_array() && noexcept; - simdjson_really_inline simdjson_result get_array() & noexcept; - - simdjson_really_inline simdjson_result get_object() && noexcept; - simdjson_really_inline simdjson_result get_object() & noexcept; + simdjson_really_inline simdjson_result get_array() noexcept; + simdjson_really_inline simdjson_result get_object() noexcept; simdjson_really_inline simdjson_result get_uint64() noexcept; simdjson_really_inline simdjson_result get_int64() noexcept; @@ -348,17 +319,13 @@ public: simdjson_really_inline simdjson_result get_bool() noexcept; simdjson_really_inline bool is_null() noexcept; - template simdjson_really_inline simdjson_result get() & noexcept; - template simdjson_really_inline simdjson_result get() && noexcept; + template simdjson_really_inline simdjson_result get() noexcept; - template simdjson_really_inline error_code get(T &out) & noexcept; - template simdjson_really_inline error_code get(T &out) && noexcept; + template 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 find_field(std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field(const char *key) && noexcept; + simdjson_really_inline simdjson_result find_field(std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result 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 find_field_unordered(std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result find_field_unordered(const char *key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](std::string_view key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](std::string_view key) && noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](const char *key) & noexcept; - /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ - simdjson_really_inline simdjson_result operator[](const char *key) && noexcept; + simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result find_field_unordered(const char *key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result operator[](std::string_view key) noexcept; + /** @overload simdjson_really_inline simdjson_result find_field_unordered(std::string_view key) noexcept; */ + simdjson_really_inline simdjson_result operator[](const char *key) noexcept; }; } // namespace simdjson diff --git a/include/simdjson/generic/ondemand/value_iterator-inl.h b/include/simdjson/generic/ondemand/value_iterator-inl.h index 76219deb..fd21ea0b 100644 --- a/include/simdjson/generic/ondemand/value_iterator-inl.h +++ b/include/simdjson/generic/ondemand/value_iterator-inl.h @@ -10,20 +10,12 @@ simdjson_really_inline value_iterator::value_iterator(json_iterator *json_iter, } simdjson_warn_unused simdjson_really_inline simdjson_result 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 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 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 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 va return get_raw_json_string().unescape(_json_iter->string_buf_loc()); } simdjson_warn_unused simdjson_really_inline simdjson_result 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 val return get_raw_json_string(); } simdjson_warn_unused simdjson_really_inline simdjson_result 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 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 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.e-308. uint8_t tmpbuf[1074+8+1]; @@ -364,14 +347,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result value_iterat return numberparsing::parse_double(tmpbuf); } simdjson_warn_unused simdjson_really_inline simdjson_result 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 ); diff --git a/include/simdjson/generic/ondemand/value_iterator.h b/include/simdjson/generic/ondemand/value_iterator.h index 60a2942a..a11d1e2e 100644 --- a/include/simdjson/generic/ondemand/value_iterator.h +++ b/include/simdjson/generic/ondemand/value_iterator.h @@ -208,13 +208,6 @@ public: * @error INCORRECT_TYPE If there is no [. */ simdjson_warn_unused simdjson_really_inline simdjson_result 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 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 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; diff --git a/tests/ondemand/CMakeLists.txt b/tests/ondemand/CMakeLists.txt index eb9ff4b7..a8039e93 100644 --- a/tests/ondemand/CMakeLists.txt +++ b/tests/ondemand/CMakeLists.txt @@ -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..." "$" # <--this is in-file - "$") # <--this is out-file path + "$") # <--this is out-file path endif(MSVC) diff --git a/tests/ondemand/ondemand_array_tests.cpp b/tests/ondemand/ondemand_array_tests.cpp new file mode 100644 index 00000000..a1ad495a --- /dev/null +++ b/tests/ondemand/ondemand_array_tests.cpp @@ -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", test_ondemand_doc(json, [&](auto doc_result) { + simdjson_result 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", 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", 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", test_ondemand_doc(json, [&](auto doc_result) { + simdjson_result 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", 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); +} diff --git a/tests/ondemand/ondemand_error_tests.cpp b/tests/ondemand/ondemand_error_tests.cpp index a5e686a1..5783ad50 100644 --- a/tests/ondemand/ondemand_error_tests.cpp +++ b/tests/ondemand/ondemand_error_tests.cpp @@ -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", test_ondemand_doc(json, [&](auto doc) { + simdjson_result 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", test_ondemand_doc(json, [&](simdjson_result 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", test_ondemand_doc(json, [&](auto doc) { + simdjson_result 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", test_ondemand_doc(json, [&](simdjson_result 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; } } diff --git a/tests/ondemand/ondemand_dom_api_tests.cpp b/tests/ondemand/ondemand_object_tests.cpp similarity index 62% rename from tests/ondemand/ondemand_dom_api_tests.cpp rename to tests/ondemand/ondemand_object_tests.cpp index c58f2d47..bbcf5e91 100644 --- a/tests/ondemand/ondemand_dom_api_tests.cpp +++ b/tests/ondemand/ondemand_object_tests.cpp @@ -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", test_ondemand_doc(json, [&](auto doc_result) { - simdjson_result 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", 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", 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", test_ondemand_doc(json, [&](auto doc_result) { - simdjson_result 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", test_ondemand_doc(json, [&](auto doc_result) { - for (simdjson_unused auto value : doc_result) { TEST_FAIL("Unexpected value"); } - return true; - })); - TEST_SUCCEED(); - } - - template - bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) { - std::cout << "- JSON: " << json << endl; - SUBTEST( "simdjson_result", 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", 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", test_ondemand_doc(array_json, [&](auto doc_result) { - int count = 0; - for (simdjson_result 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 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", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) { - int count = 0; - for (simdjson_result 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 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 ("0"_padded, 0)) { return false; } - if (!test_scalar_value("0"_padded, 0)) { return false; } - if (!test_scalar_value ("0"_padded, 0)) { return false; } - if (!test_scalar_value ("1"_padded, 1)) { return false; } - if (!test_scalar_value("1"_padded, 1)) { return false; } - if (!test_scalar_value ("1"_padded, 1)) { return false; } - if (!test_scalar_value ("-1"_padded, -1)) { return false; } - if (!test_scalar_value ("-1"_padded, -1)) { return false; } - if (!test_scalar_value ("1.1"_padded, 1.1)) { return false; } - TEST_SUCCEED(); - } - - bool boolean_values() { - TEST_START(); - if (!test_scalar_value ("true"_padded, true)) { return false; } - if (!test_scalar_value ("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", 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", 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 - 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 ("0"_padded, 0)) { return false; } - if (!test_scalar_value_exception("0"_padded, 0)) { return false; } - if (!test_scalar_value_exception ("0"_padded, 0)) { return false; } - if (!test_scalar_value_exception ("1"_padded, 1)) { return false; } - if (!test_scalar_value_exception("1"_padded, 1)) { return false; } - if (!test_scalar_value_exception ("1"_padded, 1)) { return false; } - if (!test_scalar_value_exception ("-1"_padded, -1)) { return false; } - if (!test_scalar_value_exception ("-1"_padded, -1)) { return false; } - if (!test_scalar_value_exception ("1.1"_padded, 1.1)) { return false; } - TEST_SUCCEED(); - } - - bool boolean_values_exception() { - TEST_START(); - if (!test_scalar_value_exception ("true"_padded, true)) { return false; } - if (!test_scalar_value_exception ("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); } diff --git a/tests/ondemand/ondemand_scalar_tests.cpp b/tests/ondemand/ondemand_scalar_tests.cpp new file mode 100644 index 00000000..d50f5060 --- /dev/null +++ b/tests/ondemand/ondemand_scalar_tests.cpp @@ -0,0 +1,278 @@ +#include "simdjson.h" +#include "test_ondemand.h" + +using namespace simdjson; + +namespace scalar_tests { + using namespace std; + + template + bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) { + std::cout << "- JSON: " << json << endl; + SUBTEST( "simdjson_result", 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", 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", test_ondemand_doc(array_json, [&](auto doc_result) { + int count = 0; + for (simdjson_result 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 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", test_ondemand_doc(whitespace_array_json, [&](auto doc_result) { + int count = 0; + for (simdjson_result 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 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 ("0"_padded, 0)) { return false; } + if (!test_scalar_value("0"_padded, 0)) { return false; } + if (!test_scalar_value ("0"_padded, 0)) { return false; } + if (!test_scalar_value ("1"_padded, 1)) { return false; } + if (!test_scalar_value("1"_padded, 1)) { return false; } + if (!test_scalar_value ("1"_padded, 1)) { return false; } + if (!test_scalar_value ("-1"_padded, -1)) { return false; } + if (!test_scalar_value ("-1"_padded, -1)) { return false; } + if (!test_scalar_value ("1.1"_padded, 1.1)) { return false; } + TEST_SUCCEED(); + } + + bool boolean_values() { + TEST_START(); + if (!test_scalar_value ("true"_padded, true)) { return false; } + if (!test_scalar_value ("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", 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", 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 + 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 ("0"_padded, 0)) { return false; } + if (!test_scalar_value_exception("0"_padded, 0)) { return false; } + if (!test_scalar_value_exception ("0"_padded, 0)) { return false; } + if (!test_scalar_value_exception ("1"_padded, 1)) { return false; } + if (!test_scalar_value_exception("1"_padded, 1)) { return false; } + if (!test_scalar_value_exception ("1"_padded, 1)) { return false; } + if (!test_scalar_value_exception ("-1"_padded, -1)) { return false; } + if (!test_scalar_value_exception ("-1"_padded, -1)) { return false; } + if (!test_scalar_value_exception ("1.1"_padded, 1.1)) { return false; } + TEST_SUCCEED(); + } + + bool boolean_values_exception() { + TEST_START(); + if (!test_scalar_value_exception ("true"_padded, true)) { return false; } + if (!test_scalar_value_exception ("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); +} diff --git a/tests/test_macros.h b/tests/test_macros.h index d7561b7f..b0638eac 100644 --- a/tests/test_macros.h +++ b/tests/test_macros.h @@ -48,7 +48,7 @@ template 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;