#include "simdjson/arm64/begin.h" // // Stage 1 // namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace { using namespace simd; struct json_character_block { static simdjson_really_inline json_character_block classify(const simd::simd8x64& in); simdjson_really_inline uint64_t whitespace() const { return _whitespace; } simdjson_really_inline uint64_t op() const { return _op; } simdjson_really_inline uint64_t scalar() { return ~(op() | whitespace()); } uint64_t _whitespace; uint64_t _op; }; simdjson_really_inline json_character_block json_character_block::classify(const simd::simd8x64& in) { // Functional programming causes trouble with Visual Studio. // Keeping this version in comments since it is much nicer: // auto v = in.map([&](simd8 chunk) { // auto nib_lo = chunk & 0xf; // auto nib_hi = chunk.shr<4>(); // auto shuf_lo = nib_lo.lookup_16(16, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 1, 2, 9, 0, 0); // auto shuf_hi = nib_hi.lookup_16(8, 0, 18, 4, 0, 1, 0, 1, 0, 0, 0, 3, 2, 1, 0, 0); // return shuf_lo & shuf_hi; // }); const simd8 table1(16, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 1, 2, 9, 0, 0); const simd8 table2(8, 0, 18, 4, 0, 1, 0, 1, 0, 0, 0, 3, 2, 1, 0, 0); simd8x64 v( (in.chunks[0] & 0xf).lookup_16(table1) & (in.chunks[0].shr<4>()).lookup_16(table2), (in.chunks[1] & 0xf).lookup_16(table1) & (in.chunks[1].shr<4>()).lookup_16(table2), (in.chunks[2] & 0xf).lookup_16(table1) & (in.chunks[2].shr<4>()).lookup_16(table2), (in.chunks[3] & 0xf).lookup_16(table1) & (in.chunks[3].shr<4>()).lookup_16(table2) ); // We compute whitespace and op separately. If the code later only use one or the // other, given the fact that all functions are aggressively inlined, we can // hope that useless computations will be omitted. This is namely case when // minifying (we only need whitespace). *However* if we only need spaces, // it is likely that we will still compute 'v' above with two lookup_16: one // could do it a bit cheaper. This is in contrast with the x64 implementations // where we can, efficiently, do the white space and structural matching // separately. One reason for this difference is that on ARM NEON, the table // lookups either zero or leave unchanged the characters exceeding 0xF whereas // on x64, the equivalent instruction (pshufb) automatically applies a mask, // ignoring the 4 most significant bits. Thus the x64 implementation is // optimized differently. This being said, if you use this code strictly // just for minification (or just to identify the structural characters), // there is a small untaken optimization opportunity here. We deliberately // do not pick it up. uint64_t op = simd8x64( v.chunks[0].any_bits_set(0x7), v.chunks[1].any_bits_set(0x7), v.chunks[2].any_bits_set(0x7), v.chunks[3].any_bits_set(0x7) ).to_bitmask(); uint64_t whitespace = simd8x64( v.chunks[0].any_bits_set(0x18), v.chunks[1].any_bits_set(0x18), v.chunks[2].any_bits_set(0x18), v.chunks[3].any_bits_set(0x18) ).to_bitmask(); return { whitespace, op }; } simdjson_really_inline bool is_ascii(const simd8x64& input) { simd8 bits = input.reduce_or(); return bits.max_val() < 0b10000000u; } simdjson_unused simdjson_really_inline simd8 must_be_continuation(const simd8 prev1, const simd8 prev2, const simd8 prev3) { simd8 is_second_byte = prev1 >= uint8_t(0b11000000u); simd8 is_third_byte = prev2 >= uint8_t(0b11100000u); simd8 is_fourth_byte = prev3 >= uint8_t(0b11110000u); // Use ^ instead of | for is_*_byte, because ^ is commutative, and the caller is using ^ as well. // This will work fine because we only have to report errors for cases with 0-1 lead bytes. // Multiple lead bytes implies 2 overlapping multibyte characters, and if that happens, there is // guaranteed to be at least *one* lead byte that is part of only 1 other multibyte character. // The error will be detected there. return is_second_byte ^ is_third_byte ^ is_fourth_byte; } simdjson_really_inline simd8 must_be_2_3_continuation(const simd8 prev2, const simd8 prev3) { simd8 is_third_byte = prev2 >= uint8_t(0b11100000u); simd8 is_fourth_byte = prev3 >= uint8_t(0b11110000u); return is_third_byte ^ is_fourth_byte; } } // unnamed namespace } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson #include "generic/stage1/utf8_lookup4_algorithm.h" #include "generic/stage1/json_structural_indexer.h" #include "generic/stage1/utf8_validator.h" // // Stage 2 // #include "generic/stage2/tape_builder.h" // // Implementation-specific overrides // namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace { namespace stage1 { simdjson_really_inline uint64_t json_string_scanner::find_escaped(uint64_t backslash) { // On ARM, we don't short-circuit this if there are no backslashes, because the branch gives us no // benefit and therefore makes things worse. // if (!backslash) { uint64_t escaped = prev_escaped; prev_escaped = 0; return escaped; } return find_escaped_branchless(backslash); } } // namespace stage1 } // unnamed namespace simdjson_warn_unused error_code implementation::minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept { return arm64::stage1::json_minifier::minify<64>(buf, len, dst, dst_len); } simdjson_warn_unused error_code dom_parser_implementation::stage1(const uint8_t *_buf, size_t _len, bool streaming) noexcept { this->buf = _buf; this->len = _len; return arm64::stage1::json_structural_indexer::index<64>(buf, len, *this, streaming); } simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t len) const noexcept { return arm64::stage1::generic_validate_utf8(buf,len); } simdjson_warn_unused error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { return stage2::tape_builder::parse_document(*this, _doc); } simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { return stage2::tape_builder::parse_document(*this, _doc); } simdjson_warn_unused error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept { auto error = stage1(_buf, _len, false); if (error) { return error; } return stage2(_doc); } } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson #include "simdjson/arm64/end.h"