#ifndef SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H #define SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H #include "simdjson.h" namespace simdjson { // // Parser callbacks // inline void document::parser::init_stage2() noexcept { 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) noexcept { error = new_error_code; return new_error_code; } really_inline error_code document::parser::on_success(error_code success_code) noexcept { error = success_code; valid = true; return success_code; } really_inline bool document::parser::on_start_document(uint32_t depth) noexcept { containing_scope_offset[depth] = current_loc; write_tape(0, internal::tape_type::ROOT); return true; } really_inline bool document::parser::on_start_object(uint32_t depth) noexcept { containing_scope_offset[depth] = current_loc; write_tape(0, internal::tape_type::START_OBJECT); return true; } really_inline bool document::parser::on_start_array(uint32_t depth) noexcept { containing_scope_offset[depth] = current_loc; write_tape(0, internal::tape_type::START_ARRAY); return true; } // TODO we're not checking this bool really_inline bool document::parser::on_end_document(uint32_t depth) noexcept { // 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], internal::tape_type::ROOT); return true; } really_inline bool document::parser::on_end_object(uint32_t depth) noexcept { // write our doc.tape location to the header scope write_tape(containing_scope_offset[depth], internal::tape_type::END_OBJECT); annotate_previous_loc(containing_scope_offset[depth], current_loc); return true; } really_inline bool document::parser::on_end_array(uint32_t depth) noexcept { // write our doc.tape location to the header scope write_tape(containing_scope_offset[depth], internal::tape_type::END_ARRAY); annotate_previous_loc(containing_scope_offset[depth], current_loc); return true; } really_inline bool document::parser::on_true_atom() noexcept { write_tape(0, internal::tape_type::TRUE_VALUE); return true; } really_inline bool document::parser::on_false_atom() noexcept { write_tape(0, internal::tape_type::FALSE_VALUE); return true; } really_inline bool document::parser::on_null_atom() noexcept { write_tape(0, internal::tape_type::NULL_VALUE); return true; } really_inline uint8_t *document::parser::on_start_string() noexcept { /* we advance the point, accounting for the fact that we have a NULL * termination */ write_tape(current_string_buf_loc - doc.string_buf.get(), internal::tape_type::STRING); return current_string_buf_loc + sizeof(uint32_t); } really_inline bool document::parser::on_end_string(uint8_t *dst) noexcept { 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) noexcept { write_tape(0, internal::tape_type::INT64); std::memcpy(&doc.tape[current_loc], &value, sizeof(value)); ++current_loc; return true; } really_inline bool document::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 document::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 document::parser::write_tape(uint64_t val, internal::tape_type t) noexcept { doc.tape[current_loc++] = val | ((static_cast(static_cast(t))) << 56); } really_inline void document::parser::annotate_previous_loc(uint32_t saved_loc, uint64_t val) noexcept { doc.tape[saved_loc] |= val; } } // namespace simdjson #endif // SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H