simdjson  3.2.3
Ridiculously Fast JSON
parser-inl.h
1 #ifndef SIMDJSON_PARSER_INL_H
2 #define SIMDJSON_PARSER_INL_H
3 
4 #include "simdjson/dom/base.h"
5 #include "simdjson/dom/document_stream.h"
6 #include "simdjson/implementation.h"
7 #include "simdjson/internal/dom_parser_implementation.h"
8 
9 #include "simdjson/error-inl.h"
10 #include "simdjson/padded_string-inl.h"
11 #include "simdjson/dom/document_stream-inl.h"
12 #include "simdjson/dom/element-inl.h"
13 
14 #include <climits>
15 
16 namespace simdjson {
17 namespace dom {
18 
19 //
20 // parser inline implementation
21 //
22 simdjson_inline parser::parser(size_t max_capacity) noexcept
23  : _max_capacity{max_capacity},
24  loaded_bytes(nullptr) {
25 }
26 simdjson_inline parser::parser(parser &&other) noexcept = default;
27 simdjson_inline parser &parser::operator=(parser &&other) noexcept = default;
28 
29 inline bool parser::is_valid() const noexcept { return valid; }
30 inline int parser::get_error_code() const noexcept { return error; }
31 inline std::string parser::get_error_message() const noexcept { return error_message(error); }
32 
33 inline bool parser::dump_raw_tape(std::ostream &os) const noexcept {
34  return valid ? doc.dump_raw_tape(os) : false;
35 }
36 
37 inline simdjson_result<size_t> parser::read_file(const std::string &path) noexcept {
38  // Open the file
39  SIMDJSON_PUSH_DISABLE_WARNINGS
40  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
41  std::FILE *fp = std::fopen(path.c_str(), "rb");
42  SIMDJSON_POP_DISABLE_WARNINGS
43 
44  if (fp == nullptr) {
45  return IO_ERROR;
46  }
47 
48  // Get the file size
49  int ret;
50 #if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
51  ret = _fseeki64(fp, 0, SEEK_END);
52 #else
53  ret = std::fseek(fp, 0, SEEK_END);
54 #endif // _WIN64
55  if(ret < 0) {
56  std::fclose(fp);
57  return IO_ERROR;
58  }
59 #if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
60  __int64 len = _ftelli64(fp);
61  if(len == -1L) {
62  std::fclose(fp);
63  return IO_ERROR;
64  }
65 #else
66  long len = std::ftell(fp);
67  if((len < 0) || (len == LONG_MAX)) {
68  std::fclose(fp);
69  return IO_ERROR;
70  }
71 #endif
72 
73  // Make sure we have enough capacity to load the file
74  if (_loaded_bytes_capacity < size_t(len)) {
75  loaded_bytes.reset( internal::allocate_padded_buffer(len) );
76  if (!loaded_bytes) {
77  std::fclose(fp);
78  return MEMALLOC;
79  }
80  _loaded_bytes_capacity = len;
81  }
82 
83  // Read the string
84  std::rewind(fp);
85  size_t bytes_read = std::fread(loaded_bytes.get(), 1, len, fp);
86  if (std::fclose(fp) != 0 || bytes_read != size_t(len)) {
87  return IO_ERROR;
88  }
89 
90  return bytes_read;
91 }
92 
93 inline simdjson_result<element> parser::load(const std::string &path) & noexcept {
94  size_t len;
95  auto _error = read_file(path).get(len);
96  if (_error) { return _error; }
97  return parse(loaded_bytes.get(), len, false);
98 }
99 
100 inline simdjson_result<document_stream> parser::load_many(const std::string &path, size_t batch_size) noexcept {
101  size_t len;
102  auto _error = read_file(path).get(len);
103  if (_error) { return _error; }
104  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
105  return document_stream(*this, reinterpret_cast<const uint8_t*>(loaded_bytes.get()), len, batch_size);
106 }
107 
108 inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const uint8_t *buf, size_t len, bool realloc_if_needed) & noexcept {
109  // Important: we need to ensure that document has enough capacity.
110  // Important: It is possible that provided_doc is actually the internal 'doc' within the parser!!!
111  error_code _error = ensure_capacity(provided_doc, len);
112  if (_error) { return _error; }
113  if (realloc_if_needed) {
114  // Make sure we have enough capacity to copy len bytes
115  if (!loaded_bytes || _loaded_bytes_capacity < len) {
116  loaded_bytes.reset( internal::allocate_padded_buffer(len) );
117  if (!loaded_bytes) {
118  return MEMALLOC;
119  }
120  _loaded_bytes_capacity = len;
121  }
122  std::memcpy(static_cast<void *>(loaded_bytes.get()), buf, len);
123  }
124  _error = implementation->parse(realloc_if_needed ? reinterpret_cast<const uint8_t*>(loaded_bytes.get()): buf, len, provided_doc);
125 
126  if (_error) { return _error; }
127 
128  return provided_doc.root();
129 }
130 
131 simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const char *buf, size_t len, bool realloc_if_needed) & noexcept {
132  return parse_into_document(provided_doc, reinterpret_cast<const uint8_t *>(buf), len, realloc_if_needed);
133 }
134 simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const std::string &s) & noexcept {
135  return parse_into_document(provided_doc, s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
136 }
137 simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const padded_string &s) & noexcept {
138  return parse_into_document(provided_doc, s.data(), s.length(), false);
139 }
140 
141 
142 inline simdjson_result<element> parser::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) & noexcept {
143  return parse_into_document(doc, buf, len, realloc_if_needed);
144 }
145 
146 simdjson_inline simdjson_result<element> parser::parse(const char *buf, size_t len, bool realloc_if_needed) & noexcept {
147  return parse(reinterpret_cast<const uint8_t *>(buf), len, realloc_if_needed);
148 }
149 simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & noexcept {
150  return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
151 }
152 simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
153  return parse(s.data(), s.length(), false);
154 }
155 simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
156  return parse(v.data(), v.length(), false);
157 }
158 
159 inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
160  if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
161  return document_stream(*this, buf, len, batch_size);
162 }
163 inline simdjson_result<document_stream> parser::parse_many(const char *buf, size_t len, size_t batch_size) noexcept {
164  return parse_many(reinterpret_cast<const uint8_t *>(buf), len, batch_size);
165 }
166 inline simdjson_result<document_stream> parser::parse_many(const std::string &s, size_t batch_size) noexcept {
167  return parse_many(s.data(), s.length(), batch_size);
168 }
169 inline simdjson_result<document_stream> parser::parse_many(const padded_string &s, size_t batch_size) noexcept {
170  return parse_many(s.data(), s.length(), batch_size);
171 }
172 
173 simdjson_inline size_t parser::capacity() const noexcept {
174  return implementation ? implementation->capacity() : 0;
175 }
176 simdjson_inline size_t parser::max_capacity() const noexcept {
177  return _max_capacity;
178 }
179 simdjson_inline size_t parser::max_depth() const noexcept {
180  return implementation ? implementation->max_depth() : DEFAULT_MAX_DEPTH;
181 }
182 
183 simdjson_warn_unused
184 inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept {
185  //
186  // Reallocate implementation if needed
187  //
188  error_code err;
189  if (implementation) {
190  err = implementation->allocate(capacity, max_depth);
191  } else {
192  err = simdjson::get_active_implementation()->create_dom_parser_implementation(capacity, max_depth, implementation);
193  }
194  if (err) { return err; }
195  return SUCCESS;
196 }
197 
198 #ifndef SIMDJSON_DISABLE_DEPRECATED_API
199 simdjson_warn_unused
200 inline bool parser::allocate_capacity(size_t capacity, size_t max_depth) noexcept {
201  return !allocate(capacity, max_depth);
202 }
203 #endif // SIMDJSON_DISABLE_DEPRECATED_API
204 
205 inline error_code parser::ensure_capacity(size_t desired_capacity) noexcept {
206  return ensure_capacity(doc, desired_capacity);
207 }
208 
209 
210 inline error_code parser::ensure_capacity(document& target_document, size_t desired_capacity) noexcept {
211  // 1. It is wasteful to allocate a document and a parser for documents spanning less than MINIMAL_DOCUMENT_CAPACITY bytes.
212  // 2. If we allow desired_capacity = 0 then it is possible to exit this function with implementation == nullptr.
213  if(desired_capacity < MINIMAL_DOCUMENT_CAPACITY) { desired_capacity = MINIMAL_DOCUMENT_CAPACITY; }
214  // If we don't have enough capacity, (try to) automatically bump it.
215  // If the document needs allocation, do it too.
216  // Both in one if statement to minimize unlikely branching.
217  //
218  // Note: we must make sure that this function is called if capacity() == 0. We do so because we
219  // ensure that desired_capacity > 0.
220  if (simdjson_unlikely(capacity() < desired_capacity || target_document.capacity() < desired_capacity)) {
221  if (desired_capacity > max_capacity()) {
222  return error = CAPACITY;
223  }
224  error_code err1 = target_document.capacity() < desired_capacity ? target_document.allocate(desired_capacity) : SUCCESS;
225  error_code err2 = capacity() < desired_capacity ? allocate(desired_capacity, max_depth()) : SUCCESS;
226  if(err1 != SUCCESS) { return error = err1; }
227  if(err2 != SUCCESS) { return error = err2; }
228  }
229  return SUCCESS;
230 }
231 
232 simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
233  if(max_capacity > MINIMAL_DOCUMENT_CAPACITY) {
234  _max_capacity = max_capacity;
235  } else {
236  _max_capacity = MINIMAL_DOCUMENT_CAPACITY;
237  }
238 }
239 
240 } // namespace dom
241 } // namespace simdjson
242 
243 #endif // SIMDJSON_PARSER_INL_H
A forward-only stream of documents.
A parsed JSON document.
Definition: document.h:16
simdjson_inline parser(size_t max_capacity=SIMDJSON_MAXSIZE_BYTES) noexcept
Create a JSON parser.
Definition: parser-inl.h:22
simdjson_result< element > parse(const uint8_t *buf, size_t len, bool realloc_if_needed=true) &noexcept
Parse a JSON document and return a temporary reference to it.
Definition: parser-inl.h:142
simdjson_result< element > parse_into_document(document &doc, const uint8_t *buf, size_t len, bool realloc_if_needed=true) &noexcept
Parse a JSON document into a provide document instance and return a temporary reference to it.
Definition: parser-inl.h:108
simdjson_inline size_t max_depth() const noexcept
The maximum level of nested object and arrays supported by this parser.
Definition: parser-inl.h:179
simdjson_result< document_stream > load_many(const std::string &path, size_t batch_size=dom::DEFAULT_BATCH_SIZE) noexcept
Load a file containing many JSON documents.
Definition: parser-inl.h:100
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept
Set max_capacity.
Definition: parser-inl.h:232
simdjson_inline size_t max_capacity() const noexcept
The largest document this parser can automatically support.
Definition: parser-inl.h:176
simdjson_result< element > load(const std::string &path) &noexcept
Load a JSON document from a file and return a reference to it.
Definition: parser-inl.h:93
simdjson_inline size_t capacity() const noexcept
The largest document this parser can support without reallocating.
Definition: parser-inl.h:173
simdjson_inline parser & operator=(parser &&other) noexcept
Take another parser's buffers and state.
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:184
simdjson_result< document_stream > parse_many(const uint8_t *buf, size_t len, size_t batch_size=dom::DEFAULT_BATCH_SIZE) noexcept
Parse a buffer containing many JSON documents.
Definition: parser-inl.h:159
An implementation of simdjson for a particular CPU architecture.
The top level simdjson namespace, containing everything the library provides.
Definition: base.h:8
const char * error_message(error_code error) noexcept
Get the error message for the given error code.
Definition: error-inl.h:20
constexpr size_t DEFAULT_MAX_DEPTH
By default, simdjson supports this many nested objects and arrays.
Definition: base.h:38
error_code
All possible errors returned by simdjson.
Definition: error.h:19
@ CAPACITY
This parser can't support a document that big.
Definition: error.h:21
@ MEMALLOC
Error allocating memory, most likely out of memory.
Definition: error.h:22
@ SUCCESS
No error.
Definition: error.h:20
@ IO_ERROR
Error reading a file.
Definition: error.h:40
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr< const implementation > & get_active_implementation()
The active implementation.
constexpr size_t SIMDJSON_PADDING
The amount of padding needed in a buffer to parse JSON.
Definition: base.h:31
The result of a simdjson operation that could fail.
Definition: error.h:207