De-templatize stage2::structural_parser

This commit is contained in:
John Keiser 2020-08-03 16:59:52 -07:00
parent ee6647ce40
commit ec28acba3d
6 changed files with 121 additions and 175 deletions

View File

@ -145,19 +145,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons
}
WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
if (auto error = stage2::structural_parser<stage2::tape_builder>::parse<false>(*this, _doc)) { return error; }
// If we didn't make it to the end, it's an error
if ( next_structural_index != n_structural_indexes ) {
logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!");
return TAPE_ERROR;
}
return SUCCESS;
doc = &_doc;
stage2::tape_builder builder(*doc);
return stage2::structural_parser::parse<false>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
return stage2::structural_parser<stage2::tape_builder>::parse<true>(*this, _doc);
doc = &_doc;
stage2::tape_builder builder(_doc);
return stage2::structural_parser::parse<true>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {

View File

@ -322,19 +322,15 @@ namespace {
namespace SIMDJSON_IMPLEMENTATION {
WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
if (auto error = stage2::structural_parser<stage2::tape_builder>::parse<false>(*this, _doc)) { return error; }
// If we didn't make it to the end, it's an error
if ( next_structural_index != n_structural_indexes ) {
logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!");
return TAPE_ERROR;
}
return SUCCESS;
doc = &_doc;
stage2::tape_builder builder(*doc);
return stage2::structural_parser::parse<false>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
return stage2::structural_parser<stage2::tape_builder>::parse<true>(*this, _doc);
doc = &_doc;
stage2::tape_builder builder(_doc);
return stage2::structural_parser::parse<true>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {

View File

@ -12,54 +12,41 @@ namespace stage2 {
#define SIMDJSON_TRY(EXPR) { auto _err = (EXPR); if (_err) { return _err; } }
template<typename T>
struct structural_parser : structural_iterator {
/** Receiver that actually parses the strings and builds the tape */
T builder;
/** Current depth (nested objects and arrays) */
uint32_t depth{0};
template<bool STREAMING>
WARN_UNUSED static really_inline error_code parse(dom_parser_implementation &dom_parser, dom::document &doc) noexcept;
template<bool STREAMING, typename T>
WARN_UNUSED static really_inline error_code parse(dom_parser_implementation &dom_parser, T &builder) noexcept;
// For non-streaming, to pass an explicit 0 as next_structural, which enables optimizations
really_inline structural_parser(dom_parser_implementation &_parser, uint32_t start_structural_index)
: structural_iterator(_parser, start_structural_index),
builder{parser.doc->tape.get(), parser.doc->string_buf.get()} {
: structural_iterator(_parser, start_structural_index) {
}
WARN_UNUSED really_inline error_code start_document() {
builder.start_document(*this);
parser.is_array[depth] = false;
return SUCCESS;
}
WARN_UNUSED really_inline error_code start_object() {
template<typename T>
WARN_UNUSED really_inline error_code start_object(T &builder) {
depth++;
if (depth >= parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; }
builder.start_object(*this);
parser.is_array[depth] = false;
return SUCCESS;
}
WARN_UNUSED really_inline error_code start_array() {
template<typename T>
WARN_UNUSED really_inline error_code start_array(T &builder) {
depth++;
if (depth >= parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; }
builder.start_array(*this);
parser.is_array[depth] = true;
return SUCCESS;
}
really_inline void end_object() {
builder.end_object(*this);
depth--;
}
really_inline void end_array() {
builder.end_array(*this);
depth--;
}
really_inline void end_document() {
builder.end_document(*this);
}
WARN_UNUSED really_inline bool empty_object() {
template<typename T>
WARN_UNUSED really_inline bool empty_object(T &builder) {
if (peek_next_char() == '}') {
advance_char();
builder.empty_object(*this);
@ -67,7 +54,8 @@ struct structural_parser : structural_iterator {
}
return false;
}
WARN_UNUSED really_inline bool empty_array() {
template<typename T>
WARN_UNUSED really_inline bool empty_array(T &builder) {
if (peek_next_char() == ']') {
advance_char();
builder.empty_array(*this);
@ -76,53 +64,8 @@ struct structural_parser : structural_iterator {
return false;
}
really_inline void increment_count() {
builder.increment_count(*this);
}
WARN_UNUSED really_inline error_code parse_key(const uint8_t *key) {
return builder.parse_key(*this, key);
}
WARN_UNUSED really_inline error_code parse_string(const uint8_t *value) {
return builder.parse_string(*this, value);
}
WARN_UNUSED really_inline error_code parse_number(const uint8_t *value) {
return builder.parse_number(*this, value);
}
WARN_UNUSED really_inline error_code parse_root_number(const uint8_t *value) {
return builder.parse_root_number(*this, value);
}
WARN_UNUSED really_inline error_code parse_true_atom(const uint8_t *value) {
return builder.parse_true_atom(*this, value);
}
WARN_UNUSED really_inline error_code parse_root_true_atom(const uint8_t *value) {
return builder.parse_root_true_atom(*this, value);
}
WARN_UNUSED really_inline error_code parse_false_atom(const uint8_t *value) {
return builder.parse_false_atom(*this, value);
}
WARN_UNUSED really_inline error_code parse_root_false_atom(const uint8_t *value) {
return builder.parse_root_false_atom(*this, value);
}
WARN_UNUSED really_inline error_code parse_null_atom(const uint8_t *value) {
return builder.parse_null_atom(*this, value);
}
WARN_UNUSED really_inline error_code parse_root_null_atom(const uint8_t *value) {
return builder.parse_root_null_atom(*this, value);
}
WARN_UNUSED really_inline error_code start() {
logger::log_start();
// If there are no structurals left, return EMPTY
if (at_end()) { return EMPTY; }
// Push the root scope (there is always at least one scope)
return start_document();
}
template<bool STREAMING>
WARN_UNUSED really_inline error_code finish() {
end_document();
parser.next_structural_index = uint32_t(next_structural - &parser.structural_indexes[0]);
if (depth != 0) {
@ -130,6 +73,12 @@ struct structural_parser : structural_iterator {
return TAPE_ERROR;
}
// If we didn't make it to the end, it's an error
if ( !STREAMING && parser.next_structural_index != parser.n_structural_indexes ) {
logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!");
return TAPE_ERROR;
}
return SUCCESS;
}
@ -152,12 +101,17 @@ struct structural_parser : structural_iterator {
}
}; // struct structural_parser
template<typename T>
template<bool STREAMING>
WARN_UNUSED really_inline error_code structural_parser<T>::parse(dom_parser_implementation &dom_parser, dom::document &doc) noexcept {
dom_parser.doc = &doc;
stage2::structural_parser<T> parser(dom_parser, STREAMING ? dom_parser.next_structural_index : 0);
SIMDJSON_TRY( parser.start() );
template<bool STREAMING, typename T>
WARN_UNUSED really_inline error_code structural_parser::parse(dom_parser_implementation &dom_parser, T &builder) noexcept {
stage2::structural_parser parser(dom_parser, STREAMING ? dom_parser.next_structural_index : 0);
logger::log_start();
//
// Start the document
//
if (parser.at_end()) { return EMPTY; }
SIMDJSON_TRY( parser.start_document() );
builder.start_document(parser);
//
// Read first value
@ -166,13 +120,13 @@ WARN_UNUSED really_inline error_code structural_parser<T>::parse(dom_parser_impl
const uint8_t *value = parser.advance();
switch (*value) {
case '{': {
if (parser.empty_object()) { goto document_end; }
SIMDJSON_TRY( parser.start_object() );
if (parser.empty_object(builder)) { goto document_end; }
SIMDJSON_TRY( parser.start_object(builder) );
goto object_begin;
}
case '[': {
if (parser.empty_array()) { goto document_end; }
SIMDJSON_TRY( parser.start_array() );
if (parser.empty_array(builder)) { goto document_end; }
SIMDJSON_TRY( parser.start_array(builder) );
// Make sure the outer array is closed before continuing; otherwise, there are ways we could get
// into memory corruption. See https://github.com/simdjson/simdjson/issues/906
if (!STREAMING) {
@ -182,14 +136,14 @@ WARN_UNUSED really_inline error_code structural_parser<T>::parse(dom_parser_impl
}
goto array_begin;
}
case '"': SIMDJSON_TRY( parser.parse_string(value) ); goto document_end;
case 't': SIMDJSON_TRY( parser.parse_root_true_atom(value) ); goto document_end;
case 'f': SIMDJSON_TRY( parser.parse_root_false_atom(value) ); goto document_end;
case 'n': SIMDJSON_TRY( parser.parse_root_null_atom(value) ); goto document_end;
case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); goto document_end;
case 't': SIMDJSON_TRY( builder.parse_root_true_atom(parser, value) ); goto document_end;
case 'f': SIMDJSON_TRY( builder.parse_root_false_atom(parser, value) ); goto document_end;
case 'n': SIMDJSON_TRY( builder.parse_root_null_atom(parser, value) ); goto document_end;
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
SIMDJSON_TRY( parser.parse_root_number(value) ); goto document_end;
SIMDJSON_TRY( builder.parse_root_number(parser, value) ); goto document_end;
default:
parser.log_error("Document starts with a non-value character");
return TAPE_ERROR;
@ -205,8 +159,8 @@ object_begin: {
parser.log_error("Object does not start with a key");
return TAPE_ERROR;
}
parser.increment_count();
SIMDJSON_TRY( parser.parse_key(key) );
builder.increment_count(parser);
SIMDJSON_TRY( builder.parse_key(parser, key) );
goto object_field;
} // object_begin:
@ -215,23 +169,23 @@ object_field: {
const uint8_t *value = parser.advance();
switch (*value) {
case '{': {
if (parser.empty_object()) { break; };
SIMDJSON_TRY( parser.start_object() );
if (parser.empty_object(builder)) { break; };
SIMDJSON_TRY( parser.start_object(builder) );
goto object_begin;
}
case '[': {
if (parser.empty_array()) { break; };
SIMDJSON_TRY( parser.start_array() );
if (parser.empty_array(builder)) { break; };
SIMDJSON_TRY( parser.start_array(builder) );
goto array_begin;
}
case '"': SIMDJSON_TRY( parser.parse_string(value) ); break;
case 't': SIMDJSON_TRY( parser.parse_true_atom(value) ); break;
case 'f': SIMDJSON_TRY( parser.parse_false_atom(value) ); break;
case 'n': SIMDJSON_TRY( parser.parse_null_atom(value) ); break;
case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); break;
case 't': SIMDJSON_TRY( builder.parse_true_atom(parser, value) ); break;
case 'f': SIMDJSON_TRY( builder.parse_false_atom(parser, value) ); break;
case 'n': SIMDJSON_TRY( builder.parse_null_atom(parser, value) ); break;
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
SIMDJSON_TRY( parser.parse_number(value) ); break;
SIMDJSON_TRY( builder.parse_number(parser, value) ); break;
default:
parser.log_error("Non-value found when value was expected!");
return TAPE_ERROR;
@ -241,14 +195,15 @@ object_field: {
object_continue: {
switch (parser.advance_char()) {
case ',': {
parser.increment_count();
builder.increment_count(parser);
const uint8_t *key = parser.advance();
if (unlikely( *key != '"' )) { parser.log_error("Key string missing at beginning of field in object"); return TAPE_ERROR; }
SIMDJSON_TRY( parser.parse_key(key) );
SIMDJSON_TRY( builder.parse_key(parser, key) );
goto object_field;
}
case '}':
parser.end_object();
builder.end_object(parser);
parser.depth--;
goto scope_end;
default:
parser.log_error("No comma between object fields");
@ -266,30 +221,30 @@ scope_end: {
// Array parser states
//
array_begin: {
parser.increment_count();
builder.increment_count(parser);
} // array_begin:
array_value: {
const uint8_t *value = parser.advance();
switch (*value) {
case '{': {
if (parser.empty_object()) { break; };
SIMDJSON_TRY( parser.start_object() );
if (parser.empty_object(builder)) { break; };
SIMDJSON_TRY( parser.start_object(builder) );
goto object_begin;
}
case '[': {
if (parser.empty_array()) { break; };
SIMDJSON_TRY( parser.start_array() );
if (parser.empty_array(builder)) { break; };
SIMDJSON_TRY( parser.start_array(builder) );
goto array_begin;
}
case '"': SIMDJSON_TRY( parser.parse_string(value) ); break;
case 't': SIMDJSON_TRY( parser.parse_true_atom(value) ); break;
case 'f': SIMDJSON_TRY( parser.parse_false_atom(value) ); break;
case 'n': SIMDJSON_TRY( parser.parse_null_atom(value) ); break;
case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); break;
case 't': SIMDJSON_TRY( builder.parse_true_atom(parser, value) ); break;
case 'f': SIMDJSON_TRY( builder.parse_false_atom(parser, value) ); break;
case 'n': SIMDJSON_TRY( builder.parse_null_atom(parser, value) ); break;
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
SIMDJSON_TRY( parser.parse_number(value) ); break;
SIMDJSON_TRY( builder.parse_number(parser, value) ); break;
default:
parser.log_error("Non-value found when value was expected!");
return TAPE_ERROR;
@ -299,10 +254,11 @@ array_value: {
array_continue: {
switch (parser.advance_char()) {
case ',':
parser.increment_count();
builder.increment_count(parser);
goto array_value;
case ']':
parser.end_array();
builder.end_array(parser);
parser.depth--;
goto scope_end;
default:
parser.log_error("Missing comma between array values");
@ -311,7 +267,8 @@ array_continue: {
} // array_continue:
document_end: {
return parser.finish();
builder.end_document(parser);
return parser.finish<STREAMING>();
} // document_end:
} // parse_structurals()

View File

@ -11,47 +11,52 @@ struct tape_builder {
/** Next write location in the string buf for stage 2 parsing */
uint8_t *current_string_buf_loc;
really_inline void empty_object(structural_parser<tape_builder> &parser) {
really_inline tape_builder(dom::document &doc) noexcept : tape{doc.tape.get()}, current_string_buf_loc{doc.string_buf.get()} {}
private:
friend struct structural_parser;
really_inline void empty_object(structural_parser &parser) {
parser.log_value("empty object");
empty_container(parser, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT);
}
really_inline void empty_array(structural_parser<tape_builder> &parser) {
really_inline void empty_array(structural_parser &parser) {
parser.log_value("empty array");
empty_container(parser, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY);
}
really_inline void start_document(structural_parser<tape_builder> &parser) {
really_inline void start_document(structural_parser &parser) {
parser.log_start_value("document");
start_container(parser);
}
really_inline void start_object(structural_parser<tape_builder> &parser) {
really_inline void start_object(structural_parser &parser) {
parser.log_start_value("object");
start_container(parser);
}
really_inline void start_array(structural_parser<tape_builder> &parser) {
really_inline void start_array(structural_parser &parser) {
parser.log_start_value("array");
start_container(parser);
}
really_inline void end_object(structural_parser<tape_builder> &parser) {
really_inline void end_object(structural_parser &parser) {
parser.log_end_value("object");
end_container(parser, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT);
}
really_inline void end_array(structural_parser<tape_builder> &parser) {
really_inline void end_array(structural_parser &parser) {
parser.log_end_value("array");
end_container(parser, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY);
}
really_inline void end_document(structural_parser<tape_builder> &parser) {
really_inline void end_document(structural_parser &parser) {
parser.log_end_value("document");
constexpr uint32_t start_tape_index = 0;
tape.append(start_tape_index, internal::tape_type::ROOT);
tape_writer::write(parser.parser.doc->tape[start_tape_index], next_tape_index(parser), internal::tape_type::ROOT);
}
WARN_UNUSED really_inline error_code parse_key(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_key(structural_parser &parser, const uint8_t *value) {
return parse_string(parser, value, true);
}
WARN_UNUSED really_inline error_code parse_string(structural_parser<tape_builder> &parser, const uint8_t *value, bool key = false) {
WARN_UNUSED really_inline error_code parse_string(structural_parser &parser, const uint8_t *value, bool key = false) {
parser.log_value(key ? "key" : "string");
uint8_t *dst = on_start_string(parser);
dst = stringparsing::parse_string(value, dst);
@ -63,13 +68,13 @@ struct tape_builder {
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_number(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_number(structural_parser &parser, const uint8_t *value) {
parser.log_value("number");
if (!numberparsing::parse_number(value, tape)) { parser.log_error("Invalid number"); return NUMBER_ERROR; }
return SUCCESS;
}
really_inline error_code parse_root_number(structural_parser<tape_builder> &parser, const uint8_t *value) {
really_inline error_code parse_root_number(structural_parser &parser, const uint8_t *value) {
//
// We need to make a copy to make sure that the string is space terminated.
// This is not about padding the input, which should already padded up
@ -94,42 +99,42 @@ struct tape_builder {
return error;
}
WARN_UNUSED really_inline error_code parse_true_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_true_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("true");
if (!atomparsing::is_valid_true_atom(value)) { return T_ATOM_ERROR; }
tape.append(0, internal::tape_type::TRUE_VALUE);
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_root_true_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_root_true_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("true");
if (!atomparsing::is_valid_true_atom(value, parser.remaining_len())) { return T_ATOM_ERROR; }
tape.append(0, internal::tape_type::TRUE_VALUE);
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_false_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_false_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("false");
if (!atomparsing::is_valid_false_atom(value)) { return F_ATOM_ERROR; }
tape.append(0, internal::tape_type::FALSE_VALUE);
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_root_false_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_root_false_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("false");
if (!atomparsing::is_valid_false_atom(value, parser.remaining_len())) { return F_ATOM_ERROR; }
tape.append(0, internal::tape_type::FALSE_VALUE);
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_null_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_null_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("null");
if (!atomparsing::is_valid_null_atom(value)) { return N_ATOM_ERROR; }
tape.append(0, internal::tape_type::NULL_VALUE);
return SUCCESS;
}
WARN_UNUSED really_inline error_code parse_root_null_atom(structural_parser<tape_builder> &parser, const uint8_t *value) {
WARN_UNUSED really_inline error_code parse_root_null_atom(structural_parser &parser, const uint8_t *value) {
parser.log_value("null");
if (!atomparsing::is_valid_null_atom(value, parser.remaining_len())) { return N_ATOM_ERROR; }
tape.append(0, internal::tape_type::NULL_VALUE);
@ -137,29 +142,29 @@ struct tape_builder {
}
// increment_count increments the count of keys in an object or values in an array.
really_inline void increment_count(structural_parser<tape_builder> &parser) {
really_inline void increment_count(structural_parser &parser) {
parser.parser.containing_scope[parser.depth].count++; // we have a key value pair in the object at parser.parser.depth - 1
}
// private:
really_inline uint32_t next_tape_index(structural_parser<tape_builder> &parser) {
really_inline uint32_t next_tape_index(structural_parser &parser) {
return uint32_t(tape.next_tape_loc - parser.parser.doc->tape.get());
}
really_inline void empty_container(structural_parser<tape_builder> &parser, internal::tape_type start, internal::tape_type end) {
really_inline void empty_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) {
auto start_index = next_tape_index(parser);
tape.append(start_index+2, start);
tape.append(start_index, end);
}
really_inline void start_container(structural_parser<tape_builder> &parser) {
really_inline void start_container(structural_parser &parser) {
parser.parser.containing_scope[parser.depth].tape_index = next_tape_index(parser);
parser.parser.containing_scope[parser.depth].count = 0;
tape.skip(); // We don't actually *write* the start element until the end.
}
really_inline void end_container(structural_parser<tape_builder> &parser, internal::tape_type start, internal::tape_type end) noexcept {
really_inline void end_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) noexcept {
// Write the ending tape element, pointing at the start location
const uint32_t start_tape_index = parser.parser.containing_scope[parser.depth].tape_index;
tape.append(start_tape_index, end);
@ -171,7 +176,7 @@ struct tape_builder {
tape_writer::write(parser.parser.doc->tape[start_tape_index], next_tape_index(parser) | (uint64_t(cntsat) << 32), start);
}
really_inline uint8_t *on_start_string(structural_parser<tape_builder> &parser) noexcept {
really_inline uint8_t *on_start_string(structural_parser &parser) noexcept {
// we advance the point, accounting for the fact that we have a NULL termination
tape.append(current_string_buf_loc - parser.parser.doc->string_buf.get(), internal::tape_type::STRING);
return current_string_buf_loc + sizeof(uint32_t);

View File

@ -108,19 +108,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons
}
WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
if (auto error = stage2::structural_parser<stage2::tape_builder>::parse<false>(*this, _doc)) { return error; }
// If we didn't make it to the end, it's an error
if ( next_structural_index != n_structural_indexes ) {
logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!");
return TAPE_ERROR;
}
return SUCCESS;
doc = &_doc;
stage2::tape_builder builder(_doc);
return stage2::structural_parser::parse<false>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
return stage2::structural_parser<stage2::tape_builder>::parse<true>(*this, _doc);
doc = &_doc;
stage2::tape_builder builder(_doc);
return stage2::structural_parser::parse<true>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {

View File

@ -114,19 +114,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons
}
WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept {
if (auto error = stage2::structural_parser<stage2::tape_builder>::parse<false>(*this, _doc)) { return error; }
// If we didn't make it to the end, it's an error
if ( next_structural_index != n_structural_indexes ) {
logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!");
return TAPE_ERROR;
}
return SUCCESS;
doc = &_doc;
stage2::tape_builder builder(*doc);
return stage2::structural_parser::parse<false>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept {
return stage2::structural_parser<stage2::tape_builder>::parse<true>(*this, _doc);
doc = &_doc;
stage2::tape_builder builder(_doc);
return stage2::structural_parser::parse<true>(*this, builder);
}
WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {