diff --git a/include/simdjson/document.h b/include/simdjson/document.h index b4486e7cf..606e38d8e 100644 --- a/include/simdjson/document.h +++ b/include/simdjson/document.h @@ -1022,10 +1022,6 @@ public: // Parser callbacks: these are internal! // - really_inline bool on_number_s64(int64_t value) noexcept; ///< @private - really_inline bool on_number_u64(uint64_t value) noexcept; ///< @private - really_inline bool on_number_double(double value) noexcept; ///< @private - inline void write_tape(uint64_t val, internal::tape_type t) noexcept; private: /** diff --git a/src/document_parser_callbacks.h b/src/document_parser_callbacks.h index 58d9a4817..29e682d3a 100644 --- a/src/document_parser_callbacks.h +++ b/src/document_parser_callbacks.h @@ -10,25 +10,6 @@ namespace dom { // Parser callbacks // -really_inline bool parser::on_number_s64(int64_t value) noexcept { - write_tape(0, internal::tape_type::INT64); - std::memcpy(&doc.tape[current_loc], &value, sizeof(value)); - ++current_loc; - return true; -} -really_inline bool parser::on_number_u64(uint64_t value) noexcept { - write_tape(0, internal::tape_type::UINT64); - doc.tape[current_loc++] = value; - return true; -} -really_inline bool parser::on_number_double(double value) noexcept { - write_tape(0, internal::tape_type::DOUBLE); - 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; -} - really_inline void parser::write_tape(uint64_t val, internal::tape_type t) noexcept { doc.tape[current_loc++] = val | ((uint64_t(char(t))) << 56); } diff --git a/src/generic/numberparsing.h b/src/generic/numberparsing.h index aca36897d..1db5ad69d 100644 --- a/src/generic/numberparsing.h +++ b/src/generic/numberparsing.h @@ -1,6 +1,5 @@ namespace numberparsing { - // Attempts to compute i * 10^(power) exactly; and if "negative" is // true, negate the result. // This function will only work in some cases, when it does not work, success is @@ -261,8 +260,9 @@ really_inline bool is_made_of_eight_digits_fast(const char *chars) { // // This function will almost never be called!!! // +template never_inline bool parse_large_integer(const uint8_t *const src, - parser &parser, + W writer, bool found_minus) { const char *p = reinterpret_cast(src); @@ -310,14 +310,14 @@ never_inline bool parse_large_integer(const uint8_t *const src, // as a positive signed integer, but the negative version is // possible. constexpr int64_t signed_answer = INT64_MIN; - parser.on_number_s64(signed_answer); + writer.write_s64(signed_answer); #ifdef JSON_TEST_NUMBERS // for unit testing found_integer(signed_answer, src); #endif } else { // we can negate safely int64_t signed_answer = -static_cast(i); - parser.on_number_s64(signed_answer); + writer.write_s64(signed_answer); #ifdef JSON_TEST_NUMBERS // for unit testing found_integer(signed_answer, src); #endif @@ -330,21 +330,22 @@ never_inline bool parse_large_integer(const uint8_t *const src, #ifdef JSON_TEST_NUMBERS // for unit testing found_integer(i, src); #endif - parser.on_number_s64(i); + writer.write_s64(i); } else { #ifdef JSON_TEST_NUMBERS // for unit testing found_unsigned_integer(i, src); #endif - parser.on_number_u64(i); + writer.write_u64(i); } } return is_structural_or_whitespace(*p); } -bool slow_float_parsing(UNUSED const char * src, parser &parser) { +template +bool slow_float_parsing(UNUSED const char * src, W writer) { double d; if (parse_float_strtod(src, &d)) { - parser.on_number_double(d); + writer.write_double(d); #ifdef JSON_TEST_NUMBERS // for unit testing found_float(d, (const uint8_t *)src); #endif @@ -365,12 +366,13 @@ bool slow_float_parsing(UNUSED const char * src, parser &parser) { // content and append a space before calling this function. // // Our objective is accurate parsing (ULP of 0) at high speed. +template really_inline bool parse_number(UNUSED const uint8_t *const src, UNUSED bool found_minus, - parser &parser) { + W writer) { #ifdef SIMDJSON_SKIPNUMBERPARSING // for performance analysis, it is sometimes // useful to skip parsing - parser.on_number_s64(0); // always write zero + writer.write_s64(0); // always write zero return true; // always succeeds #else const char *p = reinterpret_cast(src); @@ -522,14 +524,14 @@ really_inline bool parse_number(UNUSED const uint8_t *const src, // 10000000000000000000000000000000000000000000e+308 // 3.1415926535897932384626433832795028841971693993751 // - return slow_float_parsing((const char *) src, parser); + return slow_float_parsing((const char *) src, writer); } } if (unlikely(exponent < FASTFLOAT_SMALLEST_POWER) || (exponent > FASTFLOAT_LARGEST_POWER)) { // this is uncommon!!! // this is almost never going to get called!!! // we start anew, going slowly!!! - return slow_float_parsing((const char *) src, parser); + return slow_float_parsing((const char *) src, writer); } bool success = true; double d = compute_float_64(exponent, i, negative, &success); @@ -538,7 +540,7 @@ really_inline bool parse_number(UNUSED const uint8_t *const src, success = parse_float_strtod((const char *)src, &d); } if (success) { - parser.on_number_double(d); + writer.write_double(d); #ifdef JSON_TEST_NUMBERS // for unit testing found_float(d, src); #endif @@ -553,10 +555,10 @@ really_inline bool parse_number(UNUSED const uint8_t *const src, if (unlikely(digit_count >= 18)) { // this is uncommon!!! // there is a good chance that we had an overflow, so we need // need to recover: we parse the whole thing again. - return parse_large_integer(src, parser, found_minus); + return parse_large_integer(src, writer, found_minus); } i = negative ? 0 - i : i; - parser.on_number_s64(i); + writer.write_s64(i); #ifdef JSON_TEST_NUMBERS // for unit testing found_integer(i, src); #endif diff --git a/src/generic/stage2_build_tape.h b/src/generic/stage2_build_tape.h index d1a8a14f3..7d27ef0d6 100644 --- a/src/generic/stage2_build_tape.h +++ b/src/generic/stage2_build_tape.h @@ -113,6 +113,26 @@ public: uint8_t c{0}; // used to track the (structural) character we are looking at }; +struct number_writer { + parser &doc_parser; + + really_inline void write_s64(int64_t value) noexcept { + doc_parser.write_tape(0, internal::tape_type::INT64); + std::memcpy(&doc_parser.doc.tape[doc_parser.current_loc], &value, sizeof(value)); + ++doc_parser.current_loc; + } + really_inline void write_u64(uint64_t value) noexcept { + doc_parser.write_tape(0, internal::tape_type::UINT64); + doc_parser.doc.tape[doc_parser.current_loc++] = value; + } + really_inline void write_double(double value) noexcept { + doc_parser.write_tape(0, internal::tape_type::DOUBLE); + static_assert(sizeof(value) == sizeof(doc_parser.doc.tape[doc_parser.current_loc]), "mismatch size"); + memcpy(&doc_parser.doc.tape[doc_parser.current_loc++], &value, sizeof(double)); + // doc.tape[doc.current_loc++] = *((uint64_t *)&d); + } +}; // struct number_writer + struct structural_parser { structural_iterator structurals; parser &doc_parser; @@ -209,7 +229,8 @@ struct structural_parser { } WARN_UNUSED really_inline bool parse_number(const uint8_t *src, bool found_minus) { - return !numberparsing::parse_number(src, found_minus, doc_parser); + number_writer writer{doc_parser}; + return !numberparsing::parse_number(src, found_minus, writer); } WARN_UNUSED really_inline bool parse_number(bool found_minus) { return parse_number(structurals.current(), found_minus);