diff --git a/benchmark/benchmarker.h b/benchmark/benchmarker.h index f87f9e3b7..8736e9a88 100644 --- a/benchmark/benchmarker.h +++ b/benchmark/benchmarker.h @@ -320,7 +320,7 @@ struct benchmarker { // Stage 1 (find structurals) collector.start(); - error = active_implementation->stage1((const uint8_t *)json.data(), json.size(), parser, false); + error = parser.implementation->stage1((const uint8_t *)json.data(), json.size(), parser, false); event_count stage1_count = collector.end(); stage1 << stage1_count; if (error) { @@ -334,7 +334,7 @@ struct benchmarker { } else { event_count stage2_count; collector.start(); - error = active_implementation->stage2((const uint8_t *)json.data(), json.size(), parser); + error = parser.implementation->stage2((const uint8_t *)json.data(), json.size(), parser); if (error) { exit_error(string("Failed to parse ") + filename + " during stage 2 parsing " + error_message(error)); } @@ -345,7 +345,7 @@ struct benchmarker { // Calculate stats the first time we parse if (stats == NULL) { if (stage1_only) { // we need stage 2 once - error = active_implementation->stage2((const uint8_t *)json.data(), json.size(), parser); + error = parser.implementation->stage2((const uint8_t *)json.data(), json.size(), parser); if (error) { printf("Warning: failed to parse during stage 2. Unable to acquire statistics.\n"); } diff --git a/include/simdjson/dom/parser.h b/include/simdjson/dom/parser.h index d19d73705..6d77cf8e3 100644 --- a/include/simdjson/dom/parser.h +++ b/include/simdjson/dom/parser.h @@ -4,6 +4,7 @@ #include "simdjson/common_defs.h" #include "simdjson/dom/document.h" #include "simdjson/error.h" +#include "simdjson/internal/dom_parser_implementation.h" #include "simdjson/internal/tape_ref.h" #include "simdjson/minify.h" #include "simdjson/padded_string.h" @@ -334,7 +335,8 @@ public: /** * 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. + * The parser may reallocate internal buffers as needed up to this amount as documents are passed + * to it. * * This call will not allocate or deallocate, even if capacity is currently above max_capacity. * @@ -347,6 +349,10 @@ public: /** @private Use simdjson_error instead */ using InvalidJSON [[deprecated("Use simdjson_error instead")]] = simdjson_error; + /** @private [for benchmarking access] The implementation to use */ + std::unique_ptr implementation{}; + +public: /** @private Next location to write to in the tape */ uint32_t current_loc{0}; diff --git a/include/simdjson/implementation.h b/include/simdjson/implementation.h index 948ecc453..f32fe0f2d 100644 --- a/include/simdjson/implementation.h +++ b/include/simdjson/implementation.h @@ -2,6 +2,7 @@ #define SIMDJSON_IMPLEMENTATION_H #include "simdjson/common_defs.h" +#include "simdjson/internal/dom_parser_implementation.h" #include #include #include @@ -11,7 +12,7 @@ namespace simdjson { namespace dom { class parser; -} +} // namespace dom /** * An implementation of simdjson for a particular CPU architecture. @@ -54,16 +55,19 @@ public: /** * @private For internal implementation use * - * Run a full document parse (ensure_capacity, stage1 and stage2). + * const implementation *impl = simdjson::active_implementation; + * cout << "simdjson is optimized for " << impl->name() << "(" << impl->description() << ")" << endl; * - * Overridden by each implementation. - * - * @param buf the json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. - * @param len the length of the json document. - * @param parser the parser with the buffers to use. *MUST* have allocated up to at least len capacity. - * @return the error code, or SUCCESS if there was no error. + * @param capacity The largest document that will be passed to the parser. + * @param max_depth The maximum JSON object/array nesting this parser is expected to handle. + * @param dst The place to put the resulting parser implementation. + * @return the name of the implementation, e.g. "haswell", "westmere", "arm64" */ - WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) const noexcept = 0; + virtual error_code create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr &dst + ) const noexcept = 0; /** * @private For internal implementation use @@ -80,50 +84,6 @@ public: */ WARN_UNUSED virtual error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept = 0; - /** - * @private For internal implementation use - * - * Stage 1 of the document parser. - * - * Overridden by each implementation. - * - * @param buf the json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. - * @param len the length of the json document. - * @param parser the parser with the buffers to use. *MUST* have allocated up to at least len capacity. - * @param streaming whether this is being called by parser::parse_many. - * @return the error code, or SUCCESS if there was no error. - */ - WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) const noexcept = 0; - - /** - * @private For internal implementation use - * - * Stage 2 of the document parser. - * - * Overridden by each implementation. - * - * @param buf the json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. - * @param len the length of the json document. - * @param parser the parser with the buffers to use. *MUST* have allocated up to at least len capacity. - * @return the error code, or SUCCESS if there was no error. - */ - WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) const noexcept = 0; - - /** - * @private For internal implementation use - * - * Stage 2 of the document parser for parser::parse_many. - * - * Overridden by each implementation. - * - * @param buf the json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. - * @param len the length of the json document. - * @param parser the parser with the buffers to use. *MUST* have allocated up to at least len capacity. - * @param next_json the next structural index. Start this at 0 the first time, and it will be updated to the next value to pass each time. - * @return the error code, SUCCESS if there was no error, or SUCCESS_AND_HAS_MORE if there was no error and stage2 can be called again. - */ - WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) const noexcept = 0; - protected: /** @private Construct an implementation with the given name and description. For subclasses. */ really_inline implementation( diff --git a/include/simdjson/inline/document_stream.h b/include/simdjson/inline/document_stream.h index 0c773db08..0e3a1ad8c 100644 --- a/include/simdjson/inline/document_stream.h +++ b/include/simdjson/inline/document_stream.h @@ -172,7 +172,7 @@ inline error_code document_stream::json_parse() noexcept { if (_batch_size == 0) { return simdjson::UTF8_ERROR; } - auto stage1_is_ok = error_code(simdjson::active_implementation->stage1(buf(), _batch_size, parser, true)); + auto stage1_is_ok = error_code(parser.implementation->stage1(buf(), _batch_size, parser, true)); if (stage1_is_ok != simdjson::SUCCESS) { return stage1_is_ok; } @@ -214,14 +214,14 @@ inline error_code document_stream::json_parse() noexcept { // this->stage1_is_ok_thread // there is only one thread that may write to this value stage_1_thread = std::thread([this, b, bs] { - this->stage1_is_ok_thread = error_code(simdjson::active_implementation->stage1(b, bs, this->parser_thread, true)); + this->stage1_is_ok_thread = error_code(parser_thread.implementation->stage1(b, bs, this->parser_thread, true)); }); } } next_json = 0; load_next_batch = false; } // load_next_batch - error_code res = simdjson::active_implementation->stage2(buf(), remaining(), parser, next_json); + error_code res = parser.implementation->stage2(buf(), remaining(), parser, next_json); if (res == simdjson::SUCCESS_AND_HAS_MORE) { n_parsed_docs++; current_buffer_loc = parser.structural_indexes[next_json]; @@ -249,7 +249,7 @@ inline error_code document_stream::json_parse() noexcept { n_bytes_parsed += current_buffer_loc; _batch_size = (std::min)(_batch_size, remaining()); _batch_size = internal::trimmed_length_safe_utf8((const char *)buf(), _batch_size); - auto stage1_is_ok = (error_code)simdjson::active_implementation->stage1(buf(), _batch_size, parser, true); + auto stage1_is_ok = (error_code)parser.implementation->stage1(buf(), _batch_size, parser, true); if (stage1_is_ok != simdjson::SUCCESS) { return stage1_is_ok; } @@ -263,7 +263,7 @@ inline error_code document_stream::json_parse() noexcept { } load_next_batch = false; } // load_next_batch - error_code res = simdjson::active_implementation->stage2(buf(), remaining(), parser, next_json); + error_code res = parser.implementation->stage2(buf(), remaining(), parser, next_json); if (likely(res == simdjson::SUCCESS_AND_HAS_MORE)) { n_parsed_docs++; current_buffer_loc = parser.structural_indexes[next_json]; diff --git a/include/simdjson/inline/parser.h b/include/simdjson/inline/parser.h index baad6a6da..79ee77c61 100644 --- a/include/simdjson/inline/parser.h +++ b/include/simdjson/inline/parser.h @@ -101,7 +101,7 @@ inline simdjson_result parser::parse(const uint8_t *buf, size_t len, bo memcpy((void *)buf, tmp_buf, len); } - code = simdjson::active_implementation->parse(buf, len, *this); + code = implementation->parse(buf, len, *this); if (realloc_if_needed) { aligned_free((void *)buf); // must free before we exit } @@ -150,34 +150,54 @@ inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept { // // If capacity has changed, reallocate capacity-based buffers // - if (_capacity != capacity) { - // Set capacity to 0 until we finish, in case there's an error - _capacity = 0; + if (_capacity != capacity || _max_depth != max_depth) { + error_code err; + if (_capacity != capacity) { + // + // Reallocate the document + // + err = doc.allocate(capacity); - // - // Reallocate the document - // - error_code err = doc.allocate(capacity); - if (err) { return err; } + // + // Initialize stage 1 output + // + size_t max_structures = ROUNDUP_N(capacity, 64) + 2 + 7; + structural_indexes.reset( new (std::nothrow) uint32_t[max_structures] ); // TODO realloc + if (!structural_indexes) { _capacity = _max_depth = 0; return err; } - // - // Don't allocate 0 bytes, just return. - // - if (capacity == 0) { - structural_indexes.reset(); - return SUCCESS; + // + // Reallocate implementation capacity + // + if (implementation && !err) { err = implementation->set_capacity(capacity); } + } + + if (_max_depth != max_depth && !err) { + // + // Reallocate stage 2 state + // + containing_scope.reset(new (std::nothrow) internal::scope_descriptor[max_depth]); // TODO realloc + ret_address.reset(new (std::nothrow) internal::ret_address[max_depth]); + + if (!ret_address || !containing_scope) { + err = MEMALLOC; + } + + // + // Reallocate implementation max depth + // + if (implementation && !err) { err = implementation->set_max_depth(max_depth); } } // - // Initialize stage 1 output + // Create the implementation if it doesn't already exist // - size_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 MEMALLOC; + if (!implementation && !err) { + err = simdjson::active_implementation->create_dom_parser_implementation(capacity, max_depth, implementation); } + if (err) { _capacity = _max_depth = 0; return err; } _capacity = capacity; + _max_depth = max_depth; // // If capacity hasn't changed, but the document was taken, allocate a new document. @@ -187,31 +207,6 @@ inline error_code parser::allocate(size_t capacity, size_t max_depth) noexcept { if (err) { return err; } } - // - // If max_depth has changed, reallocate those buffers - // - if (max_depth != _max_depth) { - _max_depth = 0; - - if (max_depth == 0) { - ret_address.reset(); - containing_scope.reset(); - return SUCCESS; - } - - // - // Initialize stage 2 state - // - containing_scope.reset(new (std::nothrow) internal::scope_descriptor[max_depth]); // TODO realloc - ret_address.reset(new (std::nothrow) internal::ret_address[max_depth]); - - if (!ret_address || !containing_scope) { - // Could not allocate memory - return MEMALLOC; - } - - _max_depth = max_depth; - } return SUCCESS; } diff --git a/include/simdjson/internal/dom_parser_implementation.h b/include/simdjson/internal/dom_parser_implementation.h new file mode 100644 index 000000000..86dbe1033 --- /dev/null +++ b/include/simdjson/internal/dom_parser_implementation.h @@ -0,0 +1,115 @@ +#ifndef SIMDJSON_INTERNAL_DOM_PARSER_IMPLEMENTATION_H +#define SIMDJSON_INTERNAL_DOM_PARSER_IMPLEMENTATION_H + +#include "simdjson/common_defs.h" +#include "simdjson/error.h" +#include + +namespace simdjson { + +namespace dom { +class parser; +} // namespace dom + +namespace internal { + +/** + * An implementation of simdjson's DOM parser for a particular CPU architecture. + */ +class dom_parser_implementation { +public: + /** + * @private For internal implementation use + * + * Run a full JSON parse on a single document (stage1 + stage2). + * + * Guaranteed only to be called when capacity > document length. + * + * Overridden by each implementation. + * + * @param buf The json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. + * @param len The length of the json document. + * @param parser The parser object. TODO replace this with dom::document & when state is moved to the implementation. + * @return The error code, or SUCCESS if there was no error. + */ + WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) noexcept = 0; + + /** + * @private For internal implementation use + * + * Stage 1 of the document parser. + * + * Guaranteed only to be called when capacity > document length. + * + * Overridden by each implementation. + * + * @param buf The json document to parse. + * @param len The length of the json document. + * @param parser The parser object. TODO replace this with structural_indexes & when state is moved to the implementation. + * @param streaming Whether this is being called by parser::parse_many. + * @return The error code, or SUCCESS if there was no error. + */ + WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept = 0; + + /** + * @private For internal implementation use + * + * Stage 2 of the document parser. + * + * Guaranteed only to be called after stage1(), with the same buf/len as stage1(). + * + * Overridden by each implementation. + * + * @param buf The json document to parse. *MUST* be allocated up to len + SIMDJSON_PADDING bytes. + * @param len The length of the json document. + * @param parser The parser object. TODO replace this with dom::document & when state is moved to the implementation. + * @return The error code, or SUCCESS if there was no error. + */ + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) noexcept = 0; + + /** + * @private For internal implementation use + * + * Stage 2 of the document parser for parser::parse_many. + * + * Guaranteed only to be called after stage1(), with buf and len being a subset of the total stage1 buf/len. + * Overridden by each implementation. + * + * @param buf The json document to parse. + * @param len The length of the json document. + * @param parser The parser object. TODO replace this with dom::document & when state is moved to the implementation. + * @param next_json The next structural index. Start this at 0 the first time, and it will be updated to the next value to pass each time. + * @return The error code, SUCCESS if there was no error, or SUCCESS_AND_HAS_MORE if there was no error and stage2 can be called again. + */ + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) noexcept = 0; + + /** + * Change the capacity of this parser. + * + * Generally used for reallocation. + * + * @param capacity The new capacity. + * @param max_depth The new max_depth. + * @return The error code, or SUCCESS if there was no error. + */ + virtual error_code set_capacity(size_t capacity) noexcept = 0; + + /** + * Change the max depth of this parser. + * + * Generally used for reallocation. + * + * @param capacity The new capacity. + * @param max_depth The new max_depth. + * @return The error code, or SUCCESS if there was no error. + */ + virtual error_code set_max_depth(size_t max_depth) noexcept = 0; + + virtual ~dom_parser_implementation()=default; + +}; // class dom_parser_implementation + +} // namespace internal +} // namespace simdjson + +#endif // SIMDJSON_INTERNAL_DOM_PARSER_IMPLEMENTATION_H diff --git a/src/arm64/stage1.cpp b/src/arm64/dom_parser_implementation.cpp similarity index 89% rename from src/arm64/stage1.cpp rename to src/arm64/dom_parser_implementation.cpp index 926d368fc..b3a548da8 100644 --- a/src/arm64/stage1.cpp +++ b/src/arm64/dom_parser_implementation.cpp @@ -1,8 +1,13 @@ #include "simdjson.h" +#include "arm64/implementation.h" +#include "arm64/dom_parser_implementation.h" + +// +// Stage 1 +// #include "arm64/bitmask.h" #include "arm64/simd.h" #include "arm64/bitmanipulation.h" -#include "arm64/implementation.h" namespace simdjson { namespace arm64 { @@ -85,3 +90,22 @@ WARN_UNUSED error_code implementation::stage1(const uint8_t *buf, size_t len, pa } // namespace arm64 } // namespace simdjson + +// +// Stage 2 +// + +#include "arm64/stringparsing.h" +#include "arm64/numberparsing.h" + +namespace simdjson { +namespace arm64 { + +#include "generic/stage2/logger.h" +#include "generic/stage2/atomparsing.h" +#include "generic/stage2/structural_iterator.h" +#include "generic/stage2/structural_parser.h" +#include "generic/stage2/streaming_structural_parser.h" + +} // namespace arm64 +} // namespace simdjson diff --git a/src/arm64/dom_parser_implementation.h b/src/arm64/dom_parser_implementation.h new file mode 100644 index 000000000..6c2de5ca6 --- /dev/null +++ b/src/arm64/dom_parser_implementation.h @@ -0,0 +1,44 @@ +#ifndef SIMDJSON_ARM64_DOM_PARSER_IMPLEMENTATION_H +#define SIMDJSON_ARM64_DOM_PARSER_IMPLEMENTATION_H + +#include "simdjson.h" +#include "isadetection.h" + +namespace simdjson { +namespace arm64 { + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + really_inline dom_parser_implementation(); + + WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) noexcept; + WARN_UNUSED error_code set_capacity(size_t capacity) noexcept final; + WARN_UNUSED error_code set_max_depth(size_t max_depth) noexcept final; +}; + +really_inline dom_parser_implementation::dom_parser_implementation() {} + +// Leaving these here so they can be inlined if so desired +WARN_UNUSED error_code dom_parser_implementation::set_capacity(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::set_max_depth(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *buf, size_t len, dom::parser &doc_parser) noexcept { + error_code code = stage1(buf, len, doc_parser, false); + if (!code) { + code = stage2(buf, len, doc_parser); + } + return code; +} + +} // namespace arm64 +} // namespace simdjson + +#endif // SIMDJSON_ARM64_DOM_PARSER_IMPLEMENTATION_H \ No newline at end of file diff --git a/src/arm64/implementation.cpp b/src/arm64/implementation.cpp new file mode 100644 index 000000000..7276aa29f --- /dev/null +++ b/src/arm64/implementation.cpp @@ -0,0 +1,25 @@ +#include "simdjson.h" +#include "arm64/implementation.h" +#include "arm64/dom_parser_implementation.h" + +TARGET_HASWELL + +namespace simdjson { +namespace arm64 { + +WARN_UNUSED error_code implementation::create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr& dst +) const noexcept { + dst.reset( new (std::nothrow) dom_parser_implementation() ); + if (!dst) { return MEMALLOC; } + dst->set_capacity(capacity); + dst->set_max_depth(max_depth); + return SUCCESS; +} + +} // namespace arm64 +} // namespace simdjson + +UNTARGET_REGION diff --git a/src/arm64/implementation.h b/src/arm64/implementation.h index e8da33548..08e2e5fa5 100644 --- a/src/arm64/implementation.h +++ b/src/arm64/implementation.h @@ -12,11 +12,12 @@ using namespace simdjson::dom; class implementation final : public simdjson::implementation { public: really_inline implementation() : simdjson::implementation("arm64", "ARM NEON", instruction_set::NEON) {} - WARN_UNUSED error_code parse(const uint8_t *buf, size_t len, parser &parser) const noexcept final; + WARN_UNUSED error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; WARN_UNUSED error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; - WARN_UNUSED error_code stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser, size_t &next_json) const noexcept final; }; } // namespace arm64 diff --git a/src/arm64/stage2.cpp b/src/arm64/stage2.cpp deleted file mode 100644 index e25854af1..000000000 --- a/src/arm64/stage2.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef SIMDJSON_ARM64_STAGE2_H -#define SIMDJSON_ARM64_STAGE2_H - -#include "simdjson.h" -#include "arm64/implementation.h" -#include "arm64/stringparsing.h" -#include "arm64/numberparsing.h" - -namespace simdjson { -namespace arm64 { - -#include "generic/stage2/logger.h" -#include "generic/stage2/atomparsing.h" -#include "generic/stage2/structural_iterator.h" -#include "generic/stage2/structural_parser.h" -#include "generic/stage2/streaming_structural_parser.h" - -} // namespace arm64 -} // namespace simdjson - -#endif // SIMDJSON_ARM64_STAGE2_H diff --git a/src/fallback/stage1.cpp b/src/fallback/dom_parser_implementation.cpp similarity index 91% rename from src/fallback/stage1.cpp rename to src/fallback/dom_parser_implementation.cpp index 5f5be3c1d..29e748d08 100644 --- a/src/fallback/stage1.cpp +++ b/src/fallback/dom_parser_implementation.cpp @@ -1,6 +1,10 @@ #include "simdjson.h" #include "fallback/implementation.h" +#include "fallback/dom_parser_implementation.h" +// +// Stage 1 +// namespace simdjson { namespace fallback { namespace stage1 { @@ -8,7 +12,7 @@ namespace stage1 { class structural_scanner { public: -really_inline structural_scanner(const uint8_t *_buf, uint32_t _len, parser &_doc_parser, bool _streaming) +really_inline structural_scanner(const uint8_t *_buf, uint32_t _len, dom::parser &_doc_parser, bool _streaming) : buf{_buf}, next_structural_index{_doc_parser.structural_indexes.get()}, doc_parser{_doc_parser}, idx{0}, len{_len}, error{SUCCESS}, streaming{_streaming} {} really_inline void add_structural() { @@ -131,7 +135,7 @@ really_inline error_code scan() { private: const uint8_t *buf; uint32_t *next_structural_index; - parser &doc_parser; + dom::parser &doc_parser; uint32_t idx; uint32_t len; error_code error; @@ -141,7 +145,7 @@ private: } // namespace stage1 -WARN_UNUSED error_code implementation::stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept { +WARN_UNUSED error_code dom_parser_implementation::stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept { if (unlikely(len > parser.capacity())) { return CAPACITY; } @@ -207,3 +211,21 @@ WARN_UNUSED error_code implementation::minify(const uint8_t *buf, size_t len, ui } // namespace fallback } // namespace simdjson + +// +// Stage 2 +// +#include "fallback/stringparsing.h" +#include "fallback/numberparsing.h" + +namespace simdjson { +namespace fallback { + +#include "generic/stage2/logger.h" +#include "generic/stage2/atomparsing.h" +#include "generic/stage2/structural_iterator.h" +#include "generic/stage2/structural_parser.h" +#include "generic/stage2/streaming_structural_parser.h" + +} // namespace fallback +} // namespace simdjson diff --git a/src/fallback/dom_parser_implementation.h b/src/fallback/dom_parser_implementation.h new file mode 100644 index 000000000..dfe5c16ef --- /dev/null +++ b/src/fallback/dom_parser_implementation.h @@ -0,0 +1,44 @@ +#ifndef SIMDJSON_FALLBACK_DOM_PARSER_IMPLEMENTATION_H +#define SIMDJSON_FALLBACK_DOM_PARSER_IMPLEMENTATION_H + +#include "simdjson.h" +#include "isadetection.h" + +namespace simdjson { +namespace fallback { + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + really_inline dom_parser_implementation(); + + WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) noexcept; + WARN_UNUSED error_code set_capacity(size_t capacity) noexcept final; + WARN_UNUSED error_code set_max_depth(size_t max_depth) noexcept final; +}; + +really_inline dom_parser_implementation::dom_parser_implementation() {} + +// Leaving these here so they can be inlined if so desired +WARN_UNUSED error_code dom_parser_implementation::set_capacity(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::set_max_depth(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *buf, size_t len, dom::parser &doc_parser) noexcept { + error_code code = stage1(buf, len, doc_parser, false); + if (!code) { + code = stage2(buf, len, doc_parser); + } + return code; +} + +} // namespace fallback +} // namespace simdjson + +#endif // SIMDJSON_FALLBACK_DOM_PARSER_IMPLEMENTATION_H \ No newline at end of file diff --git a/src/fallback/implementation.cpp b/src/fallback/implementation.cpp new file mode 100644 index 000000000..3981f2229 --- /dev/null +++ b/src/fallback/implementation.cpp @@ -0,0 +1,25 @@ +#include "simdjson.h" +#include "fallback/implementation.h" +#include "fallback/dom_parser_implementation.h" + +TARGET_HASWELL + +namespace simdjson { +namespace fallback { + +WARN_UNUSED error_code implementation::create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr& dst +) const noexcept { + dst.reset( new (std::nothrow) dom_parser_implementation() ); + if (!dst) { return MEMALLOC; } + dst->set_capacity(capacity); + dst->set_max_depth(max_depth); + return SUCCESS; +} + +} // namespace fallback +} // namespace simdjson + +UNTARGET_REGION diff --git a/src/fallback/implementation.h b/src/fallback/implementation.h index 90372b004..4a52e1f8b 100644 --- a/src/fallback/implementation.h +++ b/src/fallback/implementation.h @@ -16,11 +16,12 @@ public: "Generic fallback implementation", 0 ) {} - WARN_UNUSED error_code parse(const uint8_t *buf, size_t len, parser &parser) const noexcept final; + WARN_UNUSED error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; WARN_UNUSED error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; - WARN_UNUSED error_code stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser, size_t &next_json) const noexcept final; }; } // namespace fallback diff --git a/src/fallback/stage2.cpp b/src/fallback/stage2.cpp deleted file mode 100644 index 82adad0d7..000000000 --- a/src/fallback/stage2.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "simdjson.h" - -#include "fallback/implementation.h" -#include "fallback/stringparsing.h" -#include "fallback/numberparsing.h" - -namespace simdjson { -namespace fallback { - -#include "generic/stage2/logger.h" -#include "generic/stage2/atomparsing.h" -#include "generic/stage2/structural_iterator.h" -#include "generic/stage2/structural_parser.h" -#include "generic/stage2/streaming_structural_parser.h" - -} // namespace fallback -} // namespace simdjson diff --git a/src/generic/stage1/json_structural_indexer.h b/src/generic/stage1/json_structural_indexer.h index f1ed4bf09..8da896938 100644 --- a/src/generic/stage1/json_structural_indexer.h +++ b/src/generic/stage1/json_structural_indexer.h @@ -58,7 +58,7 @@ public: class json_structural_indexer { public: template - static error_code index(const uint8_t *buf, size_t len, parser &parser, bool streaming) noexcept; + static error_code index(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept; private: really_inline json_structural_indexer(uint32_t *structural_indexes) @@ -66,7 +66,7 @@ private: template really_inline void step(const uint8_t *block, buf_block_reader &reader) noexcept; really_inline void next(simd::simd8x64 in, json_block block, size_t idx); - really_inline error_code finish(parser &parser, size_t idx, size_t len, bool streaming); + really_inline error_code finish(dom::parser &parser, size_t idx, size_t len, bool streaming); json_scanner scanner{}; utf8_checker checker{}; @@ -83,7 +83,7 @@ really_inline void json_structural_indexer::next(simd::simd8x64 in, jso unescaped_chars_error |= block.non_quote_inside_string(unescaped); } -really_inline error_code json_structural_indexer::finish(parser &parser, size_t idx, size_t len, bool streaming) { +really_inline error_code json_structural_indexer::finish(dom::parser &parser, size_t idx, size_t len, bool streaming) { // Write out the final iteration's structurals indexer.write(uint32_t(idx-64), prev_structurals); @@ -155,7 +155,7 @@ really_inline void json_structural_indexer::step<64>(const uint8_t *block, buf_b // The caller should still ensure that the input is valid UTF-8. If you are processing substrings, // you may want to call on a function like trimmed_length_safe_utf8. template -error_code json_structural_indexer::index(const uint8_t *buf, size_t len, parser &parser, bool streaming) noexcept { +error_code json_structural_indexer::index(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept { if (unlikely(len > parser.capacity())) { return CAPACITY; } buf_block_reader reader(buf, len); diff --git a/src/generic/stage2/streaming_structural_parser.h b/src/generic/stage2/streaming_structural_parser.h index ae58812fd..101db2f40 100755 --- a/src/generic/stage2/streaming_structural_parser.h +++ b/src/generic/stage2/streaming_structural_parser.h @@ -1,7 +1,7 @@ namespace stage2 { struct streaming_structural_parser: structural_parser { - really_inline streaming_structural_parser(const uint8_t *buf, size_t len, parser &_doc_parser, uint32_t next_structural) : structural_parser(buf, len, _doc_parser, next_structural) {} + really_inline streaming_structural_parser(const uint8_t *buf, size_t len, dom::parser &_doc_parser, uint32_t next_structural) : structural_parser(buf, len, _doc_parser, next_structural) {} // override to add streaming WARN_UNUSED really_inline error_code start(UNUSED size_t len, ret_address finish_parser) { @@ -44,7 +44,7 @@ struct streaming_structural_parser: structural_parser { * The JSON is parsed to a tape, see the accompanying tape.md file * for documentation. ***********/ -WARN_UNUSED error_code implementation::stage2(const uint8_t *buf, size_t len, parser &doc_parser, size_t &next_json) const noexcept { +WARN_UNUSED error_code dom_parser_implementation::stage2(const uint8_t *buf, size_t len, dom::parser &doc_parser, size_t &next_json) noexcept { static constexpr stage2::unified_machine_addresses addresses = INIT_ADDRESSES(); stage2::streaming_structural_parser parser(buf, len, doc_parser, uint32_t(next_json)); error_code result = parser.start(len, addresses.finish); diff --git a/src/generic/stage2/structural_parser.h b/src/generic/stage2/structural_parser.h index 54eb3bd04..16a84dffd 100644 --- a/src/generic/stage2/structural_parser.h +++ b/src/generic/stage2/structural_parser.h @@ -48,7 +48,7 @@ struct unified_machine_addresses { #define FAIL_IF(EXPR) { if (EXPR) { return addresses.error; } } struct number_writer { - parser &doc_parser; + dom::parser &doc_parser; really_inline void write_s64(int64_t value) noexcept { append_tape(0, internal::tape_type::INT64); @@ -72,7 +72,7 @@ struct number_writer { struct structural_parser { structural_iterator structurals; - parser &doc_parser; + dom::parser &doc_parser; /** Next write location in the string buf for stage 2 parsing */ uint8_t *current_string_buf_loc{}; uint32_t depth; @@ -80,7 +80,7 @@ struct structural_parser { really_inline structural_parser( const uint8_t *buf, size_t len, - parser &_doc_parser, + dom::parser &_doc_parser, uint32_t next_structural = 0 ) : structurals(buf, len, _doc_parser.structural_indexes.get(), next_structural), doc_parser{_doc_parser}, depth{0} {} @@ -398,7 +398,7 @@ struct structural_parser { * The JSON is parsed to a tape, see the accompanying tape.md file * for documentation. ***********/ -WARN_UNUSED error_code implementation::stage2(const uint8_t *buf, size_t len, parser &doc_parser) const noexcept { +WARN_UNUSED error_code dom_parser_implementation::stage2(const uint8_t *buf, size_t len, dom::parser &doc_parser) noexcept { static constexpr stage2::unified_machine_addresses addresses = INIT_ADDRESSES(); stage2::structural_parser parser(buf, len, doc_parser); error_code result = parser.start(len, addresses.finish); @@ -516,11 +516,3 @@ finish: error: return parser.error(); } - -WARN_UNUSED error_code implementation::parse(const uint8_t *buf, size_t len, parser &doc_parser) const noexcept { - error_code code = stage1(buf, len, doc_parser, false); - if (!code) { - code = stage2(buf, len, doc_parser); - } - return code; -} diff --git a/src/haswell/stage1.cpp b/src/haswell/dom_parser_implementation.cpp similarity index 83% rename from src/haswell/stage1.cpp rename to src/haswell/dom_parser_implementation.cpp index 01bf53f41..ff19f288c 100644 --- a/src/haswell/stage1.cpp +++ b/src/haswell/dom_parser_implementation.cpp @@ -1,9 +1,13 @@ #include "simdjson.h" +#include "haswell/implementation.h" +#include "haswell/dom_parser_implementation.h" +// +// Stage 1 +// #include "haswell/bitmask.h" #include "haswell/simd.h" #include "haswell/bitmanipulation.h" -#include "haswell/implementation.h" TARGET_HASWELL namespace simdjson { @@ -68,11 +72,30 @@ WARN_UNUSED error_code implementation::minify(const uint8_t *buf, size_t len, ui #include "generic/stage1/utf8_lookup2_algorithm.h" #include "generic/stage1/json_structural_indexer.h" -WARN_UNUSED error_code implementation::stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept { +WARN_UNUSED error_code dom_parser_implementation::stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept { return haswell::stage1::json_structural_indexer::index<128>(buf, len, parser, streaming); } } // namespace haswell - +} // namespace simdjson +UNTARGET_REGION + +// +// Stage 2 +// +#include "haswell/stringparsing.h" +#include "haswell/numberparsing.h" + +TARGET_HASWELL +namespace simdjson { +namespace haswell { + +#include "generic/stage2/logger.h" +#include "generic/stage2/atomparsing.h" +#include "generic/stage2/structural_iterator.h" +#include "generic/stage2/structural_parser.h" +#include "generic/stage2/streaming_structural_parser.h" + +} // namespace haswell } // namespace simdjson UNTARGET_REGION diff --git a/src/haswell/dom_parser_implementation.h b/src/haswell/dom_parser_implementation.h new file mode 100644 index 000000000..6954ce284 --- /dev/null +++ b/src/haswell/dom_parser_implementation.h @@ -0,0 +1,44 @@ +#ifndef SIMDJSON_HASWELL_DOM_PARSER_IMPLEMENTATION_H +#define SIMDJSON_HASWELL_DOM_PARSER_IMPLEMENTATION_H + +#include "simdjson.h" +#include "isadetection.h" + +namespace simdjson { +namespace haswell { + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + really_inline dom_parser_implementation(); + + WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) noexcept; + WARN_UNUSED error_code set_capacity(size_t capacity) noexcept final; + WARN_UNUSED error_code set_max_depth(size_t max_depth) noexcept final; +}; + +really_inline dom_parser_implementation::dom_parser_implementation() {} + +// Leaving these here so they can be inlined if so desired +WARN_UNUSED error_code dom_parser_implementation::set_capacity(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::set_max_depth(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *buf, size_t len, dom::parser &doc_parser) noexcept { + error_code code = stage1(buf, len, doc_parser, false); + if (!code) { + code = stage2(buf, len, doc_parser); + } + return code; +} + +} // namespace haswell +} // namespace simdjson + +#endif // SIMDJSON_HASWELL_DOM_PARSER_IMPLEMENTATION_H \ No newline at end of file diff --git a/src/haswell/implementation.cpp b/src/haswell/implementation.cpp new file mode 100644 index 000000000..53daa1825 --- /dev/null +++ b/src/haswell/implementation.cpp @@ -0,0 +1,25 @@ +#include "simdjson.h" +#include "haswell/implementation.h" +#include "haswell/dom_parser_implementation.h" + +TARGET_HASWELL + +namespace simdjson { +namespace haswell { + +WARN_UNUSED error_code implementation::create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr& dst +) const noexcept { + dst.reset( new (std::nothrow) dom_parser_implementation() ); + if (!dst) { return MEMALLOC; } + dst->set_capacity(capacity); + dst->set_max_depth(max_depth); + return SUCCESS; +} + +} // namespace haswell +} // namespace simdjson + +UNTARGET_REGION diff --git a/src/haswell/implementation.h b/src/haswell/implementation.h index 12024ec20..2dd89cca1 100644 --- a/src/haswell/implementation.h +++ b/src/haswell/implementation.h @@ -7,8 +7,6 @@ namespace simdjson { namespace haswell { -using namespace simdjson::dom; - class implementation final : public simdjson::implementation { public: really_inline implementation() : simdjson::implementation( @@ -16,11 +14,12 @@ public: "Intel/AMD AVX2", instruction_set::AVX2 | instruction_set::PCLMULQDQ | instruction_set::BMI1 | instruction_set::BMI2 ) {} - WARN_UNUSED error_code parse(const uint8_t *buf, size_t len, parser &parser) const noexcept final; + WARN_UNUSED error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; WARN_UNUSED error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; - WARN_UNUSED error_code stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser, size_t &next_json) const noexcept final; }; } // namespace haswell diff --git a/src/haswell/stage2.cpp b/src/haswell/stage2.cpp deleted file mode 100644 index c6ee49055..000000000 --- a/src/haswell/stage2.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "simdjson.h" -#include "haswell/implementation.h" -#include "haswell/stringparsing.h" -#include "haswell/numberparsing.h" - -TARGET_HASWELL -namespace simdjson { -namespace haswell { - -#include "generic/stage2/logger.h" -#include "generic/stage2/atomparsing.h" -#include "generic/stage2/structural_iterator.h" -#include "generic/stage2/structural_parser.h" -#include "generic/stage2/streaming_structural_parser.h" - -} // namespace haswell -} // namespace simdjson -UNTARGET_REGION diff --git a/src/implementation.cpp b/src/implementation.cpp index 9bc2533f5..5bd1b1333 100644 --- a/src/implementation.cpp +++ b/src/implementation.cpp @@ -38,21 +38,16 @@ public: const std::string &name() const noexcept final { return set_best()->name(); } const std::string &description() const noexcept final { return set_best()->description(); } uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); } - WARN_UNUSED error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) const noexcept final { - return set_best()->parse(buf, len, parser); + WARN_UNUSED error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final { + return set_best()->create_dom_parser_implementation(capacity, max_length, dst); } WARN_UNUSED error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final { return set_best()->minify(buf, len, dst, dst_len); } - WARN_UNUSED error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) const noexcept final { - return set_best()->stage1(buf, len, parser, streaming); - } - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) const noexcept final { - return set_best()->stage2(buf, len, parser); - } - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) const noexcept final { - return set_best()->stage2(buf, len, parser, next_json); - } really_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {} private: @@ -81,21 +76,16 @@ const std::initializer_list available_implementation_poi // So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support class unsupported_implementation final : public implementation { public: - WARN_UNUSED error_code parse(const uint8_t *, size_t, dom::parser &) const noexcept final { + WARN_UNUSED error_code create_dom_parser_implementation( + size_t, + size_t, + std::unique_ptr& + ) const noexcept final { return UNSUPPORTED_ARCHITECTURE; } WARN_UNUSED error_code minify(const uint8_t *, size_t, uint8_t *, size_t &) const noexcept final { return UNSUPPORTED_ARCHITECTURE; } - WARN_UNUSED error_code stage1(const uint8_t *, size_t, dom::parser &, bool) const noexcept final { - return UNSUPPORTED_ARCHITECTURE; - } - WARN_UNUSED error_code stage2(const uint8_t *, size_t, dom::parser &) const noexcept final { - return UNSUPPORTED_ARCHITECTURE; - } - WARN_UNUSED error_code stage2(const uint8_t *, size_t, dom::parser &, size_t &) const noexcept final { - return UNSUPPORTED_ARCHITECTURE; - } unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {} }; diff --git a/src/simdjson.cpp b/src/simdjson.cpp index 41c68c42e..84dc93a1e 100644 --- a/src/simdjson.cpp +++ b/src/simdjson.cpp @@ -13,20 +13,20 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS #include "simdprune_tables.h" #if SIMDJSON_IMPLEMENTATION_ARM64 -#include "arm64/stage1.cpp" -#include "arm64/stage2.cpp" +#include "arm64/implementation.cpp" +#include "arm64/dom_parser_implementation.cpp" #endif #if SIMDJSON_IMPLEMENTATION_FALLBACK -#include "fallback/stage1.cpp" -#include "fallback/stage2.cpp" +#include "fallback/implementation.cpp" +#include "fallback/dom_parser_implementation.cpp" #endif #if SIMDJSON_IMPLEMENTATION_HASWELL -#include "haswell/stage1.cpp" -#include "haswell/stage2.cpp" +#include "haswell/implementation.cpp" +#include "haswell/dom_parser_implementation.cpp" #endif #if SIMDJSON_IMPLEMENTATION_WESTMERE -#include "westmere/stage1.cpp" -#include "westmere/stage2.cpp" +#include "westmere/implementation.cpp" +#include "westmere/dom_parser_implementation.cpp" #endif SIMDJSON_POP_DISABLE_WARNINGS diff --git a/src/westmere/stage1.cpp b/src/westmere/dom_parser_implementation.cpp similarity index 82% rename from src/westmere/stage1.cpp rename to src/westmere/dom_parser_implementation.cpp index e14ec4553..2f5f84f32 100644 --- a/src/westmere/stage1.cpp +++ b/src/westmere/dom_parser_implementation.cpp @@ -1,4 +1,10 @@ #include "simdjson.h" +#include "westmere/implementation.h" +#include "westmere/dom_parser_implementation.h" + +// +// Stage 1 +// #include "westmere/bitmask.h" #include "westmere/simd.h" #include "westmere/bitmanipulation.h" @@ -67,11 +73,30 @@ WARN_UNUSED error_code implementation::minify(const uint8_t *buf, size_t len, ui #include "generic/stage1/utf8_lookup2_algorithm.h" #include "generic/stage1/json_structural_indexer.h" -WARN_UNUSED error_code implementation::stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept { +WARN_UNUSED error_code dom_parser_implementation::stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) noexcept { return westmere::stage1::json_structural_indexer::index<64>(buf, len, parser, streaming); } } // namespace westmere - +} // namespace simdjson +UNTARGET_REGION + +// +// Stage 2 +// +#include "westmere/stringparsing.h" +#include "westmere/numberparsing.h" + +TARGET_WESTMERE +namespace simdjson { +namespace westmere { + +#include "generic/stage2/logger.h" +#include "generic/stage2/atomparsing.h" +#include "generic/stage2/structural_iterator.h" +#include "generic/stage2/structural_parser.h" +#include "generic/stage2/streaming_structural_parser.h" + +} // namespace westmere } // namespace simdjson UNTARGET_REGION diff --git a/src/westmere/dom_parser_implementation.h b/src/westmere/dom_parser_implementation.h new file mode 100644 index 000000000..85ae22006 --- /dev/null +++ b/src/westmere/dom_parser_implementation.h @@ -0,0 +1,44 @@ +#ifndef SIMDJSON_WESTMERE_DOM_PARSER_IMPLEMENTATION_H +#define SIMDJSON_WESTMERE_DOM_PARSER_IMPLEMENTATION_H + +#include "simdjson.h" +#include "isadetection.h" + +namespace simdjson { +namespace westmere { + +class dom_parser_implementation final : public internal::dom_parser_implementation { +public: + really_inline dom_parser_implementation(); + + WARN_UNUSED virtual error_code parse(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage1(const uint8_t *buf, size_t len, dom::parser &parser, bool streaming) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser) noexcept; + WARN_UNUSED virtual error_code stage2(const uint8_t *buf, size_t len, dom::parser &parser, size_t &next_json) noexcept; + WARN_UNUSED error_code set_capacity(size_t capacity) noexcept final; + WARN_UNUSED error_code set_max_depth(size_t max_depth) noexcept final; +}; + +really_inline dom_parser_implementation::dom_parser_implementation() {} + +// Leaving these here so they can be inlined if so desired +WARN_UNUSED error_code dom_parser_implementation::set_capacity(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::set_max_depth(size_t) noexcept { + return SUCCESS; +} + +WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *buf, size_t len, dom::parser &doc_parser) noexcept { + error_code code = stage1(buf, len, doc_parser, false); + if (!code) { + code = stage2(buf, len, doc_parser); + } + return code; +} + +} // namespace westmere +} // namespace simdjson + +#endif // SIMDJSON_WESTMERE_DOM_PARSER_IMPLEMENTATION_H \ No newline at end of file diff --git a/src/westmere/implementation.cpp b/src/westmere/implementation.cpp new file mode 100644 index 000000000..56792a8c9 --- /dev/null +++ b/src/westmere/implementation.cpp @@ -0,0 +1,25 @@ +#include "simdjson.h" +#include "westmere/implementation.h" +#include "westmere/dom_parser_implementation.h" + +TARGET_HASWELL + +namespace simdjson { +namespace westmere { + +WARN_UNUSED error_code implementation::create_dom_parser_implementation( + size_t capacity, + size_t max_depth, + std::unique_ptr& dst +) const noexcept { + dst.reset( new (std::nothrow) dom_parser_implementation() ); + if (!dst) { return MEMALLOC; } + dst->set_capacity(capacity); + dst->set_max_depth(max_depth); + return SUCCESS; +} + +} // namespace westmere +} // namespace simdjson + +UNTARGET_REGION diff --git a/src/westmere/implementation.h b/src/westmere/implementation.h index ad4bb5996..ba1311418 100644 --- a/src/westmere/implementation.h +++ b/src/westmere/implementation.h @@ -13,11 +13,12 @@ using namespace simdjson::dom; class implementation final : public simdjson::implementation { public: really_inline implementation() : simdjson::implementation("westmere", "Intel/AMD SSE4.2", instruction_set::SSE42 | instruction_set::PCLMULQDQ) {} - WARN_UNUSED error_code parse(const uint8_t *buf, size_t len, parser &parser) const noexcept final; + WARN_UNUSED error_code create_dom_parser_implementation( + size_t capacity, + size_t max_length, + std::unique_ptr& dst + ) const noexcept final; WARN_UNUSED error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final; - WARN_UNUSED error_code stage1(const uint8_t *buf, size_t len, parser &parser, bool streaming) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser) const noexcept final; - WARN_UNUSED error_code stage2(const uint8_t *buf, size_t len, parser &parser, size_t &next_json) const noexcept final; }; } // namespace westmere diff --git a/src/westmere/stage2.cpp b/src/westmere/stage2.cpp deleted file mode 100644 index 3ae6f4881..000000000 --- a/src/westmere/stage2.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "simdjson.h" -#include "westmere/implementation.h" -#include "westmere/stringparsing.h" -#include "westmere/numberparsing.h" - -TARGET_WESTMERE -namespace simdjson { -namespace westmere { - -#include "generic/stage2/logger.h" -#include "generic/stage2/atomparsing.h" -#include "generic/stage2/structural_iterator.h" -#include "generic/stage2/structural_parser.h" -#include "generic/stage2/streaming_structural_parser.h" - -} // namespace westmere -} // namespace simdjson -UNTARGET_REGION