#ifndef SIMDJSON_INLINE_DOCUMENT_H #define SIMDJSON_INLINE_DOCUMENT_H #ifndef SIMDJSON_DOCUMENT_H #error This is an internal file only. Include document.h instead. #endif // Inline implementations go in here if they aren't small enough to go in the class itself or if // there are complex header file dependencies that need to be broken by externalizing the // implementation. #include "simdjson/implementation.h" namespace simdjson { // TODO 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); if (code) { return document::doc_ref_result(doc, code); } if (realloc_if_needed) { const uint8_t *tmp_buf = buf; buf = (uint8_t *)allocate_padded_buffer(len); if (buf == nullptr) return document::doc_ref_result(doc, MEMALLOC); memcpy((void *)buf, tmp_buf, len); } code = simdjson::active_implementation->parse(buf, len, *this); // We're indicating validity via the doc_ref_result, so set the parse state back to invalid valid = false; error = UNINITIALIZED; if (realloc_if_needed) { aligned_free((void *)buf); // must free before we exit } return document::doc_ref_result(doc, code); } really_inline document::doc_ref_result document::parser::parse(const char *buf, size_t len, bool realloc_if_needed) noexcept { return parse((const uint8_t *)buf, len, realloc_if_needed); } really_inline document::doc_ref_result document::parser::parse(const std::string &s, bool realloc_if_needed) noexcept { return parse(s.data(), s.length(), realloc_if_needed); } really_inline document::doc_ref_result document::parser::parse(const padded_string &s) noexcept { return parse(s.data(), s.length(), false); } // TODO really_inline? 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); } really_inline document::doc_result document::parse(const std::string &s, bool realloc_if_needed) noexcept { return parse(s.data(), s.length(), realloc_if_needed); } really_inline document::doc_result document::parse(const padded_string &s) noexcept { return parse(s.data(), s.length(), false); } // // Parser callbacks // WARN_UNUSED inline error_code document::parser::init_parse(size_t len) { if (len > capacity()) { return error = CAPACITY; } // If the last doc was taken, we need to allocate a new one if (!doc.tape) { if (!doc.set_capacity(len)) { return error = MEMALLOC; } } return SUCCESS; } inline void document::parser::init_stage2() { current_string_buf_loc = doc.string_buf.get(); current_loc = 0; valid = false; error = UNINITIALIZED; } really_inline error_code document::parser::on_error(error_code new_error_code) { error = new_error_code; return new_error_code; } really_inline error_code document::parser::on_success(error_code success_code) { error = success_code; valid = true; return success_code; } really_inline bool document::parser::on_start_document(uint32_t depth) { containing_scope_offset[depth] = current_loc; write_tape(0, 'r'); return true; } really_inline bool document::parser::on_start_object(uint32_t depth) { containing_scope_offset[depth] = current_loc; write_tape(0, '{'); return true; } really_inline bool document::parser::on_start_array(uint32_t depth) { containing_scope_offset[depth] = current_loc; write_tape(0, '['); return true; } // TODO we're not checking this bool really_inline bool document::parser::on_end_document(uint32_t depth) { // write our doc.tape location to the header scope // The root scope gets written *at* the previous location. annotate_previous_loc(containing_scope_offset[depth], current_loc); write_tape(containing_scope_offset[depth], 'r'); return true; } really_inline bool document::parser::on_end_object(uint32_t depth) { // write our doc.tape location to the header scope write_tape(containing_scope_offset[depth], '}'); annotate_previous_loc(containing_scope_offset[depth], current_loc); return true; } really_inline bool document::parser::on_end_array(uint32_t depth) { // write our doc.tape location to the header scope write_tape(containing_scope_offset[depth], ']'); annotate_previous_loc(containing_scope_offset[depth], current_loc); return true; } really_inline bool document::parser::on_true_atom() { write_tape(0, 't'); return true; } really_inline bool document::parser::on_false_atom() { write_tape(0, 'f'); return true; } really_inline bool document::parser::on_null_atom() { write_tape(0, 'n'); return true; } really_inline uint8_t *document::parser::on_start_string() { /* we advance the point, accounting for the fact that we have a NULL * termination */ write_tape(current_string_buf_loc - doc.string_buf.get(), '"'); return current_string_buf_loc + sizeof(uint32_t); } really_inline bool document::parser::on_end_string(uint8_t *dst) { uint32_t str_length = dst - (current_string_buf_loc + sizeof(uint32_t)); // TODO check for overflow in case someone has a crazy string (>=4GB?) // But only add the overflow check when the document itself exceeds 4GB // Currently unneeded because we refuse to parse docs larger or equal to 4GB. memcpy(current_string_buf_loc, &str_length, sizeof(uint32_t)); // NULL termination is still handy if you expect all your strings to // be NULL terminated? It comes at a small cost *dst = 0; current_string_buf_loc = dst + 1; return true; } really_inline bool document::parser::on_number_s64(int64_t value) { write_tape(0, 'l'); std::memcpy(&doc.tape[current_loc], &value, sizeof(value)); ++current_loc; return true; } really_inline bool document::parser::on_number_u64(uint64_t value) { write_tape(0, 'u'); doc.tape[current_loc++] = value; return true; } really_inline bool document::parser::on_number_double(double value) { write_tape(0, 'd'); static_assert(sizeof(value) == sizeof(doc.tape[current_loc]), "mismatch size"); memcpy(&doc.tape[current_loc++], &value, sizeof(double)); // doc.tape[doc.current_loc++] = *((uint64_t *)&d); return true; } } // namespace simdjson #endif // SIMDJSON_INLINE_DOCUMENT_H