mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Automatically allocate memory as needed in parse
This commit is contained in:
@@ -168,23 +168,48 @@ document doc = document::parse(get_corpus(filename));
|
||||
doc.print_json(cout);
|
||||
```
|
||||
|
||||
If you're using simdjson to parse multiple documents, or in a loop, you should allocate a parser once and reuse it (allocation is slow, do it as little as possible!):
|
||||
### Reusing the parser for maximum efficiency
|
||||
|
||||
If you're using simdjson to parse multiple documents, or in a loop, you should make a parser once
|
||||
and reuse it. simdjson will allocate and retain internal buffers between parses, keeping buffers
|
||||
hot in cache and keeping allocation to a minimum.
|
||||
|
||||
```c++
|
||||
// Allocate a parser big enough for all files
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(1024*1024)) { exit(1); }
|
||||
|
||||
// Read files with the parser, one by one
|
||||
for (padded_string json : { string("[1, 2, 3]"), string("true"), string("[ true, false ]") }) {
|
||||
cout << "Parsing " << json.data() << " ..." << endl;
|
||||
auto [doc, error] = parser.parse(json);
|
||||
if (error) { cerr << "Error: " << error << endl; exit(1); }
|
||||
document& doc = parser.parse(json);
|
||||
doc.print_json(cout);
|
||||
cout << endl;
|
||||
}
|
||||
```
|
||||
|
||||
If you are running a server loop and want to limit the document size to keep server memory constant,
|
||||
you can set a maximum capacity:
|
||||
|
||||
```c++
|
||||
document::parser parser(1024*1024); // Set max capacity to 1MB
|
||||
for (int i=0;i<argc;i++) {
|
||||
auto [doc, error] = parser.parse(get_corpus(argv[i]));
|
||||
if (error == CAPACITY) { cerr << "JSON files larger than 1MB are not supported!" << endl; exit(1); }
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
doc.print_json(cout);
|
||||
}
|
||||
```
|
||||
|
||||
If you want absolutely constant memory usage, you can even allocate the capacity yourself at the
|
||||
beginning:
|
||||
|
||||
```c++
|
||||
document::parser parser(0); // This parser is not allowed to auto-allocate
|
||||
auto alloc_error = parser.set_capacity(1024*1024); // Set initial capacity to 1MB
|
||||
if (alloc_error) { exit(1); };
|
||||
|
||||
for (int i=0;i<argc;i++) {
|
||||
auto [doc, error] = parser.parse(get_corpus(argv[i]));
|
||||
if (error == CAPACITY) { cerr << "JSON files larger than 1MB are not supported!" << endl; exit(1); }
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
doc.print_json(cout);
|
||||
}
|
||||
```
|
||||
|
||||
## Newline-Delimited JSON (ndjson) and JSON lines
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const padded_string EMPTY_ARRAY("[]", 2);
|
||||
|
||||
static void json_parse(State& state) {
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
if (parser.set_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
for (auto _ : state) {
|
||||
auto error = simdjson::json_parse(EMPTY_ARRAY, parser);
|
||||
if (error) { return; }
|
||||
@@ -17,7 +17,7 @@ static void json_parse(State& state) {
|
||||
BENCHMARK(json_parse);
|
||||
static void parser_parse_error_code(State& state) {
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
if (parser.set_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
for (auto _ : state) {
|
||||
auto [doc, error] = parser.parse(EMPTY_ARRAY);
|
||||
if (error) { return; }
|
||||
@@ -26,7 +26,7 @@ static void parser_parse_error_code(State& state) {
|
||||
BENCHMARK(parser_parse_error_code);
|
||||
static void parser_parse_exception(State& state) {
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
if (parser.set_capacity(EMPTY_ARRAY.length())) { return; }
|
||||
for (auto _ : state) {
|
||||
try {
|
||||
UNUSED document &doc = parser.parse(EMPTY_ARRAY);
|
||||
|
||||
@@ -298,7 +298,7 @@ struct benchmarker {
|
||||
// Allocate document::parser
|
||||
collector.start();
|
||||
document::parser parser;
|
||||
bool allocok = parser.allocate_capacity(json.size());
|
||||
error_code error = parser.set_capacity(json.size());
|
||||
event_count allocate_count = collector.end();
|
||||
allocate_stage << allocate_count;
|
||||
// Run it once to get hot buffers
|
||||
@@ -309,14 +309,14 @@ struct benchmarker {
|
||||
}
|
||||
}
|
||||
|
||||
if (!allocok) {
|
||||
if (error) {
|
||||
exit_error(string("Unable to allocate_stage ") + to_string(json.size()) + " bytes for the JSON result.");
|
||||
}
|
||||
verbose() << "[verbose] allocated memory for parsed JSON " << endl;
|
||||
|
||||
// Stage 1 (find structurals)
|
||||
collector.start();
|
||||
error_code error = active_implementation->stage1((const uint8_t *)json.data(), json.size(), parser, false);
|
||||
error = active_implementation->stage1((const uint8_t *)json.data(), json.size(), parser, false);
|
||||
event_count stage1_count = collector.end();
|
||||
stage1 << stage1_count;
|
||||
if (error) {
|
||||
|
||||
@@ -39,9 +39,9 @@ int main (int argc, char *argv[]){
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
//Actual test
|
||||
simdjson::document::parser parser;
|
||||
bool allocok = parser.allocate_capacity(p.size());
|
||||
if (!allocok) {
|
||||
std::cerr << "failed to allocate memory" << std::endl;
|
||||
simdjson::error_code alloc_error = parser.set_capacity(p.size());
|
||||
if (alloc_error) {
|
||||
std::cerr << alloc_error << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::istringstream ss(std::string(p.data(), p.size()));
|
||||
|
||||
+181
-71
@@ -199,7 +199,7 @@ public:
|
||||
private:
|
||||
class tape_ref;
|
||||
enum class tape_type;
|
||||
bool set_capacity(size_t len);
|
||||
inline error_code set_capacity(size_t len) noexcept;
|
||||
}; // class document
|
||||
|
||||
/**
|
||||
@@ -818,8 +818,8 @@ private:
|
||||
/**
|
||||
* A persistent document parser.
|
||||
*
|
||||
* Use this if you intend to parse more than one document. It holds the internal memory necessary
|
||||
* to do parsing, as well as memory for a single document that is overwritten on each parse.
|
||||
* The parser is designed to be reused, holding the internal buffers necessary to do parsing,
|
||||
* as well as memory for a single document. The parsed document is overwritten on each parse.
|
||||
*
|
||||
* This class cannot be copied, only moved, to avoid unintended allocations.
|
||||
*
|
||||
@@ -828,9 +828,20 @@ private:
|
||||
class document::parser {
|
||||
public:
|
||||
/**
|
||||
* Create a JSON parser with zero capacity. Call allocate_capacity() to initialize it.
|
||||
* Create a JSON parser.
|
||||
*
|
||||
* The new parser will have zero capacity.
|
||||
*
|
||||
* @param max_capacity The maximum document length the parser can automatically handle. The parser
|
||||
* will allocate more capacity on an as needed basis (when it sees documents too big to handle)
|
||||
* up to this amount. The parser still starts with zero capacity no matter what this number is:
|
||||
* to allocate an initial capacity, call set_capacity() after constructing the parser. Defaults
|
||||
* to SIMDJSON_MAXSIZE_BYTES (the largest single document simdjson can process).
|
||||
* @param max_depth The maximum depth--number of nested objects and arrays--this parser can handle.
|
||||
* This will not be allocated until parse() is called for the first time. Defaults to
|
||||
* DEFAULT_MAX_DEPTH.
|
||||
*/
|
||||
parser()=default;
|
||||
really_inline parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES, size_t max_depth = DEFAULT_MAX_DEPTH) noexcept;
|
||||
~parser()=default;
|
||||
|
||||
/**
|
||||
@@ -849,71 +860,136 @@ public:
|
||||
parser &operator=(const document::parser &) = delete; // Disallow copying
|
||||
|
||||
/**
|
||||
* Parse a JSON document and return a reference to it.
|
||||
* Parse a JSON document and return a temporary reference to it.
|
||||
*
|
||||
* document::parser parser;
|
||||
* const document &doc = parser.parse(buf, len);
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* The JSON document still lives in the parser: this is the most efficient way to parse JSON
|
||||
* documents because it reuses the same buffers, but you *must* use the document before you
|
||||
* destroy the parser or call parse() again.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated. If realloc_if_needed is true,
|
||||
* it is assumed that the buffer does *not* have enough padding, and it is reallocated, enlarged
|
||||
* and copied before parsing.
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* If realloc_if_needed is true, it is assumed that the buffer does *not* have enough padding,
|
||||
* and it is copied into an enlarged temporary buffer before parsing.
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than len, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param buf The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, unless
|
||||
* realloc_if_needed is true.
|
||||
* @param len The length of the JSON.
|
||||
* @param realloc_if_needed Whether to reallocate and enlarge the JSON buffer to add padding.
|
||||
* @return the document, or an error if the JSON is invalid.
|
||||
* @return The document, or an error:
|
||||
* - MEMALLOC if realloc_if_needed is true or the parser does not have enough capacity,
|
||||
* and memory allocation fails.
|
||||
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
|
||||
* - other json errors if parsing fails.
|
||||
*/
|
||||
inline doc_ref_result parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) noexcept;
|
||||
|
||||
/**
|
||||
* Parse a JSON document and return a reference to it.
|
||||
* Parse a JSON document and return a temporary reference to it.
|
||||
*
|
||||
* document::parser parser;
|
||||
* const document &doc = parser.parse(buf, len);
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* The JSON document still lives in the parser: this is the most efficient way to parse JSON
|
||||
* documents because it reuses the same buffers, but you *must* use the document before you
|
||||
* destroy the parser or call parse() again.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated. If realloc_if_needed is true,
|
||||
* it is assumed that the buffer does *not* have enough padding, and it is reallocated, enlarged
|
||||
* and copied before parsing.
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* If realloc_if_needed is true, it is assumed that the buffer does *not* have enough padding,
|
||||
* and it is copied into an enlarged temporary buffer before parsing.
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than len, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param buf The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, unless
|
||||
* realloc_if_needed is true.
|
||||
* @param len The length of the JSON.
|
||||
* @param realloc_if_needed Whether to reallocate and enlarge the JSON buffer to add padding.
|
||||
* @return the document, or an error if the JSON is invalid.
|
||||
* @return The document, or an error:
|
||||
* - MEMALLOC if realloc_if_needed is true or the parser does not have enough capacity,
|
||||
* and memory allocation fails.
|
||||
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
|
||||
* - other json errors if parsing fails.
|
||||
*/
|
||||
really_inline doc_ref_result parse(const char *buf, size_t len, bool realloc_if_needed = true) noexcept;
|
||||
|
||||
/**
|
||||
* Parse a JSON document and return a reference to it.
|
||||
* Parse a JSON document and return a temporary reference to it.
|
||||
*
|
||||
* document::parser parser;
|
||||
* const document &doc = parser.parse(s);
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* The JSON document still lives in the parser: this is the most efficient way to parse JSON
|
||||
* documents because it reuses the same buffers, but you *must* use the document before you
|
||||
* destroy the parser or call parse() again.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated. If `str.capacity() - str.size()
|
||||
* < SIMDJSON_PADDING`, the string will be copied to a string with larger capacity before parsing.
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* If s.capacity() is less than SIMDJSON_PADDING, the string will be copied into an enlarged
|
||||
* temporary buffer before parsing.
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than len, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param s The JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes, or
|
||||
* a new string will be created with the extra padding.
|
||||
* @return the document, or an error if the JSON is invalid.
|
||||
* @return The document, or an error:
|
||||
* - MEMALLOC if the string does not have enough padding or the parser does not have
|
||||
* enough capacity, and memory allocation fails.
|
||||
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
|
||||
* - other json errors if parsing fails.
|
||||
*/
|
||||
really_inline doc_ref_result parse(const std::string &s) noexcept;
|
||||
|
||||
/**
|
||||
* Parse a JSON document and return a reference to it.
|
||||
* Parse a JSON document and return a temporary reference to it.
|
||||
*
|
||||
* document::parser parser;
|
||||
* const document &doc = parser.parse(s);
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* The JSON document still lives in the parser: this is the most efficient way to parse JSON
|
||||
* documents because it reuses the same buffers, but you *must* use the document before you
|
||||
* destroy the parser or call parse() again.
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param s The JSON to parse.
|
||||
* @return the document, or an error if the JSON is invalid.
|
||||
* @return The document, or an error:
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails.
|
||||
* - CAPACITY if the parser does not have enough capacity and len > max_capacity.
|
||||
* - other json errors if parsing fails.
|
||||
*/
|
||||
really_inline doc_ref_result parse(const padded_string &s) noexcept;
|
||||
|
||||
@@ -965,8 +1041,8 @@ public:
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser is unallocated, it will be auto-allocated to batch_size. If it is already
|
||||
* allocated, it must have a capacity at least as large as batch_size.
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param buf The concatenated JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes.
|
||||
* @param len The length of the concatenated JSON.
|
||||
@@ -976,8 +1052,8 @@ public:
|
||||
* Defaults to 10MB, which has been a reasonable sweet spot in our tests.
|
||||
* @return The stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* will yield 0 documents rather than an EMPTY error. Errors:
|
||||
* - MEMALLOC if the parser is unallocated and memory allocation fails
|
||||
* - CAPACITY if the parser already has a capacity, and it is less than batch_size
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails
|
||||
* - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
|
||||
* - other json errors if parsing fails.
|
||||
*/
|
||||
inline stream parse_many(const uint8_t *buf, size_t len, size_t batch_size = 1000000) noexcept;
|
||||
@@ -1027,8 +1103,8 @@ public:
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser is unallocated, it will be auto-allocated to batch_size. If it is already
|
||||
* allocated, it must have a capacity at least as large as batch_size.
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param buf The concatenated JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes.
|
||||
* @param len The length of the concatenated JSON.
|
||||
@@ -1038,8 +1114,8 @@ public:
|
||||
* Defaults to 10MB, which has been a reasonable sweet spot in our tests.
|
||||
* @return The stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* will yield 0 documents rather than an EMPTY error. Errors:
|
||||
* - MEMALLOC if the parser is unallocated and memory allocation fails
|
||||
* - CAPACITY if the parser already has a capacity, and it is less than batch_size
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails
|
||||
* - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
|
||||
* - other json errors if parsing fails
|
||||
*/
|
||||
inline stream parse_many(const char *buf, size_t len, size_t batch_size = 1000000) noexcept;
|
||||
@@ -1089,18 +1165,18 @@ public:
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser is unallocated, it will be auto-allocated to batch_size. If it is already
|
||||
* allocated, it must have a capacity at least as large as batch_size.
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param s The concatenated JSON to parse. Must have at least len + SIMDJSON_PADDING allocated bytes.
|
||||
* @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
|
||||
* spot is cache-related: small enough to fit in cache, yet big enough to
|
||||
* parse as many documents as possible in one tight loop.
|
||||
* Defaults to 10MB, which has been a reasonable sweet spot in our tests.
|
||||
* @return he stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* @return The stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* will yield 0 documents rather than an EMPTY error. Errors:
|
||||
* - MEMALLOC if the parser is unallocated and memory allocation fails
|
||||
* - CAPACITY if the parser already has a capacity, and it is less than batch_size
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails
|
||||
* - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
|
||||
* - other json errors if parsing fails
|
||||
*/
|
||||
inline stream parse_many(const std::string &s, size_t batch_size = 1000000) noexcept;
|
||||
@@ -1138,11 +1214,6 @@ public:
|
||||
* cout << std::string(doc["title"]) << endl;
|
||||
* }
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated.
|
||||
*
|
||||
* ### Threads
|
||||
*
|
||||
* When compiled with SIMDJSON_THREADS_ENABLED, this method will use a single thread under the
|
||||
@@ -1150,18 +1221,18 @@ public:
|
||||
*
|
||||
* ### Parser Capacity
|
||||
*
|
||||
* If the parser is unallocated, it will be auto-allocated to batch_size. If it is already
|
||||
* allocated, it must have a capacity at least as large as batch_size.
|
||||
* If the parser's current capacity is less than batch_size, it will allocate enough capacity
|
||||
* to handle it (up to max_capacity).
|
||||
*
|
||||
* @param s The concatenated JSON to parse.
|
||||
* @param batch_size The batch size to use. MUST be larger than the largest document. The sweet
|
||||
* spot is cache-related: small enough to fit in cache, yet big enough to
|
||||
* parse as many documents as possible in one tight loop.
|
||||
* Defaults to 10MB, which has been a reasonable sweet spot in our tests.
|
||||
* @return he stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* @return The stream. If there is an error, it will be returned during iteration. An empty input
|
||||
* will yield 0 documents rather than an EMPTY error. Errors:
|
||||
* - MEMALLOC if the parser is unallocated and memory allocation fails
|
||||
* - CAPACITY if the parser already has a capacity, and it is less than batch_size
|
||||
* - MEMALLOC if the parser does not have enough capacity and memory allocation fails
|
||||
* - CAPACITY if the parser does not have enough capacity and batch_size > max_capacity.
|
||||
* - other json errors if parsing fails
|
||||
*/
|
||||
inline stream parse_many(const padded_string &s, size_t batch_size = 1000000) noexcept;
|
||||
@@ -1170,20 +1241,72 @@ public:
|
||||
really_inline doc_ref_result parse_many(const char *buf, size_t batch_size = 1000000) noexcept = delete;
|
||||
|
||||
/**
|
||||
* Current capacity: the largest document this parser can support without reallocating.
|
||||
* The largest document this parser can automatically support.
|
||||
*
|
||||
* The parser may reallocate internal buffers as needed up to this amount.
|
||||
*
|
||||
* @return Maximum capacity, in bytes.
|
||||
*/
|
||||
really_inline size_t max_capacity() const noexcept;
|
||||
|
||||
/**
|
||||
* The largest document this parser can support without reallocating.
|
||||
*
|
||||
* @return Current capacity, in bytes.
|
||||
*/
|
||||
really_inline size_t capacity() const noexcept;
|
||||
|
||||
/**
|
||||
* The maximum level of nested object and arrays supported by this parser.
|
||||
*
|
||||
* @return Maximum depth, in bytes.
|
||||
*/
|
||||
really_inline size_t max_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Set max_capacity. This is the largest document this parser can automatically support.
|
||||
*
|
||||
* The parser may reallocate internal buffers as needed up to this amount.
|
||||
*
|
||||
* This call will not allocate or deallocate, even if capacity is currently above max_capacity.
|
||||
*
|
||||
* @param max_capacity The new maximum capacity, in bytes.
|
||||
*/
|
||||
really_inline void set_max_capacity(size_t max_capacity) noexcept;
|
||||
|
||||
/**
|
||||
* Set capacity. This is the largest document this parser can support without reallocating.
|
||||
*
|
||||
* This will allocate or deallocate as necessary.
|
||||
*
|
||||
* @param capacity The new capacity, in bytes.
|
||||
*
|
||||
* @return MEMALLOC if unsuccessful, SUCCESS otherwise.
|
||||
*/
|
||||
WARN_UNUSED inline error_code set_capacity(size_t capacity) noexcept;
|
||||
|
||||
/**
|
||||
* Set the maximum level of nested object and arrays supported by this parser.
|
||||
*
|
||||
* This will allocate or deallocate as necessary.
|
||||
*
|
||||
* @param max_depth The new maximum depth, in bytes.
|
||||
*
|
||||
* @return MEMALLOC if unsuccessful, SUCCESS otherwise.
|
||||
*/
|
||||
WARN_UNUSED inline error_code set_max_depth(size_t max_depth) noexcept;
|
||||
|
||||
/**
|
||||
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
||||
* and `max_depth` depth.
|
||||
*
|
||||
* Equivalent to calling set_capacity() and set_max_depth().
|
||||
*
|
||||
* @param capacity The new capacity.
|
||||
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
|
||||
* @return true if successful, false if allocation failed.
|
||||
*/
|
||||
WARN_UNUSED inline bool allocate_capacity(size_t capacity, size_t max_depth = DEFAULT_MAX_DEPTH);
|
||||
WARN_UNUSED inline bool allocate_capacity(size_t capacity, size_t max_depth = DEFAULT_MAX_DEPTH) noexcept;
|
||||
|
||||
// type aliases for backcompat
|
||||
using Iterator = document::iterator;
|
||||
@@ -1258,13 +1381,6 @@ public:
|
||||
really_inline bool on_number_s64(int64_t value) noexcept;
|
||||
really_inline bool on_number_u64(uint64_t value) noexcept;
|
||||
really_inline bool on_number_double(double value) noexcept;
|
||||
//
|
||||
// Called before a parse is initiated.
|
||||
//
|
||||
// - Returns CAPACITY if the document is too large
|
||||
// - Returns MEMALLOC if we needed to allocate memory and could not
|
||||
//
|
||||
WARN_UNUSED inline error_code init_parse(size_t len) noexcept;
|
||||
|
||||
private:
|
||||
//
|
||||
@@ -1274,12 +1390,19 @@ private:
|
||||
//
|
||||
size_t _capacity{0};
|
||||
|
||||
//
|
||||
// The maximum document length this parser will automatically support.
|
||||
//
|
||||
// The parser will not be automatically allocated above this amount.
|
||||
//
|
||||
size_t _max_capacity;
|
||||
|
||||
//
|
||||
// The maximum depth (number of nested objects and arrays) supported by this parser.
|
||||
//
|
||||
// Defaults to DEFAULT_MAX_DEPTH.
|
||||
//
|
||||
size_t _max_depth{0};
|
||||
size_t _max_depth;
|
||||
|
||||
// all nodes are stored on the doc.tape using a 64-bit word.
|
||||
//
|
||||
@@ -1298,28 +1421,15 @@ private:
|
||||
inline void write_tape(uint64_t val, tape_type t) noexcept;
|
||||
inline void annotate_previous_loc(uint32_t saved_loc, uint64_t val) noexcept;
|
||||
|
||||
//
|
||||
// Set the current capacity: the largest document this parser can support without reallocating.
|
||||
//
|
||||
// This will allocate *or deallocate* as necessary.
|
||||
//
|
||||
// Returns false if allocation fails.
|
||||
//
|
||||
inline WARN_UNUSED bool set_capacity(size_t capacity);
|
||||
|
||||
//
|
||||
// Set the maximum level of nested object and arrays supported by this parser.
|
||||
//
|
||||
// This will allocate *or deallocate* as necessary.
|
||||
//
|
||||
// Returns false if allocation fails.
|
||||
//
|
||||
inline WARN_UNUSED bool set_max_depth(size_t max_depth);
|
||||
// Ensure we have enough capacity to handle at least desired_capacity bytes,
|
||||
// and auto-allocate if not.
|
||||
inline error_code ensure_capacity(size_t desired_capacity) noexcept;
|
||||
|
||||
// Used internally to get the document
|
||||
inline const document &get_document() const noexcept(false);
|
||||
|
||||
template<size_t max_depth> friend class document_iterator;
|
||||
friend class document::stream;
|
||||
}; // class parser
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
virtual uint32_t required_instruction_sets() const { return _required_instruction_sets; };
|
||||
|
||||
/**
|
||||
* Run a full document parse (init_parse, stage1 and stage2).
|
||||
* Run a full document parse (ensure_capacity, stage1 and stage2).
|
||||
*
|
||||
* Overridden by each implementation.
|
||||
*
|
||||
|
||||
@@ -198,28 +198,25 @@ inline document::element_result<document::element> document::operator[](const ch
|
||||
|
||||
inline document::doc_result document::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) noexcept {
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(len)) {
|
||||
return MEMALLOC;
|
||||
}
|
||||
auto [doc, error] = parser.parse(buf, len, realloc_if_needed);
|
||||
return document::doc_result((document &&)doc, error);
|
||||
}
|
||||
really_inline document::doc_result document::parse(const char *buf, size_t len, bool realloc_if_needed) noexcept {
|
||||
return parse((const uint8_t *)buf, len, realloc_if_needed);
|
||||
return parse((const uint8_t *)buf, len, realloc_if_needed);
|
||||
}
|
||||
really_inline document::doc_result document::parse(const std::string &s) noexcept {
|
||||
return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
|
||||
return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
|
||||
}
|
||||
really_inline document::doc_result document::parse(const padded_string &s) noexcept {
|
||||
return parse(s.data(), s.length(), false);
|
||||
return parse(s.data(), s.length(), false);
|
||||
}
|
||||
|
||||
WARN_UNUSED
|
||||
inline bool document::set_capacity(size_t capacity) {
|
||||
inline error_code document::set_capacity(size_t capacity) noexcept {
|
||||
if (capacity == 0) {
|
||||
string_buf.reset();
|
||||
tape.reset();
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// a pathological input like "[[[[..." would generate len tape elements, so
|
||||
@@ -233,7 +230,7 @@ inline bool document::set_capacity(size_t capacity) {
|
||||
size_t string_capacity = ROUNDUP_N(5 * capacity / 3 + 32, 64);
|
||||
string_buf.reset( new (std::nothrow) uint8_t[string_capacity]);
|
||||
tape.reset(new (std::nothrow) uint64_t[tape_capacity]);
|
||||
return string_buf && tape;
|
||||
return string_buf && tape ? SUCCESS : MEMALLOC;
|
||||
}
|
||||
|
||||
inline bool document::print_json(std::ostream &os, size_t max_depth) const noexcept {
|
||||
@@ -462,6 +459,10 @@ inline document::doc_result::operator document() noexcept(false) {
|
||||
//
|
||||
// document::parser inline implementation
|
||||
//
|
||||
really_inline document::parser::parser(size_t max_capacity, size_t max_depth) noexcept
|
||||
: _max_capacity{max_capacity}, _max_depth{max_depth} {
|
||||
|
||||
}
|
||||
inline bool document::parser::is_valid() const noexcept { return valid; }
|
||||
inline int document::parser::get_error_code() const noexcept { return error; }
|
||||
inline std::string document::parser::get_error_message() const noexcept { return error_message(int(error)); }
|
||||
@@ -479,7 +480,7 @@ inline const document &document::parser::get_document() const noexcept(false) {
|
||||
}
|
||||
|
||||
inline document::doc_ref_result document::parser::parse(const uint8_t *buf, size_t len, bool realloc_if_needed) noexcept {
|
||||
error_code code = init_parse(len);
|
||||
error_code code = ensure_capacity(len);
|
||||
if (code) { return document::doc_ref_result(doc, code); }
|
||||
|
||||
if (realloc_if_needed) {
|
||||
@@ -526,17 +527,17 @@ inline document::stream document::parser::parse_many(const padded_string &s, siz
|
||||
really_inline size_t document::parser::capacity() const noexcept {
|
||||
return _capacity;
|
||||
}
|
||||
really_inline size_t document::parser::max_capacity() const noexcept {
|
||||
return _max_capacity;
|
||||
}
|
||||
really_inline size_t document::parser::max_depth() const noexcept {
|
||||
return _max_depth;
|
||||
}
|
||||
WARN_UNUSED inline bool document::parser::allocate_capacity(size_t capacity, size_t max_depth) {
|
||||
return set_capacity(capacity) && set_max_depth(max_depth);
|
||||
}
|
||||
|
||||
WARN_UNUSED
|
||||
inline bool document::parser::set_capacity(size_t capacity) {
|
||||
inline error_code document::parser::set_capacity(size_t capacity) noexcept {
|
||||
if (_capacity == capacity) {
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Set capacity to 0 until we finish, in case there's an error
|
||||
@@ -545,16 +546,15 @@ inline bool document::parser::set_capacity(size_t capacity) {
|
||||
//
|
||||
// Reallocate the document
|
||||
//
|
||||
if (!doc.set_capacity(capacity)) {
|
||||
return false;
|
||||
}
|
||||
error_code err = doc.set_capacity(capacity);
|
||||
if (err) { return err; }
|
||||
|
||||
//
|
||||
// Don't allocate 0 bytes, just return.
|
||||
//
|
||||
if (capacity == 0) {
|
||||
structural_indexes.reset();
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -563,20 +563,26 @@ inline bool document::parser::set_capacity(size_t capacity) {
|
||||
uint32_t max_structures = ROUNDUP_N(capacity, 64) + 2 + 7;
|
||||
structural_indexes.reset( new (std::nothrow) uint32_t[max_structures]); // TODO realloc
|
||||
if (!structural_indexes) {
|
||||
return false;
|
||||
return MEMALLOC;
|
||||
}
|
||||
|
||||
_capacity = capacity;
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
WARN_UNUSED inline bool document::parser::set_max_depth(size_t max_depth) {
|
||||
really_inline void document::parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||
_max_capacity = max_capacity;
|
||||
}
|
||||
|
||||
WARN_UNUSED inline error_code document::parser::set_max_depth(size_t max_depth) noexcept {
|
||||
if (max_depth == _max_depth && ret_address) { return SUCCESS; }
|
||||
|
||||
_max_depth = 0;
|
||||
|
||||
if (max_depth == 0) {
|
||||
ret_address.reset();
|
||||
containing_scope_offset.reset();
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -591,24 +597,38 @@ WARN_UNUSED inline bool document::parser::set_max_depth(size_t max_depth) {
|
||||
|
||||
if (!ret_address || !containing_scope_offset) {
|
||||
// Could not allocate memory
|
||||
return false;
|
||||
return MEMALLOC;
|
||||
}
|
||||
|
||||
_max_depth = max_depth;
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
WARN_UNUSED
|
||||
inline error_code document::parser::init_parse(size_t len) noexcept {
|
||||
if (len > capacity()) {
|
||||
return error = CAPACITY;
|
||||
WARN_UNUSED inline bool document::parser::allocate_capacity(size_t capacity, size_t max_depth) noexcept {
|
||||
return !set_capacity(capacity) && !set_max_depth(max_depth);
|
||||
}
|
||||
|
||||
inline error_code document::parser::ensure_capacity(size_t desired_capacity) noexcept {
|
||||
// If we don't have enough capacity, (try to) automatically bump it.
|
||||
if (unlikely(desired_capacity > capacity())) {
|
||||
if (desired_capacity > max_capacity()) {
|
||||
return error = CAPACITY;
|
||||
}
|
||||
|
||||
error = set_capacity(desired_capacity);
|
||||
if (error) { return error; }
|
||||
}
|
||||
|
||||
// Allocate depth-based buffers if they aren't already.
|
||||
error = set_max_depth(max_depth());
|
||||
if (error) { return error; }
|
||||
|
||||
// If the last doc was taken, we need to allocate a new one
|
||||
if (!doc.tape) {
|
||||
if (!doc.set_capacity(len)) {
|
||||
return error = MEMALLOC;
|
||||
}
|
||||
error = doc.set_capacity(desired_capacity);
|
||||
if (error) { return error; }
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,21 +148,11 @@ really_inline bool document::stream::iterator::operator!=(const document::stream
|
||||
// threaded version of json_parse
|
||||
// todo: simplify this code further
|
||||
inline error_code document::stream::json_parse() noexcept {
|
||||
// TODO we should bump the parser *anytime* capacity is less than batch size, not just 0.
|
||||
if (unlikely(parser.capacity() == 0)) {
|
||||
const bool allocok = parser.allocate_capacity(_batch_size);
|
||||
if (!allocok) {
|
||||
return simdjson::MEMALLOC;
|
||||
}
|
||||
} else if (unlikely(parser.capacity() < _batch_size)) {
|
||||
return simdjson::CAPACITY;
|
||||
}
|
||||
if (unlikely(parser_thread.capacity() < _batch_size)) {
|
||||
const bool allocok_thread = parser_thread.allocate_capacity(_batch_size);
|
||||
if (!allocok_thread) {
|
||||
return simdjson::MEMALLOC;
|
||||
}
|
||||
}
|
||||
error = parser.ensure_capacity(_batch_size);
|
||||
if (error) { return error; }
|
||||
error = parser_thread.ensure_capacity(_batch_size);
|
||||
if (error) { return error; }
|
||||
|
||||
if (unlikely(load_next_batch)) {
|
||||
// First time loading
|
||||
if (!stage_1_thread.joinable()) {
|
||||
@@ -240,14 +230,9 @@ inline error_code document::stream::json_parse() noexcept {
|
||||
|
||||
// single-threaded version of json_parse
|
||||
inline error_code document::stream::json_parse() noexcept {
|
||||
if (unlikely(parser.capacity() == 0)) {
|
||||
const bool allocok = parser.allocate_capacity(_batch_size);
|
||||
if (!allocok) {
|
||||
return MEMALLOC;
|
||||
}
|
||||
} else if (unlikely(parser.capacity() < _batch_size)) {
|
||||
return CAPACITY;
|
||||
}
|
||||
error = parser.ensure_capacity(_batch_size);
|
||||
if (error) { return error; }
|
||||
|
||||
if (unlikely(load_next_batch)) {
|
||||
advance(current_buffer_loc);
|
||||
n_bytes_parsed += current_buffer_loc;
|
||||
|
||||
@@ -35,11 +35,6 @@ inline int json_parse(const padded_string &s, document::parser &parser) noexcept
|
||||
|
||||
WARN_UNUSED static document::parser build_parsed_json(const uint8_t *buf, size_t len, bool realloc_if_needed = true) noexcept {
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(len)) {
|
||||
parser.valid = false;
|
||||
parser.error = MEMALLOC;
|
||||
return parser;
|
||||
}
|
||||
json_parse(buf, len, parser, realloc_if_needed);
|
||||
return parser;
|
||||
}
|
||||
|
||||
+1
-21
@@ -33,10 +33,6 @@ inline uint64_t f64_ulp_dist(double a, double b) {
|
||||
bool number_test_small_integers() {
|
||||
char buf[1024];
|
||||
simdjson::document::parser parser;
|
||||
if (!parser.allocate_capacity(1024)) {
|
||||
printf("allocation failure in number_test_small_integers\n");
|
||||
return false;
|
||||
}
|
||||
for (int m = 10; m < 20; m++) {
|
||||
for (int i = -1024; i < 1024; i++) {
|
||||
auto n = sprintf(buf, "%*d", m, i);
|
||||
@@ -71,10 +67,6 @@ bool number_test_small_integers() {
|
||||
bool number_test_powers_of_two() {
|
||||
char buf[1024];
|
||||
simdjson::document::parser parser;
|
||||
if (!parser.allocate_capacity(1024)) {
|
||||
printf("allocation failure in number_test\n");
|
||||
return false;
|
||||
}
|
||||
int maxulp = 0;
|
||||
for (int i = -1075; i < 1024; ++i) {// large negative values should be zero.
|
||||
double expected = pow(2, i);
|
||||
@@ -138,10 +130,6 @@ bool number_test_powers_of_two() {
|
||||
bool number_test_powers_of_ten() {
|
||||
char buf[1024];
|
||||
simdjson::document::parser parser;
|
||||
if (!parser.allocate_capacity(1024)) {
|
||||
printf("allocation failure in number_test\n");
|
||||
return false;
|
||||
}
|
||||
for (int i = -1000000; i <= 308; ++i) {// large negative values should be zero.
|
||||
auto n = sprintf(buf,"1e%d", i);
|
||||
buf[n] = '\0';
|
||||
@@ -247,12 +235,8 @@ bool stable_test() {
|
||||
static bool parse_json_message_issue467(char const* message, std::size_t len, size_t expectedcount) {
|
||||
simdjson::document::parser parser;
|
||||
size_t count = 0;
|
||||
if (!parser.allocate_capacity(len)) {
|
||||
std::cerr << "Failed to allocated memory for simdjson::document::parser" << std::endl;
|
||||
return false;
|
||||
}
|
||||
simdjson::padded_string str(message,len);
|
||||
for (auto [doc, error] : parser.parse_many(str, parser.capacity())) {
|
||||
for (auto [doc, error] : parser.parse_many(str, len)) {
|
||||
if (error) {
|
||||
std::cerr << "Failed with simdjson error= " << error << std::endl;
|
||||
return false;
|
||||
@@ -639,10 +623,6 @@ bool skyprophet_test() {
|
||||
maxsize = s.size();
|
||||
}
|
||||
simdjson::document::parser parser;
|
||||
if (!parser.allocate_capacity(maxsize)) {
|
||||
printf("allocation failure in skyprophet_test\n");
|
||||
return false;
|
||||
}
|
||||
size_t counter = 0;
|
||||
for (auto &rec : data) {
|
||||
if ((counter % 10000) == 0) {
|
||||
|
||||
@@ -73,11 +73,6 @@ bool validate(const char *dirname) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::ParsedJson pj;
|
||||
bool allocok = pj.allocate_capacity(p.size(), 1024);
|
||||
if (!allocok) {
|
||||
std::cerr << "can't allocate memory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
++how_many;
|
||||
const int parse_res = json_parse(p, pj);
|
||||
printf("%s\n", parse_res == 0 ? "ok" : "invalid");
|
||||
|
||||
@@ -180,11 +180,6 @@ bool validate(const char *dirname) {
|
||||
}
|
||||
// terrible hack but just to get it working
|
||||
simdjson::ParsedJson pj;
|
||||
bool allocok = pj.allocate_capacity(p.size(), 1024);
|
||||
if (!allocok) {
|
||||
std::cerr << "can't allocate memory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
float_count = 0;
|
||||
int_count = 0;
|
||||
invalid_count = 0;
|
||||
|
||||
@@ -7,7 +7,6 @@ int main() {
|
||||
std::string json =
|
||||
"{\"/~01abc\": [0, {\"\\\\\\\" 0\": [\"value0\", \"value1\"]}]}";
|
||||
simdjson::ParsedJson pj;
|
||||
assert(pj.allocate_capacity(json.length()));
|
||||
simdjson::json_parse(json.c_str(), json.length(), pj);
|
||||
assert(pj.is_valid());
|
||||
simdjson::ParsedJson::Iterator it(pj);
|
||||
|
||||
@@ -45,14 +45,15 @@ void parser_parse() {
|
||||
|
||||
// Allocate a parser big enough for all files
|
||||
document::parser parser;
|
||||
if (!parser.allocate_capacity(1024*1024)) { exit(1); }
|
||||
simdjson::error_code capacity_error = parser.set_capacity(1024*1024);
|
||||
if (capacity_error) { cerr << "Error setting capacity: " << capacity_error << endl; exit(1); }
|
||||
|
||||
// Read files with the parser, one by one
|
||||
for (padded_string json : { string("[1, 2, 3]"), string("true"), string("[ true, false ]") }) {
|
||||
cout << "Parsing " << json.data() << " ..." << endl;
|
||||
auto [doc, error] = parser.parse(json);
|
||||
if (error) { cerr << "Error: " << error << endl; exit(1); }
|
||||
if (!doc.print_json(cout)) { exit(1); }
|
||||
if (!doc.print_json(cout)) { cerr << "print failed!\n"; exit(1); }
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +85,32 @@ void parser_parse_many_exception() {
|
||||
}
|
||||
}
|
||||
|
||||
void parser_parse_max_capacity() {
|
||||
int argc = 2;
|
||||
padded_string argv[] { string("[1,2,3]"), string("true") };
|
||||
document::parser parser(1024*1024); // Set max capacity to 1MB
|
||||
for (int i=0;i<argc;i++) {
|
||||
auto [doc, error] = parser.parse(argv[i]);
|
||||
if (error == CAPACITY) { cerr << "JSON files larger than 1MB are not supported!" << endl; exit(1); }
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
doc.print_json(cout);
|
||||
}
|
||||
}
|
||||
|
||||
void parser_parse_fixed_capacity() {
|
||||
int argc = 2;
|
||||
padded_string argv[] { string("[1,2,3]"), string("true") };
|
||||
document::parser parser(0); // This parser is not allowed to auto-allocate
|
||||
auto alloc_error = parser.set_capacity(1024*1024);
|
||||
if (alloc_error) { cerr << alloc_error << endl; exit(1); }; // Set initial capacity to 1MB
|
||||
for (int i=0;i<argc;i++) {
|
||||
auto [doc, error] = parser.parse(argv[i]);
|
||||
if (error == CAPACITY) { cerr << "JSON files larger than 1MB are not supported!" << endl; exit(1); }
|
||||
if (error) { cerr << error << endl; exit(1); }
|
||||
doc.print_json(cout);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
cout << "Running examples." << endl;
|
||||
document_parse_error_code();
|
||||
@@ -93,6 +120,8 @@ int main() {
|
||||
parser_parse();
|
||||
parser_parse_many_error_code();
|
||||
parser_parse_many_exception();
|
||||
parser_parse_max_capacity();
|
||||
parser_parse_fixed_capacity();
|
||||
cout << "Ran to completion!" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@ int main() {
|
||||
if (!pj.is_valid()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!pj.allocate_capacity(p.size())) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const int res = json_parse(p, pj);
|
||||
if (res) {
|
||||
std::cerr << error_message(res) << std::endl;
|
||||
|
||||
@@ -341,11 +341,6 @@ bool validate(const char *dirname) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::ParsedJson pj;
|
||||
bool allocok = pj.allocate_capacity(p.size(), 1024);
|
||||
if (!allocok) {
|
||||
std::cerr << "can't allocate memory" << std::endl;
|
||||
return false;
|
||||
}
|
||||
big_buffer = (char *)malloc(p.size());
|
||||
if (big_buffer == NULL) {
|
||||
std::cerr << "can't allocate memory" << std::endl;
|
||||
|
||||
@@ -80,11 +80,6 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::ParsedJson pj;
|
||||
bool allocok = pj.allocate_capacity(p.size(), 1024);
|
||||
if (!allocok) {
|
||||
std::cerr << "failed to allocate memory" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int res =
|
||||
simdjson::json_parse(p, pj); // do the parsing, return false on error
|
||||
if (res != simdjson::SUCCESS) {
|
||||
|
||||
@@ -59,11 +59,6 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
simdjson::ParsedJson pj;
|
||||
bool allocok = pj.allocate_capacity(p.size(), 1024);
|
||||
if (!allocok) {
|
||||
std::cerr << "failed to allocate memory" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int res =
|
||||
simdjson::json_parse(p, pj); // do the parsing, return false on error
|
||||
if (res) {
|
||||
|
||||
Reference in New Issue
Block a user