Skip to content

Commit e774c50

Browse files
committed
Move error to json_iterator
1 parent 57de19d commit e774c50

File tree

6 files changed

+66
-41
lines changed

6 files changed

+66
-41
lines changed

include/simdjson/generic/ondemand/array_iterator-inl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace ondemand {
55
simdjson_really_inline array_iterator::array_iterator(json_iterator_ref &_iter) noexcept : iter{&_iter} {}
66

77
simdjson_really_inline simdjson_result<value> array_iterator::operator*() noexcept {
8-
if (error) { iter->release(); return error; }
8+
if ((*iter)->error()) { iter->release(); return (*iter)->error(); }
99
return value::start(iter->borrow());
1010
}
1111
simdjson_really_inline bool array_iterator::operator==(const array_iterator &other) noexcept {
@@ -16,7 +16,7 @@ simdjson_really_inline bool array_iterator::operator!=(const array_iterator &) n
1616
}
1717
simdjson_really_inline array_iterator &array_iterator::operator++() noexcept {
1818
bool has_value;
19-
error = (*iter)->has_next_element().get(has_value); // If there's an error, has_next stays true.
19+
error_code error = (*iter)->has_next_element().get(has_value); // If there's an error, has_next stays true.
2020
if (!(error || has_value)) { iter->release(); }
2121
return *this;
2222
}

include/simdjson/generic/ondemand/array_iterator.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,6 @@ class array_iterator {
5858

5959
private:
6060
json_iterator_ref *iter{};
61-
/**
62-
* Error, if there is one. Errors are only yielded once.
63-
*
64-
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
65-
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
66-
* this is not elided, we should make sure it's at least not using up a register. Failing that,
67-
* we should store it in document so there's only one of them.
68-
*/
69-
error_code error{};
7061

7162
simdjson_really_inline array_iterator(json_iterator_ref &iter) noexcept;
7263

include/simdjson/generic/ondemand/json_iterator-inl.h

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ simdjson_really_inline json_iterator::~json_iterator() noexcept {
4141
#endif
4242

4343
SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator::start_object() noexcept {
44-
if (*advance() != '{') { logger::log_error(*this, "Not an object"); return INCORRECT_TYPE; }
44+
if (*advance() != '{') { return report_error(INCORRECT_TYPE, "Not an object"); }
4545
return started_object();
4646
}
4747

@@ -63,8 +63,7 @@ SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator:
6363
case ',':
6464
return true;
6565
default:
66-
logger::log_error(*this, "Missing comma between object fields");
67-
return TAPE_ERROR;
66+
return report_error(TAPE_ERROR, "Missing comma between object fields");
6867
}
6968
}
7069

@@ -73,7 +72,7 @@ SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator:
7372
do {
7473
raw_json_string actual_key;
7574
SIMDJSON_TRY( get_raw_json_string().get(actual_key) );
76-
if (*advance() != ':') { logger::log_error(*this, "Missing colon in object field"); return TAPE_ERROR; }
75+
if (*advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
7776
if (actual_key == key) {
7877
logger::log_event(*this, "match", key);
7978
return true;
@@ -89,17 +88,17 @@ SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator:
8988

9089
SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<raw_json_string> json_iterator::field_key() noexcept {
9190
const uint8_t *key = advance();
92-
if (*(key++) != '"') { logger::log_error(*this, "Object key is not a string"); return TAPE_ERROR; }
91+
if (*(key++) != '"') { return report_error(TAPE_ERROR, "Object key is not a string"); }
9392
return raw_json_string(key);
9493
}
9594

9695
SIMDJSON_WARN_UNUSED simdjson_really_inline error_code json_iterator::field_value() noexcept {
97-
if (*advance() != ':') { logger::log_error(*this, "Missing colon in object field"); return TAPE_ERROR; }
96+
if (*advance() != ':') { return report_error(TAPE_ERROR, "Missing colon in object field"); }
9897
return SUCCESS;
9998
}
10099

101100
SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator::start_array() noexcept {
102-
if (*advance() != '[') { logger::log_error(*this, "Not an array"); return INCORRECT_TYPE; }
101+
if (*advance() != '[') { return report_error(INCORRECT_TYPE, "Not an array"); }
103102
return started_array();
104103
}
105104

@@ -121,8 +120,7 @@ SIMDJSON_WARN_UNUSED simdjson_really_inline simdjson_result<bool> json_iterator:
121120
case ',':
122121
return true;
123122
default:
124-
logger::log_error(*this, "Missing comma between array elements");
125-
return TAPE_ERROR;
123+
return report_error(TAPE_ERROR, "Missing comma between array elements");
126124
}
127125
}
128126

@@ -148,7 +146,7 @@ SIMDJSON_WARN_UNUSED simdjson_result<bool> json_iterator::get_bool() noexcept {
148146
auto not_true = atomparsing::str4ncmp(json, "true");
149147
auto not_false = atomparsing::str4ncmp(json, "fals") | (json[4] ^ 'e');
150148
bool error = (not_true && not_false) || jsoncharutils::is_not_structural_or_whitespace(json[not_true ? 5 : 4]);
151-
if (error) { logger::log_error(*this, "not a boolean"); return INCORRECT_TYPE; }
149+
if (error) { return report_error(INCORRECT_TYPE, "not a boolean"); }
152150
return simdjson_result<bool>(!not_true);
153151
}
154152
simdjson_really_inline bool json_iterator::is_null() noexcept {
@@ -181,22 +179,28 @@ constexpr const uint32_t MAX_INT_LENGTH = 1024;
181179

182180
SIMDJSON_WARN_UNUSED simdjson_result<uint64_t> json_iterator::get_root_uint64() noexcept {
183181
uint8_t tmpbuf[20+1]; // <20 digits> is the longest possible unsigned integer
184-
if (!advance_to_buffer(tmpbuf)) { return NUMBER_ERROR; }
182+
if (!advance_to_buffer(tmpbuf)) { return report_error(NUMBER_ERROR, "Root number more than 20 digits"); }
185183
logger::log_value(*this, "uint64", "", 0);
186-
return numberparsing::parse_unsigned(buf);
184+
auto result = numberparsing::parse_unsigned(buf);
185+
if (result.error()) { report_error(result.error(), "Error parsing unsigned integer"); }
186+
return result;
187187
}
188188
SIMDJSON_WARN_UNUSED simdjson_result<int64_t> json_iterator::get_root_int64() noexcept {
189189
uint8_t tmpbuf[20+1]; // -<19 digits> is the longest possible integer
190-
if (!advance_to_buffer(tmpbuf)) { return NUMBER_ERROR; }
190+
if (!advance_to_buffer(tmpbuf)) { return report_error(NUMBER_ERROR, "Root number more than 20 characters"); }
191191
logger::log_value(*this, "int64", "", 0);
192-
return numberparsing::parse_integer(buf);
192+
auto result = numberparsing::parse_integer(buf);
193+
if (result.error()) { report_error(result.error(), "Error parsing integer"); }
194+
return result;
193195
}
194196
SIMDJSON_WARN_UNUSED simdjson_result<double> json_iterator::get_root_double() noexcept {
195197
// Per https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/, 1074 is the maximum number of significant fractional digits. Add 8 more digits for the biggest number: -0.<fraction>e-308.
196198
uint8_t tmpbuf[1074+8+1];
197-
if (!advance_to_buffer(tmpbuf)) { return NUMBER_ERROR; }
199+
if (!advance_to_buffer(tmpbuf)) { return report_error(NUMBER_ERROR, "Root float more than 1082 digits"); }
198200
logger::log_value(*this, "double", "", 0);
199-
return numberparsing::parse_double(buf);
201+
auto result = numberparsing::parse_double(buf);
202+
if (result.error()) { report_error(result.error(), "Error parsing double"); }
203+
return result;
200204
}
201205
SIMDJSON_WARN_UNUSED simdjson_result<bool> json_iterator::get_root_bool() noexcept {
202206
uint8_t tmpbuf[5+1];
@@ -248,8 +252,7 @@ SIMDJSON_WARN_UNUSED simdjson_really_inline error_code json_iterator::skip_conta
248252
}
249253
}
250254

251-
logger::log_error(*this, "not enough close braces");
252-
return TAPE_ERROR;
255+
return report_error(TAPE_ERROR, "not enough close braces");
253256
}
254257

255258
simdjson_really_inline bool json_iterator::at_start() const noexcept {
@@ -276,6 +279,16 @@ simdjson_really_inline json_iterator_ref json_iterator::borrow() noexcept {
276279
#endif
277280
}
278281

282+
simdjson_really_inline error_code json_iterator::report_error(error_code error, const char *message) noexcept {
283+
SIMDJSON_ASSUME(error != SUCCESS && error != UNINITIALIZED && error != INCORRECT_TYPE && error != NO_SUCH_FIELD);
284+
logger::log_error(*this, message);
285+
_error = error;
286+
return error;
287+
}
288+
simdjson_really_inline error_code json_iterator::error() const noexcept {
289+
return _error;
290+
}
291+
279292
//
280293
// json_iterator_ref
281294
//

include/simdjson/generic/ondemand/json_iterator.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,39 @@ class json_iterator : public token_iterator {
146146
* Tell whether the iterator is live (has not been moved).
147147
*/
148148
simdjson_really_inline bool is_alive() const noexcept;
149+
150+
/**
151+
* Report an error, preventing further iteration.
152+
*
153+
* @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
154+
* @param message An error message to report with the error.
155+
*/
156+
simdjson_really_inline error_code report_error(error_code error, const char *message) noexcept;
157+
158+
/**
159+
* Get the error (if any).
160+
*/
161+
simdjson_really_inline error_code error() const noexcept;
162+
149163
protected:
150164
ondemand::parser *parser{};
165+
/**
166+
* Next free location in the string buffer.
167+
*
168+
* Used by raw_json_string::unescape() to have a place to unescape strings to.
169+
*/
151170
uint8_t *current_string_buf_loc{};
171+
/**
172+
* JSON error, if there is one.
173+
*
174+
* INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
175+
*
176+
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
177+
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
178+
* this is not elided, we should make sure it's at least not using up a register. Failing that,
179+
* we should store it in document so there's only one of them.
180+
*/
181+
error_code _error{};
152182
#ifdef SIMDJSON_ONDEMAND_SAFETY_RAILS
153183
uint32_t active_lease_depth{};
154184
#endif

include/simdjson/generic/ondemand/object_iterator-inl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace ondemand {
99
simdjson_really_inline object_iterator::object_iterator(json_iterator_ref &_iter) noexcept : iter{&_iter} {}
1010

1111
simdjson_really_inline simdjson_result<field> object_iterator::operator*() noexcept {
12-
if (error) { iter->release(); return error; }
12+
if ((*iter)->error()) { iter->release(); return (*iter)->error(); }
1313
return field::start(iter->borrow());
1414
}
1515
simdjson_really_inline bool object_iterator::operator==(const object_iterator &other) noexcept {
@@ -19,9 +19,9 @@ simdjson_really_inline bool object_iterator::operator!=(const object_iterator &)
1919
return iter->is_alive();
2020
}
2121
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
22-
if (error) { return *this; }
22+
if ((*iter)->error()) { return *this; }
2323
bool has_value;
24-
error = (*iter)->has_next_field().get(has_value);
24+
error_code error = (*iter)->has_next_field().get(has_value);
2525
if (!(error || has_value)) { iter->release(); }
2626
return *this;
2727
}

include/simdjson/generic/ondemand/object_iterator.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,6 @@ class object_iterator {
3333
simdjson_really_inline object_iterator &operator++() noexcept;
3434
private:
3535
json_iterator_ref *iter{};
36-
/**
37-
* Error, if there is one. Errors are only yielded once.
38-
*
39-
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
40-
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
41-
* this is not elided, we should make sure it's at least not using up a register. Failing that,
42-
* we should store it in document so there's only one of them.
43-
*/
44-
error_code error{};
4536
simdjson_really_inline object_iterator(json_iterator_ref &iter) noexcept;
4637
friend struct simdjson_result<object_iterator>;
4738
friend class object;

0 commit comments

Comments
 (0)