#ifndef SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H #include "simdjson/padded_string.h" #include "simdjson/padded_string_view.h" #include "simdjson/implementation.h" #include "simdjson/internal/dom_parser_implementation.h" #include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY #include "simdjson/generic/ondemand/base.h" #include "simdjson/generic/ondemand/document_stream.h" #include "simdjson/generic/ondemand/parser.h" #include "simdjson/generic/ondemand/raw_json_string.h" #endif // SIMDJSON_CONDITIONAL_INCLUDE namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand { simdjson_inline parser::parser(size_t max_capacity) noexcept : _max_capacity{max_capacity} { } simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept { if (new_capacity > max_capacity()) { return CAPACITY; } if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; } // string_capacity copied from document::allocate _capacity = 0; size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64); string_buf.reset(new (std::nothrow) uint8_t[string_capacity]); #if SIMDJSON_DEVELOPMENT_CHECKS start_positions.reset(new (std::nothrow) token_position[new_max_depth]); #endif if (implementation) { SIMDJSON_TRY( implementation->set_capacity(new_capacity) ); SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) ); } else { SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) ); } _capacity = new_capacity; _max_depth = new_max_depth; return SUCCESS; } #if SIMDJSON_DEVELOPMENT_CHECKS simdjson_inline simdjson_warn_unused bool parser::string_buffer_overflow(const uint8_t *string_buf_loc) const noexcept { return (string_buf_loc < string_buf.get()) || (size_t(string_buf_loc - string_buf.get()) >= capacity()); } #endif simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(padded_string_view json) & noexcept { if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); // Allocate if needed if (capacity() < json.length() || !string_buf) { SIMDJSON_TRY( allocate(json.length(), max_depth()) ); } // Run stage 1. SIMDJSON_TRY( implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular) ); return document::start({ reinterpret_cast(json.data()), this }); } #ifdef SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_allow_incomplete_json(padded_string_view json) & noexcept { if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); // Allocate if needed if (capacity() < json.length() || !string_buf) { SIMDJSON_TRY( allocate(json.length(), max_depth()) ); } // Run stage 1. const simdjson::error_code err = implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular); if (err) { if (err != UNCLOSED_STRING) return err; } return document::start({ reinterpret_cast(json.data()), this, true }); } #endif // SIMDJSON_EXPERIMENTAL_ALLOW_INCOMPLETE_JSON simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const char *json, size_t len, size_t allocated) & noexcept { return iterate(padded_string_view(json, len, allocated)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept { return iterate(padded_string_view(json, len, allocated)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string_view json, size_t allocated) & noexcept { return iterate(padded_string_view(json, allocated)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(std::string &json) & noexcept { return iterate(pad_with_reserve(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const std::string &json) & noexcept { return iterate(padded_string_view(json)); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const simdjson_result &result) & noexcept { // We don't presently have a way to temporarily get a const T& from a simdjson_result without throwing an exception SIMDJSON_TRY( result.error() ); padded_string_view json = result.value_unsafe(); return iterate(json); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate(const simdjson_result &result) & noexcept { // We don't presently have a way to temporarily get a const T& from a simdjson_result without throwing an exception SIMDJSON_TRY( result.error() ); const padded_string &json = result.value_unsafe(); return iterate(json); } simdjson_warn_unused simdjson_inline simdjson_result parser::iterate_raw(padded_string_view json) & noexcept { if (!json.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } json.remove_utf8_bom(); // Allocate if needed if (capacity() < json.length()) { SIMDJSON_TRY( allocate(json.length(), max_depth()) ); } // Run stage 1. SIMDJSON_TRY( implementation->stage1(reinterpret_cast(json.data()), json.length(), stage1_mode::regular) ); return json_iterator(reinterpret_cast(json.data()), this); } inline simdjson_result parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept { // Warning: no check is done on the buffer padding. We trust the user. if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; } if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) { buf += 3; len -= 3; } if(allow_comma_separated && batch_size < len) { batch_size = len; } return document_stream(*this, buf, len, batch_size, allow_comma_separated); } inline simdjson_result parser::iterate_many(const char *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept { // Warning: no check is done on the buffer padding. We trust the user. return iterate_many(reinterpret_cast(buf), len, batch_size, allow_comma_separated); } inline simdjson_result parser::iterate_many(padded_string_view s, size_t batch_size, bool allow_comma_separated) noexcept { if (!s.has_sufficient_padding()) { return INSUFFICIENT_PADDING; } return iterate_many(s.data(), s.length(), batch_size, allow_comma_separated); } inline simdjson_result parser::iterate_many(const padded_string &s, size_t batch_size, bool allow_comma_separated) noexcept { return iterate_many(padded_string_view(s), batch_size, allow_comma_separated); } inline simdjson_result parser::iterate_many(const std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { return iterate_many(padded_string_view(s), batch_size, allow_comma_separated); } inline simdjson_result parser::iterate_many(std::string &s, size_t batch_size, bool allow_comma_separated) noexcept { return iterate_many(pad(s), batch_size, allow_comma_separated); } simdjson_pure simdjson_inline size_t parser::capacity() const noexcept { return _capacity; } simdjson_pure simdjson_inline size_t parser::max_capacity() const noexcept { return _max_capacity; } simdjson_pure simdjson_inline size_t parser::max_depth() const noexcept { return _max_depth; } simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept { if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) { _max_capacity = max_capacity; } else { _max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY; } } simdjson_inline simdjson_warn_unused simdjson_result parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept { uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement); if (!end) { return STRING_ERROR; } std::string_view result(reinterpret_cast(dst), end-dst); dst = end; return result; } simdjson_inline simdjson_warn_unused simdjson_result parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept { uint8_t *end = implementation->parse_wobbly_string(in.buf, dst); if (!end) { return STRING_ERROR; } std::string_view result(reinterpret_cast(dst), end-dst); dst = end; return result; } simdjson_inline simdjson_warn_unused ondemand::parser& parser::get_parser() { return *parser::get_parser_instance(); } simdjson_inline bool release_parser() { auto &parser_instance = parser::get_threadlocal_parser_if_exists(); if (parser_instance) { parser_instance.reset(); return true; } return false; } simdjson_inline simdjson_warn_unused std::unique_ptr& parser::get_parser_instance() { std::unique_ptr& parser_instance = get_threadlocal_parser_if_exists(); if (!parser_instance) { parser_instance.reset(new ondemand::parser()); } return parser_instance; } simdjson_inline simdjson_warn_unused std::unique_ptr& parser::get_threadlocal_parser_if_exists() { // @the-moisrex points out that this could be implemented with std::optional (C++17). thread_local std::unique_ptr parser_instance = nullptr; return parser_instance; } } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson namespace simdjson { simdjson_inline simdjson_result::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::parser &&value) noexcept : implementation_simdjson_result_base(std::forward(value)) {} simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept : implementation_simdjson_result_base(error) {} } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_PARSER_INL_H