mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33d926bd44 | |||
| e9b893ff1b | |||
| 438c2a28ff | |||
| 45182ec11b | |||
| a0c020d46d | |||
| 076f41ae4b | |||
| 6a37fc1871 | |||
| c6c29c2827 | |||
| 941e903f28 |
+2
-2
@@ -9,8 +9,8 @@ project(simdjson
|
|||||||
|
|
||||||
set(PROJECT_VERSION_MAJOR 0)
|
set(PROJECT_VERSION_MAJOR 0)
|
||||||
set(PROJECT_VERSION_MINOR 9)
|
set(PROJECT_VERSION_MINOR 9)
|
||||||
set(PROJECT_VERSION_PATCH 1)
|
set(PROJECT_VERSION_PATCH 7)
|
||||||
set(SIMDJSON_SEMANTIC_VERSION "0.9.1" CACHE STRING "simdjson semantic version")
|
set(SIMDJSON_SEMANTIC_VERSION "0.9.7" CACHE STRING "simdjson semantic version")
|
||||||
set(SIMDJSON_LIB_VERSION "8.0.0" CACHE STRING "simdjson library version")
|
set(SIMDJSON_LIB_VERSION "8.0.0" CACHE STRING "simdjson library version")
|
||||||
set(SIMDJSON_LIB_SOVERSION "8" CACHE STRING "simdjson library soversion")
|
set(SIMDJSON_LIB_SOVERSION "8" CACHE STRING "simdjson library soversion")
|
||||||
set(SIMDJSON_GITHUB_REPOSITORY https://github.com/simdjson/simdjson)
|
set(SIMDJSON_GITHUB_REPOSITORY https://github.com/simdjson/simdjson)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = "0.9.1"
|
PROJECT_NUMBER = "0.9.7"
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -37,4 +37,5 @@ if (TARGET benchmark::benchmark)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(checkperf.cmake)
|
# deliberately disabling.
|
||||||
|
# include(checkperf.cmake)
|
||||||
|
|||||||
@@ -251,4 +251,23 @@ namespace std {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
// if we have C++, then fallthrough is a default attribute
|
||||||
|
# define simdjson_fallthrough [[fallthrough]]
|
||||||
|
// check if we have __attribute__ support
|
||||||
|
#elif defined(__has_attribute)
|
||||||
|
// check if we have the __fallthrough__ attribute
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
// we are good to go:
|
||||||
|
# define simdjson_fallthrough __attribute__((__fallthrough__))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
// on some systems, we simply do not have support for fallthrough, so use a default:
|
||||||
|
#ifndef simdjson_fallthrough
|
||||||
|
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // SIMDJSON_COMMON_DEFS_H
|
#endif // SIMDJSON_COMMON_DEFS_H
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
|||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) noexcept { return out << value.value(); }
|
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) { return out << value.value(); }
|
||||||
|
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ simdjson_really_inline json_iterator::json_iterator(json_iterator &&other) noexc
|
|||||||
: token(std::forward<token_iterator>(other.token)),
|
: token(std::forward<token_iterator>(other.token)),
|
||||||
parser{other.parser},
|
parser{other.parser},
|
||||||
_string_buf_loc{other._string_buf_loc},
|
_string_buf_loc{other._string_buf_loc},
|
||||||
|
error{other.error},
|
||||||
_depth{other._depth}
|
_depth{other._depth}
|
||||||
{
|
{
|
||||||
other.parser = nullptr;
|
other.parser = nullptr;
|
||||||
@@ -14,6 +15,7 @@ simdjson_really_inline json_iterator &json_iterator::operator=(json_iterator &&o
|
|||||||
token = other.token;
|
token = other.token;
|
||||||
parser = other.parser;
|
parser = other.parser;
|
||||||
_string_buf_loc = other._string_buf_loc;
|
_string_buf_loc = other._string_buf_loc;
|
||||||
|
error = other.error;
|
||||||
_depth = other._depth;
|
_depth = other._depth;
|
||||||
other.parser = nullptr;
|
other.parser = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -139,21 +139,35 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
||||||
|
/**
|
||||||
|
* When find_field_unordered_raw is called, we can either be pointing at the
|
||||||
|
* first key, pointing outside (at the closing brace) or if a key was matched
|
||||||
|
* we can be either pointing right afterthe ':' right before the value (that we need skip),
|
||||||
|
* or we may have consumed the value and we might be at a comma or at the
|
||||||
|
* final brace (ready for a call to has_next_field()).
|
||||||
|
*/
|
||||||
error_code error;
|
error_code error;
|
||||||
bool has_value;
|
bool has_value;
|
||||||
//
|
|
||||||
|
// First, we scan from that point to the end.
|
||||||
|
// If we don't find a match, we may loop back around, and scan from the beginning to that point.
|
||||||
|
token_position search_start = _json_iter->position();
|
||||||
|
|
||||||
|
// We want to know whether we need to go back to the beginning.
|
||||||
|
bool at_first = at_first_field();
|
||||||
|
///////////////
|
||||||
// Initially, the object can be in one of a few different places:
|
// Initially, the object can be in one of a few different places:
|
||||||
//
|
//
|
||||||
// 1. The start of the object, at the first field:
|
// 1. At the first key:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
// { "a": [ 1, 2 ], "b": [ 3, 4 ] }
|
// { "a": [ 1, 2 ], "b": [ 3, 4 ] }
|
||||||
// ^ (depth 2, index 1)
|
// ^ (depth 2, index 1)
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
if (at_first_field()) {
|
if (at_first) {
|
||||||
// If we're at the beginning of the object, we definitely have a field
|
|
||||||
has_value = true;
|
has_value = true;
|
||||||
|
|
||||||
// 2. When a previous search did not yield a value or the object is empty:
|
// 2. When a previous search did not yield a value or the object is empty:
|
||||||
@@ -166,14 +180,16 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
} else if (!is_open()) {
|
} else if (!is_open()) {
|
||||||
|
|
||||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
// If we're past the end of the object, we're being iterated out of order.
|
// If we're past the end of the object, we're being iterated out of order.
|
||||||
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
||||||
// this object iterator will blithely scan that object for fields.
|
// this object iterator will blithely scan that object for fields.
|
||||||
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
||||||
#endif
|
#endif
|
||||||
has_value = false;
|
_json_iter->reenter_child(_start_position + 1, _depth);
|
||||||
|
at_first = true;
|
||||||
|
has_value = started_object();
|
||||||
// 3. When a previous search found a field or an iterator yielded a value:
|
// 3. When a previous search found a field or an iterator yielded a value:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
@@ -189,8 +205,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
// Finish the previous value and see if , or } is next
|
// If someone queried a key but they did access the value, then we are left pointing
|
||||||
|
// at the ':' and we need to move forward through the value... If the value was
|
||||||
|
// processed then skip_child() does not move the iterator (but may adjust the depth).
|
||||||
if ((error = skip_child() )) { abandon(); return error; }
|
if ((error = skip_child() )) { abandon(); return error; }
|
||||||
|
search_start = _json_iter->position();
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
||||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
if (_json_iter->start_position(_depth) != _start_position) { return OUT_OF_ORDER_ITERATION; }
|
if (_json_iter->start_position(_depth) != _start_position) { return OUT_OF_ORDER_ITERATION; }
|
||||||
@@ -211,10 +233,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
|
|
||||||
// First, we scan from that point to the end.
|
|
||||||
// If we don't find a match, we loop back around, and scan from the beginning to that point.
|
|
||||||
token_position search_start = _json_iter->position();
|
|
||||||
|
|
||||||
// Next, we find a match starting from the current position.
|
// Next, we find a match starting from the current position.
|
||||||
while (has_value) {
|
while (has_value) {
|
||||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
||||||
@@ -222,8 +240,11 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// Get the key and colon, stopping at the value.
|
// Get the key and colon, stopping at the value.
|
||||||
raw_json_string actual_key;
|
raw_json_string actual_key;
|
||||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||||
|
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||||
|
// The depth is left unchanged by field_key().
|
||||||
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
||||||
|
// field_value() will advance and check that we find a ':' separating the
|
||||||
|
// key and the value. It will also increment the depth by one.
|
||||||
if ((error = field_value() )) { abandon(); return error; }
|
if ((error = field_value() )) { abandon(); return error; }
|
||||||
|
|
||||||
// If it matches, stop and return
|
// If it matches, stop and return
|
||||||
@@ -236,31 +257,44 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// input).
|
// input).
|
||||||
if (actual_key.unsafe_is_equal(key)) {
|
if (actual_key.unsafe_is_equal(key)) {
|
||||||
logger::log_event(*this, "match", key, -2);
|
logger::log_event(*this, "match", key, -2);
|
||||||
|
// If we return here, then we return while pointing at the ':' that we just checked.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No match: skip the value and see if , or } is next
|
// No match: skip the value and see if , or } is next
|
||||||
logger::log_event(*this, "no match", key, -2);
|
logger::log_event(*this, "no match", key, -2);
|
||||||
|
// The call to skip_child is meant to skip over the value corresponding to the key.
|
||||||
|
// After skip_child(), we are right before the next comma (',') or the final brace ('}').
|
||||||
SIMDJSON_TRY( skip_child() );
|
SIMDJSON_TRY( skip_child() );
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
||||||
}
|
}
|
||||||
|
// Performance note: it maybe wasteful to rewind to the beginning when there might be
|
||||||
|
// no other query following. Indeed, it would require reskipping the whole object.
|
||||||
|
// Instead, you can just stay where you are. If there is a new query, there is always time
|
||||||
|
// to rewind.
|
||||||
|
if(at_first) { return false; }
|
||||||
|
|
||||||
// If we reach the end without finding a match, search the rest of the fields starting at the
|
// If we reach the end without finding a match, search the rest of the fields starting at the
|
||||||
// beginning of the object.
|
// beginning of the object.
|
||||||
// (We have already run through the object before, so we've already validated its structure. We
|
// (We have already run through the object before, so we've already validated its structure. We
|
||||||
// don't check errors in this bit.)
|
// don't check errors in this bit.)
|
||||||
_json_iter->reenter_child(_start_position + 1, _depth);
|
_json_iter->reenter_child(_start_position + 1, _depth);
|
||||||
|
|
||||||
has_value = started_object();
|
has_value = started_object();
|
||||||
while (_json_iter->position() < search_start) {
|
while (true) {
|
||||||
SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
|
SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
|
||||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
||||||
|
|
||||||
// Get the key and colon, stopping at the value.
|
// Get the key and colon, stopping at the value.
|
||||||
raw_json_string actual_key;
|
raw_json_string actual_key;
|
||||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||||
|
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||||
|
// The depth is left unchanged by field_key().
|
||||||
error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
|
error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
|
||||||
|
// field_value() will advance and check that we find a ':' separating the
|
||||||
|
// key and the value. It will also increment the depth by one.
|
||||||
error = field_value(); SIMDJSON_ASSUME(!error);
|
error = field_value(); SIMDJSON_ASSUME(!error);
|
||||||
|
|
||||||
// If it matches, stop and return
|
// If it matches, stop and return
|
||||||
@@ -273,16 +307,28 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// input).
|
// input).
|
||||||
if (actual_key.unsafe_is_equal(key)) {
|
if (actual_key.unsafe_is_equal(key)) {
|
||||||
logger::log_event(*this, "match", key, -2);
|
logger::log_event(*this, "match", key, -2);
|
||||||
|
// If we return here, then we return while pointing at the ':' that we just checked.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No match: skip the value and see if , or } is next
|
// No match: skip the value and see if , or } is next
|
||||||
logger::log_event(*this, "no match", key, -2);
|
logger::log_event(*this, "no match", key, -2);
|
||||||
|
// The call to skip_child is meant to skip over the value corresponding to the key.
|
||||||
|
// After skip_child(), we are right before the next comma (',') or the final brace ('}').
|
||||||
SIMDJSON_TRY( skip_child() );
|
SIMDJSON_TRY( skip_child() );
|
||||||
|
// If we reached the end of the key-value pair we started from, then we know
|
||||||
|
// that the key is not there so we return false. We are either right before
|
||||||
|
// the next comma or the final brace.
|
||||||
|
if(_json_iter->position() == search_start) { return false; }
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
|
error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
|
||||||
|
// If we make the mistake of exiting here, then we could be left pointing at a key
|
||||||
|
// in the middle of an object. That's not an allowable state.
|
||||||
}
|
}
|
||||||
|
// If the loop ended, we're out of fields to look at. The program should
|
||||||
// If the loop ended, we're out of fields to look at.
|
// never reach this point.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION 0.9.1
|
#define SIMDJSON_VERSION 0.9.7
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -19,7 +19,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 1
|
SIMDJSON_VERSION_REVISION = 7
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2021-03-18 11:30:40 -0400. Do not edit! */
|
/* auto-generated on 2021-06-05 11:33:32 -0400. Do not edit! */
|
||||||
/* begin file src/simdjson.cpp */
|
/* begin file src/simdjson.cpp */
|
||||||
#include "simdjson.h"
|
#include "simdjson.h"
|
||||||
|
|
||||||
|
|||||||
+88
-21
@@ -1,4 +1,4 @@
|
|||||||
/* auto-generated on 2021-03-18 11:30:40 -0400. Do not edit! */
|
/* auto-generated on 2021-06-05 11:33:32 -0400. Do not edit! */
|
||||||
/* begin file include/simdjson.h */
|
/* begin file include/simdjson.h */
|
||||||
#ifndef SIMDJSON_H
|
#ifndef SIMDJSON_H
|
||||||
#define SIMDJSON_H
|
#define SIMDJSON_H
|
||||||
@@ -2045,6 +2045,25 @@ namespace std {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if SIMDJSON_CPLUSPLUS17
|
||||||
|
// if we have C++, then fallthrough is a default attribute
|
||||||
|
# define simdjson_fallthrough [[fallthrough]]
|
||||||
|
// check if we have __attribute__ support
|
||||||
|
#elif defined(__has_attribute)
|
||||||
|
// check if we have the __fallthrough__ attribute
|
||||||
|
#if __has_attribute(__fallthrough__)
|
||||||
|
// we are good to go:
|
||||||
|
# define simdjson_fallthrough __attribute__((__fallthrough__))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
// on some systems, we simply do not have support for fallthrough, so use a default:
|
||||||
|
#ifndef simdjson_fallthrough
|
||||||
|
# define simdjson_fallthrough do {} while (0) /* fallthrough */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // SIMDJSON_COMMON_DEFS_H
|
#endif // SIMDJSON_COMMON_DEFS_H
|
||||||
/* end file include/simdjson/common_defs.h */
|
/* end file include/simdjson/common_defs.h */
|
||||||
|
|
||||||
@@ -2059,7 +2078,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
|
|||||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||||
|
|
||||||
/** The version of simdjson being used (major.minor.revision) */
|
/** The version of simdjson being used (major.minor.revision) */
|
||||||
#define SIMDJSON_VERSION 0.9.1
|
#define SIMDJSON_VERSION 0.9.7
|
||||||
|
|
||||||
namespace simdjson {
|
namespace simdjson {
|
||||||
enum {
|
enum {
|
||||||
@@ -2074,7 +2093,7 @@ enum {
|
|||||||
/**
|
/**
|
||||||
* The revision (major.minor.REVISION) of simdjson being used.
|
* The revision (major.minor.REVISION) of simdjson being used.
|
||||||
*/
|
*/
|
||||||
SIMDJSON_VERSION_REVISION = 1
|
SIMDJSON_VERSION_REVISION = 7
|
||||||
};
|
};
|
||||||
} // namespace simdjson
|
} // namespace simdjson
|
||||||
|
|
||||||
@@ -2368,7 +2387,7 @@ struct simdjson_result : public internal::simdjson_result_base<T> {
|
|||||||
#if SIMDJSON_EXCEPTIONS
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) noexcept { return out << value.value(); }
|
inline std::ostream& operator<<(std::ostream& out, simdjson_result<T> value) { return out << value.value(); }
|
||||||
|
|
||||||
#endif // SIMDJSON_EXCEPTIONS
|
#endif // SIMDJSON_EXCEPTIONS
|
||||||
|
|
||||||
@@ -21695,6 +21714,7 @@ simdjson_really_inline json_iterator::json_iterator(json_iterator &&other) noexc
|
|||||||
: token(std::forward<token_iterator>(other.token)),
|
: token(std::forward<token_iterator>(other.token)),
|
||||||
parser{other.parser},
|
parser{other.parser},
|
||||||
_string_buf_loc{other._string_buf_loc},
|
_string_buf_loc{other._string_buf_loc},
|
||||||
|
error{other.error},
|
||||||
_depth{other._depth}
|
_depth{other._depth}
|
||||||
{
|
{
|
||||||
other.parser = nullptr;
|
other.parser = nullptr;
|
||||||
@@ -21703,6 +21723,7 @@ simdjson_really_inline json_iterator &json_iterator::operator=(json_iterator &&o
|
|||||||
token = other.token;
|
token = other.token;
|
||||||
parser = other.parser;
|
parser = other.parser;
|
||||||
_string_buf_loc = other._string_buf_loc;
|
_string_buf_loc = other._string_buf_loc;
|
||||||
|
error = other.error;
|
||||||
_depth = other._depth;
|
_depth = other._depth;
|
||||||
other.parser = nullptr;
|
other.parser = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
@@ -22088,21 +22109,35 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_unordered_raw(const std::string_view key) noexcept {
|
||||||
|
/**
|
||||||
|
* When find_field_unordered_raw is called, we can either be pointing at the
|
||||||
|
* first key, pointing outside (at the closing brace) or if a key was matched
|
||||||
|
* we can be either pointing right afterthe ':' right before the value (that we need skip),
|
||||||
|
* or we may have consumed the value and we might be at a comma or at the
|
||||||
|
* final brace (ready for a call to has_next_field()).
|
||||||
|
*/
|
||||||
error_code error;
|
error_code error;
|
||||||
bool has_value;
|
bool has_value;
|
||||||
//
|
|
||||||
|
// First, we scan from that point to the end.
|
||||||
|
// If we don't find a match, we may loop back around, and scan from the beginning to that point.
|
||||||
|
token_position search_start = _json_iter->position();
|
||||||
|
|
||||||
|
// We want to know whether we need to go back to the beginning.
|
||||||
|
bool at_first = at_first_field();
|
||||||
|
///////////////
|
||||||
// Initially, the object can be in one of a few different places:
|
// Initially, the object can be in one of a few different places:
|
||||||
//
|
//
|
||||||
// 1. The start of the object, at the first field:
|
// 1. At the first key:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
// { "a": [ 1, 2 ], "b": [ 3, 4 ] }
|
// { "a": [ 1, 2 ], "b": [ 3, 4 ] }
|
||||||
// ^ (depth 2, index 1)
|
// ^ (depth 2, index 1)
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
if (at_first_field()) {
|
if (at_first) {
|
||||||
// If we're at the beginning of the object, we definitely have a field
|
|
||||||
has_value = true;
|
has_value = true;
|
||||||
|
|
||||||
// 2. When a previous search did not yield a value or the object is empty:
|
// 2. When a previous search did not yield a value or the object is empty:
|
||||||
@@ -22115,14 +22150,16 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
} else if (!is_open()) {
|
} else if (!is_open()) {
|
||||||
|
|
||||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
// If we're past the end of the object, we're being iterated out of order.
|
// If we're past the end of the object, we're being iterated out of order.
|
||||||
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
// Note: this isn't perfect detection. It's possible the user is inside some other object; if so,
|
||||||
// this object iterator will blithely scan that object for fields.
|
// this object iterator will blithely scan that object for fields.
|
||||||
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
if (_json_iter->depth() < depth() - 1) { return OUT_OF_ORDER_ITERATION; }
|
||||||
#endif
|
#endif
|
||||||
has_value = false;
|
_json_iter->reenter_child(_start_position + 1, _depth);
|
||||||
|
at_first = true;
|
||||||
|
has_value = started_object();
|
||||||
// 3. When a previous search found a field or an iterator yielded a value:
|
// 3. When a previous search found a field or an iterator yielded a value:
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
@@ -22138,8 +22175,14 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
// Finish the previous value and see if , or } is next
|
// If someone queried a key but they did access the value, then we are left pointing
|
||||||
|
// at the ':' and we need to move forward through the value... If the value was
|
||||||
|
// processed then skip_child() does not move the iterator (but may adjust the depth).
|
||||||
if ((error = skip_child() )) { abandon(); return error; }
|
if ((error = skip_child() )) { abandon(); return error; }
|
||||||
|
search_start = _json_iter->position();
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
||||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||||
if (_json_iter->start_position(_depth) != _start_position) { return OUT_OF_ORDER_ITERATION; }
|
if (_json_iter->start_position(_depth) != _start_position) { return OUT_OF_ORDER_ITERATION; }
|
||||||
@@ -22160,10 +22203,6 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
|
|
||||||
// First, we scan from that point to the end.
|
|
||||||
// If we don't find a match, we loop back around, and scan from the beginning to that point.
|
|
||||||
token_position search_start = _json_iter->position();
|
|
||||||
|
|
||||||
// Next, we find a match starting from the current position.
|
// Next, we find a match starting from the current position.
|
||||||
while (has_value) {
|
while (has_value) {
|
||||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
||||||
@@ -22171,8 +22210,11 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// Get the key and colon, stopping at the value.
|
// Get the key and colon, stopping at the value.
|
||||||
raw_json_string actual_key;
|
raw_json_string actual_key;
|
||||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||||
|
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||||
|
// The depth is left unchanged by field_key().
|
||||||
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
|
||||||
|
// field_value() will advance and check that we find a ':' separating the
|
||||||
|
// key and the value. It will also increment the depth by one.
|
||||||
if ((error = field_value() )) { abandon(); return error; }
|
if ((error = field_value() )) { abandon(); return error; }
|
||||||
|
|
||||||
// If it matches, stop and return
|
// If it matches, stop and return
|
||||||
@@ -22185,31 +22227,44 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// input).
|
// input).
|
||||||
if (actual_key.unsafe_is_equal(key)) {
|
if (actual_key.unsafe_is_equal(key)) {
|
||||||
logger::log_event(*this, "match", key, -2);
|
logger::log_event(*this, "match", key, -2);
|
||||||
|
// If we return here, then we return while pointing at the ':' that we just checked.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No match: skip the value and see if , or } is next
|
// No match: skip the value and see if , or } is next
|
||||||
logger::log_event(*this, "no match", key, -2);
|
logger::log_event(*this, "no match", key, -2);
|
||||||
|
// The call to skip_child is meant to skip over the value corresponding to the key.
|
||||||
|
// After skip_child(), we are right before the next comma (',') or the final brace ('}').
|
||||||
SIMDJSON_TRY( skip_child() );
|
SIMDJSON_TRY( skip_child() );
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
|
||||||
}
|
}
|
||||||
|
// Performance note: it maybe wasteful to rewind to the beginning when there might be
|
||||||
|
// no other query following. Indeed, it would require reskipping the whole object.
|
||||||
|
// Instead, you can just stay where you are. If there is a new query, there is always time
|
||||||
|
// to rewind.
|
||||||
|
if(at_first) { return false; }
|
||||||
|
|
||||||
// If we reach the end without finding a match, search the rest of the fields starting at the
|
// If we reach the end without finding a match, search the rest of the fields starting at the
|
||||||
// beginning of the object.
|
// beginning of the object.
|
||||||
// (We have already run through the object before, so we've already validated its structure. We
|
// (We have already run through the object before, so we've already validated its structure. We
|
||||||
// don't check errors in this bit.)
|
// don't check errors in this bit.)
|
||||||
_json_iter->reenter_child(_start_position + 1, _depth);
|
_json_iter->reenter_child(_start_position + 1, _depth);
|
||||||
|
|
||||||
has_value = started_object();
|
has_value = started_object();
|
||||||
while (_json_iter->position() < search_start) {
|
while (true) {
|
||||||
SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
|
SIMDJSON_ASSUME(has_value); // we should reach search_start before ever reaching the end of the object
|
||||||
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
SIMDJSON_ASSUME( _json_iter->_depth == _depth ); // We must be at the start of a field
|
||||||
|
|
||||||
// Get the key and colon, stopping at the value.
|
// Get the key and colon, stopping at the value.
|
||||||
raw_json_string actual_key;
|
raw_json_string actual_key;
|
||||||
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
// size_t max_key_length = _json_iter->peek_length() - 2; // -2 for the two quotes
|
||||||
|
// field_key() advances the pointer and checks that '"' is found (corresponding to a key).
|
||||||
|
// The depth is left unchanged by field_key().
|
||||||
error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
|
error = field_key().get(actual_key); SIMDJSON_ASSUME(!error);
|
||||||
|
// field_value() will advance and check that we find a ':' separating the
|
||||||
|
// key and the value. It will also increment the depth by one.
|
||||||
error = field_value(); SIMDJSON_ASSUME(!error);
|
error = field_value(); SIMDJSON_ASSUME(!error);
|
||||||
|
|
||||||
// If it matches, stop and return
|
// If it matches, stop and return
|
||||||
@@ -22222,16 +22277,28 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
|
|||||||
// input).
|
// input).
|
||||||
if (actual_key.unsafe_is_equal(key)) {
|
if (actual_key.unsafe_is_equal(key)) {
|
||||||
logger::log_event(*this, "match", key, -2);
|
logger::log_event(*this, "match", key, -2);
|
||||||
|
// If we return here, then we return while pointing at the ':' that we just checked.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No match: skip the value and see if , or } is next
|
// No match: skip the value and see if , or } is next
|
||||||
logger::log_event(*this, "no match", key, -2);
|
logger::log_event(*this, "no match", key, -2);
|
||||||
|
// The call to skip_child is meant to skip over the value corresponding to the key.
|
||||||
|
// After skip_child(), we are right before the next comma (',') or the final brace ('}').
|
||||||
SIMDJSON_TRY( skip_child() );
|
SIMDJSON_TRY( skip_child() );
|
||||||
|
// If we reached the end of the key-value pair we started from, then we know
|
||||||
|
// that the key is not there so we return false. We are either right before
|
||||||
|
// the next comma or the final brace.
|
||||||
|
if(_json_iter->position() == search_start) { return false; }
|
||||||
|
// The has_next_field() advances the pointer and check that either ',' or '}' is found.
|
||||||
|
// It returns true if ',' is found, false otherwise. If anything other than ',' or '}' is found,
|
||||||
|
// then we are in error and we abort.
|
||||||
error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
|
error = has_next_field().get(has_value); SIMDJSON_ASSUME(!error);
|
||||||
|
// If we make the mistake of exiting here, then we could be left pointing at a key
|
||||||
|
// in the middle of an object. That's not an allowable state.
|
||||||
}
|
}
|
||||||
|
// If the loop ended, we're out of fields to look at. The program should
|
||||||
// If the loop ended, we're out of fields to look at.
|
// never reach this point.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,135 @@ using namespace simdjson;
|
|||||||
namespace array_tests {
|
namespace array_tests {
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using simdjson::ondemand::json_type;
|
using simdjson::ondemand::json_type;
|
||||||
|
bool issue1588() {
|
||||||
|
TEST_START();
|
||||||
|
const auto json = R"({
|
||||||
|
"nodes" : [
|
||||||
|
{
|
||||||
|
"rotation" : [
|
||||||
|
0.16907575726509094,
|
||||||
|
0.7558803558349609,
|
||||||
|
-0.27217137813568115,
|
||||||
|
0.570947527885437
|
||||||
|
],
|
||||||
|
"translation" : [
|
||||||
|
4.076245307922363,
|
||||||
|
5.903861999511719,
|
||||||
|
-1.0054539442062378
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"camera" : 0,
|
||||||
|
"rotation" : [
|
||||||
|
-0.7071067690849304,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.7071067690849304
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children" : [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation" : [
|
||||||
|
7.358891487121582,
|
||||||
|
4.958309173583984,
|
||||||
|
6.925790786743164
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh" : 1,
|
||||||
|
"scale" : [
|
||||||
|
4.7498908042907715,
|
||||||
|
4.7498908042907715,
|
||||||
|
4.7498908042907715
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})"_padded;
|
||||||
|
// we query 'rotation', 'scale', 'translation' in sequence
|
||||||
|
const bool expected_value[][3] = { {true, false, true},
|
||||||
|
{true, false, false}, {false, false, true}, {false, true, false} };
|
||||||
|
|
||||||
|
SUBTEST("ondemand::issue1588::sequence", test_ondemand_doc(json, [&](auto doc_result) {
|
||||||
|
ondemand::array array;
|
||||||
|
ASSERT_SUCCESS( doc_result["nodes"].get(array) );
|
||||||
|
|
||||||
|
size_t i=0;
|
||||||
|
for (auto value : array) {
|
||||||
|
ondemand::object current_object;
|
||||||
|
ASSERT_SUCCESS( value.get_object().get(current_object) );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] acquired a new object ==========" << std::endl;
|
||||||
|
|
||||||
|
simdjson::ondemand::array rotation;
|
||||||
|
if(expected_value[i][0]) {
|
||||||
|
ASSERT_SUCCESS( current_object["rotation"].get(rotation) );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] found 'rotation' " << std::endl;
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( current_object["rotation"].get(rotation), NO_SUCH_FIELD );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] rotation not found" << std::endl;
|
||||||
|
}
|
||||||
|
simdjson::ondemand::array scale;
|
||||||
|
if(expected_value[i][1]) {
|
||||||
|
ASSERT_SUCCESS( current_object["scale"].get(scale) );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] found 'scale' " << std::endl;
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( current_object["scale"].get(scale), NO_SUCH_FIELD );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] scale not found" << std::endl;
|
||||||
|
}
|
||||||
|
simdjson::ondemand::array translation;
|
||||||
|
if(expected_value[i][2]) {
|
||||||
|
ASSERT_SUCCESS( current_object["translation"].get(translation) );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] found 'translation' " << std::endl;
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( current_object["translation"].get(translation), NO_SUCH_FIELD );
|
||||||
|
std::cout << "[ondemand::issue1588::sequence] translation not found" << std::endl;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
ASSERT_EQUAL(i, 4);
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
SUBTEST("ondemand::issue1588::originalcode", test_ondemand_doc(json, [&](auto doc_result) {
|
||||||
|
int count_nodes = 0;
|
||||||
|
simdjson::ondemand::array doc_nodes;
|
||||||
|
auto error = doc_result["nodes"].get(doc_nodes);
|
||||||
|
ASSERT_SUCCESS( error );
|
||||||
|
for (auto node_iterator : doc_nodes) {
|
||||||
|
ondemand::object node_obj;
|
||||||
|
ASSERT_SUCCESS( node_iterator.get_object().get(node_obj) );
|
||||||
|
simdjson::ondemand::array rotation;
|
||||||
|
std::cout << "checking rotation" << std::endl;
|
||||||
|
if(expected_value[count_nodes][0]) {
|
||||||
|
ASSERT_SUCCESS( node_obj["rotation"].get(rotation) );
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( node_obj["rotation"].get(rotation), NO_SUCH_FIELD );
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson::ondemand::array scale;
|
||||||
|
std::cout << "checking scale" << std::endl;
|
||||||
|
if(expected_value[count_nodes][1]) {
|
||||||
|
ASSERT_SUCCESS( node_obj["scale"].get(scale) );
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( node_obj["scale"].get(scale), NO_SUCH_FIELD );
|
||||||
|
}
|
||||||
|
|
||||||
|
simdjson::ondemand::array translation;
|
||||||
|
std::cout << "checking translation" << std::endl;
|
||||||
|
if (!error) { std::cout << "translation!\n"; }
|
||||||
|
if(expected_value[count_nodes][2]) {
|
||||||
|
ASSERT_SUCCESS( node_obj["translation"].get(translation) );
|
||||||
|
} else {
|
||||||
|
ASSERT_ERROR( node_obj["translation"].get(translation), NO_SUCH_FIELD );
|
||||||
|
}
|
||||||
|
|
||||||
|
++count_nodes;
|
||||||
|
}
|
||||||
|
ASSERT_EQUAL(count_nodes, 4);
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
bool iterate_document_array() {
|
bool iterate_document_array() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
@@ -341,6 +470,7 @@ namespace array_tests {
|
|||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
|
issue1588() &&
|
||||||
iterate_array() &&
|
iterate_array() &&
|
||||||
iterate_document_array() &&
|
iterate_document_array() &&
|
||||||
iterate_empty_array() &&
|
iterate_empty_array() &&
|
||||||
|
|||||||
@@ -7,6 +7,178 @@ namespace object_tests {
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using simdjson::ondemand::json_type;
|
using simdjson::ondemand::json_type;
|
||||||
|
|
||||||
|
// In this test, no non-trivial object in an array have a missing key
|
||||||
|
bool no_missing_keys() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"([{"a":"a"},{}])"_padded;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(docdata).get(doc);
|
||||||
|
if(error != simdjson::SUCCESS) { return false; }
|
||||||
|
simdjson::ondemand::array a;
|
||||||
|
error = doc.get_array().get(a);
|
||||||
|
if(error != simdjson::SUCCESS) { return false; }
|
||||||
|
size_t counter{0};
|
||||||
|
for(auto elem : a) {
|
||||||
|
error = elem.find_field_unordered("a").error();
|
||||||
|
if(counter == 0) {
|
||||||
|
ASSERT_EQUAL( error, simdjson::SUCCESS);
|
||||||
|
} else {
|
||||||
|
ASSERT_EQUAL( error, simdjson::NO_SUCH_FIELD);
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool missing_key_continue() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"({"a":0, "b":1, "c":2})"_padded;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||||
|
int64_t num;
|
||||||
|
ASSERT_SUCCESS(doc["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
ASSERT_SUCCESS(doc["b"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 1);
|
||||||
|
ASSERT_SUCCESS(doc["c"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 2);
|
||||||
|
// Start again, but omit a key
|
||||||
|
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||||
|
ASSERT_SUCCESS(doc["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
ASSERT_SUCCESS(doc["c"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 2);
|
||||||
|
// Start again, but request a missing key
|
||||||
|
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||||
|
simdjson::ondemand::object obj;
|
||||||
|
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
assert_error(obj["d"].get(num), NO_SUCH_FIELD);
|
||||||
|
ASSERT_SUCCESS(obj["c"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 2);
|
||||||
|
// Start again, but request a missing key first
|
||||||
|
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||||
|
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||||
|
assert_error(obj["d"].get(num), NO_SUCH_FIELD);
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
// Start again, but request a missing key twice
|
||||||
|
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||||
|
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
assert_error(obj["d"].get(num), NO_SUCH_FIELD);
|
||||||
|
assert_error(obj["z"].get(num), NO_SUCH_FIELD);
|
||||||
|
// Because we do a full circle, you can query the same
|
||||||
|
// key twice!!!
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
ASSERT_SUCCESS(obj["b"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 1);
|
||||||
|
ASSERT_SUCCESS(obj["b"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 1);
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
assert_error(obj["d"].get(num), NO_SUCH_FIELD);
|
||||||
|
ASSERT_SUCCESS(obj["a"].get(num));
|
||||||
|
ASSERT_EQUAL(num, 0);
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool missing_keys() {
|
||||||
|
TEST_START();
|
||||||
|
simdjson::ondemand::parser parser;
|
||||||
|
simdjson::padded_string docdata = R"([{"a":"a"},{}])"_padded;
|
||||||
|
simdjson::ondemand::document doc;
|
||||||
|
auto error = parser.iterate(docdata).get(doc);
|
||||||
|
if(error != simdjson::SUCCESS) { return false; }
|
||||||
|
simdjson::ondemand::array a;
|
||||||
|
error = doc.get_array().get(a);
|
||||||
|
if(error != simdjson::SUCCESS) { return false; }
|
||||||
|
for(auto elem : a) {
|
||||||
|
error = elem.find_field_unordered("keynotfound").error();
|
||||||
|
if(error != simdjson::NO_SUCH_FIELD) {
|
||||||
|
std::cout << error << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
// used in issue_1521
|
||||||
|
// difficult to use as a lambda because it is recursive.
|
||||||
|
void broken_descend(ondemand::object node) {
|
||||||
|
if(auto type = node.find_field_unordered("type"); type.error() == SUCCESS && type == "child") {
|
||||||
|
auto n = node.find_field_unordered("name");
|
||||||
|
if(n.error() == simdjson::SUCCESS) {
|
||||||
|
std::cout << std::string_view(n) << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (ondemand::object child_node : node["nodes"]) { broken_descend(child_node); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool broken_issue_1521() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
padded_string json = R"({"type":"root","nodes":[{"type":"child","nodes":[]},{"type":"child","name":"child-name","nodes":[]}]})"_padded;
|
||||||
|
ondemand::document file_tree = parser.iterate(json);
|
||||||
|
try {
|
||||||
|
broken_descend(file_tree);
|
||||||
|
} catch(simdjson::simdjson_error& e) {
|
||||||
|
std::cout << "The document is valid JSON: " << json << std::endl;
|
||||||
|
TEST_FAIL(e.error());
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fixed_broken_issue_1521() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
// We omit the ',"nodes":[]'
|
||||||
|
padded_string json = R"({"type":"root","nodes":[{"type":"child"},{"type":"child","name":"child-name","nodes":[]}]})"_padded;
|
||||||
|
ondemand::document file_tree = parser.iterate(json);
|
||||||
|
try {
|
||||||
|
broken_descend(file_tree);
|
||||||
|
} catch(simdjson::simdjson_error& e) {
|
||||||
|
std::cout << "The document is valid JSON: " << json << std::endl;
|
||||||
|
TEST_FAIL(e.error());
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// used in issue_1521
|
||||||
|
// difficult to use as a lambda because it is recursive.
|
||||||
|
void descend(ondemand::object node) {
|
||||||
|
auto n = node.find_field_unordered("name");
|
||||||
|
if(auto type = node.find_field_unordered("type"); type.error() == SUCCESS && type == "child") {
|
||||||
|
if(n.error() == simdjson::SUCCESS) {
|
||||||
|
std::cout << std::string_view(n) << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (ondemand::object child_node : node["nodes"]) { descend(child_node); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool issue_1521() {
|
||||||
|
TEST_START();
|
||||||
|
ondemand::parser parser;
|
||||||
|
padded_string json = R"({"type":"root","nodes":[{"type":"child","nodes":[]},{"type":"child","name":"child-name","nodes":[]}]})"_padded;
|
||||||
|
ondemand::document file_tree = parser.iterate(json);
|
||||||
|
try {
|
||||||
|
descend(file_tree);
|
||||||
|
} catch(simdjson::simdjson_error& e) {
|
||||||
|
std::cout << "The document is valid JSON: " << json << std::endl;
|
||||||
|
TEST_FAIL(e.error());
|
||||||
|
}
|
||||||
|
TEST_SUCCEED();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool iterate_object() {
|
bool iterate_object() {
|
||||||
TEST_START();
|
TEST_START();
|
||||||
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
|
auto json = R"({ "a": 1, "b": 2, "c": 3 })"_padded;
|
||||||
@@ -893,6 +1065,14 @@ namespace object_tests {
|
|||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
return
|
return
|
||||||
|
no_missing_keys() &&
|
||||||
|
missing_key_continue() &&
|
||||||
|
missing_keys() &&
|
||||||
|
#if SIMDJSON_EXCEPTIONS
|
||||||
|
fixed_broken_issue_1521() &&
|
||||||
|
issue_1521() &&
|
||||||
|
broken_issue_1521() &&
|
||||||
|
#endif
|
||||||
iterate_object() &&
|
iterate_object() &&
|
||||||
iterate_empty_object() &&
|
iterate_empty_object() &&
|
||||||
object_index() &&
|
object_index() &&
|
||||||
|
|||||||
Reference in New Issue
Block a user