1 #ifndef SIMDJSON_INLINE_DOCUMENT_STREAM_H
2 #define SIMDJSON_INLINE_DOCUMENT_STREAM_H
4 #include "simdjson/dom/document_stream.h"
11 #ifdef SIMDJSON_THREADS_ENABLED
12 inline void stage1_worker::finish() {
17 std::unique_lock<std::mutex> lock(locking_mutex);
18 cond_var.wait(lock, [
this]{
return has_work ==
false;});
21 inline stage1_worker::~stage1_worker() {
28 inline void stage1_worker::start_thread() {
29 std::unique_lock<std::mutex> lock(locking_mutex);
30 if(thread.joinable()) {
33 thread = std::thread([
this]{
35 std::unique_lock<std::mutex> thread_lock(locking_mutex);
37 cond_var.wait(thread_lock, [
this]{
return has_work || !can_work;});
44 this->owner->stage1_thread_error = this->owner->run_stage1(*this->stage1_thread_parser,
45 this->_next_batch_start);
46 this->has_work =
false;
50 cond_var.notify_one();
58 inline void stage1_worker::stop_thread() {
59 std::unique_lock<std::mutex> lock(locking_mutex);
63 cond_var.notify_all();
65 if(thread.joinable()) {
70 inline void stage1_worker::run(document_stream * ds, dom::parser * stage1,
size_t next_batch_start) {
71 std::unique_lock<std::mutex> lock(locking_mutex);
73 _next_batch_start = next_batch_start;
74 stage1_thread_parser = stage1;
79 cond_var.notify_one();
93 batch_size{_batch_size <= MINIMAL_BATCH_SIZE ? MINIMAL_BATCH_SIZE : _batch_size},
95 #ifdef SIMDJSON_THREADS_ENABLED
96 , use_thread(_parser.threaded)
99 #ifdef SIMDJSON_THREADS_ENABLED
100 if(worker.get() ==
nullptr) {
112 #ifdef SIMDJSON_THREADS_ENABLED
118 simdjson_inline document_stream::~document_stream() noexcept {
119 #ifdef SIMDJSON_THREADS_ENABLED
125 : stream{
nullptr}, finished{
true} {
139 : stream{_stream}, finished{is_end} {
148 if (stream->error) {
return stream->
error; }
149 return stream->parser->doc.root();
163 if (stream->error) { finished =
true; }
172 if (stream->error ==
EMPTY) { finished =
true; }
180 return finished != other.finished;
183 inline void document_stream::start() noexcept {
184 if (error) {
return; }
185 error =
parser->ensure_capacity(batch_size);
186 if (error) {
return; }
189 error = run_stage1(*parser, batch_start);
190 while(error ==
EMPTY) {
192 batch_start = next_batch_start();
193 if (batch_start >= len) {
return; }
194 error = run_stage1(*parser, batch_start);
196 if (error) {
return; }
197 #ifdef SIMDJSON_THREADS_ENABLED
198 if (use_thread && next_batch_start() < len) {
200 error = stage1_thread_parser.ensure_capacity(batch_size);
201 if (error) {
return; }
202 worker->start_thread();
203 start_stage1_thread();
204 if (error) {
return; }
210 simdjson_inline
size_t document_stream::iterator::current_index() const noexcept {
211 return stream->doc_index;
214 simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
215 const char* start =
reinterpret_cast<const char*
>(stream->buf) + current_index();
216 bool object_or_array = ((*start ==
'[') || (*start ==
'{'));
217 if(object_or_array) {
218 size_t next_doc_index = stream->batch_start + stream->parser->implementation->structural_indexes[stream->parser->implementation->next_structural_index - 1];
219 return std::string_view(start, next_doc_index - current_index() + 1);
221 size_t next_doc_index = stream->batch_start + stream->parser->implementation->structural_indexes[stream->parser->implementation->next_structural_index];
222 return std::string_view(
reinterpret_cast<const char*
>(stream->buf) + current_index(), next_doc_index - current_index() - 1);
227 inline void document_stream::next() noexcept {
229 if (error) {
return; }
232 doc_index = batch_start + parser->implementation->structural_indexes[parser->implementation->next_structural_index];
233 error = parser->implementation->stage2_next(parser->doc);
235 while (error ==
EMPTY) {
236 batch_start = next_batch_start();
237 if (batch_start >= len) {
break; }
239 #ifdef SIMDJSON_THREADS_ENABLED
241 load_from_stage1_thread();
243 error = run_stage1(*parser, batch_start);
246 error = run_stage1(*parser, batch_start);
248 if (error) {
continue; }
250 doc_index = batch_start + parser->implementation->structural_indexes[parser->implementation->next_structural_index];
251 error = parser->implementation->stage2_next(parser->doc);
259 if(error ==
CAPACITY) {
return len - batch_start; }
260 return parser->implementation->structural_indexes[
parser->implementation->n_structural_indexes] -
parser->implementation->structural_indexes[
parser->implementation->n_structural_indexes + 1];
263 inline size_t document_stream::next_batch_start() const noexcept {
264 return batch_start +
parser->implementation->structural_indexes[
parser->implementation->n_structural_indexes];
268 size_t remaining = len - _batch_start;
269 if (remaining <= batch_size) {
270 return p.implementation->stage1(&buf[_batch_start], remaining, stage1_mode::streaming_final);
272 return p.implementation->stage1(&buf[_batch_start], batch_size, stage1_mode::streaming_partial);
276 #ifdef SIMDJSON_THREADS_ENABLED
278 inline void document_stream::load_from_stage1_thread() noexcept {
282 std::swap(*parser, stage1_thread_parser);
283 error = stage1_thread_error;
284 if (error) {
return; }
287 if (next_batch_start() < len) {
288 start_stage1_thread();
292 inline void document_stream::start_stage1_thread() noexcept {
298 size_t _next_batch_start = this->next_batch_start();
300 worker->run(
this, & this->stage1_thread_parser, _next_batch_start);
307 simdjson_inline simdjson_result<dom::document_stream>::simdjson_result() noexcept
308 : simdjson_result_base() {
310 simdjson_inline simdjson_result<dom::document_stream>::simdjson_result(
error_code error) noexcept
311 : simdjson_result_base(error) {
313 simdjson_inline simdjson_result<dom::document_stream>::simdjson_result(dom::document_stream &&value) noexcept
314 : simdjson_result_base(std::forward<dom::document_stream>(value)) {
317 #if SIMDJSON_EXCEPTIONS
318 simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept(false) {
319 if (error()) {
throw simdjson_error(error()); }
320 return first.begin();
322 simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept(false) {
323 if (error()) {
throw simdjson_error(error()); }
327 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
328 simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept {
329 first.error = error();
330 return first.begin();
332 simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept {
333 first.error = error();
An iterator through a forward-only stream of documents.
simdjson_inline reference operator*() noexcept
Get the current document (or error).
simdjson_inline bool operator!=(const iterator &other) const noexcept
Check if we're at the end yet.
simdjson_inline iterator() noexcept
Default constructor.
iterator & operator++() noexcept
Advance to the next document (prefix).
A forward-only stream of documents.
size_t size_in_bytes() const noexcept
Returns the input size in bytes.
size_t truncated_bytes() const noexcept
After iterating through the stream, this method returns the number of bytes that were not parsed at t...
simdjson_inline iterator begin() noexcept
Start iterating the documents in the stream.
simdjson_inline iterator end() noexcept
The end of the stream, for iterator comparison purposes.
simdjson_inline document_stream() noexcept
Construct an uninitialized document_stream.
A persistent document parser.
We want to support argument-dependent lookup (ADL).
error_code
All possible errors returned by simdjson.
@ CAPACITY
This parser can't support a document that big.
@ EMPTY
no structural element found
@ MEMALLOC
Error allocating memory, most likely out of memory.
@ UNINITIALIZED
unknown error, or uninitialized document
The result of a simdjson operation that could fail.
simdjson_inline error_code error() const noexcept
The error.