mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
fd418f568c
- namespace x::y is C++17 - static_assert requires message in C++11
146 lines
5.4 KiB
C++
146 lines
5.4 KiB
C++
#ifndef SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H
|
|
#define SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H
|
|
|
|
#include "simdjson.h"
|
|
|
|
namespace simdjson {
|
|
namespace dom {
|
|
|
|
//
|
|
// Parser callbacks
|
|
//
|
|
|
|
inline void parser::init_stage2() noexcept {
|
|
current_string_buf_loc = doc.string_buf.get();
|
|
current_loc = 0;
|
|
valid = false;
|
|
error = UNINITIALIZED;
|
|
}
|
|
|
|
really_inline error_code parser::on_error(error_code new_error_code) noexcept {
|
|
error = new_error_code;
|
|
return new_error_code;
|
|
}
|
|
really_inline error_code parser::on_success(error_code success_code) noexcept {
|
|
error = success_code;
|
|
valid = true;
|
|
return success_code;
|
|
}
|
|
// increment_count increments the count of keys in an object or values in an array.
|
|
// Note that if you are at the level of the values or elements, the count
|
|
// must be increment in the preceding depth (depth-1) where the array or
|
|
// the object resides.
|
|
really_inline void parser::increment_count(uint32_t depth) noexcept {
|
|
containing_scope[depth].count++;
|
|
}
|
|
|
|
really_inline bool parser::on_start_document(uint32_t depth) noexcept {
|
|
containing_scope[depth].tape_index = current_loc;
|
|
containing_scope[depth].count = 0;
|
|
write_tape(0, internal::tape_type::ROOT); // if the document is correct, this gets rewritten later
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_start_object(uint32_t depth) noexcept {
|
|
containing_scope[depth].tape_index = current_loc;
|
|
containing_scope[depth].count = 0;
|
|
write_tape(0, internal::tape_type::START_OBJECT); // if the document is correct, this gets rewritten later
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_start_array(uint32_t depth) noexcept {
|
|
containing_scope[depth].tape_index = current_loc;
|
|
containing_scope[depth].count = 0;
|
|
write_tape(0, internal::tape_type::START_ARRAY); // if the document is correct, this gets rewritten later
|
|
return true;
|
|
}
|
|
// TODO we're not checking this bool
|
|
really_inline bool 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.
|
|
write_tape(containing_scope[depth].tape_index, internal::tape_type::ROOT);
|
|
end_scope(depth);
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_end_object(uint32_t depth) noexcept {
|
|
// write our doc.tape location to the header scope
|
|
write_tape(containing_scope[depth].tape_index, internal::tape_type::END_OBJECT);
|
|
end_scope(depth);
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_end_array(uint32_t depth) noexcept {
|
|
// write our doc.tape location to the header scope
|
|
write_tape(containing_scope[depth].tape_index, internal::tape_type::END_ARRAY);
|
|
end_scope(depth);
|
|
return true;
|
|
}
|
|
|
|
really_inline bool parser::on_true_atom() noexcept {
|
|
write_tape(0, internal::tape_type::TRUE_VALUE);
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_false_atom() noexcept {
|
|
write_tape(0, internal::tape_type::FALSE_VALUE);
|
|
return true;
|
|
}
|
|
really_inline bool parser::on_null_atom() noexcept {
|
|
write_tape(0, internal::tape_type::NULL_VALUE);
|
|
return true;
|
|
}
|
|
|
|
really_inline uint8_t *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 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 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 | ((static_cast<uint64_t>(static_cast<char>(t))) << 56);
|
|
}
|
|
|
|
// this function is responsible for annotating the start of the scope
|
|
really_inline void parser::end_scope(uint32_t depth) noexcept {
|
|
scope_descriptor d = containing_scope[depth];
|
|
// count can overflow if it exceeds 24 bits... so we saturate
|
|
// the convention being that a cnt of 0xffffff or more is undetermined in value (>= 0xffffff).
|
|
const uint32_t cntsat = d.count > 0xFFFFFF ? 0xFFFFFF : d.count;
|
|
// This is a load and an OR. It would be possible to just write once at doc.tape[d.tape_index]
|
|
doc.tape[d.tape_index] |= current_loc | (static_cast<uint64_t>(cntsat) << 32);
|
|
}
|
|
|
|
} // namespace simdjson
|
|
} // namespace dom
|
|
|
|
#endif // SIMDJSON_DOCUMENT_PARSER_CALLBACKS_H
|