Skip to content

Commit 1abb64f

Browse files
authored
This fixes issue 1302 (simdjson#1303)
* This verifies issue 1302 * I believe that this fixes the issue. * Let us do it differently. * Better comments.
1 parent b442b29 commit 1abb64f

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

include/simdjson/dom/document_stream-inl.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,39 @@ simdjson_really_inline document_stream::iterator::iterator(document_stream& _str
116116
}
117117

118118
simdjson_really_inline simdjson_result<element> document_stream::iterator::operator*() noexcept {
119-
// Once we have yielded any errors, we're finished.
120-
if (stream.error) { finished = true; return stream.error; }
119+
// Note that in case of error, we do not yet mark
120+
// the iterator as "finished": this detection is done
121+
// in the operator++ function since it is possible
122+
// to call operator++ repeatedly while omitting
123+
// calls to operator*.
124+
if (stream.error) { return stream.error; }
121125
return stream.parser->doc.root();
122126
}
123127

124128
simdjson_really_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
129+
// If there is an error, then we want the iterator
130+
// to be finished, no matter what. (E.g., we do not
131+
// keep generating documents with errors, or go beyond
132+
// a document with errors.)
133+
//
134+
// Users do not have to call "operator*()" when they use operator++,
135+
// so we need to end the stream in the operator++ function.
136+
//
137+
// Note that setting finished = true is essential otherwise
138+
// we would enter an infinite loop.
139+
if (stream.error) { finished = true; }
140+
// Note that stream.error() is guarded against error conditions
141+
// (it will immediately return if stream.error casts to false).
142+
// In effect, this next function does nothing when (stream.error)
143+
// is true (hence the risk of an infinite loop).
125144
stream.next();
126145
// If that was the last document, we're finished.
146+
// It is the only type of error we do not want to appear
147+
// in operator*.
127148
if (stream.error == EMPTY) { finished = true; }
149+
// If we had any other kind of error (not EMPTY) then we want
150+
// to pass it along to the operator* and we cannot mark the result
151+
// as "finished" just yet.
128152
return *this;
129153
}
130154

@@ -168,6 +192,7 @@ simdjson_really_inline std::string_view document_stream::iterator::source() cons
168192

169193

170194
inline void document_stream::next() noexcept {
195+
// We always enter at once once in an error condition.
171196
if (error) { return; }
172197

173198
// Load the next document from the batch

tests/document_stream_tests.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,22 @@ namespace document_stream_tests {
6969
}
7070
return true;
7171
}
72+
73+
bool test_naked_iterators() {
74+
std::cout << "Running " << __func__ << std::endl;
75+
auto json = R"([1,23] "lone string" {"key":"unfinished value} )"_padded;
76+
simdjson::dom::parser parser;
77+
simdjson::dom::document_stream stream;
78+
ASSERT_SUCCESS( parser.parse_many(json).get(stream) );
79+
size_t count = 0;
80+
// We do not touch the document, intentionally.
81+
for(auto i = stream.begin(); i != stream.end(); ++i) {
82+
if(count > 10) { break; }
83+
count++;
84+
}
85+
return count == 1;
86+
}
87+
7288
bool single_document() {
7389
std::cout << "Running " << __func__ << std::endl;
7490
simdjson::dom::parser parser;
@@ -322,7 +338,8 @@ namespace document_stream_tests {
322338
}
323339

324340
bool run() {
325-
return test_current_index() &&
341+
return test_naked_iterators() &&
342+
test_current_index() &&
326343
single_document() &&
327344
#if SIMDJSON_EXCEPTIONS
328345
single_document_exceptions() &&

tests/parse_many_test.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ bool validate(const char *dirname) {
7373
auto error = simdjson::padded_string::load(fullpath).get(json);
7474
if (!error) {
7575
simdjson::dom::parser parser;
76-
7776
++how_many;
7877
simdjson::dom::document_stream docs;
7978
error = parser.parse_many(json).get(docs);

0 commit comments

Comments
 (0)