#ifndef SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H #include "simdjson/generic/ondemand/base.h" #include "simdjson/generic/ondemand/raw_json_string.h" #include "simdjson/generic/ondemand/json_iterator-inl.h" #include "simdjson/generic/implementation_simdjson_result_base-inl.h" #endif // SIMDJSON_CONDITIONAL_INCLUDE namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand { simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {} simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast(buf); } simdjson_inline char raw_json_string::operator[](size_t i) const noexcept { return reinterpret_cast(buf)[i]; } simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept { size_t pos{0}; while(pos < target.size()) { pos = target.find('"', pos); if(pos == std::string_view::npos) { return true; } if(pos != 0 && target[pos-1] != '\\') { return false; } if(pos > 1 && target[pos-2] == '\\') { size_t backslash_count{2}; for(size_t i = 3; i <= pos; i++) { if(target[pos-i] == '\\') { backslash_count++; } else { break; } } if(backslash_count % 2 == 0) { return false; } } pos++; } return true; } simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept { size_t pos{0}; while(target[pos]) { const char * result = strchr(target+pos, '"'); if(result == nullptr) { return true; } pos = result - target; if(pos != 0 && target[pos-1] != '\\') { return false; } if(pos > 1 && target[pos-2] == '\\') { size_t backslash_count{2}; for(size_t i = 3; i <= pos; i++) { if(target[pos-i] == '\\') { backslash_count++; } else { break; } } if(backslash_count % 2 == 0) { return false; } } pos++; } return true; } simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept { // If we are going to call memcmp, then we must know something about the length of the raw_json_string. return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); } simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept { // Assumptions: does not contain unescaped quote characters("), and // the raw content is quote terminated within a valid JSON string. if(target.size() <= SIMDJSON_PADDING) { return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size()); } const char * r{raw()}; size_t pos{0}; for(;pos < target.size();pos++) { if(r[pos] != target[pos]) { return false; } } if(r[pos] != '"') { return false; } return true; } simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept { const char * r{raw()}; size_t pos{0}; bool escaping{false}; for(;pos < target.size();pos++) { if(r[pos] != target[pos]) { return false; } // if target is a compile-time constant and it is free from // quotes, then the next part could get optimized away through // inlining. if((target[pos] == '"') && !escaping) { // We have reached the end of the raw_json_string but // the target is not done. return false; } else if(target[pos] == '\\') { escaping = !escaping; } else { escaping = false; } } if(r[pos] != '"') { return false; } return true; } simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept { // Assumptions: 'target' does not contain unescaped quote characters, is null terminated and // the raw content is quote terminated within a valid JSON string. const char * r{raw()}; size_t pos{0}; for(;target[pos];pos++) { if(r[pos] != target[pos]) { return false; } } if(r[pos] != '"') { return false; } return true; } simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept { // Assumptions: does not contain unescaped quote characters, and // the raw content is quote terminated within a valid JSON string. const char * r{raw()}; size_t pos{0}; bool escaping{false}; for(;target[pos];pos++) { if(r[pos] != target[pos]) { return false; } // if target is a compile-time constant and it is free from // quotes, then the next part could get optimized away through // inlining. if((target[pos] == '"') && !escaping) { // We have reached the end of the raw_json_string but // the target is not done. return false; } else if(target[pos] == '\\') { escaping = !escaping; } else { escaping = false; } } if(r[pos] != '"') { return false; } return true; } simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept { return a.unsafe_is_equal(c); } simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept { return a == c; } simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept { return !(a == c); } simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept { return !(a == c); } simdjson_inline simdjson_warn_unused simdjson_result raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept { return iter.unescape(*this, allow_replacement); } simdjson_inline simdjson_warn_unused simdjson_result raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept { return iter.unescape_wobbly(*this); } simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept { bool in_escape = false; const char *s = str.raw(); while (true) { switch (*s) { case '\\': in_escape = !in_escape; break; case '"': if (in_escape) { in_escape = false; } else { return out; } break; default: if (in_escape) { in_escape = false; } } out << *s; s++; } } } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson namespace simdjson { simdjson_inline simdjson_result::simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string &&value) noexcept : implementation_simdjson_result_base(std::forward(value)) {} simdjson_inline simdjson_result::simdjson_result(error_code error) noexcept : implementation_simdjson_result_base(error) {} simdjson_inline simdjson_result simdjson_result::raw() const noexcept { if (error()) { return error(); } return first.raw(); } simdjson_inline char simdjson_result::operator[](size_t i) const noexcept { if (error()) { return error(); } return first[i]; } simdjson_inline simdjson_warn_unused simdjson_result simdjson_result::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter, bool allow_replacement) const noexcept { if (error()) { return error(); } return first.unescape(iter, allow_replacement); } simdjson_inline simdjson_warn_unused simdjson_result simdjson_result::unescape_wobbly(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept { if (error()) { return error(); } return first.unescape_wobbly(iter); } } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_RAW_JSON_STRING_INL_H