mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e1d07ee86 | |||
| 9de1b45e30 | |||
| 7a73230459 | |||
| 667f488c2c |
Vendored
+1
-11
@@ -86,16 +86,6 @@
|
||||
"vector": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"__functional_base_03": "cpp",
|
||||
"filesystem": "cpp",
|
||||
"*.inc": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"variant": "cpp",
|
||||
"__bits": "cpp",
|
||||
"csignal": "cpp",
|
||||
"future": "cpp",
|
||||
"queue": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"ranges": "cpp"
|
||||
"filesystem": "cpp"
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(
|
||||
simdjson
|
||||
# The version number is modified by tools/release.py
|
||||
VERSION 2.1.0
|
||||
VERSION 2.0.4
|
||||
DESCRIPTION "Parsing gigabytes of JSON per second"
|
||||
HOMEPAGE_URL "https://simdjson.org/"
|
||||
LANGUAGES CXX C
|
||||
@@ -20,8 +20,8 @@ string(
|
||||
# ---- Options, variables ----
|
||||
|
||||
# These version numbers are modified by tools/release.py
|
||||
set(SIMDJSON_LIB_VERSION "12.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "12" CACHE STRING "simdjson library soversion")
|
||||
set(SIMDJSON_LIB_VERSION "11.0.0" CACHE STRING "simdjson library version")
|
||||
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
|
||||
|
||||
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = "2.1.0"
|
||||
PROJECT_NUMBER = "2.0.4"
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -25,11 +25,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/simdjson_ondemand.h"
|
||||
#include "json2msgpack/rapidjson.h"
|
||||
#include "json2msgpack/yyjson.h"
|
||||
#include "json2msgpack/sajson.h"
|
||||
#include "json2msgpack/nlohmann_json.h"
|
||||
|
||||
#include "amazon_cellphones/simdjson_dom.h"
|
||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||
|
||||
@@ -48,7 +48,7 @@ BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -9,8 +9,6 @@ namespace distinct_user_id {
|
||||
struct sajson {
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||
|
||||
@@ -42,7 +42,7 @@ BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), find_id, result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -11,8 +11,6 @@ struct sajson {
|
||||
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_benchmark/file_runner.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace json_benchmark;
|
||||
|
||||
template <typename I> struct runner : public file_runner<I> {
|
||||
std::string_view result;
|
||||
std::unique_ptr<char[]> buffer;
|
||||
|
||||
bool setup(benchmark::State &state) {
|
||||
bool isok = this->load_json(state, TWITTER_JSON);
|
||||
if (isok) {
|
||||
// Let us allocate a sizeable buffer.
|
||||
buffer = std::unique_ptr<char[]>(new char[this->json.size() * 4 + 1024]);
|
||||
}
|
||||
return isok;
|
||||
}
|
||||
|
||||
bool before_run(benchmark::State &state) {
|
||||
if (!file_runner<I>::before_run(state)) {
|
||||
return false;
|
||||
}
|
||||
// Clear the buffer.
|
||||
::memset(buffer.get(), 0, this->json.size() * 4 + 1024);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run(benchmark::State &) {
|
||||
return this->implementation.run(this->json, buffer.get(), result);
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
bool diff(benchmark::State &state, runner<R> &reference) {
|
||||
return diff_results(state, result.size(), reference.result.size(), diff_flags::NONE);
|
||||
}
|
||||
};
|
||||
|
||||
struct simdjson_ondemand;
|
||||
|
||||
template <typename I>
|
||||
simdjson_really_inline static void json2msgpack(benchmark::State &state) {
|
||||
run_json_benchmark<runner<I>, runner<simdjson_ondemand>>(state);
|
||||
}
|
||||
|
||||
} // namespace json2msgpack
|
||||
@@ -1,117 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
struct nlohmann_json2msgpack {
|
||||
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf);
|
||||
|
||||
private:
|
||||
inline void write_double(const double d) noexcept;
|
||||
inline void write_byte(const uint8_t b) noexcept;
|
||||
inline void write_uint32(const uint32_t w) noexcept;
|
||||
inline void write_string(const std::string& str);
|
||||
inline void recursive_processor(basic_json<> element);
|
||||
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
std::string_view nlohmann_json2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
auto val = nlohmann::json::parse(json.data(), json.data() + json.size());
|
||||
recursive_processor(val);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void nlohmann_json2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void nlohmann_json2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void nlohmann_json2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
void nlohmann_json2msgpack::write_string(const std::string & str) {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(str.size()));
|
||||
::memcpy(buff, str.data(), str.size());
|
||||
buff += str.size();
|
||||
}
|
||||
|
||||
void nlohmann_json2msgpack::recursive_processor(json element) {
|
||||
switch (element.type()) {
|
||||
case nlohmann::detail::value_t::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
std::vector<json> array = element.get<std::vector<json>>();
|
||||
write_uint32(uint32_t(array.size()));
|
||||
for (auto child : array) {
|
||||
recursive_processor(child);
|
||||
}
|
||||
} break;
|
||||
case nlohmann::detail::value_t::object: {
|
||||
write_byte(0xdf);
|
||||
std::map<std::string,json> object = element.get<std::map<std::string,json>>();
|
||||
write_uint32(uint32_t(object.size()));
|
||||
for (auto field : object) {
|
||||
write_string(field.first);
|
||||
recursive_processor(field.second);
|
||||
}
|
||||
} break;
|
||||
|
||||
case nlohmann::detail::value_t::number_integer:
|
||||
case nlohmann::detail::value_t::number_unsigned:
|
||||
case nlohmann::detail::value_t::number_float:
|
||||
write_double(double(element));
|
||||
break;
|
||||
case nlohmann::detail::value_t::string:
|
||||
write_string(std::string(element));
|
||||
break;
|
||||
case nlohmann::detail::value_t::boolean:
|
||||
write_byte(0xc2 + bool(element));
|
||||
break;
|
||||
case nlohmann::detail::value_t::null:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
case nlohmann::detail::value_t::discarded:
|
||||
case nlohmann::detail::value_t::binary:
|
||||
default:
|
||||
printf("unexpected\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct nlohmann_json {
|
||||
using StringType = std::string_view;
|
||||
|
||||
nlohmann_json2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, nlohmann_json)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
|
||||
|
||||
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <int parseflag>
|
||||
struct rapidjson2msgpack {
|
||||
inline std::string_view to_msgpack(char *json, uint8_t *buf);
|
||||
|
||||
private:
|
||||
inline void write_double(const double d) noexcept;
|
||||
inline void write_byte(const uint8_t b) noexcept;
|
||||
inline void write_uint32(const uint32_t w) noexcept;
|
||||
inline void write_uint32_at(const uint32_t w, uint8_t *p) noexcept;
|
||||
void write_string(const char * s, size_t length) noexcept;
|
||||
inline void recursive_processor(Value &v);
|
||||
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
template <int parseflag>
|
||||
std::string_view rapidjson2msgpack<parseflag>::to_msgpack(char *json, uint8_t *buf) {
|
||||
buff = buf;
|
||||
Document doc{};
|
||||
if(parseflag & kParseInsituFlag) {
|
||||
doc.ParseInsitu<parseflag>(json);
|
||||
} else {
|
||||
doc.Parse<parseflag>(json);
|
||||
}
|
||||
recursive_processor(doc);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::write_string(const char * c, size_t len) noexcept {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(len));
|
||||
::memcpy(buff, c, len);
|
||||
buff += len;
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
void rapidjson2msgpack<parseflag>::recursive_processor(Value &v) {
|
||||
switch (v.GetType()) {
|
||||
case kArrayType:
|
||||
write_byte(0xdd);
|
||||
write_uint32(v.Size());
|
||||
for (Value::ValueIterator i = v.Begin(); i != v.End(); ++i) {
|
||||
recursive_processor(*i);
|
||||
}
|
||||
break;
|
||||
case kObjectType:
|
||||
write_byte(0xdf);
|
||||
write_uint32(uint32_t(v.MemberEnd()-v.MemberBegin()));
|
||||
for (Value::MemberIterator m = v.MemberBegin(); m != v.MemberEnd();
|
||||
++m) {
|
||||
write_string(m->name.GetString(), m->name.GetStringLength());
|
||||
recursive_processor(m->value);
|
||||
}
|
||||
break;
|
||||
case kStringType:
|
||||
write_string(v.GetString(), v.GetStringLength());
|
||||
break;
|
||||
case kNumberType:
|
||||
write_double(v.GetDouble());
|
||||
break;
|
||||
case kFalseType:
|
||||
write_byte(0xc2);
|
||||
break;
|
||||
case kTrueType:
|
||||
write_byte(0xc3);
|
||||
break;
|
||||
case kNullType:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <int parseflag>
|
||||
struct rapidjson_base {
|
||||
using StringType = std::string_view;
|
||||
|
||||
rapidjson2msgpack<parseflag> parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
result =
|
||||
parser.to_msgpack(json.data(), reinterpret_cast<uint8_t *>(buffer));
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using rapidjson_lossless = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_lossless)->UseManualTime();
|
||||
|
||||
|
||||
using rapidjson = rapidjson_base<kParseValidateEncodingFlag>;
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
|
||||
|
||||
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_RAPIDJSON
|
||||
@@ -1,131 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef SIMDJSON_COMPETITION_SAJSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace sajson;
|
||||
|
||||
|
||||
struct sajson2msgpack {
|
||||
inline std::string_view to_msgpack(char *json, size_t size, uint8_t *buf);
|
||||
virtual ~sajson2msgpack() { free(ast_buffer); }
|
||||
|
||||
private:
|
||||
inline void write_double(const double d) noexcept;
|
||||
inline void write_byte(const uint8_t b) noexcept;
|
||||
inline void write_uint32(const uint32_t w) noexcept;
|
||||
inline void write_string(const char * s, size_t length) noexcept;
|
||||
inline void recursive_processor(const sajson::value &v);
|
||||
|
||||
uint8_t *buff{};
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
};
|
||||
|
||||
|
||||
std::string_view sajson2msgpack::to_msgpack(char *json, size_t size, uint8_t *buf) {
|
||||
buff = buf;
|
||||
|
||||
if (!ast_buffer) {
|
||||
ast_buffer_size = size;
|
||||
ast_buffer = (size_t *)std::malloc(ast_buffer_size * sizeof(size_t));
|
||||
}
|
||||
auto doc = parse(
|
||||
bounded_allocation(ast_buffer, ast_buffer_size),
|
||||
mutable_string_view(size, json)
|
||||
);
|
||||
|
||||
auto root = doc.get_root();
|
||||
recursive_processor(root);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void sajson2msgpack::write_string(const char * c, size_t len) noexcept {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(len));
|
||||
::memcpy(buff, c, len);
|
||||
buff += len;
|
||||
}
|
||||
|
||||
void sajson2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void sajson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void sajson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
void sajson2msgpack::recursive_processor(const sajson::value &node) {
|
||||
using namespace sajson;
|
||||
switch (node.get_type()) {
|
||||
case TYPE_NULL:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
case TYPE_FALSE:
|
||||
write_byte(0xc2);
|
||||
break;
|
||||
case TYPE_TRUE:
|
||||
write_byte(0xc3);
|
||||
break;
|
||||
case TYPE_ARRAY: {
|
||||
auto length = node.get_length();
|
||||
write_byte(0xdf);
|
||||
write_uint32(uint32_t(length));
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
recursive_processor(node.get_array_element(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_OBJECT: {
|
||||
auto length = node.get_length();
|
||||
write_byte(0xdd);
|
||||
write_uint32(uint32_t(length));
|
||||
for (auto i = 0u; i < length; ++i) {
|
||||
auto s = node.get_object_key(i);
|
||||
write_string(s.data(), s.length());
|
||||
recursive_processor(node.get_object_value(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_STRING:
|
||||
write_string(node.as_cstring(), node.get_string_length());
|
||||
break;
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_INTEGER:
|
||||
write_double(node.get_number_value());
|
||||
break;
|
||||
default:
|
||||
assert(false && "unknown node type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct sajson {
|
||||
using StringType = std::string_view;
|
||||
|
||||
sajson2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
result =
|
||||
parser.to_msgpack(json.data(), json.size(), reinterpret_cast<uint8_t *>(buffer));
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, sajson)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_SAJSON
|
||||
@@ -1,183 +0,0 @@
|
||||
#pragma once
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* @brief The simdjson2msgpack struct is used to quickly convert
|
||||
* JSON strings to msgpack views. You must provide a pointer to
|
||||
* a large memory region where the msgpack gets written. The
|
||||
* buffer should be large enough to store the msgpack output (which
|
||||
* can never be 3x larger than the input JSON) with an additional
|
||||
* simdjson::SIMDJSON_PADDING bytes.
|
||||
*
|
||||
* Recommended usage:
|
||||
*
|
||||
* simdjson2msgpack parser{};
|
||||
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
|
||||
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
|
||||
*
|
||||
* std::string_view msgpack = parser.to_msgpack(json, buffer);
|
||||
*
|
||||
* The result (msgpack) is a string view to a msgpack serialization of the input JSON,
|
||||
* it points inside the buffer you provided.
|
||||
*
|
||||
* You may reuse the simdjson2msgpack instance though you should use
|
||||
* one per thread.
|
||||
*/
|
||||
struct simdjson2msgpack {
|
||||
/**
|
||||
* @brief Converts the provided JSON into msgpack.
|
||||
*
|
||||
* @param json JSON input
|
||||
* @param buf temporary buffer (must be large enough, with 32 bytes of
|
||||
* padding)
|
||||
* @return std::string_view msgpack output, writting to the temporary buffer
|
||||
*/
|
||||
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf);
|
||||
|
||||
private:
|
||||
simdjson_really_inline void write_double(const double d) noexcept;
|
||||
simdjson_really_inline void write_byte(const uint8_t b) noexcept;
|
||||
simdjson_really_inline void write_uint32(const uint32_t w) noexcept;
|
||||
simdjson_really_inline uint8_t *skip_uint32() noexcept;
|
||||
simdjson_really_inline void write_uint32_at(const uint32_t w,
|
||||
uint8_t *p) noexcept;
|
||||
simdjson_really_inline void
|
||||
write_raw_string(simdjson::ondemand::raw_json_string rjs);
|
||||
inline void recursive_processor(simdjson::ondemand::value element);
|
||||
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document doc;
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
std::string_view
|
||||
simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
if (doc.is_scalar()) {
|
||||
// we have a special case where the JSON document is a single document...
|
||||
switch (doc.type()) {
|
||||
case simdjson::ondemand::json_type::number:
|
||||
write_double(doc.get_double());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::string:
|
||||
write_raw_string(doc.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::boolean:
|
||||
write_byte(0xc2 + doc.get_bool());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::null:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
case simdjson::ondemand::json_type::array:
|
||||
case simdjson::ondemand::json_type::object:
|
||||
default:
|
||||
// impossible
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
simdjson::ondemand::value val = doc;
|
||||
recursive_processor(val);
|
||||
}
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
uint8_t *simdjson2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *ret = buff;
|
||||
buff += sizeof(uint32_t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_raw_string(
|
||||
simdjson::ondemand::raw_json_string in) {
|
||||
write_byte(0xdb);
|
||||
uint8_t *location = skip_uint32();
|
||||
std::string_view v = parser.unescape(in, buff);
|
||||
write_uint32_at(uint32_t(v.size()), location);
|
||||
}
|
||||
|
||||
void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
recursive_processor(child.value());
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::ondemand::json_type::object: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdf);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto field : element.get_object()) {
|
||||
counter++;
|
||||
write_raw_string(field.key());
|
||||
recursive_processor(field.value());
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::ondemand::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::ondemand::json_type::null:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string_view;
|
||||
|
||||
simdjson2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, simdjson_ondemand)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -1,122 +0,0 @@
|
||||
#pragma once
|
||||
#ifdef SIMDJSON_COMPETITION_YYJSON
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
struct yyjson2msgpack {
|
||||
inline std::string_view to_msgpack(yyjson_doc *doc, uint8_t *buf);
|
||||
|
||||
private:
|
||||
inline void write_double(const double d) noexcept;
|
||||
inline void write_byte(const uint8_t b) noexcept;
|
||||
inline void write_uint32(const uint32_t w) noexcept;
|
||||
inline void write_string(const char *s, size_t length) noexcept;
|
||||
inline void recursive_processor(yyjson_val *obj);
|
||||
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
std::string_view yyjson2msgpack::to_msgpack(yyjson_doc *doc, uint8_t *buf) {
|
||||
buff = buf;
|
||||
yyjson_val *root = yyjson_doc_get_root(doc);
|
||||
recursive_processor(root);
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void yyjson2msgpack::write_string(const char *c, size_t len) noexcept {
|
||||
write_byte(0xdb);
|
||||
write_uint32(uint32_t(len));
|
||||
::memcpy(buff, c, len);
|
||||
buff += len;
|
||||
}
|
||||
|
||||
void yyjson2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void yyjson2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void yyjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
void yyjson2msgpack::recursive_processor(yyjson_val *obj) {
|
||||
size_t idx, max;
|
||||
yyjson_val *val;
|
||||
yyjson_val *key;
|
||||
switch (yyjson_get_type(obj)) {
|
||||
case YYJSON_TYPE_STR:
|
||||
write_string(yyjson_get_str(obj), yyjson_get_len(obj));
|
||||
break;
|
||||
case YYJSON_TYPE_ARR:
|
||||
write_byte(0xdf);
|
||||
write_uint32(uint32_t(yyjson_arr_size(obj)));
|
||||
yyjson_arr_foreach(obj, idx, max, val) { recursive_processor(val); }
|
||||
break;
|
||||
case YYJSON_TYPE_OBJ:
|
||||
write_byte(0xdd);
|
||||
write_uint32(uint32_t(yyjson_obj_size(obj)));
|
||||
yyjson_obj_foreach(obj, idx, max, key, val) {
|
||||
write_string(yyjson_get_str(key), yyjson_get_len(key));
|
||||
recursive_processor(val);
|
||||
}
|
||||
break;
|
||||
case YYJSON_TYPE_BOOL:
|
||||
write_byte(0xc2 + yyjson_get_bool(obj));
|
||||
break;
|
||||
case YYJSON_TYPE_NULL:
|
||||
write_byte(0xc0);
|
||||
break;
|
||||
case YYJSON_TYPE_NUM:
|
||||
switch (yyjson_get_subtype(obj)) {
|
||||
case YYJSON_SUBTYPE_UINT:
|
||||
write_double(double(yyjson_get_uint(obj)));
|
||||
break;
|
||||
case YYJSON_SUBTYPE_SINT:
|
||||
write_double(double(yyjson_get_sint(obj)));
|
||||
break;
|
||||
case YYJSON_SUBTYPE_REAL:
|
||||
write_double(yyjson_get_real(obj));
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
struct yyjson : yyjson2msgpack {
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
yyjson_doc *doc = yyjson_read(json.data(), json.size(), 0);
|
||||
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
|
||||
|
||||
struct yyjson_insitu : yyjson2msgpack {
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
yyjson_doc *doc =
|
||||
yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0);
|
||||
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_COMPETITION_YYJSON
|
||||
@@ -42,7 +42,7 @@ struct nlohmann_json_sax {
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
|
||||
buffer[k] = double(val);
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
|
||||
@@ -51,7 +51,7 @@ BENCHMARK_TEMPLATE(kostya, rapidjson_lossless)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -11,7 +11,6 @@ struct sajson {
|
||||
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
||||
using namespace sajson;
|
||||
|
||||
@@ -34,7 +34,7 @@ struct nlohmann_json_sax {
|
||||
return true;
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
buffer[k] = double(val);
|
||||
buffer[k] = val;
|
||||
if (k == 2) {
|
||||
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
|
||||
k = 0;
|
||||
|
||||
@@ -48,7 +48,7 @@ BENCHMARK_TEMPLATE(large_random, rapidjson_lossless)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -11,7 +11,6 @@ struct sajson {
|
||||
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
|
||||
using namespace sajson;
|
||||
|
||||
@@ -70,7 +70,7 @@ BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -11,8 +11,6 @@ struct sajson {
|
||||
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
|
||||
auto val = obj.get_value_of_key({key.data(), key.length()});
|
||||
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
|
||||
|
||||
@@ -48,7 +48,7 @@ struct nlohmann_json_sax {
|
||||
}
|
||||
bool number_unsigned(number_unsigned_t val) override {
|
||||
if (values & key_rt && !(values & found_rt)) { // retweet_count
|
||||
rt = int(val);
|
||||
rt = val;
|
||||
values &= ~(key_rt);
|
||||
values |= (found_rt);
|
||||
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
|
||||
|
||||
@@ -59,7 +59,7 @@ BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
|
||||
|
||||
struct rapidjson_insitu : rapidjson_base {
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
|
||||
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), max_retweet_count, result);
|
||||
}
|
||||
};
|
||||
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
|
||||
|
||||
@@ -11,7 +11,6 @@ struct sajson {
|
||||
|
||||
size_t ast_buffer_size{0};
|
||||
size_t *ast_buffer{nullptr};
|
||||
~sajson() { free(ast_buffer); }
|
||||
|
||||
bool run(simdjson::padded_string &json, int32_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
if (!ast_buffer) {
|
||||
|
||||
+25
-66
@@ -3,35 +3,30 @@ The Basics
|
||||
|
||||
An overview of what you need to know to use simdjson, with examples.
|
||||
|
||||
- [The Basics](#the-basics)
|
||||
- [Requirements](#requirements)
|
||||
- [Including simdjson](#including-simdjson)
|
||||
- [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
||||
- [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
||||
- [Versions](#versions)
|
||||
- [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
||||
- [Documents are Iterators](#documents-are-iterators)
|
||||
- [Parser, Document and JSON Scope](#parser-document-and-json-scope)
|
||||
- [C++11 Support and string_view](#c11-support-and-string_view)
|
||||
- [Using the Parsed JSON](#using-the-parsed-json)
|
||||
- [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples)
|
||||
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||
- [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
- [JSON Pointer](#json-pointer)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions)
|
||||
- [Disabling Exceptions](#disabling-exceptions)
|
||||
- [Exceptions](#exceptions)
|
||||
- [Current location in document](#current-location-in-document)
|
||||
- [Rewinding](#rewinding)
|
||||
- [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
||||
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
|
||||
- [Dynamic Number Types](#dynamic-number-types)
|
||||
- [Raw Strings](#raw-strings)
|
||||
- [Thread Safety](#thread-safety)
|
||||
- [Standard Compliance](#standard-compliance)
|
||||
- [Backwards Compatibility](#backwards-compatibility)
|
||||
* [Requirements](#requirements)
|
||||
* [Including simdjson](#including-simdjson)
|
||||
* [Using simdjson with package managers](#using-simdjson-with-package-managers)
|
||||
* [Using simdjson as a CMake dependency](#using-simdjson-as-a-cmake-dependency)
|
||||
* [Versions](#versions)
|
||||
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
|
||||
* [Documents are Iterators](#documents-are-iterators)
|
||||
* [C++11 Support and string_view](#c11-support-and-string_view)
|
||||
* [Using the Parsed JSON](#using-the-parsed-json)
|
||||
* [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
|
||||
* [UTF-8 validation (alone)](#utf-8-validation-alone)
|
||||
* [JSON Pointer](#json-pointer)
|
||||
* [Error Handling](#error-handling)
|
||||
* [Error Handling Example without Exceptions](#error-handling-examples-without-exceptions)
|
||||
* [Disabling Exceptions](#disabling-exceptions)
|
||||
* [Exceptions](#exceptions)
|
||||
* [Current location in document](#current-location-in-document)
|
||||
* [Rewinding](#rewinding)
|
||||
* [Direct Access to the Raw String](#direct-access-to-the-raw-string)
|
||||
* [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
|
||||
* [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
|
||||
* [Dynamic Number Types](#dynamic-number-types)
|
||||
* [Thread Safety](#thread-safety)
|
||||
* [Standard Compliance](#standard-compliance)
|
||||
|
||||
|
||||
Requirements
|
||||
@@ -472,7 +467,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
|
||||
```
|
||||
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
|
||||
with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings).
|
||||
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
|
||||
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
|
||||
```c++
|
||||
void recursive_print_json(ondemand::value element) {
|
||||
@@ -1450,42 +1445,6 @@ It will output:
|
||||
9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999
|
||||
```
|
||||
|
||||
Raw Strings
|
||||
-----------
|
||||
|
||||
It is sometimes useful to have access to a raw (unescaped) string: we make available a
|
||||
minimalist `raw_json_string` data type which contains a pointer inside the string in the
|
||||
original document, right after the quote. It is accessible via `get_raw_json_string()` on a
|
||||
string instance and returned by the `key()` method on an object's field instance. It is always
|
||||
optional: replacing `get_raw_json_string()` with `get_string()` and `key()` by
|
||||
`unescaped_key()` returns an `string_view` instance of the unescaped string.
|
||||
|
||||
You can quickly compare a `raw_json_string` instance with a target string. You may also
|
||||
unescape the `raw_json_string` on your own string buffer: `parser.unescape(mystr, ptr)`
|
||||
advances the provided pointer `ptr` and returns a string_view instance on the newly serialized
|
||||
string upon success, otherwise it returns an error. When unescaping to your own string buffer,
|
||||
you should ensure that you have sufficient memory space: the total size of the strings plus
|
||||
`simdjson::SIMDJSON_PADDING` bytes. The following example illustrates how we can unescape
|
||||
JSON string to a user-provided buffer:
|
||||
|
||||
```C++
|
||||
auto json = R"( {"name": "Jack The Ripper \u0033"} )"_padded;
|
||||
// We create a buffer large enough to store all strings we need:
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[json.size() + simdjson::SIMDJSON_PADDING]);
|
||||
uint8_t * ptr = buffer.get();
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
// We store our strings as 'string_view' instances in a vector:
|
||||
std::vector<std::string_view> mystrings;
|
||||
for (auto key_value : doc.get_object()) {
|
||||
std::string_view keysv = parser.unescape(key_value.key(), ptr);// writes 'name'
|
||||
mystrings.push_back(keysv);
|
||||
std::string_view valuesv = parser.unescape(key_value.value().get_raw_json_string(), ptr);
|
||||
// writes 'Jack The Ripper 3', escaping the \u0033
|
||||
mystrings.push_back(valuesv);
|
||||
}
|
||||
```
|
||||
|
||||
Thread Safety
|
||||
-------------
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ different version of the JSON parser for different CPU architectures, often with
|
||||
algorithms to take better advantage of a given CPU!
|
||||
|
||||
The current implementations are:
|
||||
* icelake: AVX-512F, AVX-512VBMI, etc.
|
||||
* haswell: AVX2 (2013 Intel Haswell or later)
|
||||
* westmere: SSE4.2 (2010 Westmere or later).
|
||||
* arm64: 64-bit ARMv8-A NEON
|
||||
@@ -29,7 +28,7 @@ compiles *all* the implementations into the executable. On Intel, it will includ
|
||||
(haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC it will include 2 (ppc64 and fallback).
|
||||
|
||||
If you know more about where you're going to run and want to save the space, you can disable any of
|
||||
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
|
||||
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is HASWELL,
|
||||
WESTMERE, ARM64, PPC64 and FALLBACK).
|
||||
|
||||
The simdjson library automatically sets header flags for each implementation as it compiles; there
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace arm64
|
||||
|
||||
@@ -143,6 +143,13 @@ struct simdjson_result_base : protected std::pair<T, error_code> {
|
||||
*/
|
||||
simdjson_really_inline error_code get(T &value) && noexcept;
|
||||
|
||||
/**
|
||||
* Move the value to the provided variable.
|
||||
*
|
||||
* @param value The variable to assign the value to. May not be set if there is an error.
|
||||
*/
|
||||
simdjson_really_inline const T &value(error_code &error) const & noexcept;
|
||||
|
||||
/**
|
||||
* The error.
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,7 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace fallback
|
||||
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
simdjson_warn_unused error_code stage1(const uint8_t *buf, size_t len, stage1_mode partial) noexcept final;
|
||||
simdjson_warn_unused error_code stage2(dom::document &doc) noexcept final;
|
||||
simdjson_warn_unused error_code stage2_next(dom::document &doc) noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
inline simdjson_warn_unused error_code set_capacity(size_t capacity) noexcept final;
|
||||
inline simdjson_warn_unused error_code set_max_depth(size_t max_depth) noexcept final;
|
||||
private:
|
||||
|
||||
@@ -23,7 +23,7 @@ simdjson_really_inline simdjson_result<field> field::start(const value_iterator
|
||||
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key() noexcept {
|
||||
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() but Visual Studio won't let us.
|
||||
simdjson_result<std::string_view> answer = first.unescape(second.iter.json_iter());
|
||||
simdjson_result<std::string_view> answer = first.unescape(second.iter.string_buf_loc());
|
||||
first.consume();
|
||||
return answer;
|
||||
}
|
||||
|
||||
@@ -312,10 +312,6 @@ simdjson_really_inline token_position json_iterator::position() const noexcept {
|
||||
return token.position();
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in) noexcept {
|
||||
return parser->unescape(in, _string_buf_loc);
|
||||
}
|
||||
|
||||
simdjson_really_inline void json_iterator::reenter_child(token_position position, depth_t child_depth) noexcept {
|
||||
SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
|
||||
SIMDJSON_ASSUME(_depth == child_depth - 1);
|
||||
|
||||
@@ -233,14 +233,7 @@ public:
|
||||
template<int N> simdjson_warn_unused simdjson_really_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t (&tmpbuf)[N]) noexcept;
|
||||
|
||||
simdjson_really_inline token_position position() const noexcept;
|
||||
/**
|
||||
* Write the raw_json_string to the string buffer and return a string_view.
|
||||
* Each raw_json_string should be unescaped once, or else the string buffer might
|
||||
* overflow.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<std::string_view> unescape(raw_json_string in) noexcept;
|
||||
simdjson_really_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
|
||||
|
||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||
simdjson_really_inline token_position start_position(depth_t depth) const noexcept;
|
||||
simdjson_really_inline void set_start_position(depth_t depth, token_position position) noexcept;
|
||||
|
||||
@@ -117,14 +117,6 @@ simdjson_really_inline void parser::set_max_capacity(size_t max_capacity) noexce
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst) const noexcept {
|
||||
uint8_t *end = implementation->parse_string(in.buf, dst);
|
||||
if (!end) { return STRING_ERROR; }
|
||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||
dst = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ondemand
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
@@ -252,27 +252,6 @@ public:
|
||||
bool threaded{true};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||
*
|
||||
* This unescape function is a low-level function. If you want a more user-friendly approach, you should
|
||||
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
|
||||
* instead of get_raw_json_string()).
|
||||
*
|
||||
* ## IMPORTANT: string_view lifetime
|
||||
*
|
||||
* The string_view is only valid as long as the bytes in dst.
|
||||
*
|
||||
* @param raw_json_string input
|
||||
* @param dst A pointer to a buffer at least large enough to write this string as well as
|
||||
* an additional SIMDJSON_PADDING bytes.
|
||||
* @return A string_view pointing at the unescaped string in dst
|
||||
* @error STRING_ERROR if escapes are incorrect.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst) const noexcept;
|
||||
private:
|
||||
/** @private [for benchmarking access] The implementation to use */
|
||||
std::unique_ptr<internal::dom_parser_implementation> implementation{};
|
||||
|
||||
@@ -6,7 +6,13 @@ namespace ondemand {
|
||||
simdjson_really_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
|
||||
|
||||
simdjson_really_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
||||
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(uint8_t *&dst) const noexcept {
|
||||
uint8_t *end = parse_string(buf, dst);
|
||||
if (!end) { return STRING_ERROR; }
|
||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||
dst = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_really_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
|
||||
size_t pos{0};
|
||||
@@ -144,7 +150,7 @@ simdjson_unused simdjson_really_inline bool operator!=(std::string_view c, const
|
||||
|
||||
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter) const noexcept {
|
||||
return iter.unescape(*this);
|
||||
return unescape(iter.string_buf_loc());
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +183,10 @@ simdjson_really_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IM
|
||||
if (error()) { return error(); }
|
||||
return first.raw();
|
||||
}
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(uint8_t *&dst) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescape(dst);
|
||||
}
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescape(iter);
|
||||
|
||||
@@ -17,19 +17,12 @@ class json_iterator;
|
||||
*
|
||||
* This class is deliberately simplistic and has little functionality. You can
|
||||
* compare a raw_json_string instance with an unescaped C string, but
|
||||
* that is nearly all you can do.
|
||||
*
|
||||
* The raw_json_string is unescaped. If you wish to write an unescaped version of it to your own
|
||||
* buffer, you may do so using the parser.unescape(string, buff) method, using an ondemand::parser
|
||||
* instance. Doing so requires you to have a sufficiently large buffer.
|
||||
*
|
||||
* The raw_json_string instances originate typically from field instance which in turn represent
|
||||
* key-value pairs from object instances. From a field instance, you get the raw_json_string
|
||||
* instance by calling key(). You can, if you want a more usable string_view instance, call
|
||||
* the unescaped_key() method on the field instance. You may also create a raw_json_string from
|
||||
* any other string value, with the value.get_raw_json_string() method. Again, you can get
|
||||
* a more usable string_view instance by calling get_string().
|
||||
* that is pretty much all you can do.
|
||||
*
|
||||
* They originate typically from field instance which in turn represent key-value pairs from
|
||||
* object instances. From a field instance, you get the raw_json_string instance by calling key().
|
||||
* You can, if you want a more usable string_view instance, call the unescaped_key() method
|
||||
* on the field instance.
|
||||
*/
|
||||
class raw_json_string {
|
||||
public:
|
||||
@@ -123,6 +116,26 @@ public:
|
||||
static simdjson_really_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
||||
static simdjson_really_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||
* The provided pointer is advanced to the end of the string by reference, and a string_view instance
|
||||
* is returned. You can ensure that your buffer is large enough by allocating a block of memory at least
|
||||
* as large as the input JSON plus SIMDJSON_PADDING and then unescape all strings to this one buffer.
|
||||
*
|
||||
* This unescape function is a low-level function. If you want a more user-friendly approach, you should
|
||||
* avoid raw_json_string instances (e.g., by calling unescaped_key() instead of key() or get_string()
|
||||
* instead of get_raw_json_string()).
|
||||
*
|
||||
* ## IMPORTANT: string_view lifetime
|
||||
*
|
||||
* The string_view is only valid as long as the bytes in dst.
|
||||
*
|
||||
* @param dst A pointer to a buffer at least large enough to write this string as well as
|
||||
* an additional SIMDJSON_PADDING bytes.
|
||||
* @return A string_view pointing at the unescaped string in dst
|
||||
* @error STRING_ERROR if escapes are incorrect.
|
||||
*/
|
||||
simdjson_really_inline simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
||||
private:
|
||||
|
||||
|
||||
@@ -151,7 +164,6 @@ private:
|
||||
const uint8_t * buf{};
|
||||
friend class object;
|
||||
friend class field;
|
||||
friend class parser;
|
||||
friend struct simdjson_result<raw_json_string>;
|
||||
};
|
||||
|
||||
@@ -182,6 +194,7 @@ public:
|
||||
simdjson_really_inline ~simdjson_result() noexcept = default; ///< @private
|
||||
|
||||
simdjson_really_inline simdjson_result<const char *> raw() const noexcept;
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(uint8_t *&dst) const noexcept;
|
||||
simdjson_really_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::ondemand::json_iterator &iter) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@ simdjson_really_inline bool value_iterator::parse_null(const uint8_t *json) cons
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<std::string_view> value_iterator::get_string() noexcept {
|
||||
return get_raw_json_string().unescape(json_iter());
|
||||
return get_raw_json_string().unescape(_json_iter->string_buf_loc());
|
||||
}
|
||||
simdjson_warn_unused simdjson_really_inline simdjson_result<raw_json_string> value_iterator::get_raw_json_string() noexcept {
|
||||
auto json = peek_scalar("string");
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace haswell
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace icelake
|
||||
|
||||
@@ -38,6 +38,20 @@ simdjson_really_inline simdjson_warn_unused bool validate_utf8(const std::string
|
||||
return validate_utf8(s.data(), s.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*
|
||||
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||
*/
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) noexcept;
|
||||
|
||||
namespace dom {
|
||||
class document;
|
||||
} // namespace dom
|
||||
@@ -134,6 +148,22 @@ public:
|
||||
*/
|
||||
simdjson_warn_unused virtual bool validate_utf8(const char *buf, size_t len) const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*
|
||||
* Overridden by each implementation.
|
||||
*
|
||||
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||
*/
|
||||
simdjson_warn_unused virtual uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept = 0;
|
||||
|
||||
protected:
|
||||
/** @private Construct an implementation with the given name and description. For subclasses. */
|
||||
simdjson_really_inline implementation(
|
||||
|
||||
@@ -102,22 +102,6 @@ public:
|
||||
*/
|
||||
simdjson_warn_unused virtual error_code stage2_next(dom::document &doc) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*
|
||||
* Overridden by each implementation.
|
||||
*
|
||||
* @param str pointer to the beginning of a valid UTF-8 JSON string, must end with an unescaped quote.
|
||||
* @param dst pointer to a destination buffer, it must point a region in memory of sufficient size.
|
||||
* @return end of the of the written region (exclusive) or nullptr in case of error.
|
||||
*/
|
||||
simdjson_warn_unused virtual uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept = 0;
|
||||
|
||||
/**
|
||||
* Change the capacity of this parser.
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf,
|
||||
size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace ppc64
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define SIMDJSON_SIMDJSON_VERSION_H
|
||||
|
||||
/** The version of simdjson being used (major.minor.revision) */
|
||||
#define SIMDJSON_VERSION 2.1.0
|
||||
#define SIMDJSON_VERSION 2.0.4
|
||||
|
||||
namespace simdjson {
|
||||
enum {
|
||||
@@ -15,11 +15,11 @@ enum {
|
||||
/**
|
||||
* The minor version (major.MINOR.revision) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_MINOR = 1,
|
||||
SIMDJSON_VERSION_MINOR = 0,
|
||||
/**
|
||||
* The revision (major.minor.REVISION) of simdjson being used.
|
||||
*/
|
||||
SIMDJSON_VERSION_REVISION = 0
|
||||
SIMDJSON_VERSION_REVISION = 4
|
||||
};
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
) const noexcept final;
|
||||
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final;
|
||||
};
|
||||
|
||||
} // namespace westmere
|
||||
|
||||
+2
-834
@@ -1,4 +1,4 @@
|
||||
/* auto-generated on 2022-06-30 10:29:50 -0400. Do not edit! */
|
||||
/* auto-generated on 2022-06-15 15:21:33 -0400. Do not edit! */
|
||||
/* begin file src/simdjson.cpp */
|
||||
#include "simdjson.h"
|
||||
|
||||
@@ -2793,6 +2793,7 @@ simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, s
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
||||
return get_active_implementation()->validate_utf8(buf, len);
|
||||
}
|
||||
|
||||
const implementation * builtin_implementation() {
|
||||
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
||||
assert(builtin_impl);
|
||||
@@ -4133,141 +4134,6 @@ bool generic_validate_utf8(const char * input, size_t length) {
|
||||
// Stage 2
|
||||
//
|
||||
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace arm64 {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace arm64
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -5107,10 +4973,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return arm64::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
@@ -5600,141 +5462,6 @@ simdjson_warn_unused bool implementation::validate_utf8(const char *buf, size_t
|
||||
//
|
||||
// Stage 2
|
||||
//
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace fallback {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace fallback
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -6545,10 +6272,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return fallback::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
@@ -7945,141 +7668,6 @@ bool generic_validate_utf8(const char * input, size_t length) {
|
||||
//
|
||||
// Stage 2
|
||||
//
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace icelake {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace icelake
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -8917,10 +8505,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return icelake::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
@@ -10272,141 +9856,6 @@ bool generic_validate_utf8(const char * input, size_t length) {
|
||||
//
|
||||
// Stage 2
|
||||
//
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace haswell {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace haswell
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -11244,10 +10693,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return haswell::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
@@ -12562,141 +12007,7 @@ bool generic_validate_utf8(const char * input, size_t length) {
|
||||
//
|
||||
// Stage 2
|
||||
//
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace ppc64 {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace ppc64
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -13536,10 +12847,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return ppc64::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
@@ -14887,141 +14194,6 @@ bool generic_validate_utf8(const char * input, size_t length) {
|
||||
//
|
||||
// Stage 2
|
||||
//
|
||||
/* begin file src/generic/stage2/stringparsing.h */
|
||||
// This file contains the common code every implementation uses
|
||||
// It is intended to be included multiple times and compiled multiple times
|
||||
|
||||
namespace simdjson {
|
||||
namespace westmere {
|
||||
namespace {
|
||||
/// @private
|
||||
namespace stringparsing {
|
||||
|
||||
// begin copypasta
|
||||
// These chars yield themselves: " \ /
|
||||
// b -> backspace, f -> formfeed, n -> newline, r -> cr, t -> horizontal tab
|
||||
// u not handled in this table as it's complex
|
||||
static const uint8_t escape_map[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2f,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x4.
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x5c, 0, 0, 0, // 0x5.
|
||||
0, 0, 0x08, 0, 0, 0, 0x0c, 0, 0, 0, 0, 0, 0, 0, 0x0a, 0, // 0x6.
|
||||
0, 0, 0x0d, 0, 0x09, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x7.
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
// handle a unicode codepoint
|
||||
// write appropriate values into dest
|
||||
// src will advance 6 bytes or 12 bytes
|
||||
// dest will advance a variable amount (return via pointer)
|
||||
// return true if the unicode codepoint was valid
|
||||
// We work in little-endian then swap at write time
|
||||
simdjson_warn_unused
|
||||
simdjson_really_inline bool handle_unicode_codepoint(const uint8_t **src_ptr,
|
||||
uint8_t **dst_ptr) {
|
||||
// jsoncharutils::hex_to_u32_nocheck fills high 16 bits of the return value with 1s if the
|
||||
// conversion isn't valid; we defer the check for this to inside the
|
||||
// multilingual plane check
|
||||
uint32_t code_point = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
*src_ptr += 6;
|
||||
// check for low surrogate for characters outside the Basic
|
||||
// Multilingual Plane.
|
||||
if (code_point >= 0xd800 && code_point < 0xdc00) {
|
||||
if (((*src_ptr)[0] != '\\') || (*src_ptr)[1] != 'u') {
|
||||
return false;
|
||||
}
|
||||
uint32_t code_point_2 = jsoncharutils::hex_to_u32_nocheck(*src_ptr + 2);
|
||||
|
||||
// if the first code point is invalid we will get here, as we will go past
|
||||
// the check for being outside the Basic Multilingual plane. If we don't
|
||||
// find a \u immediately afterwards we fail out anyhow, but if we do,
|
||||
// this check catches both the case of the first code point being invalid
|
||||
// or the second code point being invalid.
|
||||
if ((code_point | code_point_2) >> 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code_point =
|
||||
(((code_point - 0xd800) << 10) | (code_point_2 - 0xdc00)) + 0x10000;
|
||||
*src_ptr += 6;
|
||||
}
|
||||
size_t offset = jsoncharutils::codepoint_to_utf8(code_point, *dst_ptr);
|
||||
*dst_ptr += offset;
|
||||
return offset > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape a valid UTF-8 string from src to dst, stopping at a final unescaped quote. There
|
||||
* must be an unescaped quote terminating the string. It returns the final output
|
||||
* position as pointer. In case of error (e.g., the string has bad escaped codes),
|
||||
* then null_nullptrptr is returned. It is assumed that the output buffer is large
|
||||
* enough. E.g., if src points at 'joe"', then dst needs to have four free bytes +
|
||||
* SIMDJSON_PADDING bytes.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t *src, uint8_t *dst) {
|
||||
while (1) {
|
||||
// Copy the next n bytes, and find the backslash and quote in them.
|
||||
auto bs_quote = backslash_and_quote::copy_and_find(src, dst);
|
||||
// If the next thing is the end quote, copy and return
|
||||
if (bs_quote.has_quote_first()) {
|
||||
// we encountered quotes first. Move dst to point to quotes and exit
|
||||
return dst + bs_quote.quote_index();
|
||||
}
|
||||
if (bs_quote.has_backslash()) {
|
||||
/* find out where the backspace is */
|
||||
auto bs_dist = bs_quote.backslash_index();
|
||||
uint8_t escape_char = src[bs_dist + 1];
|
||||
/* we encountered backslash first. Handle backslash */
|
||||
if (escape_char == 'u') {
|
||||
/* move src/dst up to the start; they will be further adjusted
|
||||
within the unicode codepoint handling code. */
|
||||
src += bs_dist;
|
||||
dst += bs_dist;
|
||||
if (!handle_unicode_codepoint(&src, &dst)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
/* simple 1:1 conversion. Will eat bs_dist+2 characters in input and
|
||||
* write bs_dist+1 characters to output
|
||||
* note this may reach beyond the part of the buffer we've actually
|
||||
* seen. I think this is ok */
|
||||
uint8_t escape_result = escape_map[escape_char];
|
||||
if (escape_result == 0u) {
|
||||
return nullptr; /* bogus escape value is an error */
|
||||
}
|
||||
dst[bs_dist] = escape_result;
|
||||
src += bs_dist + 2;
|
||||
dst += bs_dist + 1;
|
||||
}
|
||||
} else {
|
||||
/* they are the same. Since they can't co-occur, it means we
|
||||
* encountered neither. */
|
||||
src += backslash_and_quote::BYTES_PROCESSED;
|
||||
dst += backslash_and_quote::BYTES_PROCESSED;
|
||||
}
|
||||
}
|
||||
/* can't be reached */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace westmere
|
||||
} // namespace simdjson
|
||||
/* end file src/generic/stage2/stringparsing.h */
|
||||
/* begin file src/generic/stage2/tape_builder.h */
|
||||
/* begin file src/generic/stage2/json_iterator.h */
|
||||
/* begin file src/generic/stage2/logger.h */
|
||||
@@ -15860,10 +15032,6 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return westmere::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
|
||||
+875
-92
File diff suppressed because it is too large
Load Diff
@@ -152,10 +152,11 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return arm64::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
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, stage1_mode::regular);
|
||||
if (error) { return error; }
|
||||
|
||||
@@ -360,7 +360,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return fallback::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,6 +127,15 @@ simdjson_warn_unused simdjson_really_inline uint8_t *parse_string(const uint8_t
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_warn_unused simdjson_really_inline error_code parse_string_to_buffer(const uint8_t *src, uint8_t *¤t_string_buf_loc, std::string_view &s) {
|
||||
if (*(src++) != '"') { return STRING_ERROR; }
|
||||
auto end = stringparsing::parse_string(src, current_string_buf_loc);
|
||||
if (!end) { return STRING_ERROR; }
|
||||
s = std::string_view(reinterpret_cast<const char *>(current_string_buf_loc), end-current_string_buf_loc);
|
||||
current_string_buf_loc = end;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace stringparsing
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -153,7 +153,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return haswell::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return icelake::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
|
||||
return set_best()->validate_utf8(buf, len);
|
||||
}
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) const noexcept final override {
|
||||
return set_best()->parse_string(src, dst);
|
||||
}
|
||||
simdjson_really_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
|
||||
private:
|
||||
const implementation *set_best() const noexcept;
|
||||
@@ -124,6 +127,9 @@ public:
|
||||
// what are the chances that the programmer has a fallback? Given that *we* provide the
|
||||
// fallback, it implies that the programmer would need a fallback for our fallback.
|
||||
}
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *, uint8_t *) const noexcept final override {
|
||||
return nullptr;
|
||||
}
|
||||
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
|
||||
};
|
||||
|
||||
@@ -188,6 +194,9 @@ simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, s
|
||||
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
||||
return get_active_implementation()->validate_utf8(buf, len);
|
||||
}
|
||||
simdjson_warn_unused uint8_t *parse_string(const uint8_t *src, uint8_t *dst) noexcept {
|
||||
return get_active_implementation()->parse_string(src, dst);
|
||||
}
|
||||
const implementation * builtin_implementation() {
|
||||
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
||||
assert(builtin_impl);
|
||||
|
||||
@@ -122,7 +122,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return ppc64::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ simdjson_warn_unused error_code dom_parser_implementation::stage2_next(dom::docu
|
||||
return stage2::tape_builder::parse_document<true>(*this, _doc);
|
||||
}
|
||||
|
||||
simdjson_warn_unused uint8_t *dom_parser_implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
simdjson_warn_unused uint8_t *implementation::parse_string(const uint8_t *src, uint8_t *dst) const noexcept {
|
||||
return westmere::stringparsing::parse_string(src, dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ using error_code=simdjson::error_code;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void recursive_print_json(ondemand::value element) {
|
||||
@@ -791,29 +792,6 @@ bool simple_error_example() {
|
||||
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool raw_string() {
|
||||
TEST_START();
|
||||
auto json = R"( {"name": "Jack The Ripper \u0033"} )"_padded;
|
||||
// We create a buffer large enough to store all strings we need:
|
||||
std::unique_ptr<uint8_t[]> buffer(new uint8_t[json.size() + simdjson::SIMDJSON_PADDING]);
|
||||
uint8_t * ptr = buffer.get();
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
// We store our strings as 'string_view' instances in a vector:
|
||||
std::vector<std::string_view> mystrings;
|
||||
for (auto key_value : doc.get_object()) {
|
||||
std::string_view keysv = parser.unescape(key_value.key(), ptr);// writes 'name'
|
||||
mystrings.push_back(keysv);
|
||||
std::string_view valuesv = parser.unescape(key_value.value().get_raw_json_string(), ptr);
|
||||
// writes 'Jack The Ripper 3', escaping the \u0033
|
||||
mystrings.push_back(valuesv);
|
||||
}
|
||||
ASSERT_EQUAL(mystrings[0],"name");
|
||||
ASSERT_EQUAL(mystrings[1],"Jack The Ripper 3");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool simple_error_example_except() {
|
||||
TEST_START();
|
||||
ondemand::parser parser;
|
||||
@@ -822,34 +800,30 @@ bool simple_error_example() {
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
double x = doc["bad number"].get_double();
|
||||
std::cout << "Got " << x << std::endl;
|
||||
TEST_SUCCEED();
|
||||
return true;
|
||||
} catch(simdjson_error& e) {
|
||||
// e.error() == NUMBER_ERROR
|
||||
std::cout << e.error() << std::endl;
|
||||
TEST_FAIL("I did not expect an exception");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t current_location_tape_error_with_except() {
|
||||
TEST_START();
|
||||
auto broken_json = R"( {"double": 13.06, false, "integer": -343} )"_padded;
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc;
|
||||
ondemand::document doc = parser.iterate(broken_json);
|
||||
try {
|
||||
doc = parser.iterate(broken_json);
|
||||
return int64_t(doc["integer"]);
|
||||
} catch(simdjson_error& err) {
|
||||
std::cout << err.error() << std::endl;
|
||||
std::cout << doc.current_location() << std::endl;
|
||||
TEST_SUCCEED();
|
||||
std::cerr << err.error() << std::endl;
|
||||
std::cerr << doc.current_location() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
TEST_FAIL("I expected an exception!");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int load_example() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
simdjson::ondemand::document tweets;
|
||||
padded_string json;
|
||||
@@ -898,7 +872,6 @@ int example_1() {
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
int load_example_except() {
|
||||
TEST_START();
|
||||
simdjson::ondemand::parser parser;
|
||||
padded_string json = padded_string::load("twitter.json");
|
||||
simdjson::ondemand::document tweets = parser.iterate(json);
|
||||
@@ -985,12 +958,15 @@ bool current_location_no_error() {
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return true
|
||||
int main() {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
basics_treewalk();
|
||||
basics_treewalk_breakline();
|
||||
#endif
|
||||
if (
|
||||
true
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
// && basics_1() // Fails because twitter.json isn't in current directory. Compile test only.
|
||||
&& basics_treewalk()
|
||||
&& basics_treewalk_breakline()
|
||||
&& json_value_with_array_count()
|
||||
&& json_array_with_array_count()
|
||||
&& json_array_count_complex()
|
||||
@@ -1023,13 +999,12 @@ bool run() {
|
||||
&& current_location_out_of_bounds()
|
||||
&& current_location_no_error()
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
&& raw_string()
|
||||
&& number_tests()
|
||||
&& current_location_tape_error_with_except()
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, run);
|
||||
) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user