simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
parser-inl.h
1#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
5#include "simdjson/padded_string.h"
6#include "simdjson/padded_string_view.h"
7#include "simdjson/implementation.h"
8#include "simdjson/internal/dom_parser_implementation.h"
9#include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY
10#include "simdjson/generic/ondemand/base.h"
11#include "simdjson/generic/ondemand/document_stream.h"
12#include "simdjson/generic/ondemand/parser.h"
13#include "simdjson/generic/ondemand/raw_json_string.h"
14#endif // SIMDJSON_CONDITIONAL_INCLUDE
15
16namespace simdjson {
17namespace SIMDJSON_IMPLEMENTATION {
18namespace ondemand {
19
20simdjson_inline parser::parser(size_t max_capacity) noexcept
21 : _max_capacity{max_capacity} {
22}
23
24simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
25 if (new_capacity > max_capacity()) { return CAPACITY; }
26 if (string_buf && new_capacity <= capacity() && new_max_depth <= max_depth()) { return SUCCESS; }
27
28 // string_capacity copied from document::allocate
29 _capacity = 0;
30 if(5 * (new_capacity / 3) + SIMDJSON_PADDING < SIMDJSON_PADDING) {
31 return CAPACITY; // overflow, only happen on legacy 32-bit systems with very large capacity
32 }
33 size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * (new_capacity / 3) + SIMDJSON_PADDING, 64);
34 string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
35#if SIMDJSON_DEVELOPMENT_CHECKS
36 start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
37#endif
38 if (implementation) {
39 SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
40 SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
41 } else {
42 SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
43 }
44 _capacity = new_capacity;
45 _max_depth = new_max_depth;
46 return SUCCESS;
47}
48#if SIMDJSON_DEVELOPMENT_CHECKS
49simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept {
50 return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity());
51}
52#endif
53
54simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
55 if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
56
57 json.remove_utf8_bom();
58 _document_len = json.length();
59
60 // Allocate if needed
61 if (capacity() < json.length() || !string_buf) {
62 SIMDJSON_TRY( allocate(json.length(), max_depth()) );
63 }
64
65 // Run stage 1.
66 SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
67 return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
68}
69
70#ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
71simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept {
72 if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
73
74 json.remove_utf8_bom();
75 _document_len = json.length();
76
77 // Allocate if needed
78 if (capacity() < json.length() || !string_buf) {
79 SIMDJSON_TRY( allocate(json.length(), max_depth()) );
80 }
81
82 // Run stage 1.
83 const simdjson::error_code err = implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular);
84 if (err) {
85 if (err != UNCLOSED_STRING)
86 return err;
87 }
88 return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this, true });
89}
90#endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON
91
92simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
93 return iterate(padded_string_view(json, len, allocated));
94}
95
96simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
97 return iterate(padded_string_view(json, len, allocated));
98}
99
100simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
101 return iterate(padded_string_view(json, allocated));
102}
103
104simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string &json) & noexcept {
105 return iterate(pad_with_reserve(json));
106}
107
108simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
109 return iterate(padded_string_view(json));
110}
111
112simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
113 // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
114 SIMDJSON_TRY( result.error() );
115 padded_string_view json = result.value_unsafe();
116 return iterate(json);
117}
118
119simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
120 // We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
121 SIMDJSON_TRY( result.error() );
122 const padded_string &json = result.value_unsafe();
123 return iterate(json);
124}
125
126simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
127 if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
128
129 json.remove_utf8_bom();
130
131 // Allocate if needed
132 if (capacity() < json.length()) {
133 SIMDJSON_TRY( allocate(json.length(), max_depth()) );
134 }
135
136 // Run stage 1.
137 SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
138 return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
139}
140
141inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
142 if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
143 if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
144 buf += 3;
145 len -= 3;
146 }
147 return document_stream(*this, buf, len, batch_size, false, stream_format::whitespace_delimited);
148}
149inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size) noexcept {
150 return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size);
151}
153 if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
154 return iterate_many(s.data(), s.length(), batch_size);
155}
156inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size) noexcept {
157 return iterate_many(padded_string_view(s), batch_size);
158}
159inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size) noexcept {
160 return iterate_many(padded_string_view(s), batch_size);
161}
162inline simdjson_result<document_stream> parser::iterate_many(std::string &s, size_t batch_size) noexcept {
163 return iterate_many(pad(s), batch_size);
164}
165
166#ifndef SIMDJSON_DISABLE_DEPRECATED_API
167SIMDJSON_PUSH_DISABLE_WARNINGS
168SIMDJSON_DISABLE_DEPRECATED_WARNING
169inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
170 // Warning: no check is done on the buffer padding. We trust the user.
171 if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
172 if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
173 buf += 3;
174 len -= 3;
175 }
176 // Map allow_comma_separated to stream_format::comma_delimited
177 if (allow_comma_separated) {
178 return document_stream(*this, buf, len, batch_size, false, stream_format::comma_delimited);
179 }
180 return document_stream(*this, buf, len, batch_size, false, stream_format::whitespace_delimited);
181}
182
183inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
184 // Warning: no check is done on the buffer padding. We trust the user.
185 return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, allow_comma_separated);
186}
187inline simdjson_result<document_stream> parser::iterate_many(padded_string_view s, size_t batch_size, bool allow_comma_separated) noexcept {
188 if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
189 return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated);
190}
191inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept {
192 return iterate_many(padded_string_view(s), batch_size, allow_comma_separated);
193}
194inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
195 return iterate_many(padded_string_view(s), batch_size, allow_comma_separated);
196}
197inline simdjson_result<document_stream> parser::iterate_many(std::string &s, size_t batch_size, bool allow_comma_separated) noexcept {
198 return iterate_many(pad(s), batch_size, allow_comma_separated);
199}
200SIMDJSON_POP_DISABLE_WARNINGS
201#endif // SIMDJSON_DISABLE_DEPRECATED_API
202
203inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, stream_format format) noexcept {
204 if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
205 if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
206 buf += 3;
207 len -= 3;
208 }
210 // Strip leading JSON whitespace.
211 while (len > 0 && (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n' || buf[0] == '\r')) {
212 buf++; len--;
213 }
214 // Expect the opening '['.
215 if (len == 0 || buf[0] != '[') { return TAPE_ERROR; }
216 buf++; len--;
217 // Strip trailing JSON whitespace.
218 while (len > 0 && (buf[len-1] == ' ' || buf[len-1] == '\t' || buf[len-1] == '\n' || buf[len-1] == '\r')) {
219 len--;
220 }
221 // Expect the closing ']'.
222 if (len == 0 || buf[len-1] != ']') { return TAPE_ERROR; }
223 len--;
224 // Fall through to comma_delimited over the array contents.
226 }
227 return document_stream(*this, buf, len, batch_size, false, format);
228}
229inline simdjson_result<document_stream> parser::iterate_many(const char *buf, size_t len, size_t batch_size, stream_format format) noexcept {
230 return iterate_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size, format);
231}
233 if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; }
234 return iterate_many(s.data(), s.length(), batch_size, format);
235}
236inline simdjson_result<document_stream> parser::iterate_many(const std::string &s, size_t batch_size, stream_format format) noexcept {
237 return iterate_many(padded_string_view(s), batch_size, format);
238}
239inline simdjson_result<document_stream> parser::iterate_many(std::string &s, size_t batch_size, stream_format format) noexcept {
240 return iterate_many(pad(s), batch_size, format);
241}
242inline simdjson_result<document_stream> parser::iterate_many(const padded_string &s, size_t batch_size, stream_format format) noexcept {
243 return iterate_many(padded_string_view(s), batch_size, format);
244}
245simdjson_pure simdjson_inline size_t parser::capacity() const noexcept {
246 return _capacity;
247}
248simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept {
249 return _max_capacity;
250}
251simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept {
252 return _max_depth;
253}
254
255simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
256 if(max_capacity > dom::MINIMAL_DOCUMENT_CAPACITY) {
257 _max_capacity = max_capacity;
258 } else {
259 _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
260 }
261}
262
263simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
264 uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
265 if (!end) { return STRING_ERROR; }
266 std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
267 dst = end;
268 return result;
269}
270
271simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
272 uint8_t *end = implementation->parse_wobbly_string(in.buf, dst);
273 if (!end) { return STRING_ERROR; }
274 std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
275 dst = end;
276 return result;
277}
278
279simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() {
280 return *parser::get_parser_instance();
281}
282
283simdjson_inline bool parser::release_parser() {
284 auto &parser_instance = parser::get_threadlocal_parser_if_exists();
285 if (parser_instance) {
286 parser_instance.reset();
287 return true;
288 }
289 return false;
290}
291
292simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::get_parser_instance() {
293 std::unique_ptr<ondemand::parser>& parser_instance = get_threadlocal_parser_if_exists();
294 if (!parser_instance) {
295 parser_instance.reset(new ondemand::parser());
296 }
297 return parser_instance;
298}
299
300simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::get_threadlocal_parser_if_exists() {
301 // @the-moisrex points out that this could be implemented with std::optional (C++17).
302 thread_local std::unique_ptr<ondemand::parser> parser_instance = nullptr;
303 return parser_instance;
304}
305
306
307} // namespace ondemand
308} // namespace SIMDJSON_IMPLEMENTATION
309} // namespace simdjson
310
311namespace simdjson {
312
313simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::parser>::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::parser &&value) noexcept
314 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::parser>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::parser>(value)) {}
315simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::parser>::simdjson_result(error_code error) noexcept
316 : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::parser>(error) {}
317
318} // namespace simdjson
319
320#endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H
simdjson_warn_unused simdjson_result< document > iterate(padded_string_view json) &noexcept
Start iterating an on-demand JSON document.
Definition parser-inl.h:54
simdjson_pure simdjson_inline size_t max_capacity() const noexcept
The maximum capacity of this parser (the largest document it is allowed to process).
Definition parser-inl.h:248
simdjson_inline simdjson_result< std::string_view > unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement=false) const noexcept
Unescape this JSON string, replacing \ with \, with newline, etc.
Definition parser-inl.h:263
static simdjson_inline bool release_parser()
Release the parser instance initialized by get_parser() and all the associated resources (memory).
Definition parser-inl.h:283
simdjson_pure simdjson_inline size_t max_depth() const noexcept
The maximum depth of this parser (the most deeply nested objects and arrays it can process).
Definition parser-inl.h:251
simdjson_pure simdjson_inline size_t capacity() const noexcept
The capacity of this parser (the largest document it can process).
Definition parser-inl.h:245
parser(size_t max_capacity=SIMDJSON_MAXSIZE_BYTES) noexcept
Create a JSON parser.
Definition parser-inl.h:20
simdjson_inline simdjson_result< std::string_view > unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept
Unescape this JSON string, replacing \ with \, with newline, etc.
Definition parser-inl.h:271
simdjson_result< document_stream > iterate_many(const uint8_t *buf, size_t len, size_t batch_size=DEFAULT_BATCH_SIZE) noexcept
Parse a buffer containing many JSON documents.
Definition parser-inl.h:141
simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept
Ensure this parser has enough memory to process JSON documents up to capacity bytes in length and max...
Definition parser-inl.h:24
static simdjson_inline simdjson_warn_unused ondemand::parser & get_parser()
Get a unique parser instance corresponding to the current thread.
Definition parser-inl.h:279
A string escaped per JSON rules, terminated with quote (").
An implementation of simdjson for a particular CPU architecture.
User-provided string that promises it has extra padded bytes at the end for use with parser::parse().
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr< const implementation > & get_active_implementation()
The active implementation.
stream_format
Stream format for parse_many/iterate_many.
Definition base.h:61
@ comma_delimited
Comma-separated JSON documents (e.g., {...},{...},{...})
@ whitespace_delimited
Whitespace-delimited JSON documents (default, includes NDJSON/JSONL)
@ comma_delimited_array
A single JSON array whose elements are iterated as comma-separated documents (e.g....
padded_string_view pad_with_reserve(std::string &s) noexcept
Create a padded_string_view from a string.
error_code
All possible errors returned by simdjson.
Definition error.h:19
@ UNCLOSED_STRING
missing quote at the end
Definition error.h:35
@ CAPACITY
This parser can't support a document that big.
Definition error.h:21
@ TAPE_ERROR
Something went wrong, this is a generic error. Fatal/unrecoverable error.
Definition error.h:23
@ STRING_ERROR
Problem while parsing a string.
Definition error.h:25
@ SUCCESS
No error.
Definition error.h:20
@ INSUFFICIENT_PADDING
The JSON doesn't have enough padding for simdjson to safely parse it.
Definition error.h:47
padded_string_view pad(std::string &s) noexcept
Create a padded_string_view from a string.
constexpr size_t SIMDJSON_PADDING
The amount of padding needed in a buffer to parse JSON.
Definition base.h:42
The result of a simdjson operation that could fail.
Definition error.h:281