mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7edd32dc6b | |||
| 91b74c593c | |||
| fa629bd783 | |||
| 7784aa86c2 | |||
| a47b64e0ff | |||
| d92bc82b37 | |||
| 5b02e117bb | |||
| ef6fc77861 |
@@ -20,7 +20,7 @@ jobs:
|
||||
# fuzzers that change behaviour with SIMDJSON_FORCE_IMPLEMENTATION
|
||||
defaultimplfuzzers: atpointer dump dump_raw_tape element minify parser print_json
|
||||
# fuzzers that loop over the implementations themselves, or don't need to switch.
|
||||
implfuzzers: implementations minifyimpl ndjson ondemand padded utf8
|
||||
implfuzzers: implementations minifyimpl ndjson ondemand padded utf8 # TODO add singlestage
|
||||
implementations: haswell westmere fallback
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
MAXLEN: -max_len=4000
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "amazon_cellphones.h"
|
||||
|
||||
namespace amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
parser.threaded = threaded;
|
||||
#endif
|
||||
singlestage::document_stream stream = parser.iterate_many(json);
|
||||
singlestage::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
uint64_t reviews;
|
||||
for ( auto value : doc ) {
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
copy = StringType(std::string_view(value));
|
||||
break;
|
||||
case 5:
|
||||
rating = double(value);
|
||||
break;
|
||||
case 7:
|
||||
reviews = uint64_t(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, amazon_cellphones::brand{
|
||||
rating * reviews,
|
||||
reviews
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += rating * reviews;
|
||||
x->second.reviews_count += reviews;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_singlestage<UNTHREADED>)->UseManualTime();
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_singlestage<THREADED>)->UseManualTime();
|
||||
#endif
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -26,6 +26,7 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/simdjson_ondemand.h"
|
||||
#include "json2msgpack/simdjson_singlestage.h"
|
||||
#include "json2msgpack/simdjson_dom.h"
|
||||
#include "json2msgpack/yyjson.h"
|
||||
#include "json2msgpack/rapidjson.h"
|
||||
@@ -35,6 +36,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#include "json2msgpack/nlohmann_json.h"
|
||||
|
||||
#include "partial_tweets/simdjson_ondemand.h"
|
||||
#include "partial_tweets/simdjson_singlestage.h"
|
||||
#include "partial_tweets/simdjson_dom.h"
|
||||
#include "partial_tweets/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -52,6 +54,8 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
#include "distinct_user_id/simdjson_ondemand.h"
|
||||
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
|
||||
#include "distinct_user_id/simdjson_singlestage.h"
|
||||
#include "distinct_user_id/simdjson_singlestage_json_pointer.h"
|
||||
#include "distinct_user_id/simdjson_dom.h"
|
||||
#include "distinct_user_id/simdjson_dom_json_pointer.h"
|
||||
#include "distinct_user_id/yyjson.h"
|
||||
@@ -68,6 +72,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
|
||||
#include "find_tweet/simdjson_ondemand.h"
|
||||
#include "find_tweet/simdjson_singlestage.h"
|
||||
#include "find_tweet/simdjson_dom.h"
|
||||
#include "find_tweet/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -83,6 +88,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#endif // SIMDJSON_COMPETITION_SAX
|
||||
|
||||
#include "top_tweet/simdjson_ondemand.h"
|
||||
#include "top_tweet/simdjson_singlestage.h"
|
||||
#include "top_tweet/simdjson_dom.h"
|
||||
#include "top_tweet/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -99,6 +105,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
|
||||
#include "kostya/simdjson_ondemand.h"
|
||||
#include "kostya/simdjson_singlestage.h"
|
||||
#include "kostya/simdjson_dom.h"
|
||||
#include "kostya/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -117,6 +124,10 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||
#include "large_random/simdjson_ondemand_unordered.h"
|
||||
#endif // SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
|
||||
#include "large_random/simdjson_singlestage.h"
|
||||
#if SIMDJSON_COMPETITION_SINGLESTAGE_UNORDERED
|
||||
#include "large_random/simdjson_singlestage_unordered.h"
|
||||
#endif // SIMDJSON_COMPETITION_SINGLESTAGE_UNORDERED
|
||||
#include "large_random/simdjson_dom.h"
|
||||
#include "large_random/yyjson.h"
|
||||
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
|
||||
@@ -133,8 +144,10 @@ SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
#include "amazon_cellphones/simdjson_dom.h"
|
||||
#include "amazon_cellphones/simdjson_ondemand.h"
|
||||
#include "amazon_cellphones/simdjson_singlestage.h"
|
||||
|
||||
#include "large_amazon_cellphones/simdjson_dom.h"
|
||||
#include "large_amazon_cellphones/simdjson_ondemand.h"
|
||||
#include "large_amazon_cellphones/simdjson_singlestage.h"
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
// We believe that all statuses have a matching
|
||||
// user, and we are willing to throw when they do not.
|
||||
result.push_back(tweet.find_field("user").find_field("id"));
|
||||
// Not all tweets have a "retweeted_status", but when they do
|
||||
// we want to go and find the user within.
|
||||
auto retweet = tweet.find_field("retweeted_status");
|
||||
if (!retweet.error()) {
|
||||
result.push_back(retweet.find_field("user").find_field("id"));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "distinct_user_id.h"
|
||||
|
||||
namespace distinct_user_id {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage_json_pointer {
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
// We believe that all statuses have a matching
|
||||
// user, and we are willing to throw when they do not.
|
||||
result.push_back(tweet.at_pointer("/user/id"));
|
||||
// Not all tweets have a "retweeted_status", but when they do
|
||||
// we want to go and find the user within.
|
||||
auto retweet_id = tweet.at_pointer("/retweeted_status/user/id");
|
||||
if (retweet_id.error() != NO_SUCH_FIELD) {
|
||||
result.push_back(retweet_id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_singlestage_json_pointer)->UseManualTime();
|
||||
|
||||
} // namespace distinct_user_id
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "find_tweet.h"
|
||||
|
||||
namespace find_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
|
||||
// Walk the document, parsing as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc.find_field("statuses")) {
|
||||
if (uint64_t(tweet.find_field("id")) == find_id) {
|
||||
result = tweet.find_field("text");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(find_tweet, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace find_tweet
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -8,7 +8,7 @@ namespace json2msgpack {
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* @brief The simdjson2msgpack struct is used to quickly convert
|
||||
* @brief The simdjsonondemand2msgpack 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
|
||||
@@ -17,7 +17,7 @@ using namespace simdjson;
|
||||
*
|
||||
* Recommended usage:
|
||||
*
|
||||
* simdjson2msgpack parser{};
|
||||
* simdjsonondemand2msgpack parser{};
|
||||
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
|
||||
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
|
||||
*
|
||||
@@ -26,10 +26,10 @@ using namespace simdjson;
|
||||
* 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
|
||||
* You may reuse the simdjsonondemand2msgpack instance though you should use
|
||||
* one per thread.
|
||||
*/
|
||||
struct simdjson2msgpack {
|
||||
struct simdjsonondemand2msgpack {
|
||||
/**
|
||||
* @brief Converts the provided JSON into msgpack.
|
||||
*
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
};
|
||||
|
||||
std::string_view
|
||||
simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
simdjsonondemand2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
ondemand::document doc = parser.iterate(json);
|
||||
@@ -106,33 +106,33 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_double(const double d) noexcept {
|
||||
void simdjsonondemand2msgpack::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 {
|
||||
void simdjsonondemand2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
void simdjsonondemand2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
uint8_t *simdjson2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *simdjsonondemand2msgpack::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 {
|
||||
void simdjsonondemand2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void simdjson2msgpack::write_raw_string(
|
||||
void simdjsonondemand2msgpack::write_raw_string(
|
||||
simdjson::ondemand::raw_json_string in) {
|
||||
write_byte(0xdb);
|
||||
uint8_t *location = skip_uint32();
|
||||
@@ -140,7 +140,7 @@ void simdjson2msgpack::write_raw_string(
|
||||
write_uint32_at(uint32_t(v.size()), location);
|
||||
}
|
||||
|
||||
void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
void simdjsonondemand2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
@@ -185,7 +185,7 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
|
||||
}
|
||||
|
||||
|
||||
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||
void simdjsonondemand2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::ondemand::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
@@ -234,7 +234,7 @@ void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& elemen
|
||||
struct simdjson_ondemand {
|
||||
using StringType = std::string_view;
|
||||
|
||||
simdjson2msgpack parser{};
|
||||
simdjsonondemand2msgpack parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, char *buffer,
|
||||
std::string_view &result) {
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
#pragma once
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "json2msgpack.h"
|
||||
|
||||
namespace json2msgpack {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
/**
|
||||
* @brief The simdjsonsinglestage2msgpack 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:
|
||||
*
|
||||
* simdjsonsinglestage2msgpack 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 simdjsonsinglestage2msgpack instance though you should use
|
||||
* one per thread.
|
||||
*/
|
||||
struct simdjsonsinglestage2msgpack {
|
||||
/**
|
||||
* @brief Converts the provided JSON into msgpack.
|
||||
*
|
||||
* @param json JSON input
|
||||
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
|
||||
* of padding)
|
||||
* @return std::string_view msgpack output, writing to the temporary buffer
|
||||
*/
|
||||
inline std::string_view to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf);
|
||||
|
||||
private:
|
||||
simdjson_inline void write_double(const double d) noexcept;
|
||||
simdjson_inline void write_byte(const uint8_t b) noexcept;
|
||||
simdjson_inline void write_uint32(const uint32_t w) noexcept;
|
||||
simdjson_inline uint8_t *skip_uint32() noexcept;
|
||||
simdjson_inline void write_uint32_at(const uint32_t w,
|
||||
uint8_t *p) noexcept;
|
||||
simdjson_inline void
|
||||
write_raw_string(simdjson::singlestage::raw_json_string rjs);
|
||||
inline void recursive_processor(simdjson::singlestage::value element);
|
||||
inline void recursive_processor_ref(simdjson::singlestage::value& element);
|
||||
|
||||
simdjson::singlestage::parser parser;
|
||||
uint8_t *buff{};
|
||||
};
|
||||
|
||||
std::string_view
|
||||
simdjsonsinglestage2msgpack::to_msgpack(const simdjson::padded_string &json,
|
||||
uint8_t *buf) {
|
||||
buff = buf;
|
||||
singlestage::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::singlestage::json_type::number:
|
||||
write_double(doc.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(doc.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + doc.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(doc.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
case simdjson::singlestage::json_type::array:
|
||||
case simdjson::singlestage::json_type::object:
|
||||
default:
|
||||
// impossible
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
} else {
|
||||
simdjson::singlestage::value val = doc;
|
||||
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
|
||||
#if SIMDJSON_GCC_COMPILER
|
||||
// the GCC compiler does well with by-value passing.
|
||||
// GCC has superior recursive inlining:
|
||||
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
|
||||
// https://godbolt.org/z/TeK4doE51
|
||||
recursive_processor(val);
|
||||
#else
|
||||
recursive_processor_ref(val);
|
||||
#endif
|
||||
}
|
||||
if (!doc.at_end()) {
|
||||
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
|
||||
}
|
||||
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_double(const double d) noexcept {
|
||||
*buff++ = 0xcb;
|
||||
::memcpy(buff, &d, sizeof(d));
|
||||
buff += sizeof(d);
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_byte(const uint8_t b) noexcept {
|
||||
*buff = b;
|
||||
buff++;
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_uint32(const uint32_t w) noexcept {
|
||||
::memcpy(buff, &w, sizeof(w));
|
||||
buff += sizeof(w);
|
||||
}
|
||||
|
||||
uint8_t *simdjsonsinglestage2msgpack::skip_uint32() noexcept {
|
||||
uint8_t *ret = buff;
|
||||
buff += sizeof(uint32_t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
|
||||
::memcpy(p, &w, sizeof(w));
|
||||
}
|
||||
|
||||
void simdjsonsinglestage2msgpack::write_raw_string(
|
||||
simdjson::singlestage::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 simdjsonsinglestage2msgpack::recursive_processor(simdjson::singlestage::value element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::singlestage::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::singlestage::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::singlestage::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void simdjsonsinglestage2msgpack::recursive_processor_ref(simdjson::singlestage::value& element) {
|
||||
switch (element.type()) {
|
||||
case simdjson::singlestage::json_type::array: {
|
||||
uint32_t counter = 0;
|
||||
write_byte(0xdd);
|
||||
uint8_t *location = skip_uint32();
|
||||
for (auto child : element.get_array()) {
|
||||
counter++;
|
||||
simdjson::singlestage::value v = child.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::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());
|
||||
simdjson::singlestage::value v = field.value();
|
||||
recursive_processor_ref(v);
|
||||
}
|
||||
write_uint32_at(counter, location);
|
||||
} break;
|
||||
case simdjson::singlestage::json_type::number:
|
||||
write_double(element.get_double());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::string:
|
||||
write_raw_string(element.get_raw_json_string());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::boolean:
|
||||
write_byte(0xc2 + element.get_bool());
|
||||
break;
|
||||
case simdjson::singlestage::json_type::null:
|
||||
// We check that the value is indeed null
|
||||
// otherwise: an error is thrown.
|
||||
if(element.is_null()) {
|
||||
write_byte(0xc0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string_view;
|
||||
|
||||
simdjsonsinglestage2msgpack 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_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace json2msgpack
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -13,6 +13,8 @@ void maybe_display_implementation() {
|
||||
std::cout << "simdjson::dom implementation: " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::singlestage implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
|
||||
std::cout << "simdjson::singlestage implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "kostya.h"
|
||||
|
||||
namespace kostya {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object point : doc.find_field("coordinates")) {
|
||||
result.emplace_back(json_benchmark::point{point.find_field("x"), point.find_field("y"), point.find_field("z")});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(kostya, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace kostya
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_amazon_cellphones.h"
|
||||
|
||||
namespace large_amazon_cellphones {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
template<bool threaded>
|
||||
struct simdjson_singlestage {
|
||||
using StringType = std::string;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
parser.threaded = threaded;
|
||||
#endif
|
||||
singlestage::document_stream stream = parser.iterate_many(json);
|
||||
singlestage::document_stream::iterator i = stream.begin();
|
||||
++i; // Skip first line
|
||||
for (;i != stream.end(); ++i) {
|
||||
auto doc = *i;
|
||||
size_t index{0};
|
||||
StringType copy;
|
||||
double rating;
|
||||
uint64_t reviews;
|
||||
for ( auto value : doc ) {
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
copy = StringType(std::string_view(value));
|
||||
break;
|
||||
case 5:
|
||||
rating = double(value);
|
||||
break;
|
||||
case 7:
|
||||
reviews = uint64_t(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
auto x = result.find(copy);
|
||||
if (x == result.end()) { // If key not found, add new key
|
||||
result.emplace(copy, large_amazon_cellphones::brand{
|
||||
rating * reviews,
|
||||
reviews
|
||||
});
|
||||
} else { // Otherwise, update key data
|
||||
x->second.cumulative_rating += rating * reviews;
|
||||
x->second.reviews_count += reviews;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_singlestage<UNTHREADED>)->UseManualTime();
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_singlestage<THREADED>)->UseManualTime();
|
||||
#endif
|
||||
|
||||
} // namespace amazon_cellphones
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
result.emplace_back(json_benchmark::point{coord.find_field("x"), coord.find_field("y"), coord.find_field("z")});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "large_random.h"
|
||||
|
||||
namespace large_random {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage_unordered {
|
||||
static constexpr diff_flags DiffFlags = diff_flags::NONE;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<point> &result) {
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
result.emplace_back(json_benchmark::point{coord["x"], coord["y"], coord["z"]});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(large_random, simdjson_singlestage_unordered)->UseManualTime();
|
||||
|
||||
} // namespace large_random
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "largerandom.h"
|
||||
|
||||
namespace largerandom {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
class OnDemand {
|
||||
public:
|
||||
simdjson_inline bool Run(const padded_string &json);
|
||||
simdjson_inline const std::vector<my_point> &Result() { return container; }
|
||||
simdjson_inline size_t ItemCount() { return container.size(); }
|
||||
|
||||
private:
|
||||
singlestage::parser parser{};
|
||||
std::vector<my_point> container{};
|
||||
};
|
||||
|
||||
simdjson_inline bool OnDemand::Run(const padded_string &json) {
|
||||
container.clear();
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object coord : doc) {
|
||||
container.emplace_back(my_point{coord.find_field("x"), coord.find_field("y"), coord.find_field("z")});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(LargeRandom, OnDemand);
|
||||
|
||||
} // namespace largerandom
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
simdjson_inline uint64_t nullable_int(singlestage::value value) {
|
||||
if (value.is_null()) { return 0; }
|
||||
return value;
|
||||
}
|
||||
|
||||
simdjson_inline twitter_user<std::string_view> read_user(singlestage::object user) {
|
||||
return { user.find_field("id"), user.find_field("screen_name") };
|
||||
}
|
||||
|
||||
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
|
||||
// Walk the document, parsing the tweets as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
result.emplace_back(partial_tweets::tweet<std::string_view>{
|
||||
tweet.find_field("created_at"),
|
||||
tweet.find_field("id"),
|
||||
tweet.find_field("text"),
|
||||
nullable_int(tweet.find_field("in_reply_to_status_id")),
|
||||
read_user(tweet.find_field("user")),
|
||||
tweet.find_field("retweet_count"),
|
||||
tweet.find_field("favorite_count")
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(partial_tweets, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "partial_tweets.h"
|
||||
|
||||
namespace partial_tweets {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
|
||||
class SingleStage {
|
||||
public:
|
||||
SingleStage() {
|
||||
if(!displayed_implementation) {
|
||||
std::cout << "On Demand implementation: " << builtin_implementation()->name() << std::endl;
|
||||
displayed_implementation = true;
|
||||
}
|
||||
}
|
||||
simdjson_inline bool Run(const padded_string &json);
|
||||
simdjson_inline const std::vector<tweet> &Result() { return tweets; }
|
||||
simdjson_inline size_t ItemCount() { return tweets.size(); }
|
||||
|
||||
private:
|
||||
singlestage::parser parser{};
|
||||
std::vector<tweet> tweets{};
|
||||
|
||||
simdjson_inline uint64_t nullable_int(singlestage::value value) {
|
||||
if (value.is_null()) { return 0; }
|
||||
return value;
|
||||
}
|
||||
|
||||
simdjson_inline twitter_user read_user(singlestage::object user) {
|
||||
return { user.find_field("id"), user.find_field("screen_name") };
|
||||
}
|
||||
|
||||
static inline bool displayed_implementation = false;
|
||||
};
|
||||
|
||||
simdjson_inline bool SingleStage::Run(const padded_string &json) {
|
||||
tweets.clear();
|
||||
|
||||
// Walk the document, parsing the tweets as we go
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc.find_field("statuses")) {
|
||||
tweets.emplace_back(partial_tweets::tweet{
|
||||
tweet.find_field("created_at"),
|
||||
tweet.find_field("id"),
|
||||
tweet.find_field("text"),
|
||||
nullable_int(tweet.find_field("in_reply_to_status_id")),
|
||||
read_user(tweet.find_field("user")),
|
||||
tweet.find_field("retweet_count"),
|
||||
tweet.find_field("favorite_count")
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(PartialTweets, SingleStage);
|
||||
|
||||
} // namespace partial_tweets
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
#include "top_tweet.h"
|
||||
|
||||
namespace top_tweet {
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
struct simdjson_singlestage {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
// We save these DOM values for later so we don't have to parse them
|
||||
// into string_views until we're sure which ones we want to parse
|
||||
// NOTE: simdjson does not presently support reuse of objects or arrays--just scalars. This is
|
||||
// why we have to grab the text and screen_name fields instead of just saving the tweet object.
|
||||
singlestage::value screen_name, text;
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc["statuses"]) {
|
||||
// Since text, user.screen_name, and retweet_count generally appear in order, it's nearly free
|
||||
// for us to retrieve them here (and will cost a bit more if we do it in the if
|
||||
// statement).
|
||||
auto tweet_text = tweet["text"];
|
||||
auto tweet_screen_name = tweet["user"]["screen_name"];
|
||||
int64_t retweet_count = tweet["retweet_count"];
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
// TODO std::move should not be necessary
|
||||
text = std::move(tweet_text);
|
||||
screen_name = std::move(tweet_screen_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we know which was the most retweeted, parse the values in it
|
||||
result.screen_name = screen_name;
|
||||
result.text = text;
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, simdjson_singlestage)->UseManualTime();
|
||||
|
||||
struct simdjson_singlestage_forward_only {
|
||||
using StringType=std::string_view;
|
||||
|
||||
singlestage::parser parser{};
|
||||
|
||||
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
|
||||
result.retweet_count = -1;
|
||||
|
||||
auto doc = parser.iterate(json);
|
||||
for (auto tweet : doc["statuses"]) {
|
||||
// Since text, user.screen_name, and retweet_count generally appear in order, it's nearly free
|
||||
// for us to retrieve them here (and will cost a bit more if we do it in the if
|
||||
// statement).
|
||||
auto tweet_text = tweet["text"];
|
||||
auto tweet_screen_name = tweet["user"]["screen_name"];
|
||||
int64_t retweet_count = tweet["retweet_count"];
|
||||
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
|
||||
result.retweet_count = retweet_count;
|
||||
result.text = tweet_text;
|
||||
result.screen_name = tweet_screen_name;
|
||||
}
|
||||
}
|
||||
|
||||
return result.retweet_count != -1;
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_TEMPLATE(top_tweet, simdjson_singlestage_forward_only)->UseManualTime();
|
||||
|
||||
} // namespace top_tweet
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
@@ -35,4 +35,14 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
add_quickstart_test(quickstart_ondemand_noexceptions quickstart_ondemand_noexceptions.cpp NO_EXCEPTIONS LABELS quickstart_ondemand acceptance)
|
||||
add_quickstart_test(quickstart_ondemand_noexceptions11 quickstart_ondemand_noexceptions.cpp NO_EXCEPTIONS CXX_STANDARD c++11 LABELS quickstart_ondemand)
|
||||
|
||||
# SingleStage Quick Start
|
||||
if (SIMDJSON_EXCEPTIONS)
|
||||
add_quickstart_test(quickstart_singlestage quickstart_singlestage.cpp LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage11 quickstart_singlestage.cpp CXX_STANDARD c++11 LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage14 quickstart_singlestage.cpp CXX_STANDARD c++14 LABELS quickstart_singlestage)
|
||||
endif()
|
||||
|
||||
add_quickstart_test(quickstart_singlestage_noexceptions quickstart_singlestage_noexceptions.cpp NO_EXCEPTIONS LABELS quickstart_singlestage acceptance)
|
||||
add_quickstart_test(quickstart_singlestage_noexceptions11 quickstart_singlestage_noexceptions.cpp NO_EXCEPTIONS CXX_STANDARD c++11 LABELS quickstart_singlestage)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
ondemand::parser parser;
|
||||
padded_string json = padded_string::load("twitter.json");
|
||||
ondemand::document tweets = parser.iterate(json);
|
||||
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
using namespace simdjson;
|
||||
int main(void) {
|
||||
padded_string json;
|
||||
auto error = padded_string::load("twitter.json").get(json);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
ondemand::parser parser;
|
||||
ondemand::document tweets;
|
||||
error = parser.iterate(json).get(tweets);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
uint64_t count;
|
||||
error = tweets["search_metadata"]["count"].get(count);
|
||||
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
|
||||
|
||||
std::cout << count << " results." << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -63,6 +63,7 @@ if(SIMDJSON_ENABLE_FUZZING)
|
||||
implement_fuzzer(fuzz_minifyimpl) # minify *without* parsing, plus compare implementations
|
||||
implement_fuzzer(fuzz_ndjson) # the ndjson api
|
||||
implement_fuzzer(fuzz_ondemand)
|
||||
# implement_fuzzer(fuzz_singlestage) # TODO why no worky
|
||||
implement_fuzzer(fuzz_padded)
|
||||
implement_fuzzer(fuzz_parser)
|
||||
implement_fuzzer(fuzz_print_json)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "FuzzUtils.h"
|
||||
#include "simdjson.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
FuzzData fd(Data, Size);
|
||||
const int action = fd.getInt<0, 12>();
|
||||
|
||||
// split the remainder of the document into strings
|
||||
auto strings = fd.splitIntoStrings();
|
||||
while (strings.size() < 1) {
|
||||
strings.emplace_back();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
simdjson::singlestage::parser parser;
|
||||
simdjson::padded_string padded(strings[0]);
|
||||
auto doc = parser.iterate(padded);
|
||||
if (doc.error()) {
|
||||
return 0;
|
||||
}
|
||||
for (auto item : doc) {
|
||||
switch (action) {
|
||||
case 0: {
|
||||
simdjson_unused auto x = item.get_string();
|
||||
} break;
|
||||
case 1: {
|
||||
simdjson_unused auto x = item.get_bool();
|
||||
} break;
|
||||
case 2: {
|
||||
simdjson_unused auto x = item.get_array();
|
||||
} break;
|
||||
case 3: {
|
||||
simdjson_unused auto x = item.get_int64();
|
||||
} break;
|
||||
case 4: {
|
||||
simdjson_unused auto x = item.get_double();
|
||||
} break;
|
||||
case 5: {
|
||||
simdjson_unused auto x = item.get_object();
|
||||
} break;
|
||||
case 6: {
|
||||
simdjson_unused auto x = item.get_uint64();
|
||||
} break;
|
||||
case 7: {
|
||||
simdjson_unused auto x = item.get_raw_json_string();
|
||||
} break;
|
||||
case 8: {
|
||||
simdjson_unused auto x = item.is_null();
|
||||
} break;
|
||||
case 9: {
|
||||
simdjson_unused auto x = item.begin();
|
||||
} break;
|
||||
case 10: {
|
||||
simdjson_unused auto x = item.end();
|
||||
} break;
|
||||
case 11: {
|
||||
for (auto e : item) {
|
||||
simdjson_unused auto x = e.is_null();
|
||||
}
|
||||
} break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
} catch (...) {
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,5 +53,6 @@
|
||||
|
||||
#include "simdjson/dom.h"
|
||||
#include "simdjson/ondemand.h"
|
||||
#include "simdjson/singlestage.h"
|
||||
|
||||
#endif // SIMDJSON_H
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_ARM64_SINGLESTAGE_H
|
||||
#define SIMDJSON_ARM64_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/arm64/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/arm64/end.h"
|
||||
|
||||
#endif // SIMDJSON_ARM64_SINGLESTAGE_H
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef SIMDJSON_BUILTIN_SINGLESTAGE_H
|
||||
#define SIMDJSON_BUILTIN_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/builtin.h"
|
||||
#include "simdjson/builtin/base.h"
|
||||
|
||||
#include "simdjson/generic/singlestage/dependencies.h"
|
||||
|
||||
#define SIMDJSON_AMALGAMATED
|
||||
|
||||
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
|
||||
#include "simdjson/arm64/singlestage.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
|
||||
#include "simdjson/fallback/singlestage.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
|
||||
#include "simdjson/haswell/singlestage.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
|
||||
#include "simdjson/icelake/singlestage.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
|
||||
#include "simdjson/ppc64/singlestage.h"
|
||||
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
|
||||
#include "simdjson/westmere/singlestage.h"
|
||||
#else
|
||||
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#undef SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* @copydoc simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::singlestage
|
||||
*/
|
||||
namespace singlestage = SIMDJSON_BUILTIN_IMPLEMENTATION::singlestage;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_BUILTIN_SINGLESTAGE_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_FALLBACK_SINGLESTAGE_H
|
||||
#define SIMDJSON_FALLBACK_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/fallback/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/fallback/end.h"
|
||||
|
||||
#endif // SIMDJSON_FALLBACK_SINGLESTAGE_H
|
||||
@@ -96,6 +96,16 @@ static simdjson_inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi)
|
||||
}
|
||||
#endif
|
||||
|
||||
inline std::string_view trim(const std::string_view str) noexcept {
|
||||
// We can almost surely do better by rolling our own find_first_not_of function.
|
||||
size_t first = str.find_first_not_of(" \t\n\r");
|
||||
// If we have the empty string (just white space), then no trimming is possible, and
|
||||
// we return the empty string_view.
|
||||
if (std::string_view::npos == first) { return std::string_view(); }
|
||||
size_t last = str.find_last_not_of(" \t\n\r");
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
|
||||
} // namespace jsoncharutils
|
||||
} // unnamed namespace
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
|
||||
@@ -13,29 +13,18 @@
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline std::string_view trim(const std::string_view str) noexcept {
|
||||
// We can almost surely do better by rolling our own find_first_not_of function.
|
||||
size_t first = str.find_first_not_of(" \t\n\r");
|
||||
// If we have the empty string (just white space), then no trimming is possible, and
|
||||
// we return the empty string_view.
|
||||
if (std::string_view::npos == first) { return std::string_view(); }
|
||||
size_t last = str.find_last_not_of(" \t\n\r");
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return trim(v);
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::document_reference& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return trim(v);
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::value& x) noexcept {
|
||||
@@ -66,7 +55,7 @@ inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION:
|
||||
return to_json_string(object);
|
||||
}
|
||||
default:
|
||||
return trim(x.raw_json_token());
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(x.raw_json_token());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,14 +63,14 @@ inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION:
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return trim(v);
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::ondemand::array& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return trim(v);
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> x) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#if defined(SIMDJSON_AMALGAMATED) && !defined(SIMDJSON_GENERIC_SINGLESTAGE_DEPENDENCIES_H)
|
||||
#error simdjson/generic/singlestage/dependencies.h must be included before simdjson/generic/singlestage/amalgamated.h!
|
||||
#endif
|
||||
|
||||
// Stuff other things depend on
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#include "simdjson/generic/singlestage/logger.h"
|
||||
#include "simdjson/generic/singlestage/token_iterator.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/json_type.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/parser.h"
|
||||
|
||||
// All other declarations
|
||||
#include "simdjson/generic/singlestage/array.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator.h"
|
||||
#include "simdjson/generic/singlestage/document.h"
|
||||
#include "simdjson/generic/singlestage/field.h"
|
||||
#include "simdjson/generic/singlestage/object.h"
|
||||
#include "simdjson/generic/singlestage/object_iterator.h"
|
||||
#include "simdjson/generic/singlestage/serialization.h"
|
||||
|
||||
// Inline definitions
|
||||
#include "simdjson/generic/singlestage/array-inl.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/document-inl.h"
|
||||
#include "simdjson/generic/singlestage/field-inl.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/json_type-inl.h"
|
||||
#include "simdjson/generic/singlestage/logger-inl.h"
|
||||
#include "simdjson/generic/singlestage/object-inl.h"
|
||||
#include "simdjson/generic/singlestage/object_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/parser-inl.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string-inl.h"
|
||||
#include "simdjson/generic/singlestage/serialization-inl.h"
|
||||
#include "simdjson/generic/singlestage/token_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/value-inl.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
@@ -0,0 +1,226 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/array.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
//
|
||||
// ### Live States
|
||||
//
|
||||
// While iterating or looking up values, depth >= iter->depth. at_start may vary. Error is
|
||||
// always SUCCESS:
|
||||
//
|
||||
// - Start: This is the state when the array is first found and the iterator is just past the `{`.
|
||||
// In this state, at_start == true.
|
||||
// - Next: After we hand a scalar value to the user, or an array/object which they then fully
|
||||
// iterate over, the iterator is at the `,` before the next value (or `]`). In this state,
|
||||
// depth == iter->depth, at_start == false, and error == SUCCESS.
|
||||
// - Unfinished Business: When we hand an array/object to the user which they do not fully
|
||||
// iterate over, we need to finish that iteration by skipping child values until we reach the
|
||||
// Next state. In this state, depth > iter->depth, at_start == false, and error == SUCCESS.
|
||||
//
|
||||
// ## Error States
|
||||
//
|
||||
// In error states, we will yield exactly one more value before stopping. iter->depth == depth
|
||||
// and at_start is always false. We decrement after yielding the error, moving to the Finished
|
||||
// state.
|
||||
//
|
||||
// - Chained Error: When the array iterator is part of an error chain--for example, in
|
||||
// `for (auto tweet : doc["tweets"])`, where the tweet element may be missing or not be an
|
||||
// array--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
|
||||
// iter->depth == depth, and at_start == false. We decrement depth when we yield the error.
|
||||
// - Missing Comma Error: When the iterator ++ method discovers there is no comma between elements,
|
||||
// we flag that as an error and treat it exactly the same as a Chained Error. In this state,
|
||||
// error == TAPE_ERROR, iter->depth == depth, and at_start == false.
|
||||
//
|
||||
// ## Terminal State
|
||||
//
|
||||
// The terminal state has iter->depth < depth. at_start is always false.
|
||||
//
|
||||
// - Finished: When we have reached a `]` or have reported an error, we are finished. We signal this
|
||||
// by decrementing depth. In this state, iter->depth < depth, at_start == false, and
|
||||
// error == SUCCESS.
|
||||
//
|
||||
|
||||
simdjson_inline array::array(const value_iterator &_iter) noexcept
|
||||
: iter{_iter}
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<array> array::start(value_iterator &iter) noexcept {
|
||||
// We don't need to know if the array is empty to start iteration, but we do want to know if there
|
||||
// is an error--thus `simdjson_unused`.
|
||||
simdjson_unused bool has_value;
|
||||
SIMDJSON_TRY( iter.start_array().get(has_value) );
|
||||
return array(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<array> array::start_root(value_iterator &iter) noexcept {
|
||||
simdjson_unused bool has_value;
|
||||
SIMDJSON_TRY( iter.start_root_array().get(has_value) );
|
||||
return array(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<array> array::started(value_iterator &iter) noexcept {
|
||||
bool has_value;
|
||||
SIMDJSON_TRY(iter.started_array().get(has_value));
|
||||
return array(iter);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<array_iterator> array::begin() noexcept {
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
|
||||
#endif
|
||||
return array_iterator(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<array_iterator> array::end() noexcept {
|
||||
return array_iterator(iter);
|
||||
}
|
||||
simdjson_inline error_code array::consume() noexcept {
|
||||
auto error = iter.json_iter().skip_child(iter.depth()-1);
|
||||
if(error) { iter.abandon(); }
|
||||
return error;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> array::raw_json() noexcept {
|
||||
const uint8_t * starting_point{iter.peek_start()};
|
||||
auto error = consume();
|
||||
if(error) { return error; }
|
||||
// After 'consume()', we could be left pointing just beyond the document, but that
|
||||
// is ok because we are not going to dereference the final pointer position, we just
|
||||
// use it to compute the length in bytes.
|
||||
const uint8_t * final_point{iter._json_iter->unsafe_pointer()};
|
||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||
}
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
simdjson_inline simdjson_result<size_t> array::count_elements() & noexcept {
|
||||
size_t count{0};
|
||||
// Important: we do not consume any of the values.
|
||||
for(simdjson_unused auto v : *this) { count++; }
|
||||
// The above loop will always succeed, but we want to report errors.
|
||||
if(iter.error()) { return iter.error(); }
|
||||
// We need to move back at the start because we expect users to iterate through
|
||||
// the array after counting the number of elements.
|
||||
iter.reset_array();
|
||||
return count;
|
||||
}
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
simdjson_inline simdjson_result<bool> array::is_empty() & noexcept {
|
||||
bool is_not_empty;
|
||||
auto error = iter.reset_array().get(is_not_empty);
|
||||
if(error) { return error; }
|
||||
return !is_not_empty;
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> array::reset() & noexcept {
|
||||
return iter.reset_array();
|
||||
}
|
||||
|
||||
inline simdjson_result<value> array::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
|
||||
json_pointer = json_pointer.substr(1);
|
||||
// - means "the append position" or "the element after the end of the array"
|
||||
// We don't support this, because we're returning a real element, not a position.
|
||||
if (json_pointer == "-") { return INDEX_OUT_OF_BOUNDS; }
|
||||
|
||||
// Read the array index
|
||||
size_t array_index = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < json_pointer.length() && json_pointer[i] != '/'; i++) {
|
||||
uint8_t digit = uint8_t(json_pointer[i] - '0');
|
||||
// Check for non-digit in array index. If it's there, we're trying to get a field in an object
|
||||
if (digit > 9) { return INCORRECT_TYPE; }
|
||||
array_index = array_index*10 + digit;
|
||||
}
|
||||
|
||||
// 0 followed by other digits is invalid
|
||||
if (i > 1 && json_pointer[0] == '0') { return INVALID_JSON_POINTER; } // "JSON pointer array index has other characters after 0"
|
||||
|
||||
// Empty string is invalid; so is a "/" with no digits before it
|
||||
if (i == 0) { return INVALID_JSON_POINTER; } // "Empty string in JSON pointer array index"
|
||||
// Get the child
|
||||
auto child = at(array_index);
|
||||
// If there is an error, it ends here
|
||||
if(child.error()) {
|
||||
return child;
|
||||
}
|
||||
|
||||
// If there is a /, we're not done yet, call recursively.
|
||||
if (i < json_pointer.length()) {
|
||||
child = child.at_pointer(json_pointer.substr(i));
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> array::at(size_t index) noexcept {
|
||||
size_t i = 0;
|
||||
for (auto value : *this) {
|
||||
if (i == index) { return value; }
|
||||
i++;
|
||||
}
|
||||
return INDEX_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::array &&value
|
||||
) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array>(
|
||||
std::forward<SIMDJSON_IMPLEMENTATION::singlestage::array>(value)
|
||||
)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::simdjson_result(
|
||||
error_code error
|
||||
) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array>(error)
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::begin() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::end() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.end();
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::count_elements() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::is_empty() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_empty();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::at(size_t index) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array>::raw_json() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json();
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_INL_H
|
||||
@@ -0,0 +1,199 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A forward-only JSON array.
|
||||
*/
|
||||
class array {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid array.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline array() noexcept = default;
|
||||
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> begin() noexcept;
|
||||
/**
|
||||
* Sentinel representing the end of the array.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> end() noexcept;
|
||||
/**
|
||||
* This method scans the array and counts the number of elements.
|
||||
* The count_elements method should always be called before you have begun
|
||||
* iterating through the array: it is expected that you are pointing at
|
||||
* the beginning of the array.
|
||||
* The runtime complexity is linear in the size of the array. After
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*
|
||||
* To check that an array is empty, it is more performant to use
|
||||
* the is_empty() method.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
/**
|
||||
* This method scans the beginning of the array and checks whether the
|
||||
* array is empty.
|
||||
* The runtime complexity is constant time. After
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_empty() & noexcept;
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
* beginning of the array. You should still consume values only once even if you
|
||||
* can iterate through the array more than once. If you unescape a string
|
||||
* within the array more than once, you have unsafe code. Note that rewinding
|
||||
* an array means that you may need to reparse it anew: it is not a free
|
||||
* operation.
|
||||
*
|
||||
* @returns true if the array contains some elements (not empty)
|
||||
*/
|
||||
inline simdjson_result<bool> reset() & noexcept;
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
|
||||
* as the root of its own JSON document.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"([ { "foo": { "a": [ 10, 20, 30 ] }} ])"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("/0/foo/a/1") == 20
|
||||
*
|
||||
* Note that at_pointer() called on the document automatically calls the document's rewind
|
||||
* method between each call. It invalidates all previously accessed arrays, objects and values
|
||||
* that have not been consumed. Yet it is not the case when calling at_pointer on an array
|
||||
* instance: there is no rewind and no invalidation.
|
||||
*
|
||||
* You may only call at_pointer on an array after it has been created, but before it has
|
||||
* been first accessed. When calling at_pointer on an array, the pointer is advanced to
|
||||
* the location indicated by the JSON pointer (in case of success). It is no longer possible
|
||||
* to call at_pointer on the same array.
|
||||
*
|
||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
||||
*
|
||||
* @return The value associated with the given JSON pointer, or:
|
||||
* - NO_SUCH_FIELD if a field does not exist in an object
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
|
||||
* - INCORRECT_TYPE if a non-integer is used to access an array
|
||||
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
|
||||
*/
|
||||
inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
/**
|
||||
* Consumes the array and returns a string_view instance corresponding to the
|
||||
* array as represented in JSON. It points inside the original document.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
/**
|
||||
* Get the value at the given index. This function has linear-time complexity.
|
||||
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
protected:
|
||||
/**
|
||||
* Go to the end of the array, no matter where you are right now.
|
||||
*/
|
||||
simdjson_inline error_code consume() noexcept;
|
||||
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
* @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
|
||||
* resulting array.
|
||||
* @error INCORRECT_TYPE if the iterator is not at [.
|
||||
*/
|
||||
static simdjson_inline simdjson_result<array> start(value_iterator &iter) noexcept;
|
||||
/**
|
||||
* Begin array iteration from the root.
|
||||
*
|
||||
* @param iter The iterator. Must be where the initial [ is expected. Will be *moved* into the
|
||||
* resulting array.
|
||||
* @error INCORRECT_TYPE if the iterator is not at [.
|
||||
* @error TAPE_ERROR if there is no closing ] at the end of the document.
|
||||
*/
|
||||
static simdjson_inline simdjson_result<array> start_root(value_iterator &iter) noexcept;
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
* This version of the method should be called after the initial [ has been verified, and is
|
||||
* intended for use by switch statements that check the type of a value.
|
||||
*
|
||||
* @param iter The iterator. Must be after the initial [. Will be *moved* into the resulting array.
|
||||
*/
|
||||
static simdjson_inline simdjson_result<array> started(value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* Create an array at the given Internal array creation. Call array::start() or array::started() instead of this.
|
||||
*
|
||||
* @param iter The iterator. Must either be at the start of the first element with iter.is_alive()
|
||||
* == true, or past the [] with is_alive() == false if the array is empty. Will be *moved*
|
||||
* into the resulting array.
|
||||
*/
|
||||
simdjson_inline array(const value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* Iterator marking current position.
|
||||
*
|
||||
* iter.is_alive() == false indicates iteration is complete.
|
||||
*/
|
||||
value_iterator iter{};
|
||||
|
||||
friend class value;
|
||||
friend class document;
|
||||
friend struct simdjson_result<value>;
|
||||
friend struct simdjson_result<array>;
|
||||
friend class array_iterator;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::array &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> begin() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> end() noexcept;
|
||||
inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
inline simdjson_result<bool> is_empty() & noexcept;
|
||||
inline simdjson_result<bool> reset() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at(size_t index) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_H
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator.h"
|
||||
#include "simdjson/generic/singlestage/value-inl.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline array_iterator::array_iterator(const value_iterator &_iter) noexcept
|
||||
: iter{_iter}
|
||||
{}
|
||||
|
||||
simdjson_inline simdjson_result<value> array_iterator::operator*() noexcept {
|
||||
if (iter.error()) { iter.abandon(); return iter.error(); }
|
||||
return value(iter.child());
|
||||
}
|
||||
simdjson_inline bool array_iterator::operator==(const array_iterator &other) const noexcept {
|
||||
return !(*this != other);
|
||||
}
|
||||
simdjson_inline bool array_iterator::operator!=(const array_iterator &) const noexcept {
|
||||
return iter.is_open();
|
||||
}
|
||||
simdjson_inline array_iterator &array_iterator::operator++() noexcept {
|
||||
error_code error;
|
||||
// PERF NOTE this is a safety rail ... users should exit loops as soon as they receive an error, so we'll never get here.
|
||||
// However, it does not seem to make a perf difference, so we add it out of an abundance of caution.
|
||||
if (( error = iter.error() )) { return *this; }
|
||||
if (( error = iter.skip_child() )) { return *this; }
|
||||
if (( error = iter.has_next_element().error() )) { return *this; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::array_iterator &&value
|
||||
) noexcept
|
||||
: SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>(value))
|
||||
{
|
||||
first.iter.assert_is_valid();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::simdjson_result(error_code error) noexcept
|
||||
: SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>({}, error)
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::operator*() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return *first;
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &other) const noexcept {
|
||||
if (!first.iter.is_valid()) { return !error(); }
|
||||
return first == other.first;
|
||||
}
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &other) const noexcept {
|
||||
if (!first.iter.is_valid()) { return error(); }
|
||||
return first != other.first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator>::operator++() noexcept {
|
||||
// Clear the error if there is one, so we don't yield it twice
|
||||
if (error()) { second = SUCCESS; return *this; }
|
||||
++(first);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_INL_H
|
||||
@@ -0,0 +1,96 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_H
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A forward-only JSON array.
|
||||
*
|
||||
* This is an input_iterator, meaning:
|
||||
* - It is forward-only
|
||||
* - * must be called exactly once per element.
|
||||
* - ++ must be called exactly once in between each * (*, ++, *, ++, * ...)
|
||||
*/
|
||||
class array_iterator {
|
||||
public:
|
||||
/** Create a new, invalid array iterator. */
|
||||
simdjson_inline array_iterator() noexcept = default;
|
||||
|
||||
//
|
||||
// Iterator interface
|
||||
//
|
||||
|
||||
/**
|
||||
* Get the current element.
|
||||
*
|
||||
* Part of the std::iterator interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
|
||||
/**
|
||||
* Check if we are at the end of the JSON.
|
||||
*
|
||||
* Part of the std::iterator interface.
|
||||
*
|
||||
* @return true if there are no more elements in the JSON array.
|
||||
*/
|
||||
simdjson_inline bool operator==(const array_iterator &) const noexcept;
|
||||
/**
|
||||
* Check if there are more elements in the JSON array.
|
||||
*
|
||||
* Part of the std::iterator interface.
|
||||
*
|
||||
* @return true if there are more elements in the JSON array.
|
||||
*/
|
||||
simdjson_inline bool operator!=(const array_iterator &) const noexcept;
|
||||
/**
|
||||
* Move to the next element.
|
||||
*
|
||||
* Part of the std::iterator interface.
|
||||
*/
|
||||
simdjson_inline array_iterator &operator++() noexcept;
|
||||
|
||||
private:
|
||||
value_iterator iter{};
|
||||
|
||||
simdjson_inline array_iterator(const value_iterator &iter) noexcept;
|
||||
|
||||
friend class array;
|
||||
friend class value;
|
||||
friend struct simdjson_result<array_iterator>;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::array_iterator &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
//
|
||||
// Iterator interface
|
||||
//
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
|
||||
simdjson_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &) const noexcept;
|
||||
simdjson_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &) const noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> &operator++() noexcept;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_ARRAY_ITERATOR_H
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_BASE_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_BASE_H
|
||||
#include "simdjson/generic/base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
/**
|
||||
* A fast, simple, DOM-like interface that parses JSON as you use it.
|
||||
*
|
||||
* Designed for maximum speed and a lower memory profile.
|
||||
*/
|
||||
namespace singlestage {
|
||||
|
||||
/** Represents the depth of a JSON value (number of nested arrays/objects). */
|
||||
using depth_t = int32_t;
|
||||
|
||||
/** @copydoc simdjson::SIMDJSON_IMPLEMENTATION::number_type */
|
||||
using number_type = simdjson::SIMDJSON_IMPLEMENTATION::number_type;
|
||||
|
||||
/** @private Position in the JSON buffer indexes */
|
||||
using token_position = const uint32_t *;
|
||||
|
||||
class array;
|
||||
class array_iterator;
|
||||
class document;
|
||||
class document_reference;
|
||||
class field;
|
||||
class json_iterator;
|
||||
enum class json_type;
|
||||
struct number;
|
||||
class object;
|
||||
class object_iterator;
|
||||
class parser;
|
||||
class raw_json_string;
|
||||
class token_iterator;
|
||||
class value;
|
||||
class value_iterator;
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_BASE_H
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifdef SIMDJSON_AMALGAMATED
|
||||
#error simdjson/generic/singlestage/dependencies.h must be included before defining SIMDJSON_AMALGAMATED!
|
||||
#endif
|
||||
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_DEPENDENCIES_H
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_DEPENDENCIES_H
|
||||
|
||||
// Internal headers needed for singlestage generics.
|
||||
// All includes not under simdjson/generic/singlestage must be here!
|
||||
// Otherwise, amalgamation will fail.
|
||||
#include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_DEPENDENCIES_H
|
||||
@@ -0,0 +1,823 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/array-inl.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator.h"
|
||||
#include "simdjson/generic/singlestage/document.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator-inl.h"
|
||||
#include "simdjson/generic/singlestage/json_type.h"
|
||||
#include "simdjson/generic/singlestage/object-inl.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline document::document(singlestage::json_iterator &&_iter) noexcept
|
||||
: iter{std::forward<json_iterator>(_iter)}
|
||||
{
|
||||
logger::log_start_value(iter, "document");
|
||||
}
|
||||
|
||||
simdjson_inline document document::start(json_iterator &&iter) noexcept {
|
||||
return document(std::forward<json_iterator>(iter));
|
||||
}
|
||||
|
||||
inline void document::rewind() noexcept {
|
||||
iter.rewind();
|
||||
}
|
||||
|
||||
inline std::string document::to_debug_string() noexcept {
|
||||
return iter.to_string();
|
||||
}
|
||||
|
||||
inline simdjson_result<const char *> document::current_location() const noexcept {
|
||||
return iter.current_location();
|
||||
}
|
||||
|
||||
inline int32_t document::current_depth() const noexcept {
|
||||
return iter.depth();
|
||||
}
|
||||
|
||||
inline bool document::at_end() const noexcept {
|
||||
return iter.at_end();
|
||||
}
|
||||
|
||||
|
||||
inline bool document::is_alive() noexcept {
|
||||
return iter.is_alive();
|
||||
}
|
||||
simdjson_inline value_iterator document::resume_value_iterator() noexcept {
|
||||
return value_iterator(&iter, 1, iter.root_position());
|
||||
}
|
||||
simdjson_inline value_iterator document::get_root_value_iterator() noexcept {
|
||||
return resume_value_iterator();
|
||||
}
|
||||
simdjson_inline simdjson_result<object> document::start_or_resume_object() noexcept {
|
||||
if (iter.at_root()) {
|
||||
return get_object();
|
||||
} else {
|
||||
return object::resume(resume_value_iterator());
|
||||
}
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::get_value() noexcept {
|
||||
// Make sure we start any arrays or objects before returning, so that start_root_<object/array>()
|
||||
// gets called.
|
||||
iter.assert_at_document_depth();
|
||||
switch (*iter.peek()) {
|
||||
case '[': {
|
||||
// The following lines check that the document ends with ].
|
||||
auto value_iterator = get_root_value_iterator();
|
||||
auto error = value_iterator.check_root_array();
|
||||
if(error) { return error; }
|
||||
return value(get_root_value_iterator());
|
||||
}
|
||||
case '{': {
|
||||
// The following lines would check that the document ends with }.
|
||||
auto value_iterator = get_root_value_iterator();
|
||||
auto error = value_iterator.check_root_object();
|
||||
if(error) { return error; }
|
||||
return value(get_root_value_iterator());
|
||||
}
|
||||
default:
|
||||
// Unfortunately, scalar documents are a special case in simdjson and they cannot
|
||||
// be safely converted to value instances.
|
||||
return SCALAR_DOCUMENT_AS_VALUE;
|
||||
}
|
||||
}
|
||||
simdjson_inline simdjson_result<array> document::get_array() & noexcept {
|
||||
auto value = get_root_value_iterator();
|
||||
return array::start_root(value);
|
||||
}
|
||||
simdjson_inline simdjson_result<object> document::get_object() & noexcept {
|
||||
auto value = get_root_value_iterator();
|
||||
return object::start_root(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
|
||||
* give an error, so we check for trailing content. We want to disallow trailing
|
||||
* content.
|
||||
* Thus, in several implementations below, we pass a 'true' parameter value to
|
||||
* a get_root_value_iterator() method: this indicates that we disallow trailing content.
|
||||
*/
|
||||
|
||||
simdjson_inline simdjson_result<uint64_t> document::get_uint64() noexcept {
|
||||
return get_root_value_iterator().get_root_uint64(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> document::get_uint64_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_uint64_in_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> document::get_int64() noexcept {
|
||||
return get_root_value_iterator().get_root_int64(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> document::get_int64_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_int64_in_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<double> document::get_double() noexcept {
|
||||
return get_root_value_iterator().get_root_double(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<double> document::get_double_in_string() noexcept {
|
||||
return get_root_value_iterator().get_root_double_in_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> document::get_string(bool allow_replacement) noexcept {
|
||||
return get_root_value_iterator().get_root_string(true, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
|
||||
return get_root_value_iterator().get_root_wobbly_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<raw_json_string> document::get_raw_json_string() noexcept {
|
||||
return get_root_value_iterator().get_root_raw_json_string(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> document::get_bool() noexcept {
|
||||
return get_root_value_iterator().get_root_bool(true);
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> document::is_null() noexcept {
|
||||
return get_root_value_iterator().is_root_null(true);
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<array> document::get() & noexcept { return get_array(); }
|
||||
template<> simdjson_inline simdjson_result<object> document::get() & noexcept { return get_object(); }
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> document::get() & noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_inline simdjson_result<std::string_view> document::get() & noexcept { return get_string(false); }
|
||||
template<> simdjson_inline simdjson_result<double> document::get() & noexcept { return get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() & noexcept { return get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> document::get() & noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() & noexcept { return get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() & noexcept { return get_value(); }
|
||||
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> document::get() && noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_inline simdjson_result<std::string_view> document::get() && noexcept { return get_string(false); }
|
||||
template<> simdjson_inline simdjson_result<double> document::get() && noexcept { return std::forward<document>(*this).get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> document::get() && noexcept { return std::forward<document>(*this).get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> document::get() && noexcept { return std::forward<document>(*this).get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> document::get() && noexcept { return std::forward<document>(*this).get_bool(); }
|
||||
template<> simdjson_inline simdjson_result<value> document::get() && noexcept { return get_value(); }
|
||||
|
||||
template<typename T> simdjson_inline error_code document::get(T &out) & noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
template<typename T> simdjson_inline error_code document::get(T &out) && noexcept {
|
||||
return std::forward<document>(*this).get<T>().get(out);
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline document::operator array() & noexcept(false) { return get_array(); }
|
||||
simdjson_inline document::operator object() & noexcept(false) { return get_object(); }
|
||||
simdjson_inline document::operator uint64_t() noexcept(false) { return get_uint64(); }
|
||||
simdjson_inline document::operator int64_t() noexcept(false) { return get_int64(); }
|
||||
simdjson_inline document::operator double() noexcept(false) { return get_double(); }
|
||||
simdjson_inline document::operator std::string_view() noexcept(false) { return get_string(false); }
|
||||
simdjson_inline document::operator raw_json_string() noexcept(false) { return get_raw_json_string(); }
|
||||
simdjson_inline document::operator bool() noexcept(false) { return get_bool(); }
|
||||
simdjson_inline document::operator value() noexcept(false) { return get_value(); }
|
||||
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> document::count_elements() & noexcept {
|
||||
auto a = get_array();
|
||||
simdjson_result<size_t> answer = a.count_elements();
|
||||
/* If there was an array, we are now left pointing at its first element. */
|
||||
if(answer.error() == SUCCESS) { rewind(); }
|
||||
return answer;
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> document::count_fields() & noexcept {
|
||||
auto a = get_object();
|
||||
simdjson_result<size_t> answer = a.count_fields();
|
||||
/* If there was an object, we are now left pointing at its first element. */
|
||||
if(answer.error() == SUCCESS) { rewind(); }
|
||||
return answer;
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::at(size_t index) & noexcept {
|
||||
auto a = get_array();
|
||||
return a.at(index);
|
||||
}
|
||||
simdjson_inline simdjson_result<array_iterator> document::begin() & noexcept {
|
||||
return get_array().begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<array_iterator> document::end() & noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> document::find_field(std::string_view key) & noexcept {
|
||||
return start_or_resume_object().find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
|
||||
return start_or_resume_object().find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
|
||||
return start_or_resume_object().find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::find_field_unordered(const char *key) & noexcept {
|
||||
return start_or_resume_object().find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::operator[](std::string_view key) & noexcept {
|
||||
return start_or_resume_object()[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<value> document::operator[](const char *key) & noexcept {
|
||||
return start_or_resume_object()[key];
|
||||
}
|
||||
|
||||
simdjson_inline error_code document::consume() noexcept {
|
||||
auto error = iter.skip_child(0);
|
||||
if(error) { iter.abandon(); }
|
||||
return error;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> document::raw_json() noexcept {
|
||||
auto _iter = get_root_value_iterator();
|
||||
const uint8_t * starting_point{_iter.peek_start()};
|
||||
auto error = consume();
|
||||
if(error) { return error; }
|
||||
// After 'consume()', we could be left pointing just beyond the document, but that
|
||||
// is ok because we are not going to dereference the final pointer position, we just
|
||||
// use it to compute the length in bytes.
|
||||
const uint8_t * final_point{iter.unsafe_pointer()};
|
||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<json_type> document::type() noexcept {
|
||||
return get_root_value_iterator().type();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> document::is_scalar() noexcept {
|
||||
json_type this_type;
|
||||
auto error = type().get(this_type);
|
||||
if(error) { return error; }
|
||||
return ! ((this_type == json_type::array) || (this_type == json_type::object));
|
||||
}
|
||||
|
||||
simdjson_inline bool document::is_negative() noexcept {
|
||||
return get_root_value_iterator().is_root_negative();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> document::is_integer() noexcept {
|
||||
return get_root_value_iterator().is_root_integer(true);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<number_type> document::get_number_type() noexcept {
|
||||
return get_root_value_iterator().get_root_number_type(true);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<number> document::get_number() noexcept {
|
||||
return get_root_value_iterator().get_root_number(true);
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> document::raw_json_token() noexcept {
|
||||
auto _iter = get_root_value_iterator();
|
||||
return std::string_view(reinterpret_cast<const char*>(_iter.peek_start()), _iter.peek_start_length());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> document::at_pointer(std::string_view json_pointer) noexcept {
|
||||
rewind(); // Rewind the document each time at_pointer is called
|
||||
if (json_pointer.empty()) {
|
||||
return this->get_value();
|
||||
}
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
switch (t)
|
||||
{
|
||||
case json_type::array:
|
||||
return (*this).get_array().at_pointer(json_pointer);
|
||||
case json_type::object:
|
||||
return (*this).get_object().at_pointer(json_pointer);
|
||||
default:
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::document &&value
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::document>(
|
||||
std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document>(value)
|
||||
)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::simdjson_result(
|
||||
error_code error
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::document>(
|
||||
error
|
||||
)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::count_elements() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::count_fields() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_fields();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::at(size_t index) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::rewind() noexcept {
|
||||
if (error()) { return error(); }
|
||||
first.rewind();
|
||||
return SUCCESS;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::begin() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::end() & noexcept {
|
||||
return {};
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::find_field_unordered(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::find_field_unordered(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator[](std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator[](const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::find_field(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::find_field(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_array() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_array();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_object() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_object();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_uint64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_uint64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_int64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_int64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_double_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_string(bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_raw_json_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_raw_json_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_bool() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>();
|
||||
}
|
||||
template<typename T>
|
||||
simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get() && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document>(first).get<T>();
|
||||
}
|
||||
template<typename T>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get(T &out) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>(out);
|
||||
}
|
||||
template<typename T>
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get(T &out) && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document>(first).get<T>(out);
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get<SIMDJSON_IMPLEMENTATION::singlestage::document>() & noexcept = delete;
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get<SIMDJSON_IMPLEMENTATION::singlestage::document>() && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document>(first);
|
||||
}
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get<SIMDJSON_IMPLEMENTATION::singlestage::document>(SIMDJSON_IMPLEMENTATION::singlestage::document &out) & noexcept = delete;
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get<SIMDJSON_IMPLEMENTATION::singlestage::document>(SIMDJSON_IMPLEMENTATION::singlestage::document &out) && noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document>(first);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.type();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator SIMDJSON_IMPLEMENTATION::singlestage::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator SIMDJSON_IMPLEMENTATION::singlestage::object() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator uint64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator int64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator double() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator std::string_view() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator bool() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::operator SIMDJSON_IMPLEMENTATION::singlestage::value() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::at_end() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_end();
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline int32_t simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::current_depth() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_depth();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline document_reference::document_reference() noexcept : doc{nullptr} {}
|
||||
simdjson_inline document_reference::document_reference(document &d) noexcept : doc(&d) {}
|
||||
simdjson_inline void document_reference::rewind() noexcept { doc->rewind(); }
|
||||
simdjson_inline simdjson_result<array> document_reference::get_array() & noexcept { return doc->get_array(); }
|
||||
simdjson_inline simdjson_result<object> document_reference::get_object() & noexcept { return doc->get_object(); }
|
||||
/**
|
||||
* The document_reference instances are used primarily/solely for streams of JSON
|
||||
* documents.
|
||||
* We decided that calling 'get_double()' on the JSON document '1.233 blabla' should
|
||||
* give an error, so we check for trailing content.
|
||||
*
|
||||
* However, for streams of JSON documents, we want to be able to start from
|
||||
* "321" "321" "321"
|
||||
* and parse it successfully as a stream of JSON documents, calling get_uint64_in_string()
|
||||
* successfully each time.
|
||||
*
|
||||
* To achieve this result, we pass a 'false' to a get_root_value_iterator() method:
|
||||
* this indicates that we allow trailing content.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64() noexcept { return doc->get_root_value_iterator().get_root_uint64(false); }
|
||||
simdjson_inline simdjson_result<uint64_t> document_reference::get_uint64_in_string() noexcept { return doc->get_root_value_iterator().get_root_uint64_in_string(false); }
|
||||
simdjson_inline simdjson_result<int64_t> document_reference::get_int64() noexcept { return doc->get_root_value_iterator().get_root_int64(false); }
|
||||
simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string() noexcept { return doc->get_root_value_iterator().get_root_int64_in_string(false); }
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<double> document_reference::get_double_in_string() noexcept { return doc->get_root_value_iterator().get_root_double(false); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_string(bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(false, allow_replacement); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::get_wobbly_string() noexcept { return doc->get_root_value_iterator().get_root_wobbly_string(false); }
|
||||
simdjson_inline simdjson_result<raw_json_string> document_reference::get_raw_json_string() noexcept { return doc->get_root_value_iterator().get_root_raw_json_string(false); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::get_bool() noexcept { return doc->get_root_value_iterator().get_root_bool(false); }
|
||||
simdjson_inline simdjson_result<value> document_reference::get_value() noexcept { return doc->get_value(); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::is_null() noexcept { return doc->get_root_value_iterator().is_root_null(false); }
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline document_reference::operator array() & noexcept(false) { return array(*doc); }
|
||||
simdjson_inline document_reference::operator object() & noexcept(false) { return object(*doc); }
|
||||
simdjson_inline document_reference::operator uint64_t() noexcept(false) { return get_uint64(); }
|
||||
simdjson_inline document_reference::operator int64_t() noexcept(false) { return get_int64(); }
|
||||
simdjson_inline document_reference::operator double() noexcept(false) { return get_double(); }
|
||||
simdjson_inline document_reference::operator std::string_view() noexcept(false) { return std::string_view(*doc); }
|
||||
simdjson_inline document_reference::operator raw_json_string() noexcept(false) { return raw_json_string(*doc); }
|
||||
simdjson_inline document_reference::operator bool() noexcept(false) { return get_bool(); }
|
||||
simdjson_inline document_reference::operator value() noexcept(false) { return value(*doc); }
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> document_reference::count_elements() & noexcept { return doc->count_elements(); }
|
||||
simdjson_inline simdjson_result<size_t> document_reference::count_fields() & noexcept { return doc->count_fields(); }
|
||||
simdjson_inline simdjson_result<value> document_reference::at(size_t index) & noexcept { return doc->at(index); }
|
||||
simdjson_inline simdjson_result<array_iterator> document_reference::begin() & noexcept { return doc->begin(); }
|
||||
simdjson_inline simdjson_result<array_iterator> document_reference::end() & noexcept { return doc->end(); }
|
||||
simdjson_inline simdjson_result<value> document_reference::find_field(std::string_view key) & noexcept { return doc->find_field(key); }
|
||||
simdjson_inline simdjson_result<value> document_reference::find_field(const char *key) & noexcept { return doc->find_field(key); }
|
||||
simdjson_inline simdjson_result<value> document_reference::operator[](std::string_view key) & noexcept { return (*doc)[key]; }
|
||||
simdjson_inline simdjson_result<value> document_reference::operator[](const char *key) & noexcept { return (*doc)[key]; }
|
||||
simdjson_inline simdjson_result<value> document_reference::find_field_unordered(std::string_view key) & noexcept { return doc->find_field_unordered(key); }
|
||||
simdjson_inline simdjson_result<value> document_reference::find_field_unordered(const char *key) & noexcept { return doc->find_field_unordered(key); }
|
||||
simdjson_inline simdjson_result<json_type> document_reference::type() noexcept { return doc->type(); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::is_scalar() noexcept { return doc->is_scalar(); }
|
||||
simdjson_inline simdjson_result<const char *> document_reference::current_location() noexcept { return doc->current_location(); }
|
||||
simdjson_inline int32_t document_reference::current_depth() const noexcept { return doc->current_depth(); }
|
||||
simdjson_inline bool document_reference::is_negative() noexcept { return doc->is_negative(); }
|
||||
simdjson_inline simdjson_result<bool> document_reference::is_integer() noexcept { return doc->get_root_value_iterator().is_root_integer(false); }
|
||||
simdjson_inline simdjson_result<number_type> document_reference::get_number_type() noexcept { return doc->get_root_value_iterator().get_root_number_type(false); }
|
||||
simdjson_inline simdjson_result<number> document_reference::get_number() noexcept { return doc->get_root_value_iterator().get_root_number(false); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json_token() noexcept { return doc->raw_json_token(); }
|
||||
simdjson_inline simdjson_result<value> document_reference::at_pointer(std::string_view json_pointer) noexcept { return doc->at_pointer(json_pointer); }
|
||||
simdjson_inline simdjson_result<std::string_view> document_reference::raw_json() noexcept { return doc->raw_json();}
|
||||
simdjson_inline document_reference::operator document&() const noexcept { return *doc; }
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::document_reference value, error_code error)
|
||||
noexcept : implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>(value), error) {}
|
||||
|
||||
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::count_elements() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::count_fields() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_fields();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::at(size_t index) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::rewind() noexcept {
|
||||
if (error()) { return error(); }
|
||||
first.rewind();
|
||||
return SUCCESS;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::begin() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::end() & noexcept {
|
||||
return {};
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::find_field_unordered(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::find_field_unordered(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator[](std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator[](const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::find_field(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::find_field(const char *key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_array() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_array();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_object() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_object();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_uint64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_uint64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_int64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_int64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_double_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_string(bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_raw_json_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_raw_json_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_bool() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_value();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.type();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator SIMDJSON_IMPLEMENTATION::singlestage::array() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator SIMDJSON_IMPLEMENTATION::singlestage::object() & noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator uint64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator int64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator double() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator std::string_view() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator bool() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::operator SIMDJSON_IMPLEMENTATION::singlestage::value() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_INL_H
|
||||
@@ -0,0 +1,806 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A JSON document. It holds a json_iterator instance.
|
||||
*
|
||||
* Used by tokens to get text, and string buffer location.
|
||||
*
|
||||
* You must keep the document around during iteration.
|
||||
*/
|
||||
class document {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid document.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline document() noexcept = default;
|
||||
simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy
|
||||
simdjson_inline document(document &&other) noexcept = default;
|
||||
simdjson_inline document &operator=(const document &other) noexcept = delete;
|
||||
simdjson_inline document &operator=(document &&other) noexcept = default;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
*
|
||||
* @returns An object that can be used to iterate the array.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an array.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array> get_array() & noexcept;
|
||||
/**
|
||||
* Cast this JSON value to an object.
|
||||
*
|
||||
* @returns An object that can be used to look up or iterate fields.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<object> get_object() & noexcept;
|
||||
/**
|
||||
* Cast this JSON value to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
/**
|
||||
* Cast this JSON value (inside string) to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* Important: Calling get_string() twice on the same document is an error.
|
||||
*
|
||||
* @param Whether to allow a replacement character for unmatched surrogate pairs.
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
* The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/
|
||||
*
|
||||
* Important: Calling get_wobbly_string() twice on the same document is an error.
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a raw_json_string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
|
||||
*
|
||||
* @returns A pointer to the raw JSON for the given string.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a bool.
|
||||
*
|
||||
* @returns A bool value.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a value when the document is an object or an array.
|
||||
*
|
||||
* @returns A value if a JSON array or object cannot be found.
|
||||
* @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function).
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
/**
|
||||
* Checks if this JSON value is null. If and only if the value is
|
||||
* null, then it is consumed (we advance). If we find a token that
|
||||
* begins with 'n' but is not 'null', then an error is returned.
|
||||
*
|
||||
* @returns Whether the value is null.
|
||||
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
||||
*
|
||||
* You may use get_double(), get_bool(), get_uint64(), get_int64(),
|
||||
* get_object(), get_array(), get_raw_json_string(), or get_string() instead.
|
||||
*
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
/** @overload template<typename T> simdjson_result<T> get() & noexcept */
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value
|
||||
*
|
||||
* Be mindful that the document instance must remain in scope while you are accessing object, array and value instances.
|
||||
*
|
||||
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
/** @overload template<typename T> error_code get(T &out) & noexcept */
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
*
|
||||
* @returns An object that can be used to iterate the array.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
|
||||
*/
|
||||
simdjson_inline operator array() & noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to an object.
|
||||
*
|
||||
* @returns An object that can be used to look up or iterate fields.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
|
||||
*/
|
||||
simdjson_inline operator object() & noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a raw_json_string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
|
||||
*
|
||||
* @returns A pointer to the raw JSON for the given string.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline operator raw_json_string() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a bool.
|
||||
*
|
||||
* @returns A bool value.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a value.
|
||||
*
|
||||
* @returns A value value.
|
||||
* @exception if a JSON value cannot be found
|
||||
*/
|
||||
simdjson_inline operator value() noexcept(false);
|
||||
#endif
|
||||
/**
|
||||
* This method scans the array and counts the number of elements.
|
||||
* The count_elements method should always be called before you have begun
|
||||
* iterating through the array: it is expected that you are pointing at
|
||||
* the beginning of the array.
|
||||
* The runtime complexity is linear in the size of the array. After
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
/**
|
||||
* This method scans the object and counts the number of key-value pairs.
|
||||
* The count_fields method should always be called before you have begun
|
||||
* iterating through the object: it is expected that you are pointing at
|
||||
* the beginning of the object.
|
||||
* The runtime complexity is linear in the size of the object. After
|
||||
* calling this function, if successful, the object is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*
|
||||
* To check that an object is empty, it is more performant to use
|
||||
* the is_empty() method.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
/**
|
||||
* Get the value at the given index in the array. This function has linear-time complexity.
|
||||
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
|
||||
/**
|
||||
* Sentinel representing the end of the array.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> end() & noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
*
|
||||
* ```c++
|
||||
* simdjson::singlestage::parser parser;
|
||||
* auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
|
||||
* double z = obj.find_field("z");
|
||||
* double y = obj.find_field("y");
|
||||
* double x = obj.find_field("x");
|
||||
* ```
|
||||
*
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* You are expected to access keys only once. You should access the value corresponding to
|
||||
* a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string()
|
||||
* is an error.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object, without regard to key order.
|
||||
*
|
||||
* **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
|
||||
* and often appears negligible. It starts out normally, starting out at the last field; but if
|
||||
* the field is not found, it scans from the beginning of the object to see if it missed it. That
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. E.g., the array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* You are expected to access keys only once. You should access the value corresponding to a key
|
||||
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
|
||||
* is an error.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||
* "type()" returns json_type::null.
|
||||
*
|
||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||
* let it throw an exception).
|
||||
*
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_inline simdjson_result<json_type> type() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the document is a scalar (string, number, null, Boolean).
|
||||
* Returns false when there it is an array or object.
|
||||
*
|
||||
* @returns true if the type is string, number, null, Boolean
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the document is a negative number.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_inline bool is_negative() noexcept;
|
||||
/**
|
||||
* Checks whether the document is an integer number. Note that
|
||||
* this requires to partially parse the number string. If
|
||||
* the value is determined to be an integer, it may still
|
||||
* not parse properly as an integer in subsequent steps
|
||||
* (e.g., it might overflow).
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number) as quickly
|
||||
* as possible. This function does not fully validate the input. It is
|
||||
* useful when you only need to classify the numbers, without parsing them.
|
||||
*
|
||||
* If you are planning to retrieve the value or you need full validation,
|
||||
* consider using the get_number() method instead: it will fully parse
|
||||
* and validate the input, and give you access to the type:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function requires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
* parse the number value.
|
||||
*
|
||||
* @returns the type of the number
|
||||
*/
|
||||
simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
|
||||
/**
|
||||
* Attempt to parse an singlestage::number. An singlestage::number may
|
||||
* contain an integer value or a floating-point value, the simdjson
|
||||
* library will autodetect the type. Thus it is a dynamically typed
|
||||
* number. Before accessing the value, you must determine the detected
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
* number.get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer in [9223372036854775808,18446744073709551616)
|
||||
* You can recover the value by calling number.get_uint64() and you
|
||||
* have that number.is_uint64() is true.
|
||||
*
|
||||
* Otherwise, number.get_number_type() has value number_type::floating_point_number
|
||||
* and we have a binary64 number.
|
||||
* You can recover the value by calling number.get_double() and you
|
||||
* have that number.is_double() is true.
|
||||
*
|
||||
* You must check the type before accessing the value: it is an error
|
||||
* to call "get_int64()" when number.get_number_type() is not
|
||||
* number_type::signed_integer and when number.is_int64() is false.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
/**
|
||||
* Get the raw JSON for this token.
|
||||
*
|
||||
* The string_view will always point into the input buffer.
|
||||
*
|
||||
* The string_view will start at the beginning of the token, and include the entire token
|
||||
* *as well as all spaces until the next token (or EOF).* This means, for example, that a
|
||||
* string token always begins with a " and is always terminated by the final ", possibly
|
||||
* followed by a number of spaces.
|
||||
*
|
||||
* The string_view is *not* null-terminated. If this is a scalar (string, number,
|
||||
* boolean, or null), the character after the end of the string_view may be the padded buffer.
|
||||
*
|
||||
* Tokens include:
|
||||
* - {
|
||||
* - [
|
||||
* - "a string (possibly with UTF-8 or backslashed characters like \\\")".
|
||||
* - -1.2e-100
|
||||
* - true
|
||||
* - false
|
||||
* - null
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
/**
|
||||
* Reset the iterator inside the document instance so we are pointing back at the
|
||||
* beginning of the document, as if it had just been created. It invalidates all
|
||||
* values, objects and arrays that you have created so far (including unescaped strings).
|
||||
*/
|
||||
inline void rewind() noexcept;
|
||||
/**
|
||||
* Returns debugging information.
|
||||
*/
|
||||
inline std::string to_debug_string() noexcept;
|
||||
/**
|
||||
* Some unrecoverable error conditions may render the document instance unusable.
|
||||
* The is_alive() method returns true when the document is still suitable.
|
||||
*/
|
||||
inline bool is_alive() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
inline simdjson_result<const char *> current_location() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns true if this document has been fully parsed.
|
||||
* If you have consumed the whole document and at_end() returns
|
||||
* false, then there may be trailing content.
|
||||
*/
|
||||
inline bool at_end() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current depth in the document if in bounds.
|
||||
*
|
||||
* E.g.,
|
||||
* 0 = finished with document
|
||||
* 1 = document root value (could be [ or {, not yet known)
|
||||
* 2 = , or } inside root array/object
|
||||
* 3 = key or value inside root array/object.
|
||||
*/
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("/foo/a/1") == 20
|
||||
*
|
||||
* It is allowed for a key to be the empty string:
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("//a/1") == 20
|
||||
*
|
||||
* Note that at_pointer() automatically calls rewind between each call. Thus
|
||||
* all values, objects and arrays that you have created so far (including unescaped strings)
|
||||
* are invalidated. After calling at_pointer, you need to consume the result: string values
|
||||
* should be stored in your own variables, arrays should be decoded and stored in your own array-like
|
||||
* structures and so forth.
|
||||
*
|
||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
||||
*
|
||||
* @return The value associated with the given JSON pointer, or:
|
||||
* - NO_SUCH_FIELD if a field does not exist in an object
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
|
||||
* - INCORRECT_TYPE if a non-integer is used to access an array
|
||||
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
|
||||
* - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function).
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
/**
|
||||
* Consumes the document and returns a string_view instance corresponding to the
|
||||
* document as represented in JSON. It points inside the original byte array containing
|
||||
* the JSON document.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
protected:
|
||||
/**
|
||||
* Consumes the document.
|
||||
*/
|
||||
simdjson_inline error_code consume() noexcept;
|
||||
|
||||
simdjson_inline document(singlestage::json_iterator &&iter) noexcept;
|
||||
simdjson_inline const uint8_t *text(uint32_t idx) const noexcept;
|
||||
|
||||
simdjson_inline value_iterator resume_value_iterator() noexcept;
|
||||
simdjson_inline value_iterator get_root_value_iterator() noexcept;
|
||||
simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
|
||||
static simdjson_inline document start(singlestage::json_iterator &&iter) noexcept;
|
||||
|
||||
//
|
||||
// Fields
|
||||
//
|
||||
json_iterator iter{}; ///< Current position in the document
|
||||
static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0
|
||||
|
||||
friend class array_iterator;
|
||||
friend class value;
|
||||
friend class singlestage::parser;
|
||||
friend class object;
|
||||
friend class array;
|
||||
friend class field;
|
||||
friend class token;
|
||||
friend class document_reference;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A document_reference is a thin wrapper around a document reference instance.
|
||||
*/
|
||||
class document_reference {
|
||||
public:
|
||||
simdjson_inline document_reference() noexcept;
|
||||
simdjson_inline document_reference(document &d) noexcept;
|
||||
simdjson_inline document_reference(const document_reference &other) noexcept = default;
|
||||
simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default;
|
||||
simdjson_inline void rewind() noexcept;
|
||||
simdjson_inline simdjson_result<array> get_array() & noexcept;
|
||||
simdjson_inline simdjson_result<object> get_object() & noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<value> get_value() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
simdjson_inline operator document&() const noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline operator array() & noexcept(false);
|
||||
simdjson_inline operator object() & noexcept(false);
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
simdjson_inline operator raw_json_string() noexcept(false);
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
simdjson_inline operator value() noexcept(false);
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
simdjson_inline simdjson_result<value> at(size_t index) & noexcept;
|
||||
simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
|
||||
simdjson_inline simdjson_result<array_iterator> end() & noexcept;
|
||||
simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) & noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<json_type> type() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
simdjson_inline bool is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
private:
|
||||
document *doc{nullptr};
|
||||
};
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::document> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::document &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
simdjson_inline error_code rewind() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> get_array() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> get_object() & noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> get_value() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() & noexcept;
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() && noexcept;
|
||||
|
||||
template<typename T> simdjson_inline error_code get(T &out) & noexcept;
|
||||
template<typename T> simdjson_inline error_code get(T &out) && noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::array() & noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::object() & noexcept(false);
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false);
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::value() noexcept(false);
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at(size_t index) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> begin() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> end() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> type() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
simdjson_inline bool at_end() const noexcept;
|
||||
simdjson_inline bool is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> get_number_type() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> get_number() noexcept;
|
||||
/** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::document_reference> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::document_reference value, error_code error) noexcept;
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
simdjson_inline error_code rewind() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> get_array() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> get_object() & noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> get_value() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::array() & noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::object() & noexcept(false);
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false);
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::value() noexcept(false);
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at(size_t index) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> begin() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> end() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(const char *key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> type() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> get_number_type() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> get_number() noexcept;
|
||||
/** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_DOCUMENT_H
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_FIELD_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_FIELD_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/field.h"
|
||||
#include "simdjson/generic/singlestage/value-inl.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
// clang 6 doesn't think the default constructor can be noexcept, so we make it explicit
|
||||
simdjson_inline field::field() noexcept : std::pair<raw_json_string, singlestage::value>() {}
|
||||
|
||||
simdjson_inline field::field(raw_json_string key, singlestage::value &&value) noexcept
|
||||
: std::pair<raw_json_string, singlestage::value>(key, std::forward<singlestage::value>(value))
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<field> field::start(value_iterator &parent_iter) noexcept {
|
||||
raw_json_string key;
|
||||
SIMDJSON_TRY( parent_iter.field_key().get(key) );
|
||||
SIMDJSON_TRY( parent_iter.field_value() );
|
||||
return field::start(parent_iter, key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<field> field::start(const value_iterator &parent_iter, raw_json_string key) noexcept {
|
||||
return field(key, parent_iter.child());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> field::unescaped_key(bool allow_replacement) 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(), allow_replacement);
|
||||
first.consume();
|
||||
return answer;
|
||||
}
|
||||
|
||||
simdjson_inline raw_json_string field::key() const noexcept {
|
||||
SIMDJSON_ASSUME(first.buf != nullptr); // We would like to call .alive() by Visual Studio won't let us.
|
||||
return first;
|
||||
}
|
||||
|
||||
simdjson_inline value &field::value() & noexcept {
|
||||
return second;
|
||||
}
|
||||
|
||||
simdjson_inline value field::value() && noexcept {
|
||||
return std::forward<field>(*this).second;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::field &&value
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::field>(
|
||||
std::forward<SIMDJSON_IMPLEMENTATION::singlestage::field>(value)
|
||||
)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field>::simdjson_result(
|
||||
error_code error
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::field>(error)
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field>::key() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.key();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field>::unescaped_key(bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescaped_key(allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field>::value() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::move(first.value());
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_FIELD_INL_H
|
||||
@@ -0,0 +1,82 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_FIELD_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_FIELD_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A JSON field (key/value pair) in an object.
|
||||
*
|
||||
* Returned from object iteration.
|
||||
*
|
||||
* Extends from std::pair<raw_json_string, value> so you can use C++ algorithms that rely on pairs.
|
||||
*/
|
||||
class field : public std::pair<raw_json_string, value> {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid field.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline field() noexcept;
|
||||
|
||||
/**
|
||||
* Get the key as a string_view (for higher speed, consider raw_key).
|
||||
* We deliberately use a more cumbersome name (unescaped_key) to force users
|
||||
* to think twice about using it.
|
||||
*
|
||||
* This consumes the key: once you have called unescaped_key(), you cannot
|
||||
* call it again nor can you call key().
|
||||
*/
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescaped_key(bool allow_replacement) noexcept;
|
||||
/**
|
||||
* Get the key as a raw_json_string. Can be used for direct comparison with
|
||||
* an unescaped C string: e.g., key() == "test".
|
||||
*/
|
||||
simdjson_inline raw_json_string key() const noexcept;
|
||||
/**
|
||||
* Get the field value.
|
||||
*/
|
||||
simdjson_inline singlestage::value &value() & noexcept;
|
||||
/**
|
||||
* @overload singlestage::value &singlestage::value() & noexcept
|
||||
*/
|
||||
simdjson_inline singlestage::value value() && noexcept;
|
||||
|
||||
protected:
|
||||
simdjson_inline field(raw_json_string key, singlestage::value &&value) noexcept;
|
||||
static simdjson_inline simdjson_result<field> start(value_iterator &parent_iter) noexcept;
|
||||
static simdjson_inline simdjson_result<field> start(const value_iterator &parent_iter, raw_json_string key) noexcept;
|
||||
friend struct simdjson_result<field>;
|
||||
friend class object_iterator;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::field> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::field &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> unescaped_key(bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> key() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> value() noexcept;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_FIELD_H
|
||||
@@ -0,0 +1,409 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_INL_H
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/parser.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/logger-inl.h"
|
||||
#include "simdjson/generic/singlestage/parser-inl.h"
|
||||
#include "simdjson/generic/singlestage/token_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline json_iterator::json_iterator(json_iterator &&other) noexcept
|
||||
: token(std::forward<token_iterator>(other.token)),
|
||||
parser{other.parser},
|
||||
_string_buf_loc{other._string_buf_loc},
|
||||
error{other.error},
|
||||
_depth{other._depth},
|
||||
_root{other._root},
|
||||
_streaming{other._streaming}
|
||||
{
|
||||
other.parser = nullptr;
|
||||
}
|
||||
simdjson_inline json_iterator &json_iterator::operator=(json_iterator &&other) noexcept {
|
||||
token = other.token;
|
||||
parser = other.parser;
|
||||
_string_buf_loc = other._string_buf_loc;
|
||||
error = other.error;
|
||||
_depth = other._depth;
|
||||
_root = other._root;
|
||||
_streaming = other._streaming;
|
||||
other.parser = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
simdjson_inline json_iterator::json_iterator(const uint8_t *buf, singlestage::parser *_parser) noexcept
|
||||
: token(buf, &_parser->implementation->structural_indexes[0]),
|
||||
parser{_parser},
|
||||
_string_buf_loc{parser->string_buf.get()},
|
||||
_depth{1},
|
||||
_root{parser->implementation->structural_indexes.get()},
|
||||
_streaming{false}
|
||||
|
||||
{
|
||||
logger::log_headers();
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void json_iterator::rewind() noexcept {
|
||||
token.set_position( root_position() );
|
||||
logger::log_headers(); // We start again
|
||||
_string_buf_loc = parser->string_buf.get();
|
||||
_depth = 1;
|
||||
}
|
||||
|
||||
inline bool json_iterator::balanced() const noexcept {
|
||||
token_iterator ti(token);
|
||||
int32_t count{0};
|
||||
ti.set_position( root_position() );
|
||||
while(ti.peek() <= peek_last()) {
|
||||
switch (*ti.return_current_and_advance())
|
||||
{
|
||||
case '[': case '{':
|
||||
count++;
|
||||
break;
|
||||
case ']': case '}':
|
||||
count--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
|
||||
// GCC 7 warns when the first line of this function is inlined away into oblivion due to the caller
|
||||
// relating depth and parent_depth, which is a desired effect. The warning does not show up if the
|
||||
// skip_child() function is not marked inline).
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
simdjson_warn_unused simdjson_inline error_code json_iterator::skip_child(depth_t parent_depth) noexcept {
|
||||
if (depth() <= parent_depth) { return SUCCESS; }
|
||||
switch (*return_current_and_advance()) {
|
||||
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
|
||||
// *missing* braces, then future lookups are not in the object/arrays they think they are,
|
||||
// violating the rule "validate enough structure that the user can be confident they are
|
||||
// looking at the right values."
|
||||
// PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
|
||||
|
||||
// For the first open array/object in a value, we've already incremented depth, so keep it the same
|
||||
// We never stop at colon, but if we did, it wouldn't affect depth
|
||||
case '[': case '{': case ':':
|
||||
logger::log_start_value(*this, "skip");
|
||||
break;
|
||||
// If there is a comma, we have just finished a value in an array/object, and need to get back in
|
||||
case ',':
|
||||
logger::log_value(*this, "skip");
|
||||
break;
|
||||
// ] or } means we just finished a value and need to jump out of the array/object
|
||||
case ']': case '}':
|
||||
logger::log_end_value(*this, "skip");
|
||||
_depth--;
|
||||
if (depth() <= parent_depth) { return SUCCESS; }
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
// If there are no more tokens, the parent is incomplete.
|
||||
if (at_end()) { return report_error(INCOMPLETE_ARRAY_OR_OBJECT, "Missing [ or { at start"); }
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
break;
|
||||
case '"':
|
||||
if(*peek() == ':') {
|
||||
// We are at a key!!!
|
||||
// This might happen if you just started an object and you skip it immediately.
|
||||
// Performance note: it would be nice to get rid of this check as it is somewhat
|
||||
// expensive.
|
||||
// https://github.com/simdjson/simdjson/issues/1742
|
||||
logger::log_value(*this, "key");
|
||||
return_current_and_advance(); // eat up the ':'
|
||||
break; // important!!!
|
||||
}
|
||||
simdjson_fallthrough;
|
||||
// Anything else must be a scalar value
|
||||
default:
|
||||
// For the first scalar, we will have incremented depth already, so we decrement it here.
|
||||
logger::log_value(*this, "skip");
|
||||
_depth--;
|
||||
if (depth() <= parent_depth) { return SUCCESS; }
|
||||
break;
|
||||
}
|
||||
|
||||
// Now that we've considered the first value, we only increment/decrement for arrays/objects
|
||||
while (position() < end_position()) {
|
||||
switch (*return_current_and_advance()) {
|
||||
case '[': case '{':
|
||||
logger::log_start_value(*this, "skip");
|
||||
_depth++;
|
||||
break;
|
||||
// TODO consider whether matching braces is a requirement: if non-matching braces indicates
|
||||
// *missing* braces, then future lookups are not in the object/arrays they think they are,
|
||||
// violating the rule "validate enough structure that the user can be confident they are
|
||||
// looking at the right values."
|
||||
// PERF TODO we can eliminate the switch here with a lookup of how much to add to depth
|
||||
case ']': case '}':
|
||||
logger::log_end_value(*this, "skip");
|
||||
_depth--;
|
||||
if (depth() <= parent_depth) { return SUCCESS; }
|
||||
break;
|
||||
default:
|
||||
logger::log_value(*this, "skip", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return report_error(TAPE_ERROR, "not enough close braces");
|
||||
}
|
||||
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
simdjson_inline bool json_iterator::at_root() const noexcept {
|
||||
return position() == root_position();
|
||||
}
|
||||
|
||||
simdjson_inline bool json_iterator::is_single_token() const noexcept {
|
||||
return parser->implementation->n_structural_indexes == 1;
|
||||
}
|
||||
|
||||
simdjson_inline bool json_iterator::streaming() const noexcept {
|
||||
return _streaming;
|
||||
}
|
||||
|
||||
simdjson_inline token_position json_iterator::root_position() const noexcept {
|
||||
return _root;
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::assert_at_document_depth() const noexcept {
|
||||
SIMDJSON_ASSUME( _depth == 1 );
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::assert_at_root() const noexcept {
|
||||
SIMDJSON_ASSUME( _depth == 1 );
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
// Under Visual Studio, the next SIMDJSON_ASSUME fails with: the argument
|
||||
// has side effects that will be discarded.
|
||||
SIMDJSON_ASSUME( token.position() == _root );
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::assert_more_tokens(uint32_t required_tokens) const noexcept {
|
||||
assert_valid_position(token._position + required_tokens - 1);
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::assert_valid_position(token_position position) const noexcept {
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
SIMDJSON_ASSUME( position >= &parser->implementation->structural_indexes[0] );
|
||||
SIMDJSON_ASSUME( position < &parser->implementation->structural_indexes[parser->implementation->n_structural_indexes] );
|
||||
#endif
|
||||
}
|
||||
|
||||
simdjson_inline bool json_iterator::at_end() const noexcept {
|
||||
return position() == end_position();
|
||||
}
|
||||
simdjson_inline token_position json_iterator::end_position() const noexcept {
|
||||
uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
|
||||
return &parser->implementation->structural_indexes[n_structural_indexes];
|
||||
}
|
||||
|
||||
inline std::string json_iterator::to_string() const noexcept {
|
||||
if( !is_alive() ) { return "dead json_iterator instance"; }
|
||||
const char * current_structural = reinterpret_cast<const char *>(token.peek());
|
||||
return std::string("json_iterator [ depth : ") + std::to_string(_depth)
|
||||
+ std::string(", structural : '") + std::string(current_structural,1)
|
||||
+ std::string("', offset : ") + std::to_string(token.current_offset())
|
||||
+ std::string("', error : ") + error_message(error)
|
||||
+ std::string(" ]");
|
||||
}
|
||||
|
||||
inline simdjson_result<const char *> json_iterator::current_location() const noexcept {
|
||||
if (!is_alive()) { // Unrecoverable error
|
||||
if (!at_root()) {
|
||||
return reinterpret_cast<const char *>(token.peek(-1));
|
||||
} else {
|
||||
return reinterpret_cast<const char *>(token.peek());
|
||||
}
|
||||
}
|
||||
if (at_end()) {
|
||||
return OUT_OF_BOUNDS;
|
||||
}
|
||||
return reinterpret_cast<const char *>(token.peek());
|
||||
}
|
||||
|
||||
simdjson_inline bool json_iterator::is_alive() const noexcept {
|
||||
return parser;
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::abandon() noexcept {
|
||||
parser = nullptr;
|
||||
_depth = 0;
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *json_iterator::return_current_and_advance() noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens();
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.return_current_and_advance();
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *json_iterator::unsafe_pointer() const noexcept {
|
||||
// deliberately done without safety guard:
|
||||
return token.peek(0);
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *json_iterator::peek(int32_t delta) const noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens(delta+1);
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek(delta);
|
||||
}
|
||||
|
||||
simdjson_inline uint32_t json_iterator::peek_length(int32_t delta) const noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_more_tokens(delta+1);
|
||||
#endif // #if SIMDJSON_CHECK_EOF
|
||||
return token.peek_length(delta);
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *json_iterator::peek(token_position position) const noexcept {
|
||||
// todo: currently we require end-of-string buffering, but the following
|
||||
// assert_valid_position should be turned on if/when we lift that condition.
|
||||
// assert_valid_position(position);
|
||||
// This is almost surely related to SIMDJSON_CHECK_EOF but given that SIMDJSON_CHECK_EOF
|
||||
// is ON by default, we have no choice but to disable it for real with a comment.
|
||||
return token.peek(position);
|
||||
}
|
||||
|
||||
simdjson_inline uint32_t json_iterator::peek_length(token_position position) const noexcept {
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
assert_valid_position(position);
|
||||
#endif // SIMDJSON_CHECK_EOF
|
||||
return token.peek_length(position);
|
||||
}
|
||||
|
||||
simdjson_inline token_position json_iterator::last_position() const noexcept {
|
||||
// The following line fails under some compilers...
|
||||
// SIMDJSON_ASSUME(parser->implementation->n_structural_indexes > 0);
|
||||
// since it has side-effects.
|
||||
uint32_t n_structural_indexes{parser->implementation->n_structural_indexes};
|
||||
SIMDJSON_ASSUME(n_structural_indexes > 0);
|
||||
return &parser->implementation->structural_indexes[n_structural_indexes - 1];
|
||||
}
|
||||
simdjson_inline const uint8_t *json_iterator::peek_last() const noexcept {
|
||||
return token.peek(last_position());
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::ascend_to(depth_t parent_depth) noexcept {
|
||||
SIMDJSON_ASSUME(parent_depth >= 0 && parent_depth < INT32_MAX - 1);
|
||||
SIMDJSON_ASSUME(_depth == parent_depth + 1);
|
||||
_depth = parent_depth;
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::descend_to(depth_t child_depth) noexcept {
|
||||
SIMDJSON_ASSUME(child_depth >= 1 && child_depth < INT32_MAX);
|
||||
SIMDJSON_ASSUME(_depth == child_depth - 1);
|
||||
_depth = child_depth;
|
||||
}
|
||||
|
||||
simdjson_inline depth_t json_iterator::depth() const noexcept {
|
||||
return _depth;
|
||||
}
|
||||
|
||||
simdjson_inline uint8_t *&json_iterator::string_buf_loc() noexcept {
|
||||
return _string_buf_loc;
|
||||
}
|
||||
|
||||
simdjson_inline error_code json_iterator::report_error(error_code _error, const char *message) noexcept {
|
||||
SIMDJSON_ASSUME(_error != SUCCESS && _error != UNINITIALIZED && _error != INCORRECT_TYPE && _error != NO_SUCH_FIELD);
|
||||
logger::log_error(*this, message);
|
||||
error = _error;
|
||||
return error;
|
||||
}
|
||||
|
||||
simdjson_inline token_position json_iterator::position() const noexcept {
|
||||
return token.position();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape(raw_json_string in, bool allow_replacement) noexcept {
|
||||
return parser->unescape(in, _string_buf_loc, allow_replacement);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> json_iterator::unescape_wobbly(raw_json_string in) noexcept {
|
||||
return parser->unescape_wobbly(in, _string_buf_loc);
|
||||
}
|
||||
|
||||
simdjson_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);
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
#ifndef SIMDJSON_CLANG_VISUAL_STUDIO
|
||||
SIMDJSON_ASSUME(size_t(child_depth) < parser->max_depth());
|
||||
SIMDJSON_ASSUME(position >= parser->start_positions[child_depth]);
|
||||
#endif
|
||||
#endif
|
||||
token.set_position(position);
|
||||
_depth = child_depth;
|
||||
}
|
||||
|
||||
simdjson_inline error_code json_iterator::consume_character(char c) noexcept {
|
||||
if (*peek() == c) {
|
||||
return_current_and_advance();
|
||||
return SUCCESS;
|
||||
}
|
||||
return TAPE_ERROR;
|
||||
}
|
||||
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
|
||||
simdjson_inline token_position json_iterator::start_position(depth_t depth) const noexcept {
|
||||
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||
return size_t(depth) < parser->max_depth() ? parser->start_positions[depth] : 0;
|
||||
}
|
||||
|
||||
simdjson_inline void json_iterator::set_start_position(depth_t depth, token_position position) noexcept {
|
||||
SIMDJSON_ASSUME(size_t(depth) < parser->max_depth());
|
||||
if(size_t(depth) < parser->max_depth()) { parser->start_positions[depth] = position; }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
simdjson_inline error_code json_iterator::optional_error(error_code _error, const char *message) noexcept {
|
||||
SIMDJSON_ASSUME(_error == INCORRECT_TYPE || _error == NO_SUCH_FIELD);
|
||||
logger::log_error(*this, message);
|
||||
return _error;
|
||||
}
|
||||
|
||||
|
||||
simdjson_warn_unused simdjson_inline bool json_iterator::copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept {
|
||||
// This function is not expected to be called in performance-sensitive settings.
|
||||
// Let us guard against silly cases:
|
||||
if((N < max_len) || (N == 0)) { return false; }
|
||||
// Copy to the buffer.
|
||||
std::memcpy(tmpbuf, json, max_len);
|
||||
if(N > max_len) { // We pad whatever remains with ' '.
|
||||
std::memset(tmpbuf + max_len, ' ', N - max_len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator>(error) {}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_INL_H
|
||||
@@ -0,0 +1,324 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/token_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* Iterates through JSON tokens, keeping track of depth and string buffer.
|
||||
*
|
||||
* @private This is not intended for external use.
|
||||
*/
|
||||
class json_iterator {
|
||||
protected:
|
||||
token_iterator token{};
|
||||
singlestage::parser *parser{};
|
||||
/**
|
||||
* Next free location in the string buffer.
|
||||
*
|
||||
* Used by raw_json_string::unescape() to have a place to unescape strings to.
|
||||
*/
|
||||
uint8_t *_string_buf_loc{};
|
||||
/**
|
||||
* JSON error, if there is one.
|
||||
*
|
||||
* INCORRECT_TYPE and NO_SUCH_FIELD are *not* stored here, ever.
|
||||
*
|
||||
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
|
||||
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
|
||||
* this is not elided, we should make sure it's at least not using up a register. Failing that,
|
||||
* we should store it in document so there's only one of them.
|
||||
*/
|
||||
error_code error{SUCCESS};
|
||||
/**
|
||||
* Depth of the current token in the JSON.
|
||||
*
|
||||
* - 0 = finished with document
|
||||
* - 1 = document root value (could be [ or {, not yet known)
|
||||
* - 2 = , or } inside root array/object
|
||||
* - 3 = key or value inside root array/object.
|
||||
*/
|
||||
depth_t _depth{};
|
||||
/**
|
||||
* Beginning of the document indexes.
|
||||
* Normally we have root == parser->implementation->structural_indexes.get()
|
||||
* but this may differ, especially in streaming mode (where we have several
|
||||
* documents);
|
||||
*/
|
||||
token_position _root{};
|
||||
/**
|
||||
* Normally, a json_iterator operates over a single document, but in
|
||||
* some cases, we may have a stream of documents. This attribute is meant
|
||||
* as meta-data: the json_iterator works the same irrespective of the
|
||||
* value of this attribute.
|
||||
*/
|
||||
bool _streaming{false};
|
||||
|
||||
public:
|
||||
simdjson_inline json_iterator() noexcept = default;
|
||||
simdjson_inline json_iterator(json_iterator &&other) noexcept;
|
||||
simdjson_inline json_iterator &operator=(json_iterator &&other) noexcept;
|
||||
simdjson_inline explicit json_iterator(const json_iterator &other) noexcept = default;
|
||||
simdjson_inline json_iterator &operator=(const json_iterator &other) noexcept = default;
|
||||
/**
|
||||
* Skips a JSON value, whether it is a scalar, array or object.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code skip_child(depth_t parent_depth) noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the iterator is still at the start
|
||||
*/
|
||||
simdjson_inline bool at_root() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether we should be expected to run in streaming
|
||||
* mode (iterating over many documents). It is pure metadata
|
||||
* that does not affect how the iterator works. It is used by
|
||||
* start_root_array() and start_root_object().
|
||||
*/
|
||||
simdjson_inline bool streaming() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the root value iterator
|
||||
*/
|
||||
simdjson_inline token_position root_position() const noexcept;
|
||||
/**
|
||||
* Assert that we are at the document depth (== 1)
|
||||
*/
|
||||
simdjson_inline void assert_at_document_depth() const noexcept;
|
||||
/**
|
||||
* Assert that we are at the root of the document
|
||||
*/
|
||||
simdjson_inline void assert_at_root() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the iterator is at the EOF mark
|
||||
*/
|
||||
simdjson_inline bool at_end() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the iterator is live (has not been moved).
|
||||
*/
|
||||
simdjson_inline bool is_alive() const noexcept;
|
||||
|
||||
/**
|
||||
* Abandon this iterator, setting depth to 0 (as if the document is finished).
|
||||
*/
|
||||
simdjson_inline void abandon() noexcept;
|
||||
|
||||
/**
|
||||
* Advance the current token without modifying depth.
|
||||
*/
|
||||
simdjson_inline const uint8_t *return_current_and_advance() noexcept;
|
||||
|
||||
/**
|
||||
* Returns true if there is a single token in the index (i.e., it is
|
||||
* a JSON with a scalar value such as a single number).
|
||||
*
|
||||
* @return whether there is a single token
|
||||
*/
|
||||
simdjson_inline bool is_single_token() const noexcept;
|
||||
|
||||
/**
|
||||
* Assert that there are at least the given number of tokens left.
|
||||
*
|
||||
* Has no effect in release builds.
|
||||
*/
|
||||
simdjson_inline void assert_more_tokens(uint32_t required_tokens=1) const noexcept;
|
||||
/**
|
||||
* Assert that the given position addresses an actual token (is within bounds).
|
||||
*
|
||||
* Has no effect in release builds.
|
||||
*/
|
||||
simdjson_inline void assert_valid_position(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the JSON text for a given token (relative).
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
|
||||
*
|
||||
* TODO consider a string_view, assuming the length will get stripped out by the optimizer when
|
||||
* it isn't used ...
|
||||
*/
|
||||
simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
|
||||
/**
|
||||
* Get the maximum length of the JSON text for the current token (or relative).
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = next token, -1 = prev token.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
|
||||
/**
|
||||
* Get a pointer to the current location in the input buffer.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* You may be pointing outside of the input buffer: it is not generally
|
||||
* safe to dereference this pointer.
|
||||
*/
|
||||
simdjson_inline const uint8_t *unsafe_pointer() const noexcept;
|
||||
/**
|
||||
* Get the JSON text for a given token.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param position The position of the token to retrieve.
|
||||
*
|
||||
* TODO consider a string_view, assuming the length will get stripped out by the optimizer when
|
||||
* it isn't used ...
|
||||
*/
|
||||
simdjson_inline const uint8_t *peek(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the maximum length of the JSON text for the current token (or relative).
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param position The position of the token to retrieve.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the JSON text for the last token in the document.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* TODO consider a string_view, assuming the length will get stripped out by the optimizer when
|
||||
* it isn't used ...
|
||||
*/
|
||||
simdjson_inline const uint8_t *peek_last() const noexcept;
|
||||
|
||||
/**
|
||||
* Ascend one level.
|
||||
*
|
||||
* Validates that the depth - 1 == parent_depth.
|
||||
*
|
||||
* @param parent_depth the expected parent depth.
|
||||
*/
|
||||
simdjson_inline void ascend_to(depth_t parent_depth) noexcept;
|
||||
|
||||
/**
|
||||
* Descend one level.
|
||||
*
|
||||
* Validates that the new depth == child_depth.
|
||||
*
|
||||
* @param child_depth the expected child depth.
|
||||
*/
|
||||
simdjson_inline void descend_to(depth_t child_depth) noexcept;
|
||||
simdjson_inline void descend_to(depth_t child_depth, int32_t delta) noexcept;
|
||||
|
||||
/**
|
||||
* Get current depth.
|
||||
*/
|
||||
simdjson_inline depth_t depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get current (writeable) location in the string buffer.
|
||||
*/
|
||||
simdjson_inline uint8_t *&string_buf_loc() noexcept;
|
||||
|
||||
/**
|
||||
* Report an unrecoverable error, preventing further iteration.
|
||||
*
|
||||
* @param error The error to report. Must not be SUCCESS, UNINITIALIZED, INCORRECT_TYPE, or NO_SUCH_FIELD.
|
||||
* @param message An error message to report with the error.
|
||||
*/
|
||||
simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
|
||||
|
||||
/**
|
||||
* Log error, but don't stop iteration.
|
||||
* @param error The error to report. Must be INCORRECT_TYPE, or NO_SUCH_FIELD.
|
||||
* @param message An error message to report with the error.
|
||||
*/
|
||||
simdjson_inline error_code optional_error(error_code error, const char *message) noexcept;
|
||||
|
||||
/**
|
||||
* Take an input in json containing max_len characters and attempt to copy it over to tmpbuf, a buffer with
|
||||
* N bytes of capacity. It will return false if N is too small (smaller than max_len) of if it is zero.
|
||||
* The buffer (tmpbuf) is padded with space characters.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline bool copy_to_buffer(const uint8_t *json, uint32_t max_len, uint8_t *tmpbuf, size_t N) noexcept;
|
||||
|
||||
simdjson_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_inline simdjson_result<std::string_view> unescape(raw_json_string in, bool allow_replacement) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> unescape_wobbly(raw_json_string in) noexcept;
|
||||
simdjson_inline void reenter_child(token_position position, depth_t child_depth) noexcept;
|
||||
|
||||
simdjson_inline error_code consume_character(char c) noexcept;
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
simdjson_inline token_position start_position(depth_t depth) const noexcept;
|
||||
simdjson_inline void set_start_position(depth_t depth, token_position position) noexcept;
|
||||
#endif
|
||||
|
||||
/* Useful for debugging and logging purposes. */
|
||||
inline std::string to_string() const noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
inline simdjson_result<const char *> current_location() const noexcept;
|
||||
|
||||
/**
|
||||
* Updates this json iterator so that it is back at the beginning of the document,
|
||||
* as if it had just been created.
|
||||
*/
|
||||
inline void rewind() noexcept;
|
||||
/**
|
||||
* This checks whether the {,},[,] are balanced so that the document
|
||||
* ends with proper zero depth. This requires scanning the whole document
|
||||
* and it may be expensive. It is expected that it will be rarely called.
|
||||
* It does not attempt to match { with } and [ with ].
|
||||
*/
|
||||
inline bool balanced() const noexcept;
|
||||
protected:
|
||||
simdjson_inline json_iterator(const uint8_t *buf, singlestage::parser *parser) noexcept;
|
||||
/// The last token before the end
|
||||
simdjson_inline token_position last_position() const noexcept;
|
||||
/// The token *at* the end. This points at gibberish and should only be used for comparison.
|
||||
simdjson_inline token_position end_position() const noexcept;
|
||||
/// The end of the buffer.
|
||||
simdjson_inline token_position end() const noexcept;
|
||||
|
||||
friend class document;
|
||||
friend class object;
|
||||
friend class array;
|
||||
friend class value;
|
||||
friend class raw_json_string;
|
||||
friend class parser;
|
||||
friend class value_iterator;
|
||||
template <typename... Args>
|
||||
friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
|
||||
template <typename... Args>
|
||||
friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
|
||||
}; // json_iterator
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_iterator> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_JSON_ITERATOR_H
|
||||
@@ -0,0 +1,118 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/json_type.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept {
|
||||
switch (type) {
|
||||
case json_type::array: out << "array"; break;
|
||||
case json_type::object: out << "object"; break;
|
||||
case json_type::number: out << "number"; break;
|
||||
case json_type::string: out << "string"; break;
|
||||
case json_type::boolean: out << "boolean"; break;
|
||||
case json_type::null: out << "null"; break;
|
||||
default: SIMDJSON_UNREACHABLE();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false) {
|
||||
return out << type.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
simdjson_inline number_type number::get_number_type() const noexcept {
|
||||
return type;
|
||||
}
|
||||
|
||||
simdjson_inline bool number::is_uint64() const noexcept {
|
||||
return get_number_type() == number_type::unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_inline uint64_t number::get_uint64() const noexcept {
|
||||
return payload.unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_inline number::operator uint64_t() const noexcept {
|
||||
return get_uint64();
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline bool number::is_int64() const noexcept {
|
||||
return get_number_type() == number_type::signed_integer;
|
||||
}
|
||||
|
||||
simdjson_inline int64_t number::get_int64() const noexcept {
|
||||
return payload.signed_integer;
|
||||
}
|
||||
|
||||
simdjson_inline number::operator int64_t() const noexcept {
|
||||
return get_int64();
|
||||
}
|
||||
|
||||
simdjson_inline bool number::is_double() const noexcept {
|
||||
return get_number_type() == number_type::floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_inline double number::get_double() const noexcept {
|
||||
return payload.floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_inline number::operator double() const noexcept {
|
||||
return get_double();
|
||||
}
|
||||
|
||||
simdjson_inline double number::as_double() const noexcept {
|
||||
if(is_double()) {
|
||||
return payload.floating_point_number;
|
||||
}
|
||||
if(is_int64()) {
|
||||
return double(payload.signed_integer);
|
||||
}
|
||||
return double(payload.unsigned_integer);
|
||||
}
|
||||
|
||||
simdjson_inline void number::append_s64(int64_t value) noexcept {
|
||||
payload.signed_integer = value;
|
||||
type = number_type::signed_integer;
|
||||
}
|
||||
|
||||
simdjson_inline void number::append_u64(uint64_t value) noexcept {
|
||||
payload.unsigned_integer = value;
|
||||
type = number_type::unsigned_integer;
|
||||
}
|
||||
|
||||
simdjson_inline void number::append_double(double value) noexcept {
|
||||
payload.floating_point_number = value;
|
||||
type = number_type::floating_point_number;
|
||||
}
|
||||
|
||||
simdjson_inline void number::skip_double() noexcept {
|
||||
type = number_type::floating_point_number;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::json_type &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_type>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::json_type>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_type>(error) {}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_INL_H
|
||||
@@ -0,0 +1,162 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/numberparsing.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* The type of a JSON value.
|
||||
*/
|
||||
enum class json_type {
|
||||
// Start at 1 to catch uninitialized / default values more easily
|
||||
array=1, ///< A JSON array ( [ 1, 2, 3 ... ] )
|
||||
object, ///< A JSON object ( { "a": 1, "b" 2, ... } )
|
||||
number, ///< A JSON number ( 1 or -2.3 or 4.5e6 ...)
|
||||
string, ///< A JSON string ( "a" or "hello world\n" ...)
|
||||
boolean, ///< A JSON boolean (true or false)
|
||||
null ///< A JSON null (null)
|
||||
};
|
||||
|
||||
/**
|
||||
* A type representing a JSON number.
|
||||
* The design of the struct is deliberately straight-forward. All
|
||||
* functions return standard values with no error check.
|
||||
*/
|
||||
struct number {
|
||||
|
||||
/**
|
||||
* return the automatically determined type of
|
||||
* the number: number_type::floating_point_number,
|
||||
* number_type::signed_integer or number_type::unsigned_integer.
|
||||
*
|
||||
* enum class number_type {
|
||||
* floating_point_number=1, /// a binary64 number
|
||||
* signed_integer, /// a signed integer that fits in a 64-bit word using two's complement
|
||||
* unsigned_integer /// a positive integer larger or equal to 1<<63
|
||||
* };
|
||||
*/
|
||||
simdjson_inline singlestage::number_type get_number_type() const noexcept;
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::unsigned_integer.
|
||||
*/
|
||||
simdjson_inline bool is_uint64() const noexcept;
|
||||
/**
|
||||
* return the value as a uint64_t, only valid if is_uint64() is true.
|
||||
*/
|
||||
simdjson_inline uint64_t get_uint64() const noexcept;
|
||||
simdjson_inline operator uint64_t() const noexcept;
|
||||
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::signed_integer.
|
||||
*/
|
||||
simdjson_inline bool is_int64() const noexcept;
|
||||
/**
|
||||
* return the value as a int64_t, only valid if is_int64() is true.
|
||||
*/
|
||||
simdjson_inline int64_t get_int64() const noexcept;
|
||||
simdjson_inline operator int64_t() const noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* return true if the automatically determined type of
|
||||
* the number is number_type::floating_point_number.
|
||||
*/
|
||||
simdjson_inline bool is_double() const noexcept;
|
||||
/**
|
||||
* return the value as a double, only valid if is_double() is true.
|
||||
*/
|
||||
simdjson_inline double get_double() const noexcept;
|
||||
simdjson_inline operator double() const noexcept;
|
||||
|
||||
/**
|
||||
* Convert the number to a double. Though it always succeed, the conversion
|
||||
* may be lossy if the number cannot be represented exactly.
|
||||
*/
|
||||
simdjson_inline double as_double() const noexcept;
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The next block of declaration is designed so that we can call the number parsing
|
||||
* functions on a number type. They are protected and should never be used outside
|
||||
* of the core simdjson library.
|
||||
*/
|
||||
friend class value_iterator;
|
||||
template<typename W>
|
||||
friend error_code numberparsing::slow_float_parsing(simdjson_unused const uint8_t * src, W writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::write_float(const uint8_t *const src, bool negative, uint64_t i, const uint8_t * start_digits, size_t digit_count, int64_t exponent, W &writer);
|
||||
template<typename W>
|
||||
friend error_code numberparsing::parse_number(const uint8_t *const src, W &writer);
|
||||
/** Store a signed 64-bit value to the number. */
|
||||
simdjson_inline void append_s64(int64_t value) noexcept;
|
||||
/** Store an unsigned 64-bit value to the number. */
|
||||
simdjson_inline void append_u64(uint64_t value) noexcept;
|
||||
/** Store a double value to the number. */
|
||||
simdjson_inline void append_double(double value) noexcept;
|
||||
/** Specifies that the value is a double, but leave it undefined. */
|
||||
simdjson_inline void skip_double() noexcept;
|
||||
/**
|
||||
* End of friend declarations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Our attributes are a union type (size = 64 bits)
|
||||
* followed by a type indicator.
|
||||
*/
|
||||
union {
|
||||
double floating_point_number;
|
||||
int64_t signed_integer;
|
||||
uint64_t unsigned_integer;
|
||||
} payload{0};
|
||||
number_type type{number_type::signed_integer};
|
||||
};
|
||||
|
||||
/**
|
||||
* Write the JSON type to the output stream
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param type The json_type.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, json_type type) noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Send JSON type to an output stream.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param type The json_type.
|
||||
* @throw simdjson_error if the result being printed has an error. If there is an error with the
|
||||
* underlying output stream, that error will be propagated (simdjson_error will not be
|
||||
* thrown).
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson_result<json_type> &type) noexcept(false);
|
||||
#endif
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::json_type> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::json_type &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_JSON_TYPE_H
|
||||
@@ -0,0 +1,222 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/logger.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
namespace logger {
|
||||
|
||||
static constexpr const char * DASHES = "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
|
||||
static constexpr const int LOG_EVENT_LEN = 20;
|
||||
static constexpr const int LOG_BUFFER_LEN = 30;
|
||||
static constexpr const int LOG_SMALL_BUFFER_LEN = 10;
|
||||
static int log_depth = 0; // Not threadsafe. Log only.
|
||||
|
||||
// Helper to turn unprintable or newline characters into spaces
|
||||
static inline char printable_char(char c) {
|
||||
if (c >= 0x20) {
|
||||
return c;
|
||||
} else {
|
||||
return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static inline std::string string_format(const std::string& format, const Args&... args)
|
||||
{
|
||||
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
||||
auto size = static_cast<size_t>(size_s);
|
||||
if (size <= 0) return std::string();
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
return std::string(buf.get(), buf.get() + size - 1);
|
||||
}
|
||||
|
||||
static inline log_level get_log_level_from_env()
|
||||
{
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
char *lvl = getenv("SIMDJSON_LOG_LEVEL");
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
if (lvl && simdjson_strcasecmp(lvl, "ERROR") == 0) { return log_level::error; }
|
||||
return log_level::info;
|
||||
}
|
||||
|
||||
static inline log_level log_threshold()
|
||||
{
|
||||
static log_level threshold = get_log_level_from_env();
|
||||
return threshold;
|
||||
}
|
||||
|
||||
static inline bool should_log(log_level level)
|
||||
{
|
||||
return level >= log_threshold();
|
||||
}
|
||||
|
||||
inline void log_event(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
|
||||
log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
|
||||
}
|
||||
|
||||
inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
|
||||
log_line(iter, index, depth, "", type, detail, log_level::info);
|
||||
}
|
||||
inline void log_value(const json_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
|
||||
log_line(iter, "", type, detail, delta, depth_delta, log_level::info);
|
||||
}
|
||||
|
||||
inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail) noexcept {
|
||||
log_line(iter, index, depth, "+", type, detail, log_level::info);
|
||||
if (LOG_ENABLED) { log_depth++; }
|
||||
}
|
||||
inline void log_start_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
|
||||
log_line(iter, "+", type, "", delta, depth_delta, log_level::info);
|
||||
if (LOG_ENABLED) { log_depth++; }
|
||||
}
|
||||
|
||||
inline void log_end_value(const json_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
|
||||
if (LOG_ENABLED) { log_depth--; }
|
||||
log_line(iter, "-", type, "", delta, depth_delta, log_level::info);
|
||||
}
|
||||
|
||||
inline void log_error(const json_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
|
||||
log_line(iter, "ERROR: ", error, detail, delta, depth_delta, log_level::error);
|
||||
}
|
||||
inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail) noexcept {
|
||||
log_line(iter, index, depth, "ERROR: ", error, detail, log_level::error);
|
||||
}
|
||||
|
||||
inline void log_event(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
|
||||
log_event(iter.json_iter(), type, detail, delta, depth_delta);
|
||||
}
|
||||
|
||||
inline void log_value(const value_iterator &iter, const char *type, std::string_view detail, int delta, int depth_delta) noexcept {
|
||||
log_value(iter.json_iter(), type, detail, delta, depth_delta);
|
||||
}
|
||||
|
||||
inline void log_start_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
|
||||
log_start_value(iter.json_iter(), type, delta, depth_delta);
|
||||
}
|
||||
|
||||
inline void log_end_value(const value_iterator &iter, const char *type, int delta, int depth_delta) noexcept {
|
||||
log_end_value(iter.json_iter(), type, delta, depth_delta);
|
||||
}
|
||||
|
||||
inline void log_error(const value_iterator &iter, const char *error, const char *detail, int delta, int depth_delta) noexcept {
|
||||
log_error(iter.json_iter(), error, detail, delta, depth_delta);
|
||||
}
|
||||
|
||||
inline void log_headers() noexcept {
|
||||
if (LOG_ENABLED) {
|
||||
if (simdjson_unlikely(should_log(log_level::info))) {
|
||||
// Technically a static variable is not thread-safe, but if you are using threads and logging... well...
|
||||
static bool displayed_hint{false};
|
||||
log_depth = 0;
|
||||
printf("\n");
|
||||
if (!displayed_hint) {
|
||||
// We only print this helpful header once.
|
||||
printf("# Logging provides the depth and position of the iterator user-visible steps:\n");
|
||||
printf("# +array says 'this is where we were when we discovered the start array'\n");
|
||||
printf(
|
||||
"# -array says 'this is where we were when we ended the array'\n");
|
||||
printf("# skip says 'this is a structural or value I am skipping'\n");
|
||||
printf("# +/-skip says 'this is a start/end array or object I am skipping'\n");
|
||||
printf("#\n");
|
||||
printf("# The indentation of the terms (array, string,...) indicates the depth,\n");
|
||||
printf("# in addition to the depth being displayed.\n");
|
||||
printf("#\n");
|
||||
printf("# Every token in the document has a single depth determined by the tokens before it,\n");
|
||||
printf("# and is not affected by what the token actually is.\n");
|
||||
printf("#\n");
|
||||
printf("# Not all structural elements are presented as tokens in the logs.\n");
|
||||
printf("#\n");
|
||||
printf("# We never give control to the user within an empty array or an empty object.\n");
|
||||
printf("#\n");
|
||||
printf("# Inside an array, having a depth greater than the array's depth means that\n");
|
||||
printf("# we are pointing inside a value.\n");
|
||||
printf("# Having a depth equal to the array means that we are pointing right before a value.\n");
|
||||
printf("# Having a depth smaller than the array means that we have moved beyond the array.\n");
|
||||
displayed_hint = true;
|
||||
}
|
||||
printf("\n");
|
||||
printf("| %-*s ", LOG_EVENT_LEN, "Event");
|
||||
printf("| %-*s ", LOG_BUFFER_LEN, "Buffer");
|
||||
printf("| %-*s ", LOG_SMALL_BUFFER_LEN, "Next");
|
||||
// printf("| %-*s ", 5, "Next#");
|
||||
printf("| %-*s ", 5, "Depth");
|
||||
printf("| Detail ");
|
||||
printf("|\n");
|
||||
|
||||
printf("|%.*s", LOG_EVENT_LEN + 2, DASHES);
|
||||
printf("|%.*s", LOG_BUFFER_LEN + 2, DASHES);
|
||||
printf("|%.*s", LOG_SMALL_BUFFER_LEN + 2, DASHES);
|
||||
// printf("|%.*s", 5+2, DASHES);
|
||||
printf("|%.*s", 5 + 2, DASHES);
|
||||
printf("|--------");
|
||||
printf("|\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, log_level level, Args&&... args) noexcept {
|
||||
log_line(iter, iter.position()+delta, depth_t(iter.depth()+depth_delta), title_prefix, title, detail, level, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, log_level level, Args&&... args) noexcept {
|
||||
if (LOG_ENABLED) {
|
||||
if (simdjson_unlikely(should_log(level))) {
|
||||
const int indent = depth * 2;
|
||||
const auto buf = iter.token.buf;
|
||||
auto msg = string_format(title, std::forward<Args>(args)...);
|
||||
printf("| %*s%s%-*s ", indent, "", title_prefix,
|
||||
LOG_EVENT_LEN - indent - int(strlen(title_prefix)), msg.c_str());
|
||||
{
|
||||
// Print the current structural.
|
||||
printf("| ");
|
||||
// Before we begin, the index might point right before the document.
|
||||
// This could be unsafe, see https://github.com/simdjson/simdjson/discussions/1938
|
||||
if (index < iter._root) {
|
||||
printf("%*s", LOG_BUFFER_LEN, "");
|
||||
} else {
|
||||
auto current_structural = &buf[*index];
|
||||
for (int i = 0; i < LOG_BUFFER_LEN; i++) {
|
||||
printf("%c", printable_char(current_structural[i]));
|
||||
}
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
{
|
||||
// Print the next structural.
|
||||
printf("| ");
|
||||
auto next_structural = &buf[*(index + 1)];
|
||||
for (int i = 0; i < LOG_SMALL_BUFFER_LEN; i++) {
|
||||
printf("%c", printable_char(next_structural[i]));
|
||||
}
|
||||
printf(" ");
|
||||
}
|
||||
// printf("| %5u ", *(index+1));
|
||||
printf("| %5i ", depth);
|
||||
printf("| %6.*s ", int(detail.size()), detail.data());
|
||||
printf("|\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace logger
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_INL_H
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
// Logging should be free unless SIMDJSON_VERBOSE_LOGGING is set. Importantly, it is critical
|
||||
// that the call to the log functions be side-effect free. Thus, for example, you should not
|
||||
// create temporary std::string instances.
|
||||
namespace logger {
|
||||
|
||||
enum class log_level : int32_t {
|
||||
info = 0,
|
||||
error = 1
|
||||
};
|
||||
|
||||
#if SIMDJSON_VERBOSE_LOGGING
|
||||
static constexpr const bool LOG_ENABLED = true;
|
||||
#else
|
||||
static constexpr const bool LOG_ENABLED = false;
|
||||
#endif
|
||||
|
||||
// We do not want these functions to be 'really inlined' since real inlining is
|
||||
// for performance purposes and if you are using the loggers, you do not care about
|
||||
// performance (or should not).
|
||||
static inline void log_headers() noexcept;
|
||||
// If args are provided, title will be treated as format string
|
||||
template <typename... Args>
|
||||
static inline void log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
|
||||
template <typename... Args>
|
||||
static inline void log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
|
||||
static inline void log_event(const json_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
|
||||
static inline void log_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
|
||||
static inline void log_value(const json_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
|
||||
static inline void log_start_value(const json_iterator &iter, token_position index, depth_t depth, const char *type, std::string_view detail="") noexcept;
|
||||
static inline void log_start_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
|
||||
static inline void log_end_value(const json_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
|
||||
|
||||
static inline void log_error(const json_iterator &iter, token_position index, depth_t depth, const char *error, const char *detail="") noexcept;
|
||||
static inline void log_error(const json_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
|
||||
|
||||
static inline void log_event(const value_iterator &iter, const char *type, std::string_view detail="", int delta=0, int depth_delta=0) noexcept;
|
||||
static inline void log_value(const value_iterator &iter, const char *type, std::string_view detail="", int delta=-1, int depth_delta=0) noexcept;
|
||||
static inline void log_start_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
|
||||
static inline void log_end_value(const value_iterator &iter, const char *type, int delta=-1, int depth_delta=0) noexcept;
|
||||
static inline void log_error(const value_iterator &iter, const char *error, const char *detail="", int delta=-1, int depth_delta=0) noexcept;
|
||||
|
||||
} // namespace logger
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_LOGGER_H
|
||||
@@ -0,0 +1,260 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/field.h"
|
||||
#include "simdjson/generic/singlestage/object.h"
|
||||
#include "simdjson/generic/singlestage/object_iterator.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/value-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) & noexcept {
|
||||
bool has_value;
|
||||
SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
|
||||
if (!has_value) {
|
||||
logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return value(iter.child());
|
||||
}
|
||||
simdjson_inline simdjson_result<value> object::find_field_unordered(const std::string_view key) && noexcept {
|
||||
bool has_value;
|
||||
SIMDJSON_TRY( iter.find_field_unordered_raw(key).get(has_value) );
|
||||
if (!has_value) {
|
||||
logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return value(iter.child());
|
||||
}
|
||||
simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
|
||||
return find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
|
||||
return std::forward<object>(*this).find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) & noexcept {
|
||||
bool has_value;
|
||||
SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
|
||||
if (!has_value) {
|
||||
logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return value(iter.child());
|
||||
}
|
||||
simdjson_inline simdjson_result<value> object::find_field(const std::string_view key) && noexcept {
|
||||
bool has_value;
|
||||
SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
|
||||
if (!has_value) {
|
||||
logger::log_line(iter.json_iter(), "ERROR: ", "Cannot find key %.*s", "", -1, 0, logger::log_level::error, static_cast<int>(key.size()), key.data());
|
||||
return NO_SUCH_FIELD;
|
||||
}
|
||||
return value(iter.child());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
|
||||
SIMDJSON_TRY( iter.start_object().error() );
|
||||
return object(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<object> object::start_root(value_iterator &iter) noexcept {
|
||||
SIMDJSON_TRY( iter.start_root_object().error() );
|
||||
return object(iter);
|
||||
}
|
||||
simdjson_inline error_code object::consume() noexcept {
|
||||
if(iter.is_at_key()) {
|
||||
/**
|
||||
* whenever you are pointing at a key, calling skip_child() is
|
||||
* unsafe because you will hit a string and you will assume that
|
||||
* it is string value, and this mistake will lead you to make bad
|
||||
* depth computation.
|
||||
*/
|
||||
/**
|
||||
* We want to 'consume' the key. We could really
|
||||
* just do _json_iter->return_current_and_advance(); at this
|
||||
* point, but, for clarity, we will use the high-level API to
|
||||
* eat the key. We assume that the compiler optimizes away
|
||||
* most of the work.
|
||||
*/
|
||||
simdjson_unused raw_json_string actual_key;
|
||||
auto error = iter.field_key().get(actual_key);
|
||||
if (error) { iter.abandon(); return error; };
|
||||
// Let us move to the value while we are at it.
|
||||
if ((error = iter.field_value())) { iter.abandon(); return error; }
|
||||
}
|
||||
auto error_skip = iter.json_iter().skip_child(iter.depth()-1);
|
||||
if(error_skip) { iter.abandon(); }
|
||||
return error_skip;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> object::raw_json() noexcept {
|
||||
const uint8_t * starting_point{iter.peek_start()};
|
||||
auto error = consume();
|
||||
if(error) { return error; }
|
||||
const uint8_t * final_point{iter._json_iter->peek(0)};
|
||||
return std::string_view(reinterpret_cast<const char*>(starting_point), size_t(final_point - starting_point));
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<object> object::started(value_iterator &iter) noexcept {
|
||||
SIMDJSON_TRY( iter.started_object().error() );
|
||||
return object(iter);
|
||||
}
|
||||
|
||||
simdjson_inline object object::resume(const value_iterator &iter) noexcept {
|
||||
return iter;
|
||||
}
|
||||
|
||||
simdjson_inline object::object(const value_iterator &_iter) noexcept
|
||||
: iter{_iter}
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<object_iterator> object::begin() noexcept {
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
if (!iter.is_at_iterator_start()) { return OUT_OF_ORDER_ITERATION; }
|
||||
#endif
|
||||
return object_iterator(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<object_iterator> object::end() noexcept {
|
||||
return object_iterator(iter);
|
||||
}
|
||||
|
||||
inline simdjson_result<value> object::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (json_pointer[0] != '/') { return INVALID_JSON_POINTER; }
|
||||
json_pointer = json_pointer.substr(1);
|
||||
size_t slash = json_pointer.find('/');
|
||||
std::string_view key = json_pointer.substr(0, slash);
|
||||
// Grab the child with the given key
|
||||
simdjson_result<value> child;
|
||||
|
||||
// If there is an escape character in the key, unescape it and then get the child.
|
||||
size_t escape = key.find('~');
|
||||
if (escape != std::string_view::npos) {
|
||||
// Unescape the key
|
||||
std::string unescaped(key);
|
||||
do {
|
||||
switch (unescaped[escape+1]) {
|
||||
case '0':
|
||||
unescaped.replace(escape, 2, "~");
|
||||
break;
|
||||
case '1':
|
||||
unescaped.replace(escape, 2, "/");
|
||||
break;
|
||||
default:
|
||||
return INVALID_JSON_POINTER; // "Unexpected ~ escape character in JSON pointer");
|
||||
}
|
||||
escape = unescaped.find('~', escape+1);
|
||||
} while (escape != std::string::npos);
|
||||
child = find_field(unescaped); // Take note find_field does not unescape keys when matching
|
||||
} else {
|
||||
child = find_field(key);
|
||||
}
|
||||
if(child.error()) {
|
||||
return child; // we do not continue if there was an error
|
||||
}
|
||||
// If there is a /, we have to recurse and look up more of the path
|
||||
if (slash != std::string_view::npos) {
|
||||
child = child.at_pointer(json_pointer.substr(slash));
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<size_t> object::count_fields() & noexcept {
|
||||
size_t count{0};
|
||||
// Important: we do not consume any of the values.
|
||||
for(simdjson_unused auto v : *this) { count++; }
|
||||
// The above loop will always succeed, but we want to report errors.
|
||||
if(iter.error()) { return iter.error(); }
|
||||
// We need to move back at the start because we expect users to iterate through
|
||||
// the object after counting the number of elements.
|
||||
iter.reset_object();
|
||||
return count;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> object::is_empty() & noexcept {
|
||||
bool is_not_empty;
|
||||
auto error = iter.reset_object().get(is_not_empty);
|
||||
if(error) { return error; }
|
||||
return !is_not_empty;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> object::reset() & noexcept {
|
||||
return iter.reset_object();
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::object &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::object>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object>(error) {}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::begin() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::end() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.end();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::find_field_unordered(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::find_field_unordered(std::string_view key) && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::object>(first).find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::operator[](std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::operator[](std::string_view key) && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::object>(first)[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::find_field(std::string_view key) & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::find_field(std::string_view key) && noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::forward<SIMDJSON_IMPLEMENTATION::singlestage::object>(first).find_field(key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::reset() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.reset();
|
||||
}
|
||||
|
||||
inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::is_empty() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_empty();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::count_fields() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_fields();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object>::raw_json() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json();
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_INL_H
|
||||
@@ -0,0 +1,239 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A forward-only JSON object field iterator.
|
||||
*/
|
||||
class object {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid object.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline object() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<object_iterator> begin() noexcept;
|
||||
simdjson_inline simdjson_result<object_iterator> end() noexcept;
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
*
|
||||
* ```c++
|
||||
* simdjson::singlestage::parser parser;
|
||||
* auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
|
||||
* double z = obj.find_field("z");
|
||||
* double y = obj.find_field("y");
|
||||
* double x = obj.find_field("x");
|
||||
* ```
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
*
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. The value instance you get
|
||||
* from `content["bids"]` becomes invalid when you call `content["asks"]`. The array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* You are expected to access keys only once. You should access the value corresponding to a
|
||||
* key a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string()
|
||||
* is an error.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object, without regard to key order.
|
||||
*
|
||||
* **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
|
||||
* and often appears negligible. It starts out normally, starting out at the last field; but if
|
||||
* the field is not found, it scans from the beginning of the object to see if it missed it. That
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
*
|
||||
* You must consume the fields on an object one at a time. A request for a new key
|
||||
* invalidates previous field values: it makes them unsafe. The value instance you get
|
||||
* from `content["bids"]` becomes invalid when you call `content["asks"]`. The array
|
||||
* given by content["bids"].get_array() should not be accessed after you have called
|
||||
* content["asks"].get_array(). You can detect such mistakes by first compiling and running
|
||||
* the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an
|
||||
* OUT_OF_ORDER_ITERATION error is generated.
|
||||
*
|
||||
* You are expected to access keys only once. You should access the value corresponding to a key
|
||||
* a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() is an error.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) && noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) & noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) & noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard, interpreting the current node
|
||||
* as the root of its own JSON document.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("/foo/a/1") == 20
|
||||
*
|
||||
* It is allowed for a key to be the empty string:
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("//a/1") == 20
|
||||
*
|
||||
* Note that at_pointer() called on the document automatically calls the document's rewind
|
||||
* method between each call. It invalidates all previously accessed arrays, objects and values
|
||||
* that have not been consumed. Yet it is not the case when calling at_pointer on an object
|
||||
* instance: there is no rewind and no invalidation.
|
||||
*
|
||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||
*
|
||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching.
|
||||
*
|
||||
* @return The value associated with the given JSON pointer, or:
|
||||
* - NO_SUCH_FIELD if a field does not exist in an object
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
|
||||
* - INCORRECT_TYPE if a non-integer is used to access an array
|
||||
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
|
||||
*/
|
||||
inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
|
||||
/**
|
||||
* Reset the iterator so that we are pointing back at the
|
||||
* beginning of the object. You should still consume values only once even if you
|
||||
* can iterate through the object more than once. If you unescape a string within
|
||||
* the object more than once, you have unsafe code. Note that rewinding an object
|
||||
* means that you may need to reparse it anew: it is not a free operation.
|
||||
*
|
||||
* @returns true if the object contains some elements (not empty)
|
||||
*/
|
||||
inline simdjson_result<bool> reset() & noexcept;
|
||||
/**
|
||||
* This method scans the beginning of the object and checks whether the
|
||||
* object is empty.
|
||||
* The runtime complexity is constant time. After
|
||||
* calling this function, if successful, the object is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*/
|
||||
inline simdjson_result<bool> is_empty() & noexcept;
|
||||
/**
|
||||
* This method scans the object and counts the number of key-value pairs.
|
||||
* The count_fields method should always be called before you have begun
|
||||
* iterating through the object: it is expected that you are pointing at
|
||||
* the beginning of the object.
|
||||
* The runtime complexity is linear in the size of the object. After
|
||||
* calling this function, if successful, the object is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*
|
||||
* To check that an object is empty, it is more performant to use
|
||||
* the is_empty() method.
|
||||
*
|
||||
* Performance hint: You should only call count_fields() as a last
|
||||
* resort as it may require scanning the document twice or more.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
/**
|
||||
* Consumes the object and returns a string_view instance corresponding to the
|
||||
* object as represented in JSON. It points inside the original byte array containing
|
||||
* the JSON document.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Go to the end of the object, no matter where you are right now.
|
||||
*/
|
||||
simdjson_inline error_code consume() noexcept;
|
||||
static simdjson_inline simdjson_result<object> start(value_iterator &iter) noexcept;
|
||||
static simdjson_inline simdjson_result<object> start_root(value_iterator &iter) noexcept;
|
||||
static simdjson_inline simdjson_result<object> started(value_iterator &iter) noexcept;
|
||||
static simdjson_inline object resume(const value_iterator &iter) noexcept;
|
||||
simdjson_inline object(const value_iterator &iter) noexcept;
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code find_field_raw(const std::string_view key) noexcept;
|
||||
|
||||
value_iterator iter{};
|
||||
|
||||
friend class value;
|
||||
friend class document;
|
||||
friend struct simdjson_result<object>;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::object &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> begin() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> end() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) && noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) && noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](std::string_view key) & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](std::string_view key) && noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
inline simdjson_result<bool> reset() noexcept;
|
||||
inline simdjson_result<bool> is_empty() noexcept;
|
||||
inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
inline simdjson_result<std::string_view> raw_json() noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_H
|
||||
@@ -0,0 +1,138 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/object_iterator.h"
|
||||
#include "simdjson/generic/singlestage/field-inl.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
//
|
||||
// object_iterator
|
||||
//
|
||||
|
||||
simdjson_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
|
||||
: iter{_iter}
|
||||
{}
|
||||
|
||||
simdjson_inline simdjson_result<field> object_iterator::operator*() noexcept {
|
||||
error_code error = iter.error();
|
||||
if (error) { iter.abandon(); return error; }
|
||||
auto result = field::start(iter);
|
||||
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
||||
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
||||
if (result.error()) { iter.abandon(); }
|
||||
return result;
|
||||
}
|
||||
simdjson_inline bool object_iterator::operator==(const object_iterator &other) const noexcept {
|
||||
return !(*this != other);
|
||||
}
|
||||
simdjson_inline bool object_iterator::operator!=(const object_iterator &) const noexcept {
|
||||
return iter.is_open();
|
||||
}
|
||||
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
|
||||
simdjson_inline object_iterator &object_iterator::operator++() noexcept {
|
||||
// TODO this is a safety rail ... users should exit loops as soon as they receive an error.
|
||||
// Nonetheless, let's see if performance is OK with this if statement--the compiler may give it to us for free.
|
||||
if (!iter.is_open()) { return *this; } // Iterator will be released if there is an error
|
||||
|
||||
simdjson_unused error_code error;
|
||||
if ((error = iter.skip_child() )) { return *this; }
|
||||
|
||||
simdjson_unused bool has_value;
|
||||
if ((error = iter.has_next_field().get(has_value) )) { return *this; };
|
||||
return *this;
|
||||
}
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
|
||||
//
|
||||
// ### Live States
|
||||
//
|
||||
// While iterating or looking up values, depth >= iter.depth. at_start may vary. Error is
|
||||
// always SUCCESS:
|
||||
//
|
||||
// - Start: This is the state when the object is first found and the iterator is just past the {.
|
||||
// In this state, at_start == true.
|
||||
// - Next: After we hand a scalar value to the user, or an array/object which they then fully
|
||||
// iterate over, the iterator is at the , or } before the next value. In this state,
|
||||
// depth == iter.depth, at_start == false, and error == SUCCESS.
|
||||
// - Unfinished Business: When we hand an array/object to the user which they do not fully
|
||||
// iterate over, we need to finish that iteration by skipping child values until we reach the
|
||||
// Next state. In this state, depth > iter.depth, at_start == false, and error == SUCCESS.
|
||||
//
|
||||
// ## Error States
|
||||
//
|
||||
// In error states, we will yield exactly one more value before stopping. iter.depth == depth
|
||||
// and at_start is always false. We decrement after yielding the error, moving to the Finished
|
||||
// state.
|
||||
//
|
||||
// - Chained Error: When the object iterator is part of an error chain--for example, in
|
||||
// `for (auto tweet : doc["tweets"])`, where the tweet field may be missing or not be an
|
||||
// object--we yield that error in the loop, exactly once. In this state, error != SUCCESS and
|
||||
// iter.depth == depth, and at_start == false. We decrement depth when we yield the error.
|
||||
// - Missing Comma Error: When the iterator ++ method discovers there is no comma between fields,
|
||||
// we flag that as an error and treat it exactly the same as a Chained Error. In this state,
|
||||
// error == TAPE_ERROR, iter.depth == depth, and at_start == false.
|
||||
//
|
||||
// Errors that occur while reading a field to give to the user (such as when the key is not a
|
||||
// string or the field is missing a colon) are yielded immediately. Depth is then decremented,
|
||||
// moving to the Finished state without transitioning through an Error state at all.
|
||||
//
|
||||
// ## Terminal State
|
||||
//
|
||||
// The terminal state has iter.depth < depth. at_start is always false.
|
||||
//
|
||||
// - Finished: When we have reached a }, we are finished. We signal this by decrementing depth.
|
||||
// In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
|
||||
//
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::object_iterator &&value
|
||||
) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>(value))
|
||||
{
|
||||
first.iter.assert_is_valid();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>({}, error)
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::operator*() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return *first;
|
||||
}
|
||||
// If we're iterating and there is an error, return the error once.
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &other) const noexcept {
|
||||
if (!first.iter.is_valid()) { return !error(); }
|
||||
return first == other.first;
|
||||
}
|
||||
// If we're iterating and there is an error, return the error once.
|
||||
simdjson_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &other) const noexcept {
|
||||
if (!first.iter.is_valid()) { return error(); }
|
||||
return first != other.first;
|
||||
}
|
||||
// Checks for ']' and ','
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator>::operator++() noexcept {
|
||||
// Clear the error if there is one, so we don't yield it twice
|
||||
if (error()) { second = SUCCESS; return *this; }
|
||||
++first;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_INL_H
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
class object_iterator {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid object_iterator.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline object_iterator() noexcept = default;
|
||||
|
||||
//
|
||||
// Iterator interface
|
||||
//
|
||||
|
||||
// Reads key and value, yielding them to the user.
|
||||
// MUST ONLY BE CALLED ONCE PER ITERATION.
|
||||
simdjson_inline simdjson_result<field> operator*() noexcept;
|
||||
// Assumes it's being compared with the end. true if depth < iter->depth.
|
||||
simdjson_inline bool operator==(const object_iterator &) const noexcept;
|
||||
// Assumes it's being compared with the end. true if depth >= iter->depth.
|
||||
simdjson_inline bool operator!=(const object_iterator &) const noexcept;
|
||||
// Checks for ']' and ','
|
||||
simdjson_inline object_iterator &operator++() noexcept;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The underlying JSON iterator.
|
||||
*
|
||||
* PERF NOTE: expected to be elided in favor of the parent document: this is set when the object
|
||||
* is first used, and never changes afterwards.
|
||||
*/
|
||||
value_iterator iter{};
|
||||
|
||||
simdjson_inline object_iterator(const value_iterator &iter) noexcept;
|
||||
friend struct simdjson_result<object_iterator>;
|
||||
friend class object;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::object_iterator &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
//
|
||||
// Iterator interface
|
||||
//
|
||||
|
||||
// Reads key and value, yielding them to the user.
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
|
||||
// Assumes it's being compared with the end. true if depth < iter->depth.
|
||||
simdjson_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &) const noexcept;
|
||||
// Assumes it's being compared with the end. true if depth >= iter->depth.
|
||||
simdjson_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &) const noexcept;
|
||||
// Checks for ']' and ','
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object_iterator> &operator++() noexcept;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_OBJECT_ITERATOR_H
|
||||
@@ -0,0 +1,149 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_PARSER_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_PARSER_INL_H
|
||||
#include "simdjson/padded_string.h"
|
||||
#include "simdjson/padded_string_view.h"
|
||||
#include "simdjson/implementation.h"
|
||||
#include "simdjson/internal/dom_parser_implementation.h"
|
||||
#include "simdjson/dom/base.h" // for MINIMAL_DOCUMENT_CAPACITY
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/document.h"
|
||||
#include "simdjson/generic/singlestage/parser.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline parser::parser(size_t max_capacity) noexcept
|
||||
: _max_capacity{max_capacity} {
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capacity, size_t new_max_depth) noexcept {
|
||||
if (new_capacity > max_capacity()) { return CAPACITY; }
|
||||
if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }
|
||||
|
||||
// string_capacity copied from document::allocate
|
||||
_capacity = 0;
|
||||
size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
|
||||
string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
|
||||
#endif
|
||||
if (implementation) {
|
||||
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
|
||||
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
|
||||
} else {
|
||||
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
|
||||
}
|
||||
_capacity = new_capacity;
|
||||
_max_depth = new_max_depth;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
|
||||
// Allocate if needed
|
||||
if (capacity() < json.length() || !string_buf) {
|
||||
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
|
||||
}
|
||||
|
||||
// Run stage 1.
|
||||
SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
|
||||
return document::start({ reinterpret_cast<const uint8_t *>(json.data()), this });
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const char *json, size_t len, size_t allocated) & noexcept {
|
||||
return iterate(padded_string_view(json, len, allocated));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const uint8_t *json, size_t len, size_t allocated) & noexcept {
|
||||
return iterate(padded_string_view(json, len, allocated));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(std::string_view json, size_t allocated) & noexcept {
|
||||
return iterate(padded_string_view(json, allocated));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const std::string &json) & noexcept {
|
||||
return iterate(padded_string_view(json));
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string_view> &result) & noexcept {
|
||||
// We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
|
||||
SIMDJSON_TRY( result.error() );
|
||||
padded_string_view json = result.value_unsafe();
|
||||
return iterate(json);
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(const simdjson_result<padded_string> &result) & noexcept {
|
||||
// We don't presently have a way to temporarily get a const T& from a simdjson_result<T> without throwing an exception
|
||||
SIMDJSON_TRY( result.error() );
|
||||
const padded_string &json = result.value_unsafe();
|
||||
return iterate(json);
|
||||
}
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iterate_raw(padded_string_view json) & noexcept {
|
||||
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
|
||||
|
||||
// Allocate if needed
|
||||
if (capacity() < json.length()) {
|
||||
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
|
||||
}
|
||||
|
||||
// Run stage 1.
|
||||
SIMDJSON_TRY( implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.length(), stage1_mode::regular) );
|
||||
return json_iterator(reinterpret_cast<const uint8_t *>(json.data()), this);
|
||||
}
|
||||
|
||||
simdjson_inline size_t parser::capacity() const noexcept {
|
||||
return _capacity;
|
||||
}
|
||||
simdjson_inline size_t parser::max_capacity() const noexcept {
|
||||
return _max_capacity;
|
||||
}
|
||||
simdjson_inline size_t parser::max_depth() const noexcept {
|
||||
return _max_depth;
|
||||
}
|
||||
|
||||
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
|
||||
if(max_capacity < dom::MINIMAL_DOCUMENT_CAPACITY) {
|
||||
_max_capacity = max_capacity;
|
||||
} else {
|
||||
_max_capacity = dom::MINIMAL_DOCUMENT_CAPACITY;
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement) const noexcept {
|
||||
uint8_t *end = implementation->parse_string(in.buf, dst, allow_replacement);
|
||||
if (!end) { return STRING_ERROR; }
|
||||
std::string_view result(reinterpret_cast<const char *>(dst), end-dst);
|
||||
dst = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> parser::unescape_wobbly(raw_json_string in, uint8_t *&dst) const noexcept {
|
||||
uint8_t *end = implementation->parse_wobbly_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 singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::parser>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::parser &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::parser>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::parser>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::parser>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::parser>(error) {}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_PARSER_INL_H
|
||||
@@ -0,0 +1,253 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_PARSER_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_PARSER_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A JSON fragment iterator.
|
||||
*
|
||||
* This holds the actual iterator as well as the buffer for writing strings.
|
||||
*/
|
||||
class parser {
|
||||
public:
|
||||
/**
|
||||
* Create a JSON parser.
|
||||
*
|
||||
* The new parser will have zero capacity.
|
||||
*/
|
||||
inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
|
||||
|
||||
inline parser(parser &&other) noexcept = default;
|
||||
simdjson_inline parser(const parser &other) = delete;
|
||||
simdjson_inline parser &operator=(const parser &other) = delete;
|
||||
simdjson_inline parser &operator=(parser &&other) noexcept = default;
|
||||
|
||||
/** Deallocate the JSON parser. */
|
||||
inline ~parser() noexcept = default;
|
||||
|
||||
/**
|
||||
* Start iterating an on-demand JSON document.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* document doc = parser.iterate(json);
|
||||
*
|
||||
* It is expected that the content is a valid UTF-8 file, containing a valid JSON document.
|
||||
* Otherwise the iterate method may return an error. In particular, the whole input should be
|
||||
* valid: we do not attempt to tolerate incorrect content either before or after a JSON
|
||||
* document.
|
||||
*
|
||||
* ### IMPORTANT: Validate what you use
|
||||
*
|
||||
* Calling iterate on an invalid JSON document may not immediately trigger an error. The call to
|
||||
* iterate does not parse and validate the whole document.
|
||||
*
|
||||
* ### IMPORTANT: Buffer Lifetime
|
||||
*
|
||||
* Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
|
||||
* long as the document iteration.
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
|
||||
* iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
|
||||
* you call parse() again or destroy the parser.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||
*
|
||||
* @param json The JSON to parse.
|
||||
* @param len The length of the JSON.
|
||||
* @param capacity The number of bytes allocated in the JSON (must be at least len+SIMDJSON_PADDING).
|
||||
*
|
||||
* @return The document, or an error:
|
||||
* - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
|
||||
* - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
|
||||
* allocation fails.
|
||||
* - EMPTY if the document is all whitespace.
|
||||
* - UTF8_ERROR if the document is not valid UTF-8.
|
||||
* - UNESCAPED_CHARS if a string contains control characters that must be escaped
|
||||
* - UNCLOSED_STRING if there is an unclosed string in the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_result<document> iterate(padded_string_view json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const char *json, size_t len, size_t capacity) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const uint8_t *json, size_t len, size_t capacity) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(std::string_view json, size_t capacity) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const std::string &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string> &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(const simdjson_result<padded_string_view> &json) & noexcept;
|
||||
/** @overload simdjson_result<document> iterate(padded_string_view json) & noexcept */
|
||||
simdjson_warn_unused simdjson_result<document> iterate(padded_string &&json) & noexcept = delete;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* Start iterating an on-demand JSON document.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* json_iterator doc = parser.iterate(json);
|
||||
*
|
||||
* ### IMPORTANT: Buffer Lifetime
|
||||
*
|
||||
* Because parsing is done while you iterate, you *must* keep the JSON buffer around at least as
|
||||
* long as the document iteration.
|
||||
*
|
||||
* ### IMPORTANT: Document Lifetime
|
||||
*
|
||||
* Only one iteration at a time can happen per parser, and the parser *must* be kept alive during
|
||||
* iteration to ensure intermediate buffers can be accessed. Any document must be destroyed before
|
||||
* you call parse() again or destroy the parser.
|
||||
*
|
||||
* The singlestage::document instance holds the iterator. The document must remain in scope
|
||||
* while you are accessing instances of singlestage::value, singlestage::object, singlestage::array.
|
||||
*
|
||||
* ### REQUIRED: Buffer Padding
|
||||
*
|
||||
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
|
||||
* those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
|
||||
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
|
||||
* SIMDJSON_PADDING bytes to avoid runtime warnings.
|
||||
*
|
||||
* @param json The JSON to parse.
|
||||
*
|
||||
* @return The iterator, or an error:
|
||||
* - INSUFFICIENT_PADDING if the input has less than SIMDJSON_PADDING extra bytes.
|
||||
* - MEMALLOC if realloc_if_needed the parser does not have enough capacity, and memory
|
||||
* allocation fails.
|
||||
* - EMPTY if the document is all whitespace.
|
||||
* - UTF8_ERROR if the document is not valid UTF-8.
|
||||
* - UNESCAPED_CHARS if a string contains control characters that must be escaped
|
||||
* - UNCLOSED_STRING if there is an unclosed string in the document.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_result<json_iterator> iterate_raw(padded_string_view json) & noexcept;
|
||||
|
||||
/** The capacity of this parser (the largest document it can process). */
|
||||
simdjson_inline size_t capacity() const noexcept;
|
||||
/** The maximum capacity of this parser (the largest document it is allowed to process). */
|
||||
simdjson_inline size_t max_capacity() const noexcept;
|
||||
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
|
||||
/**
|
||||
* The maximum depth of this parser (the most deeply nested objects and arrays it can process).
|
||||
* This parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||
* The document's instance current_depth() method should be used to monitor the parsing
|
||||
* depth and limit it if desired.
|
||||
*/
|
||||
simdjson_inline size_t max_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Ensure this parser has enough memory to process JSON documents up to `capacity` bytes in length
|
||||
* and `max_depth` depth.
|
||||
*
|
||||
* The max_depth parameter is only relevant when the macro SIMDJSON_DEVELOPMENT_CHECKS is set to true.
|
||||
* The document's instance current_depth() method should be used to monitor the parsing
|
||||
* depth and limit it if desired.
|
||||
*
|
||||
* @param capacity The new capacity.
|
||||
* @param max_depth The new max_depth. Defaults to DEFAULT_MAX_DEPTH.
|
||||
* @return The error, if there is one.
|
||||
*/
|
||||
simdjson_warn_unused error_code allocate(size_t capacity, size_t max_depth=DEFAULT_MAX_DEPTH) noexcept;
|
||||
|
||||
#ifdef SIMDJSON_THREADS_ENABLED
|
||||
/**
|
||||
* The parser instance can use threads when they are available to speed up some
|
||||
* operations. It is enabled by default. Changing this attribute will change the
|
||||
* behavior of the parser for future operations.
|
||||
*/
|
||||
bool threaded{true};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||
* The result must be valid UTF-8.
|
||||
* 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.
|
||||
* @param allow_replacement Whether we allow a replacement if the input string contains unmatched surrogate pairs.
|
||||
* @return A string_view pointing at the unescaped string in dst
|
||||
* @error STRING_ERROR if escapes are incorrect.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> unescape(raw_json_string in, uint8_t *&dst, bool allow_replacement = false) const noexcept;
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc. to a user-provided buffer.
|
||||
* The result may not be valid UTF-8. See https://simonsapin.github.io/wtf-8/
|
||||
* 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_inline simdjson_result<std::string_view> unescape_wobbly(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{};
|
||||
size_t _capacity{0};
|
||||
size_t _max_capacity;
|
||||
size_t _max_depth{DEFAULT_MAX_DEPTH};
|
||||
std::unique_ptr<uint8_t[]> string_buf{};
|
||||
#if SIMDJSON_DEVELOPMENT_CHECKS
|
||||
std::unique_ptr<token_position[]> start_positions{};
|
||||
#endif
|
||||
|
||||
friend class json_iterator;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::parser> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::parser> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::parser &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_PARSER_H
|
||||
@@ -0,0 +1,203 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator-inl.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline raw_json_string::raw_json_string(const uint8_t * _buf) noexcept : buf{_buf} {}
|
||||
|
||||
simdjson_inline const char * raw_json_string::raw() const noexcept { return reinterpret_cast<const char *>(buf); }
|
||||
|
||||
|
||||
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(std::string_view target) noexcept {
|
||||
size_t pos{0};
|
||||
// if the content has no escape character, just scan through it quickly!
|
||||
for(;pos < target.size() && target[pos] != '\\';pos++) {}
|
||||
// slow path may begin.
|
||||
bool escaping{false};
|
||||
for(;pos < target.size();pos++) {
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::is_free_from_unescaped_quote(const char* target) noexcept {
|
||||
size_t pos{0};
|
||||
// if the content has no escape character, just scan through it quickly!
|
||||
for(;target[pos] && target[pos] != '\\';pos++) {}
|
||||
// slow path may begin.
|
||||
bool escaping{false};
|
||||
for(;target[pos];pos++) {
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline bool raw_json_string::unsafe_is_equal(size_t length, std::string_view target) const noexcept {
|
||||
// If we are going to call memcmp, then we must know something about the length of the raw_json_string.
|
||||
return (length >= target.size()) && (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::unsafe_is_equal(std::string_view target) const noexcept {
|
||||
// Assumptions: does not contain unescaped quote characters, and
|
||||
// the raw content is quote terminated within a valid JSON string.
|
||||
if(target.size() <= SIMDJSON_PADDING) {
|
||||
return (raw()[target.size()] == '"') && !memcmp(raw(), target.data(), target.size());
|
||||
}
|
||||
const char * r{raw()};
|
||||
size_t pos{0};
|
||||
for(;pos < target.size();pos++) {
|
||||
if(r[pos] != target[pos]) { return false; }
|
||||
}
|
||||
if(r[pos] != '"') { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::is_equal(std::string_view target) const noexcept {
|
||||
const char * r{raw()};
|
||||
size_t pos{0};
|
||||
bool escaping{false};
|
||||
for(;pos < target.size();pos++) {
|
||||
if(r[pos] != target[pos]) { return false; }
|
||||
// if target is a compile-time constant and it is free from
|
||||
// quotes, then the next part could get optimized away through
|
||||
// inlining.
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
// We have reached the end of the raw_json_string but
|
||||
// the target is not done.
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
}
|
||||
}
|
||||
if(r[pos] != '"') { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline bool raw_json_string::unsafe_is_equal(const char * target) const noexcept {
|
||||
// Assumptions: 'target' does not contain unescaped quote characters, is null terminated and
|
||||
// the raw content is quote terminated within a valid JSON string.
|
||||
const char * r{raw()};
|
||||
size_t pos{0};
|
||||
for(;target[pos];pos++) {
|
||||
if(r[pos] != target[pos]) { return false; }
|
||||
}
|
||||
if(r[pos] != '"') { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_inline bool raw_json_string::is_equal(const char* target) const noexcept {
|
||||
// Assumptions: does not contain unescaped quote characters, and
|
||||
// the raw content is quote terminated within a valid JSON string.
|
||||
const char * r{raw()};
|
||||
size_t pos{0};
|
||||
bool escaping{false};
|
||||
for(;target[pos];pos++) {
|
||||
if(r[pos] != target[pos]) { return false; }
|
||||
// if target is a compile-time constant and it is free from
|
||||
// quotes, then the next part could get optimized away through
|
||||
// inlining.
|
||||
if((target[pos] == '"') && !escaping) {
|
||||
// We have reached the end of the raw_json_string but
|
||||
// the target is not done.
|
||||
return false;
|
||||
} else if(target[pos] == '\\') {
|
||||
escaping = !escaping;
|
||||
} else {
|
||||
escaping = false;
|
||||
}
|
||||
}
|
||||
if(r[pos] != '"') { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept {
|
||||
return a.unsafe_is_equal(c);
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept {
|
||||
return a == c;
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept {
|
||||
return !(a == c);
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept {
|
||||
return !(a == c);
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape(json_iterator &iter, bool allow_replacement) const noexcept {
|
||||
return iter.unescape(*this, allow_replacement);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> raw_json_string::unescape_wobbly(json_iterator &iter) const noexcept {
|
||||
return iter.unescape_wobbly(*this);
|
||||
}
|
||||
|
||||
simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &out, const raw_json_string &str) noexcept {
|
||||
bool in_escape = false;
|
||||
const char *s = str.raw();
|
||||
while (true) {
|
||||
switch (*s) {
|
||||
case '\\': in_escape = !in_escape; break;
|
||||
case '"': if (in_escape) { in_escape = false; } else { return out; } break;
|
||||
default: if (in_escape) { in_escape = false; }
|
||||
}
|
||||
out << *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>(error) {}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>::raw() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw();
|
||||
}
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>::unescape(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &iter, bool allow_replacement) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescape(iter, allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string>::unescape_wobbly(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &iter) const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.unescape_wobbly(iter);
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_INL_H
|
||||
@@ -0,0 +1,206 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* A string escaped per JSON rules, terminated with quote ("). They are used to represent
|
||||
* unescaped keys inside JSON documents.
|
||||
*
|
||||
* (In other words, a pointer to the beginning of a string, just after the start quote, inside a
|
||||
* JSON file.)
|
||||
*
|
||||
* 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 singlestage::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().
|
||||
*
|
||||
*/
|
||||
class raw_json_string {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid raw_json_string.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline raw_json_string() noexcept = default;
|
||||
|
||||
/**
|
||||
* Create a new invalid raw_json_string pointed at the given location in the JSON.
|
||||
*
|
||||
* The given location must be just *after* the beginning quote (") in the JSON file.
|
||||
*
|
||||
* It *must* be terminated by a ", and be a valid JSON string.
|
||||
*/
|
||||
simdjson_inline raw_json_string(const uint8_t * _buf) noexcept;
|
||||
/**
|
||||
* Get the raw pointer to the beginning of the string in the JSON (just after the ").
|
||||
*
|
||||
* It is possible for this function to return a null pointer if the instance
|
||||
* has outlived its existence.
|
||||
*/
|
||||
simdjson_inline const char * raw() const noexcept;
|
||||
|
||||
/**
|
||||
* This compares the current instance to the std::string_view target: returns true if
|
||||
* they are byte-by-byte equal (no escaping is done) on target.size() characters,
|
||||
* and if the raw_json_string instance has a quote character at byte index target.size().
|
||||
* We never read more than length + 1 bytes in the raw_json_string instance.
|
||||
* If length is smaller than target.size(), this will return false.
|
||||
*
|
||||
* The std::string_view instance may contain any characters. However, the caller
|
||||
* is responsible for setting length so that length bytes may be read in the
|
||||
* raw_json_string.
|
||||
*
|
||||
* Performance: the comparison may be done using memcmp which may be efficient
|
||||
* for long strings.
|
||||
*/
|
||||
simdjson_inline bool unsafe_is_equal(size_t length, std::string_view target) const noexcept;
|
||||
|
||||
/**
|
||||
* This compares the current instance to the std::string_view target: returns true if
|
||||
* they are byte-by-byte equal (no escaping is done).
|
||||
* The std::string_view instance should not contain unescaped quote characters:
|
||||
* the caller is responsible for this check. See is_free_from_unescaped_quote.
|
||||
*
|
||||
* Performance: the comparison is done byte-by-byte which might be inefficient for
|
||||
* long strings.
|
||||
*
|
||||
* If target is a compile-time constant, and your compiler likes you,
|
||||
* you should be able to do the following without performance penalty...
|
||||
*
|
||||
* static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
|
||||
* s.unsafe_is_equal(target);
|
||||
*/
|
||||
simdjson_inline bool unsafe_is_equal(std::string_view target) const noexcept;
|
||||
|
||||
/**
|
||||
* This compares the current instance to the C string target: returns true if
|
||||
* they are byte-by-byte equal (no escaping is done).
|
||||
* The provided C string should not contain an unescaped quote character:
|
||||
* the caller is responsible for this check. See is_free_from_unescaped_quote.
|
||||
*
|
||||
* If target is a compile-time constant, and your compiler likes you,
|
||||
* you should be able to do the following without performance penalty...
|
||||
*
|
||||
* static_assert(raw_json_string::is_free_from_unescaped_quote(target), "");
|
||||
* s.unsafe_is_equal(target);
|
||||
*/
|
||||
simdjson_inline bool unsafe_is_equal(const char* target) const noexcept;
|
||||
|
||||
/**
|
||||
* This compares the current instance to the std::string_view target: returns true if
|
||||
* they are byte-by-byte equal (no escaping is done).
|
||||
*/
|
||||
simdjson_inline bool is_equal(std::string_view target) const noexcept;
|
||||
|
||||
/**
|
||||
* This compares the current instance to the C string target: returns true if
|
||||
* they are byte-by-byte equal (no escaping is done).
|
||||
*/
|
||||
simdjson_inline bool is_equal(const char* target) const noexcept;
|
||||
|
||||
/**
|
||||
* Returns true if target is free from unescaped quote. If target is known at
|
||||
* compile-time, we might expect the computation to happen at compile time with
|
||||
* many compilers (not all!).
|
||||
*/
|
||||
static simdjson_inline bool is_free_from_unescaped_quote(std::string_view target) noexcept;
|
||||
static simdjson_inline bool is_free_from_unescaped_quote(const char* target) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/**
|
||||
* This will set the inner pointer to zero, effectively making
|
||||
* this instance unusable.
|
||||
*/
|
||||
simdjson_inline void consume() noexcept { buf = nullptr; }
|
||||
|
||||
/**
|
||||
* Checks whether the inner pointer is non-null and thus usable.
|
||||
*/
|
||||
simdjson_inline simdjson_warn_unused bool alive() const noexcept { return buf != nullptr; }
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||
* The result will be a valid UTF-8.
|
||||
*
|
||||
* ## IMPORTANT: string_view lifetime
|
||||
*
|
||||
* The string_view is only valid until the next parse() call on the parser.
|
||||
*
|
||||
* @param iter A json_iterator, which contains a buffer where the string will be written.
|
||||
* @param allow_replacement Whether we allow replacement of invalid surrogate pairs.
|
||||
*/
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(json_iterator &iter, bool allow_replacement) const noexcept;
|
||||
|
||||
/**
|
||||
* Unescape this JSON string, replacing \\ with \, \n with newline, etc.
|
||||
* The result may not be a valid UTF-8. https://simonsapin.github.io/wtf-8/
|
||||
*
|
||||
* ## IMPORTANT: string_view lifetime
|
||||
*
|
||||
* The string_view is only valid until the next parse() call on the parser.
|
||||
*
|
||||
* @param iter A json_iterator, which contains a buffer where the string will be written.
|
||||
*/
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(json_iterator &iter) const noexcept;
|
||||
const uint8_t * buf{};
|
||||
friend class object;
|
||||
friend class field;
|
||||
friend class parser;
|
||||
friend struct simdjson_result<raw_json_string>;
|
||||
};
|
||||
|
||||
simdjson_unused simdjson_inline std::ostream &operator<<(std::ostream &, const raw_json_string &) noexcept;
|
||||
|
||||
/**
|
||||
* Comparisons between raw_json_string and std::string_view instances are potentially unsafe: the user is responsible
|
||||
* for providing a string with no unescaped quote. Note that unescaped quotes cannot be present in valid JSON strings.
|
||||
*/
|
||||
simdjson_unused simdjson_inline bool operator==(const raw_json_string &a, std::string_view c) noexcept;
|
||||
simdjson_unused simdjson_inline bool operator==(std::string_view c, const raw_json_string &a) noexcept;
|
||||
simdjson_unused simdjson_inline bool operator!=(const raw_json_string &a, std::string_view c) noexcept;
|
||||
simdjson_unused simdjson_inline bool operator!=(std::string_view c, const raw_json_string &a) noexcept;
|
||||
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
|
||||
|
||||
simdjson_inline simdjson_result<const char *> raw() const noexcept;
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &iter, bool allow_replacement) const noexcept;
|
||||
simdjson_inline simdjson_warn_unused simdjson_result<std::string_view> unescape_wobbly(SIMDJSON_IMPLEMENTATION::singlestage::json_iterator &iter) const noexcept;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_RAW_JSON_STRING_H
|
||||
@@ -0,0 +1,223 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/array.h"
|
||||
#include "simdjson/generic/singlestage/document-inl.h"
|
||||
#include "simdjson/generic/singlestage/json_type.h"
|
||||
#include "simdjson/generic/singlestage/object.h"
|
||||
#include "simdjson/generic/singlestage/serialization.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#include "simdjson/generic/jsoncharutils.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::document& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::document_reference& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::value& x) noexcept {
|
||||
/**
|
||||
* If we somehow receive a value that has already been consumed,
|
||||
* then the following code could be in trouble. E.g., we create
|
||||
* an array as needed, but if an array was already created, then
|
||||
* it could be bad.
|
||||
*/
|
||||
using namespace SIMDJSON_IMPLEMENTATION::singlestage;
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::json_type t;
|
||||
auto error = x.type().get(t);
|
||||
if(error != SUCCESS) { return error; }
|
||||
switch (t)
|
||||
{
|
||||
case json_type::array:
|
||||
{
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::array array;
|
||||
error = x.get_array().get(array);
|
||||
if(error) { return error; }
|
||||
return to_json_string(array);
|
||||
}
|
||||
case json_type::object:
|
||||
{
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::object object;
|
||||
error = x.get_object().get(object);
|
||||
if(error) { return error; }
|
||||
return to_json_string(object);
|
||||
}
|
||||
default:
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(x.raw_json_token());
|
||||
}
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::object& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::array& x) noexcept {
|
||||
std::string_view v;
|
||||
auto error = x.raw_json().get(v);
|
||||
if(error) {return error; }
|
||||
return SIMDJSON_IMPLEMENTATION::jsoncharutils::trim(v);
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document_reference> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> x) {
|
||||
if (x.error()) { return x.error(); }
|
||||
return to_json_string(x.value_unsafe());
|
||||
}
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace singlestage {
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::value x) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(x).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::value> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#else
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::value x) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(x).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
return (out << error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::array value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::array> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#else
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::array value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
return (out << error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document& value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document_reference& value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document>&& x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document_reference>&& x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#else
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document& value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
return (out << error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::object value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
throw simdjson::simdjson_error(error);
|
||||
}
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::object> x) {
|
||||
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
|
||||
return (out << x.value());
|
||||
}
|
||||
#else
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::object value) {
|
||||
std::string_view v;
|
||||
auto error = simdjson::to_json_string(value).get(v);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
return (out << v);
|
||||
} else {
|
||||
return (out << error);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::singlestage
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_INL_H
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* Create a string-view instance out of a document instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::document& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of a value instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again. The value must
|
||||
* not have been accessed previously. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::value& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of an object instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::object& x) noexcept;
|
||||
/**
|
||||
* Create a string-view instance out of an array instance. The string-view instance
|
||||
* contains JSON text that is suitable to be parsed as JSON again. It does not
|
||||
* validate the content.
|
||||
*/
|
||||
inline simdjson_result<std::string_view> to_json_string(SIMDJSON_IMPLEMENTATION::singlestage::array& x) noexcept;
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::document> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> x);
|
||||
inline simdjson_result<std::string_view> to_json_string(simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> x);
|
||||
} // namespace simdjson
|
||||
|
||||
/**
|
||||
* We want to support argument-dependent lookup (ADL).
|
||||
* Hence we should define operator<< in the namespace
|
||||
* where the argument (here value, object, etc.) resides.
|
||||
* Credit: @madhur4127
|
||||
* See https://github.com/simdjson/simdjson/issues/1768
|
||||
*/
|
||||
namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace singlestage {
|
||||
|
||||
/**
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The element.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::value x);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::value> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The array.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::array value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::array> x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The array.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document& value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document>&& x);
|
||||
#endif
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document_reference& value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::document_reference>&& x);
|
||||
#endif
|
||||
/**
|
||||
* Print JSON to an output stream. It does not
|
||||
* validate the content.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param value The object.
|
||||
* @throw if there is an error with the underlying output stream. simdjson itself will not throw.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::SIMDJSON_IMPLEMENTATION::singlestage::object value);
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::SIMDJSON_IMPLEMENTATION::singlestage::object> x);
|
||||
#endif
|
||||
}}} // namespace simdjson::SIMDJSON_IMPLEMENTATION::singlestage
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_SERIALIZATION_H
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/token_iterator.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline token_iterator::token_iterator(
|
||||
const uint8_t *_buf,
|
||||
token_position position
|
||||
) noexcept : buf{_buf}, _position{position}
|
||||
{
|
||||
}
|
||||
|
||||
simdjson_inline uint32_t token_iterator::current_offset() const noexcept {
|
||||
return *(_position);
|
||||
}
|
||||
|
||||
|
||||
simdjson_inline const uint8_t *token_iterator::return_current_and_advance() noexcept {
|
||||
return &buf[*(_position++)];
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *token_iterator::peek(token_position position) const noexcept {
|
||||
return &buf[*position];
|
||||
}
|
||||
simdjson_inline uint32_t token_iterator::peek_index(token_position position) const noexcept {
|
||||
return *position;
|
||||
}
|
||||
simdjson_inline uint32_t token_iterator::peek_length(token_position position) const noexcept {
|
||||
return *(position+1) - *position;
|
||||
}
|
||||
|
||||
simdjson_inline const uint8_t *token_iterator::peek(int32_t delta) const noexcept {
|
||||
return &buf[*(_position+delta)];
|
||||
}
|
||||
simdjson_inline uint32_t token_iterator::peek_index(int32_t delta) const noexcept {
|
||||
return *(_position+delta);
|
||||
}
|
||||
simdjson_inline uint32_t token_iterator::peek_length(int32_t delta) const noexcept {
|
||||
return *(_position+delta+1) - *(_position+delta);
|
||||
}
|
||||
|
||||
simdjson_inline token_position token_iterator::position() const noexcept {
|
||||
return _position;
|
||||
}
|
||||
simdjson_inline void token_iterator::set_position(token_position target_position) noexcept {
|
||||
_position = target_position;
|
||||
}
|
||||
|
||||
simdjson_inline bool token_iterator::operator==(const token_iterator &other) const noexcept {
|
||||
return _position == other._position;
|
||||
}
|
||||
simdjson_inline bool token_iterator::operator!=(const token_iterator &other) const noexcept {
|
||||
return _position != other._position;
|
||||
}
|
||||
simdjson_inline bool token_iterator::operator>(const token_iterator &other) const noexcept {
|
||||
return _position > other._position;
|
||||
}
|
||||
simdjson_inline bool token_iterator::operator>=(const token_iterator &other) const noexcept {
|
||||
return _position >= other._position;
|
||||
}
|
||||
simdjson_inline bool token_iterator::operator<(const token_iterator &other) const noexcept {
|
||||
return _position < other._position;
|
||||
}
|
||||
simdjson_inline bool token_iterator::operator<=(const token_iterator &other) const noexcept {
|
||||
return _position <= other._position;
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator>::simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::token_iterator &&value) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator>(value)) {}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator>::simdjson_result(error_code error) noexcept
|
||||
: implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator>(error) {}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_INL_H
|
||||
@@ -0,0 +1,151 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/logger.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* Iterates through JSON tokens (`{` `}` `[` `]` `,` `:` `"<string>"` `123` `true` `false` `null`)
|
||||
* detected by stage 1.
|
||||
*
|
||||
* @private This is not intended for external use.
|
||||
*/
|
||||
class token_iterator {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid token_iterator.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline token_iterator() noexcept = default;
|
||||
simdjson_inline token_iterator(token_iterator &&other) noexcept = default;
|
||||
simdjson_inline token_iterator &operator=(token_iterator &&other) noexcept = default;
|
||||
simdjson_inline token_iterator(const token_iterator &other) noexcept = default;
|
||||
simdjson_inline token_iterator &operator=(const token_iterator &other) noexcept = default;
|
||||
|
||||
/**
|
||||
* Advance to the next token (returning the current one).
|
||||
*/
|
||||
simdjson_inline const uint8_t *return_current_and_advance() noexcept;
|
||||
/**
|
||||
* Reports the current offset in bytes from the start of the underlying buffer.
|
||||
*/
|
||||
simdjson_inline uint32_t current_offset() const noexcept;
|
||||
/**
|
||||
* Get the JSON text for a given token (relative).
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = current token,
|
||||
* 1 = next token, -1 = prev token.
|
||||
*
|
||||
* TODO consider a string_view, assuming the length will get stripped out by the optimizer when
|
||||
* it isn't used ...
|
||||
*/
|
||||
simdjson_inline const uint8_t *peek(int32_t delta=0) const noexcept;
|
||||
/**
|
||||
* Get the maximum length of the JSON text for a given token.
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = current token,
|
||||
* 1 = next token, -1 = prev token.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(int32_t delta=0) const noexcept;
|
||||
|
||||
/**
|
||||
* Get the JSON text for a given token.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param position The position of the token.
|
||||
*
|
||||
*/
|
||||
simdjson_inline const uint8_t *peek(token_position position) const noexcept;
|
||||
/**
|
||||
* Get the maximum length of the JSON text for a given token.
|
||||
*
|
||||
* The length will include any whitespace at the end of the token.
|
||||
*
|
||||
* @param position The position of the token.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_length(token_position position) const noexcept;
|
||||
|
||||
/**
|
||||
* Return the current index.
|
||||
*/
|
||||
simdjson_inline token_position position() const noexcept;
|
||||
/**
|
||||
* Reset to a previously saved index.
|
||||
*/
|
||||
simdjson_inline void set_position(token_position target_position) noexcept;
|
||||
|
||||
// NOTE: we don't support a full C++ iterator interface, because we expect people to make
|
||||
// different calls to advance the iterator based on *their own* state.
|
||||
|
||||
simdjson_inline bool operator==(const token_iterator &other) const noexcept;
|
||||
simdjson_inline bool operator!=(const token_iterator &other) const noexcept;
|
||||
simdjson_inline bool operator>(const token_iterator &other) const noexcept;
|
||||
simdjson_inline bool operator>=(const token_iterator &other) const noexcept;
|
||||
simdjson_inline bool operator<(const token_iterator &other) const noexcept;
|
||||
simdjson_inline bool operator<=(const token_iterator &other) const noexcept;
|
||||
|
||||
protected:
|
||||
simdjson_inline token_iterator(const uint8_t *buf, token_position position) noexcept;
|
||||
|
||||
/**
|
||||
* Get the index of the JSON text for a given token (relative).
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param delta The relative position of the token to retrieve. e.g. 0 = current token,
|
||||
* 1 = next token, -1 = prev token.
|
||||
*/
|
||||
simdjson_inline uint32_t peek_index(int32_t delta=0) const noexcept;
|
||||
/**
|
||||
* Get the index of the JSON text for a given token.
|
||||
*
|
||||
* This is not null-terminated; it is a view into the JSON.
|
||||
*
|
||||
* @param position The position of the token.
|
||||
*
|
||||
*/
|
||||
simdjson_inline uint32_t peek_index(token_position position) const noexcept;
|
||||
|
||||
const uint8_t *buf{};
|
||||
token_position _position{};
|
||||
|
||||
friend class json_iterator;
|
||||
friend class value_iterator;
|
||||
friend class object;
|
||||
template <typename... Args>
|
||||
friend simdjson_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta, logger::log_level level, Args&&... args) noexcept;
|
||||
template <typename... Args>
|
||||
friend simdjson_inline void logger::log_line(const json_iterator &iter, token_position index, depth_t depth, const char *title_prefix, const char *title, std::string_view detail, logger::log_level level, Args&&... args) noexcept;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::token_iterator> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::token_iterator &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
simdjson_inline ~simdjson_result() noexcept = default; ///< @private
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_TOKEN_ITERATOR_H
|
||||
@@ -0,0 +1,439 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_VALUE_INL_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_VALUE_INL_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/singlestage/array.h"
|
||||
#include "simdjson/generic/singlestage/array_iterator.h"
|
||||
#include "simdjson/generic/singlestage/json_iterator.h"
|
||||
#include "simdjson/generic/singlestage/json_type.h"
|
||||
#include "simdjson/generic/singlestage/object.h"
|
||||
#include "simdjson/generic/singlestage/raw_json_string.h"
|
||||
#include "simdjson/generic/singlestage/value.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
simdjson_inline value::value(const value_iterator &_iter) noexcept
|
||||
: iter{_iter}
|
||||
{
|
||||
}
|
||||
simdjson_inline value value::start(const value_iterator &iter) noexcept {
|
||||
return iter;
|
||||
}
|
||||
simdjson_inline value value::resume(const value_iterator &iter) noexcept {
|
||||
return iter;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<array> value::get_array() noexcept {
|
||||
return array::start(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<object> value::get_object() noexcept {
|
||||
return object::start(iter);
|
||||
}
|
||||
simdjson_inline simdjson_result<object> value::start_or_resume_object() noexcept {
|
||||
if (iter.at_start()) {
|
||||
return get_object();
|
||||
} else {
|
||||
return object::resume(iter);
|
||||
}
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() noexcept {
|
||||
return iter.get_raw_json_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
|
||||
return iter.get_string(allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
|
||||
return iter.get_wobbly_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> value::get_double() noexcept {
|
||||
return iter.get_double();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> value::get_double_in_string() noexcept {
|
||||
return iter.get_double_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> value::get_uint64() noexcept {
|
||||
return iter.get_uint64();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> value::get_uint64_in_string() noexcept {
|
||||
return iter.get_uint64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> value::get_int64() noexcept {
|
||||
return iter.get_int64();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> value::get_int64_in_string() noexcept {
|
||||
return iter.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> value::get_bool() noexcept {
|
||||
return iter.get_bool();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> value::is_null() noexcept {
|
||||
return iter.is_null();
|
||||
}
|
||||
template<> simdjson_inline simdjson_result<array> value::get() noexcept { return get_array(); }
|
||||
template<> simdjson_inline simdjson_result<object> value::get() noexcept { return get_object(); }
|
||||
template<> simdjson_inline simdjson_result<raw_json_string> value::get() noexcept { return get_raw_json_string(); }
|
||||
template<> simdjson_inline simdjson_result<std::string_view> value::get() noexcept { return get_string(false); }
|
||||
template<> simdjson_inline simdjson_result<number> value::get() noexcept { return get_number(); }
|
||||
template<> simdjson_inline simdjson_result<double> value::get() noexcept { return get_double(); }
|
||||
template<> simdjson_inline simdjson_result<uint64_t> value::get() noexcept { return get_uint64(); }
|
||||
template<> simdjson_inline simdjson_result<int64_t> value::get() noexcept { return get_int64(); }
|
||||
template<> simdjson_inline simdjson_result<bool> value::get() noexcept { return get_bool(); }
|
||||
|
||||
template<typename T> simdjson_inline error_code value::get(T &out) noexcept {
|
||||
return get<T>().get(out);
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline value::operator array() noexcept(false) {
|
||||
return get_array();
|
||||
}
|
||||
simdjson_inline value::operator object() noexcept(false) {
|
||||
return get_object();
|
||||
}
|
||||
simdjson_inline value::operator uint64_t() noexcept(false) {
|
||||
return get_uint64();
|
||||
}
|
||||
simdjson_inline value::operator int64_t() noexcept(false) {
|
||||
return get_int64();
|
||||
}
|
||||
simdjson_inline value::operator double() noexcept(false) {
|
||||
return get_double();
|
||||
}
|
||||
simdjson_inline value::operator std::string_view() noexcept(false) {
|
||||
return get_string(false);
|
||||
}
|
||||
simdjson_inline value::operator raw_json_string() noexcept(false) {
|
||||
return get_raw_json_string();
|
||||
}
|
||||
simdjson_inline value::operator bool() noexcept(false) {
|
||||
return get_bool();
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline simdjson_result<array_iterator> value::begin() & noexcept {
|
||||
return get_array().begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<array_iterator> value::end() & noexcept {
|
||||
return {};
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> value::count_elements() & noexcept {
|
||||
simdjson_result<size_t> answer;
|
||||
auto a = get_array();
|
||||
answer = a.count_elements();
|
||||
// count_elements leaves you pointing inside the array, at the first element.
|
||||
// We need to move back so that the user can create a new array (which requires that
|
||||
// we point at '[').
|
||||
iter.move_at_start();
|
||||
return answer;
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> value::count_fields() & noexcept {
|
||||
simdjson_result<size_t> answer;
|
||||
auto a = get_object();
|
||||
answer = a.count_fields();
|
||||
iter.move_at_start();
|
||||
return answer;
|
||||
}
|
||||
simdjson_inline simdjson_result<value> value::at(size_t index) noexcept {
|
||||
auto a = get_array();
|
||||
return a.at(index);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> value::find_field(std::string_view key) noexcept {
|
||||
return start_or_resume_object().find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> value::find_field(const char *key) noexcept {
|
||||
return start_or_resume_object().find_field(key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
|
||||
return start_or_resume_object().find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<value> value::find_field_unordered(const char *key) noexcept {
|
||||
return start_or_resume_object().find_field_unordered(key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> value::operator[](std::string_view key) noexcept {
|
||||
return start_or_resume_object()[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<value> value::operator[](const char *key) noexcept {
|
||||
return start_or_resume_object()[key];
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<json_type> value::type() noexcept {
|
||||
return iter.type();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> value::is_scalar() noexcept {
|
||||
json_type this_type;
|
||||
auto error = type().get(this_type);
|
||||
if(error) { return error; }
|
||||
return ! ((this_type == json_type::array) || (this_type == json_type::object));
|
||||
}
|
||||
|
||||
simdjson_inline bool value::is_negative() noexcept {
|
||||
return iter.is_negative();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<bool> value::is_integer() noexcept {
|
||||
return iter.is_integer();
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> value::get_number_type() noexcept {
|
||||
return iter.get_number_type();
|
||||
}
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> value::get_number() noexcept {
|
||||
return iter.get_number();
|
||||
}
|
||||
|
||||
simdjson_inline std::string_view value::raw_json_token() noexcept {
|
||||
return std::string_view(reinterpret_cast<const char*>(iter.peek_start()), iter.peek_start_length());
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
|
||||
return iter.json_iter().current_location();
|
||||
}
|
||||
|
||||
simdjson_inline int32_t value::current_depth() const noexcept{
|
||||
return iter.json_iter().depth();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<value> value::at_pointer(std::string_view json_pointer) noexcept {
|
||||
json_type t;
|
||||
SIMDJSON_TRY(type().get(t));
|
||||
switch (t)
|
||||
{
|
||||
case json_type::array:
|
||||
return (*this).get_array().at_pointer(json_pointer);
|
||||
case json_type::object:
|
||||
return (*this).get_object().at_pointer(json_pointer);
|
||||
default:
|
||||
return INVALID_JSON_POINTER;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::simdjson_result(
|
||||
SIMDJSON_IMPLEMENTATION::singlestage::value &&value
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::value>(
|
||||
std::forward<SIMDJSON_IMPLEMENTATION::singlestage::value>(value)
|
||||
)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::simdjson_result(
|
||||
error_code error
|
||||
) noexcept :
|
||||
implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::value>(error)
|
||||
{
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::count_elements() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_elements();
|
||||
}
|
||||
simdjson_inline simdjson_result<size_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::count_fields() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.count_fields();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::at(size_t index) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at(index);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::begin() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.begin();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::end() & noexcept {
|
||||
if (error()) { return error(); }
|
||||
return {};
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::find_field(std::string_view key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::find_field(const char *key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field(key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::find_field_unordered(std::string_view key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::find_field_unordered(const char *key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.find_field_unordered(key);
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator[](std::string_view key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator[](const char *key) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first[key];
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_array() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_array();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_object() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_object();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_uint64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64();
|
||||
}
|
||||
simdjson_inline simdjson_result<uint64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_uint64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_uint64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_int64() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64();
|
||||
}
|
||||
simdjson_inline simdjson_result<int64_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_int64_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_int64_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_double() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double();
|
||||
}
|
||||
simdjson_inline simdjson_result<double> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_double_in_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_double_in_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_string(bool allow_replacement) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_string(allow_replacement);
|
||||
}
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_wobbly_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_wobbly_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_raw_json_string() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_raw_json_string();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_bool() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_bool();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::is_null() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_null();
|
||||
}
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>();
|
||||
}
|
||||
template<typename T> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get(T &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get<T>(out);
|
||||
}
|
||||
|
||||
template<> simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get<SIMDJSON_IMPLEMENTATION::singlestage::value>() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return std::move(first);
|
||||
}
|
||||
template<> simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get<SIMDJSON_IMPLEMENTATION::singlestage::value>(SIMDJSON_IMPLEMENTATION::singlestage::value &out) noexcept {
|
||||
if (error()) { return error(); }
|
||||
out = first;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.type();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::is_scalar() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_scalar();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::is_negative() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_negative();
|
||||
}
|
||||
simdjson_inline simdjson_result<bool> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::is_integer() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.is_integer();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_number_type() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number_type();
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::get_number() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.get_number();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator SIMDJSON_IMPLEMENTATION::singlestage::array() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator SIMDJSON_IMPLEMENTATION::singlestage::object() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator uint64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator int64_t() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator double() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator std::string_view() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::operator bool() noexcept(false) {
|
||||
if (error()) { throw simdjson_error(error()); }
|
||||
return first;
|
||||
}
|
||||
#endif
|
||||
|
||||
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::raw_json_token() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.raw_json_token();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::current_location() noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_location();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<int32_t> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::current_depth() const noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.current_depth();
|
||||
}
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value>::at_pointer(std::string_view json_pointer) noexcept {
|
||||
if (error()) { return error(); }
|
||||
return first.at_pointer(json_pointer);
|
||||
}
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_VALUE_INL_H
|
||||
@@ -0,0 +1,707 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_VALUE_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_VALUE_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#include "simdjson/generic/singlestage/value_iterator.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* An ephemeral JSON value returned during iteration. It is only valid for as long as you do
|
||||
* not access more data in the JSON document.
|
||||
*/
|
||||
class value {
|
||||
public:
|
||||
/**
|
||||
* Create a new invalid value.
|
||||
*
|
||||
* Exists so you can declare a variable and later assign to it before use.
|
||||
*/
|
||||
simdjson_inline value() noexcept = default;
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
||||
*
|
||||
* You may use get_double(), get_bool(), get_uint64(), get_int64(),
|
||||
* get_object(), get_array(), get_raw_json_string(), or get_string() instead.
|
||||
*
|
||||
* @returns A value of the given type, parsed from the JSON.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not the given type.
|
||||
*/
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept {
|
||||
// Unless the simdjson library provides an inline implementation, calling this method should
|
||||
// immediately fail.
|
||||
static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this value as the given type.
|
||||
*
|
||||
* Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool
|
||||
*
|
||||
* @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
* @returns SUCCESS If the parse succeeded and the out parameter was set to the value.
|
||||
*/
|
||||
template<typename T> simdjson_inline error_code get(T &out) noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
*
|
||||
* @returns An object that can be used to iterate the array.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an array.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array> get_array() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an object.
|
||||
*
|
||||
* @returns An object that can be used to look up or iterate fields.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<object> get_object() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to an unsigned integer.
|
||||
*
|
||||
* @returns A unsigned 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a unsigned integer.
|
||||
*
|
||||
* @returns A unsigned 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value (inside string) to a double
|
||||
*
|
||||
* @returns A double.
|
||||
* @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* Equivalent to get<std::string_view>().
|
||||
*
|
||||
* Important: a value should be consumed once. Calling get_string() twice on the same value
|
||||
* is an error.
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a "wobbly" string.
|
||||
*
|
||||
* The string is may not be a valid UTF-8 string.
|
||||
* See https://simonsapin.github.io/wtf-8/
|
||||
*
|
||||
* Important: a value should be consumed once. Calling get_wobbly_string() twice on the same value
|
||||
* is an error.
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
/**
|
||||
* Cast this JSON value to a raw_json_string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
|
||||
*
|
||||
* @returns A pointer to the raw JSON for the given string.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
|
||||
/**
|
||||
* Cast this JSON value to a bool.
|
||||
*
|
||||
* @returns A bool value.
|
||||
* @returns INCORRECT_TYPE if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
|
||||
/**
|
||||
* Checks if this JSON value is null. If and only if the value is
|
||||
* null, then it is consumed (we advance). If we find a token that
|
||||
* begins with 'n' but is not 'null', then an error is returned.
|
||||
*
|
||||
* @returns Whether the value is null.
|
||||
* @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
/**
|
||||
* Cast this JSON value to an array.
|
||||
*
|
||||
* @returns An object that can be used to iterate the array.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array.
|
||||
*/
|
||||
simdjson_inline operator array() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to an object.
|
||||
*
|
||||
* @returns An object that can be used to look up or iterate fields.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object.
|
||||
*/
|
||||
simdjson_inline operator object() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to an unsigned integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer.
|
||||
*/
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a signed integer.
|
||||
*
|
||||
* @returns A signed 64-bit integer.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer.
|
||||
*/
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a double.
|
||||
*
|
||||
* @returns A double.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number.
|
||||
*/
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8.
|
||||
*
|
||||
* Equivalent to get<std::string_view>().
|
||||
*
|
||||
* @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next
|
||||
* time it parses a document or when it is destroyed.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a raw_json_string.
|
||||
*
|
||||
* The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n).
|
||||
*
|
||||
* @returns A pointer to the raw JSON for the given string.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string.
|
||||
*/
|
||||
simdjson_inline operator raw_json_string() noexcept(false);
|
||||
/**
|
||||
* Cast this JSON value to a bool.
|
||||
*
|
||||
* @returns A bool value.
|
||||
* @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false.
|
||||
*/
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Begin array iteration.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*
|
||||
* @returns INCORRECT_TYPE If the JSON value is not an array.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> begin() & noexcept;
|
||||
/**
|
||||
* Sentinel representing the end of the array.
|
||||
*
|
||||
* Part of the std::iterable interface.
|
||||
*/
|
||||
simdjson_inline simdjson_result<array_iterator> end() & noexcept;
|
||||
/**
|
||||
* This method scans the array and counts the number of elements.
|
||||
* The count_elements method should always be called before you have begun
|
||||
* iterating through the array: it is expected that you are pointing at
|
||||
* the beginning of the array.
|
||||
* The runtime complexity is linear in the size of the array. After
|
||||
* calling this function, if successful, the array is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*
|
||||
* Performance hint: You should only call count_elements() as a last
|
||||
* resort as it may require scanning the document twice or more.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
/**
|
||||
* This method scans the object and counts the number of key-value pairs.
|
||||
* The count_fields method should always be called before you have begun
|
||||
* iterating through the object: it is expected that you are pointing at
|
||||
* the beginning of the object.
|
||||
* The runtime complexity is linear in the size of the object. After
|
||||
* calling this function, if successful, the object is 'rewinded' at its
|
||||
* beginning as if it had never been accessed. If the JSON is malformed (e.g.,
|
||||
* there is a missing comma), then an error is returned and it is no longer
|
||||
* safe to continue.
|
||||
*
|
||||
* To check that an object is empty, it is more performant to use
|
||||
* the is_empty() method on the object instance.
|
||||
*
|
||||
* Performance hint: You should only call count_fields() as a last
|
||||
* resort as it may require scanning the document twice or more.
|
||||
*/
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
/**
|
||||
* Get the value at the given index in the array. This function has linear-time complexity.
|
||||
* This function should only be called once on an array instance since the array iterator is not reset between each call.
|
||||
*
|
||||
* @return The value at the given index, or:
|
||||
* - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at(size_t index) noexcept;
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
*
|
||||
* ```c++
|
||||
* simdjson::singlestage::parser parser;
|
||||
* auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
|
||||
* double z = obj.find_field("z");
|
||||
* double y = obj.find_field("y");
|
||||
* double x = obj.find_field("x");
|
||||
* ```
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field(const char *key) noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object, without regard to key order.
|
||||
*
|
||||
* **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
|
||||
* and often appears negligible. It starts out normally, starting out at the last field; but if
|
||||
* the field is not found, it scans from the beginning of the object to see if it missed it. That
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* If you have multiple fields with a matching key ({"x": 1, "x": 1}) be mindful
|
||||
* that only one field is returned.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<value> find_field_unordered(const char *key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<value> operator[](const char *key) noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value. It does not validate or consume the value.
|
||||
* E.g., you must still call "is_null()" to check that a value is null even if
|
||||
* "type()" returns json_type::null.
|
||||
*
|
||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||
* let it throw an exception).
|
||||
*
|
||||
* @return The type of JSON value (json_type::array, json_type::object, json_type::string,
|
||||
* json_type::number, json_type::boolean, or json_type::null).
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_inline simdjson_result<json_type> type() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the value is a scalar (string, number, null, Boolean).
|
||||
* Returns false when there it is an array or object.
|
||||
*
|
||||
* @returns true if the type is string, number, null, Boolean
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
|
||||
/**
|
||||
* Checks whether the value is a negative number.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_inline bool is_negative() noexcept;
|
||||
/**
|
||||
* Checks whether the value is an integer number. Note that
|
||||
* this requires to partially parse the number string. If
|
||||
* the value is determined to be an integer, it may still
|
||||
* not parse properly as an integer in subsequent steps
|
||||
* (e.g., it might overflow).
|
||||
*
|
||||
* Performance note: if you call this function systematically
|
||||
* before parsing a number, you may have fallen for a performance
|
||||
* anti-pattern.
|
||||
*
|
||||
* @returns true if the number if negative.
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
/**
|
||||
* Determine the number type (integer or floating-point number) as quickly
|
||||
* as possible. This function does not fully validate the input. It is
|
||||
* useful when you only need to classify the numbers, without parsing them.
|
||||
*
|
||||
* If you are planning to retrieve the value or you need full validation,
|
||||
* consider using the get_number() method instead: it will fully parse
|
||||
* and validate the input, and give you access to the type:
|
||||
* get_number().get_number_type().
|
||||
*
|
||||
* get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer greater or equal to 9223372036854775808
|
||||
* get_number_type() is number_type::signed_integer if we have an
|
||||
* integer that is less than 9223372036854775808
|
||||
* Otherwise, get_number_type() has value number_type::floating_point_number
|
||||
*
|
||||
* This function requires processing the number string, but it is expected
|
||||
* to be faster than get_number().get_number_type() because it is does not
|
||||
* parse the number value.
|
||||
*
|
||||
* @returns the type of the number
|
||||
*/
|
||||
simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
|
||||
/**
|
||||
* Attempt to parse an singlestage::number. An singlestage::number may
|
||||
* contain an integer value or a floating-point value, the simdjson
|
||||
* library will autodetect the type. Thus it is a dynamically typed
|
||||
* number. Before accessing the value, you must determine the detected
|
||||
* type.
|
||||
*
|
||||
* number.get_number_type() is number_type::signed_integer if we have
|
||||
* an integer in [-9223372036854775808,9223372036854775808)
|
||||
* You can recover the value by calling number.get_int64() and you
|
||||
* have that number.is_int64() is true.
|
||||
*
|
||||
* number.get_number_type() is number_type::unsigned_integer if we have
|
||||
* an integer in [9223372036854775808,18446744073709551616)
|
||||
* You can recover the value by calling number.get_uint64() and you
|
||||
* have that number.is_uint64() is true.
|
||||
*
|
||||
* Otherwise, number.get_number_type() has value number_type::floating_point_number
|
||||
* and we have a binary64 number.
|
||||
* You can recover the value by calling number.get_double() and you
|
||||
* have that number.is_double() is true.
|
||||
*
|
||||
* You must check the type before accessing the value: it is an error
|
||||
* to call "get_int64()" when number.get_number_type() is not
|
||||
* number_type::signed_integer and when number.is_int64() is false.
|
||||
*
|
||||
* Performance note: this is designed with performance in mind. When
|
||||
* calling 'get_number()', you scan the number string only once, determining
|
||||
* efficiently the type and storing it in an efficient manner.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
|
||||
/**
|
||||
* Get the raw JSON for this token.
|
||||
*
|
||||
* The string_view will always point into the input buffer.
|
||||
*
|
||||
* The string_view will start at the beginning of the token, and include the entire token
|
||||
* *as well as all spaces until the next token (or EOF).* This means, for example, that a
|
||||
* string token always begins with a " and is always terminated by the final ", possibly
|
||||
* followed by a number of spaces.
|
||||
*
|
||||
* The string_view is *not* null-terminated. However, if this is a scalar (string, number,
|
||||
* boolean, or null), the character after the end of the string_view is guaranteed to be
|
||||
* a non-space token.
|
||||
*
|
||||
* Tokens include:
|
||||
* - {
|
||||
* - [
|
||||
* - "a string (possibly with UTF-8 or backslashed characters like \\\")".
|
||||
* - -1.2e-100
|
||||
* - true
|
||||
* - false
|
||||
* - null
|
||||
*/
|
||||
simdjson_inline std::string_view raw_json_token() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current location in the document if in bounds.
|
||||
*/
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
|
||||
/**
|
||||
* Returns the current depth in the document if in bounds.
|
||||
*
|
||||
* E.g.,
|
||||
* 0 = finished with document
|
||||
* 1 = document root value (could be [ or {, not yet known)
|
||||
* 2 = , or } inside root array/object
|
||||
* 3 = key or value inside root array/object.
|
||||
*/
|
||||
simdjson_inline int32_t current_depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the value associated with the given JSON pointer. We use the RFC 6901
|
||||
* https://tools.ietf.org/html/rfc6901 standard.
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("/foo/a/1") == 20
|
||||
*
|
||||
* It is allowed for a key to be the empty string:
|
||||
*
|
||||
* singlestage::parser parser;
|
||||
* auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded;
|
||||
* auto doc = parser.iterate(json);
|
||||
* doc.at_pointer("//a/1") == 20
|
||||
*
|
||||
* Note that at_pointer() called on the document automatically calls the document's rewind
|
||||
* method between each call. It invalidates all previously accessed arrays, objects and values
|
||||
* that have not been consumed.
|
||||
*
|
||||
* Calling at_pointer() on non-document instances (e.g., arrays and objects) is not
|
||||
* standardized (by RFC 6901). We provide some experimental support for JSON pointers
|
||||
* on non-document instances. Yet it is not the case when calling at_pointer on an array
|
||||
* or an object instance: there is no rewind and no invalidation.
|
||||
*
|
||||
* You may only call at_pointer on an array after it has been created, but before it has
|
||||
* been first accessed. When calling at_pointer on an array, the pointer is advanced to
|
||||
* the location indicated by the JSON pointer (in case of success). It is no longer possible
|
||||
* to call at_pointer on the same array.
|
||||
*
|
||||
* You may call at_pointer more than once on an object, but each time the pointer is advanced
|
||||
* to be within the value matched by the key indicated by the JSON pointer query. Thus any preceding
|
||||
* key (as well as the current key) can no longer be used with following JSON pointer calls.
|
||||
*
|
||||
* Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching
|
||||
*
|
||||
* @return The value associated with the given JSON pointer, or:
|
||||
* - NO_SUCH_FIELD if a field does not exist in an object
|
||||
* - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length
|
||||
* - INCORRECT_TYPE if a non-integer is used to access an array
|
||||
* - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed
|
||||
*/
|
||||
simdjson_inline simdjson_result<value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Create a value.
|
||||
*/
|
||||
simdjson_inline value(const value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* Skip this value, allowing iteration to continue.
|
||||
*/
|
||||
simdjson_inline void skip() noexcept;
|
||||
|
||||
/**
|
||||
* Start a value at the current position.
|
||||
*
|
||||
* (It should already be started; this is just a self-documentation method.)
|
||||
*/
|
||||
static simdjson_inline value start(const value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* Resume a value.
|
||||
*/
|
||||
static simdjson_inline value resume(const value_iterator &iter) noexcept;
|
||||
|
||||
/**
|
||||
* Get the object, starting or resuming it as necessary
|
||||
*/
|
||||
simdjson_inline simdjson_result<object> start_or_resume_object() noexcept;
|
||||
|
||||
// simdjson_inline void log_value(const char *type) const noexcept;
|
||||
// simdjson_inline void log_error(const char *message) const noexcept;
|
||||
|
||||
value_iterator iter{};
|
||||
|
||||
friend class document;
|
||||
friend class array_iterator;
|
||||
friend class field;
|
||||
friend class object;
|
||||
friend struct simdjson_result<value>;
|
||||
friend struct simdjson_result<field>;
|
||||
};
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::value> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::value &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array> get_array() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::object> get_object() noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement = false) noexcept;
|
||||
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline simdjson_result<T> get() noexcept;
|
||||
|
||||
template<typename T> simdjson_inline error_code get(T &out) noexcept;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::array() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::object() noexcept(false);
|
||||
simdjson_inline operator uint64_t() noexcept(false);
|
||||
simdjson_inline operator int64_t() noexcept(false);
|
||||
simdjson_inline operator double() noexcept(false);
|
||||
simdjson_inline operator std::string_view() noexcept(false);
|
||||
simdjson_inline operator SIMDJSON_IMPLEMENTATION::singlestage::raw_json_string() noexcept(false);
|
||||
simdjson_inline operator bool() noexcept(false);
|
||||
#endif
|
||||
simdjson_inline simdjson_result<size_t> count_elements() & noexcept;
|
||||
simdjson_inline simdjson_result<size_t> count_fields() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at(size_t index) noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> begin() & noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::array_iterator> end() & noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object (order-sensitive).
|
||||
*
|
||||
* The following code reads z, then y, then x, and thus will not retrieve x or y if fed the
|
||||
* JSON `{ "x": 1, "y": 2, "z": 3 }`:
|
||||
*
|
||||
* ```c++
|
||||
* simdjson::singlestage::parser parser;
|
||||
* auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded);
|
||||
* double z = obj.find_field("z");
|
||||
* double y = obj.find_field("y");
|
||||
* double x = obj.find_field("x");
|
||||
* ```
|
||||
*
|
||||
* **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys.
|
||||
* e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`.
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field(const char *key) noexcept;
|
||||
|
||||
/**
|
||||
* Look up a field by name on an object, without regard to key order.
|
||||
*
|
||||
* **Performance Notes:** This is a bit less performant than find_field(), though its effect varies
|
||||
* and often appears negligible. It starts out normally, starting out at the last field; but if
|
||||
* the field is not found, it scans from the beginning of the object to see if it missed it. That
|
||||
* missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object
|
||||
* in question is large. The fact that the extra code is there also bumps the executable size.
|
||||
*
|
||||
* It is the default, however, because it would be highly surprising (and hard to debug) if the
|
||||
* default behavior failed to look up a field just because it was in the wrong order--and many
|
||||
* APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order.
|
||||
*
|
||||
* Use find_field() if you are sure fields will be in order (or are willing to treat it as if the
|
||||
* field wasn't there when they aren't).
|
||||
*
|
||||
* @param key The key to look up.
|
||||
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object.
|
||||
*/
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(const char *key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](std::string_view key) noexcept;
|
||||
/** @overload simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> find_field_unordered(std::string_view key) noexcept; */
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> operator[](const char *key) noexcept;
|
||||
|
||||
/**
|
||||
* Get the type of this JSON value.
|
||||
*
|
||||
* NOTE: If you're only expecting a value to be one type (a typical case), it's generally
|
||||
* better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just
|
||||
* let it throw an exception).
|
||||
*/
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::json_type> type() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_scalar() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_negative() noexcept;
|
||||
simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::number_type> get_number_type() noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::number> get_number() noexcept;
|
||||
|
||||
/** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
|
||||
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
|
||||
|
||||
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
|
||||
simdjson_inline simdjson_result<const char *> current_location() noexcept;
|
||||
/** @copydoc simdjson_inline int32_t current_depth() const noexcept */
|
||||
simdjson_inline simdjson_result<int32_t> current_depth() const noexcept;
|
||||
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value> at_pointer(std::string_view json_pointer) noexcept;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_VALUE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,486 @@
|
||||
#ifndef SIMDJSON_GENERIC_SINGLESTAGE_VALUE_ITERATOR_H
|
||||
|
||||
#ifndef SIMDJSON_AMALGAMATED
|
||||
#define SIMDJSON_GENERIC_SINGLESTAGE_VALUE_ITERATOR_H
|
||||
#include "simdjson/generic/singlestage/base.h"
|
||||
#include "simdjson/generic/implementation_simdjson_result_base.h"
|
||||
#endif // SIMDJSON_AMALGAMATED
|
||||
|
||||
namespace simdjson {
|
||||
namespace SIMDJSON_IMPLEMENTATION {
|
||||
namespace singlestage {
|
||||
|
||||
/**
|
||||
* Iterates through a single JSON value at a particular depth.
|
||||
*
|
||||
* Does not keep track of the type of value: provides methods for objects, arrays and scalars and expects
|
||||
* the caller to call the right ones.
|
||||
*
|
||||
* @private This is not intended for external use.
|
||||
*/
|
||||
class value_iterator {
|
||||
protected:
|
||||
/** The underlying JSON iterator */
|
||||
json_iterator *_json_iter{};
|
||||
/** The depth of this value */
|
||||
depth_t _depth{};
|
||||
/**
|
||||
* The starting token index for this value
|
||||
*/
|
||||
token_position _start_position{};
|
||||
|
||||
public:
|
||||
simdjson_inline value_iterator() noexcept = default;
|
||||
|
||||
/**
|
||||
* Denote that we're starting a document.
|
||||
*/
|
||||
simdjson_inline void start_document() noexcept;
|
||||
|
||||
/**
|
||||
* Skips a non-iterated or partially-iterated JSON value, whether it is a scalar, array or object.
|
||||
*
|
||||
* Optimized for scalars.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code skip_child() noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the iterator is at the EOF mark
|
||||
*/
|
||||
simdjson_inline bool at_end() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the iterator is at the start of the value
|
||||
*/
|
||||
simdjson_inline bool at_start() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the value is open--if the value has not been used, or the array/object is still open.
|
||||
*/
|
||||
simdjson_inline bool is_open() const noexcept;
|
||||
|
||||
/**
|
||||
* Tell whether the value is at an object's first field (just after the {).
|
||||
*/
|
||||
simdjson_inline bool at_first_field() const noexcept;
|
||||
|
||||
/**
|
||||
* Abandon all iteration.
|
||||
*/
|
||||
simdjson_inline void abandon() noexcept;
|
||||
|
||||
/**
|
||||
* Get the child value as a value_iterator.
|
||||
*/
|
||||
simdjson_inline value_iterator child_value() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the depth of this value.
|
||||
*/
|
||||
simdjson_inline int32_t depth() const noexcept;
|
||||
|
||||
/**
|
||||
* Get the JSON type of this value.
|
||||
*
|
||||
* @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse".
|
||||
*/
|
||||
simdjson_inline simdjson_result<json_type> type() const noexcept;
|
||||
|
||||
/**
|
||||
* @addtogroup object Object iteration
|
||||
*
|
||||
* Methods to iterate and find object fields. These methods generally *assume* the value is
|
||||
* actually an object; the caller is responsible for keeping track of that fact.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Start an object iteration.
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCORRECT_TYPE if there is no opening {
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_object() noexcept;
|
||||
/**
|
||||
* Start an object iteration from the root.
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCORRECT_TYPE if there is no opening {
|
||||
* @error TAPE_ERROR if there is no matching } at end of document
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_object() noexcept;
|
||||
/**
|
||||
* Checks whether an object could be started from the root. May be called by start_root_object.
|
||||
*
|
||||
* @returns SUCCESS if it is possible to safely start an object from the root (document level).
|
||||
* @error INCORRECT_TYPE if there is no opening {
|
||||
* @error TAPE_ERROR if there is no matching } at end of document
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code check_root_object() noexcept;
|
||||
/**
|
||||
* Start an object iteration after the user has already checked and moved past the {.
|
||||
*
|
||||
* Does not move the iterator unless the object is empty ({}).
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_object() noexcept;
|
||||
/**
|
||||
* Start an object iteration from the root, after the user has already checked and moved past the {.
|
||||
*
|
||||
* Does not move the iterator unless the object is empty ({}).
|
||||
*
|
||||
* @returns Whether the object had any fields (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_object() noexcept;
|
||||
|
||||
/**
|
||||
* Moves to the next field in an object.
|
||||
*
|
||||
* Looks for , and }. If } is found, the object is finished and the iterator advances past it.
|
||||
* Otherwise, it advances to the next value.
|
||||
*
|
||||
* @return whether there is another field in the object.
|
||||
* @error TAPE_ERROR If there is a comma missing between fields.
|
||||
* @error TAPE_ERROR If there is a comma, but not enough tokens remaining to have a key, :, and value.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_field() noexcept;
|
||||
|
||||
/**
|
||||
* Get the current field's key.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> field_key() noexcept;
|
||||
|
||||
/**
|
||||
* Pass the : in the field and move to its value.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code field_value() noexcept;
|
||||
|
||||
/**
|
||||
* Find the next field with the given key.
|
||||
*
|
||||
* Assumes you have called next_field() or otherwise matched the previous value.
|
||||
*
|
||||
* This means the iterator must be sitting at the next key:
|
||||
*
|
||||
* ```
|
||||
* { "a": 1, "b": 2 }
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
|
||||
* unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
|
||||
* fail to match some keys with escapes (\u, \n, etc.).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code find_field(const std::string_view key) noexcept;
|
||||
|
||||
/**
|
||||
* Find the next field with the given key, *without* unescaping. This assumes object order: it
|
||||
* will not find the field if it was already passed when looking for some *other* field.
|
||||
*
|
||||
* Assumes you have called next_field() or otherwise matched the previous value.
|
||||
*
|
||||
* This means the iterator must be sitting at the next key:
|
||||
*
|
||||
* ```
|
||||
* { "a": 1, "b": 2 }
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
|
||||
* unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
|
||||
* fail to match some keys with escapes (\u, \n, etc.).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
|
||||
|
||||
/**
|
||||
* Find the field with the given key without regard to order, and *without* unescaping.
|
||||
*
|
||||
* This is an unordered object lookup: if the field is not found initially, it will cycle around and scan from the beginning.
|
||||
*
|
||||
* Assumes you have called next_field() or otherwise matched the previous value.
|
||||
*
|
||||
* This means the iterator must be sitting at the next key:
|
||||
*
|
||||
* ```
|
||||
* { "a": 1, "b": 2 }
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* Key is *raw JSON,* meaning it will be matched against the verbatim JSON without attempting to
|
||||
* unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
|
||||
* fail to match some keys with escapes (\u, \n, etc.).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> find_field_unordered_raw(const std::string_view key) noexcept;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @addtogroup array Array iteration
|
||||
* Methods to iterate over array elements. These methods generally *assume* the value is actually
|
||||
* an object; the caller is responsible for keeping track of that fact.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check for an opening [ and start an array iteration.
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCORRECT_TYPE If there is no [.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_array() noexcept;
|
||||
/**
|
||||
* Check for an opening [ and start an array iteration while at the root.
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCORRECT_TYPE If there is no [.
|
||||
* @error TAPE_ERROR if there is no matching ] at end of document
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> start_root_array() noexcept;
|
||||
/**
|
||||
* Checks whether an array could be started from the root. May be called by start_root_array.
|
||||
*
|
||||
* @returns SUCCESS if it is possible to safely start an array from the root (document level).
|
||||
* @error INCORRECT_TYPE If there is no [.
|
||||
* @error TAPE_ERROR if there is no matching ] at end of document
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline error_code check_root_array() noexcept;
|
||||
/**
|
||||
* Start an array iteration, after the user has already checked and moved past the [.
|
||||
*
|
||||
* Does not move the iterator unless the array is empty ([]).
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_array() noexcept;
|
||||
/**
|
||||
* Start an array iteration from the root, after the user has already checked and moved past the [.
|
||||
*
|
||||
* Does not move the iterator unless the array is empty ([]).
|
||||
*
|
||||
* @returns Whether the array had any elements (returns false for empty).
|
||||
* @error INCOMPLETE_ARRAY_OR_OBJECT If there are no more tokens (implying the *parent*
|
||||
* array or object is incomplete).
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> started_root_array() noexcept;
|
||||
|
||||
/**
|
||||
* Moves to the next element in an array.
|
||||
*
|
||||
* Looks for , and ]. If ] is found, the array is finished and the iterator advances past it.
|
||||
* Otherwise, it advances to the next value.
|
||||
*
|
||||
* @return Whether there is another element in the array.
|
||||
* @error TAPE_ERROR If there is a comma missing between elements.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> has_next_element() noexcept;
|
||||
|
||||
/**
|
||||
* Get a child value iterator.
|
||||
*/
|
||||
simdjson_warn_unused simdjson_inline value_iterator child() const noexcept;
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup scalar Scalar values
|
||||
* @addtogroup scalar
|
||||
* @{
|
||||
*/
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_raw_json_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_uint64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_int64_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_double_in_string() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_bool() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_null() noexcept;
|
||||
simdjson_warn_unused simdjson_inline bool is_negative() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_integer() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_number_type() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_number() noexcept;
|
||||
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_string(bool check_trailing, bool allow_replacement) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_root_wobbly_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<raw_json_string> get_root_raw_json_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<uint64_t> get_root_uint64_in_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<int64_t> get_root_int64_in_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<double> get_root_double_in_string(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> get_root_bool(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline bool is_root_negative() noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_integer(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number_type> get_root_number_type(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<number> get_root_number(bool check_trailing) noexcept;
|
||||
simdjson_warn_unused simdjson_inline simdjson_result<bool> is_root_null(bool check_trailing) noexcept;
|
||||
|
||||
simdjson_inline error_code error() const noexcept;
|
||||
simdjson_inline uint8_t *&string_buf_loc() noexcept;
|
||||
simdjson_inline const json_iterator &json_iter() const noexcept;
|
||||
simdjson_inline json_iterator &json_iter() noexcept;
|
||||
|
||||
simdjson_inline void assert_is_valid() const noexcept;
|
||||
simdjson_inline bool is_valid() const noexcept;
|
||||
|
||||
/** @} */
|
||||
protected:
|
||||
/**
|
||||
* Restarts an array iteration.
|
||||
* @returns Whether the array has any elements (returns false for empty).
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> reset_array() noexcept;
|
||||
/**
|
||||
* Restarts an object iteration.
|
||||
* @returns Whether the object has any fields (returns false for empty).
|
||||
*/
|
||||
simdjson_inline simdjson_result<bool> reset_object() noexcept;
|
||||
/**
|
||||
* move_at_start(): moves us so that we are pointing at the beginning of
|
||||
* the container. It updates the index so that at_start() is true and it
|
||||
* syncs the depth. The user can then create a new container instance.
|
||||
*
|
||||
* Usage: used with value::count_elements().
|
||||
**/
|
||||
simdjson_inline void move_at_start() noexcept;
|
||||
|
||||
/**
|
||||
* move_at_container_start(): moves us so that we are pointing at the beginning of
|
||||
* the container so that assert_at_container_start() passes.
|
||||
*
|
||||
* Usage: used with reset_array() and reset_object().
|
||||
**/
|
||||
simdjson_inline void move_at_container_start() noexcept;
|
||||
/* Useful for debugging and logging purposes. */
|
||||
inline std::string to_string() const noexcept;
|
||||
simdjson_inline value_iterator(json_iterator *json_iter, depth_t depth, token_position start_index) noexcept;
|
||||
|
||||
simdjson_inline simdjson_result<bool> parse_null(const uint8_t *json) const noexcept;
|
||||
simdjson_inline simdjson_result<bool> parse_bool(const uint8_t *json) const noexcept;
|
||||
simdjson_inline const uint8_t *peek_start() const noexcept;
|
||||
simdjson_inline uint32_t peek_start_length() const noexcept;
|
||||
|
||||
/**
|
||||
* The general idea of the advance_... methods and the peek_* methods
|
||||
* is that you first peek and check that you have desired type. If you do,
|
||||
* and only if you do, then you advance.
|
||||
*
|
||||
* We used to unconditionally advance. But this made reasoning about our
|
||||
* current state difficult.
|
||||
* Suppose you always advance. Look at the 'value' matching the key
|
||||
* "shadowable" in the following example...
|
||||
*
|
||||
* ({"globals":{"a":{"shadowable":[}}}})
|
||||
*
|
||||
* If the user thinks it is a Boolean and asks for it, then we check the '[',
|
||||
* decide it is not a Boolean, but still move into the next character ('}'). Now
|
||||
* we are left pointing at '}' right after a '['. And we have not yet reported
|
||||
* an error, only that we do not have a Boolean.
|
||||
*
|
||||
* If, instead, you just stand your ground until it is content that you know, then
|
||||
* you will only even move beyond the '[' if the user tells you that you have an
|
||||
* array. So you will be at the '}' character inside the array and, hopefully, you
|
||||
* will then catch the error because an array cannot start with '}', but the code
|
||||
* processing Boolean values does not know this.
|
||||
*
|
||||
* So the contract is: first call 'peek_...' and then call 'advance_...' only
|
||||
* if you have determined that it is a type you can handle.
|
||||
*
|
||||
* Unfortunately, it makes the code more verbose, longer and maybe more error prone.
|
||||
*/
|
||||
|
||||
simdjson_inline void advance_scalar(const char *type) noexcept;
|
||||
simdjson_inline void advance_root_scalar(const char *type) noexcept;
|
||||
simdjson_inline void advance_non_root_scalar(const char *type) noexcept;
|
||||
|
||||
simdjson_inline const uint8_t *peek_scalar(const char *type) noexcept;
|
||||
simdjson_inline const uint8_t *peek_root_scalar(const char *type) noexcept;
|
||||
simdjson_inline const uint8_t *peek_non_root_scalar(const char *type) noexcept;
|
||||
|
||||
|
||||
simdjson_inline error_code start_container(uint8_t start_char, const char *incorrect_type_message, const char *type) noexcept;
|
||||
simdjson_inline error_code end_container() noexcept;
|
||||
|
||||
/**
|
||||
* Advance to a place expecting a value (increasing depth).
|
||||
*
|
||||
* @return The current token (the one left behind).
|
||||
* @error TAPE_ERROR If the document ended early.
|
||||
*/
|
||||
simdjson_inline simdjson_result<const uint8_t *> advance_to_value() noexcept;
|
||||
|
||||
simdjson_inline error_code incorrect_type_error(const char *message) const noexcept;
|
||||
simdjson_inline error_code error_unless_more_tokens(uint32_t tokens=1) const noexcept;
|
||||
|
||||
simdjson_inline bool is_at_start() const noexcept;
|
||||
/**
|
||||
* is_at_iterator_start() returns true on an array or object after it has just been
|
||||
* created, whether the instance is empty or not.
|
||||
*
|
||||
* Usage: used by array::begin() in debug mode (SIMDJSON_DEVELOPMENT_CHECKS)
|
||||
*/
|
||||
simdjson_inline bool is_at_iterator_start() const noexcept;
|
||||
|
||||
/**
|
||||
* Assuming that we are within an object, this returns true if we
|
||||
* are pointing at a key.
|
||||
*
|
||||
* Usage: the skip_child() method should never be used while we are pointing
|
||||
* at a key inside an object.
|
||||
*/
|
||||
simdjson_inline bool is_at_key() const noexcept;
|
||||
|
||||
inline void assert_at_start() const noexcept;
|
||||
inline void assert_at_container_start() const noexcept;
|
||||
inline void assert_at_root() const noexcept;
|
||||
inline void assert_at_child() const noexcept;
|
||||
inline void assert_at_next() const noexcept;
|
||||
inline void assert_at_non_root_start() const noexcept;
|
||||
|
||||
/** Get the starting position of this value */
|
||||
simdjson_inline token_position start_position() const noexcept;
|
||||
|
||||
/** @copydoc error_code json_iterator::position() const noexcept; */
|
||||
simdjson_inline token_position position() const noexcept;
|
||||
/** @copydoc error_code json_iterator::end_position() const noexcept; */
|
||||
simdjson_inline token_position last_position() const noexcept;
|
||||
/** @copydoc error_code json_iterator::end_position() const noexcept; */
|
||||
simdjson_inline token_position end_position() const noexcept;
|
||||
/** @copydoc error_code json_iterator::report_error(error_code error, const char *message) noexcept; */
|
||||
simdjson_inline error_code report_error(error_code error, const char *message) noexcept;
|
||||
|
||||
friend class document;
|
||||
friend class object;
|
||||
friend class array;
|
||||
friend class value;
|
||||
}; // value_iterator
|
||||
|
||||
} // namespace singlestage
|
||||
} // namespace SIMDJSON_IMPLEMENTATION
|
||||
} // namespace simdjson
|
||||
|
||||
namespace simdjson {
|
||||
|
||||
template<>
|
||||
struct simdjson_result<SIMDJSON_IMPLEMENTATION::singlestage::value_iterator> : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base<SIMDJSON_IMPLEMENTATION::singlestage::value_iterator> {
|
||||
public:
|
||||
simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::singlestage::value_iterator &&value) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
|
||||
simdjson_inline simdjson_result() noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_GENERIC_SINGLESTAGE_VALUE_ITERATOR_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_HASWELL_SINGLESTAGE_H
|
||||
#define SIMDJSON_HASWELL_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/haswell/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/haswell/end.h"
|
||||
|
||||
#endif // SIMDJSON_HASWELL_SINGLESTAGE_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_ICELAKE_SINGLESTAGE_H
|
||||
#define SIMDJSON_ICELAKE_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/icelake/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/icelake/end.h"
|
||||
|
||||
#endif // SIMDJSON_ICELAKE_SINGLESTAGE_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_PPC64_SINGLESTAGE_H
|
||||
#define SIMDJSON_PPC64_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/ppc64/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/ppc64/end.h"
|
||||
|
||||
#endif // SIMDJSON_PPC64_SINGLESTAGE_H
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef SIMDJSON_SINGLESTAGE_H
|
||||
#define SIMDJSON_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/builtin/singlestage.h"
|
||||
|
||||
namespace simdjson {
|
||||
/**
|
||||
* @copydoc simdjson::builtin::singlestage
|
||||
*/
|
||||
namespace singlestage = builtin::singlestage;
|
||||
} // namespace simdjson
|
||||
|
||||
#endif // SIMDJSON_SINGLESTAGE_H
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef SIMDJSON_WESTMERE_SINGLESTAGE_H
|
||||
#define SIMDJSON_WESTMERE_SINGLESTAGE_H
|
||||
|
||||
#include "simdjson/westmere/begin.h"
|
||||
#include "simdjson/generic/singlestage/amalgamated.h"
|
||||
#include "simdjson/westmere/end.h"
|
||||
|
||||
#endif // SIMDJSON_WESTMERE_IMPLEMENTATION_H
|
||||
@@ -12,6 +12,9 @@ cpus=$( grep processor /proc/cpuinfo | cut -d: -f 2 )
|
||||
if [ "$1" = "ondemand" ]; then
|
||||
echo "setting up ondemand"
|
||||
policy="ondemand"
|
||||
elif [ "$1" = "singlestage" ]; then
|
||||
echo "setting up singlestage"
|
||||
policy="singlestage"
|
||||
elif [ "$1" = "performance" ]; then
|
||||
echo "setting up for performance"
|
||||
policy="performance"
|
||||
@@ -19,7 +22,7 @@ elif [ "$1" = "list" ]; then
|
||||
cpufreq-info
|
||||
exit 0
|
||||
else
|
||||
echo "usage: powerpolicy.sh ondemand | performance list"
|
||||
echo "usage: powerpolicy.sh ondemand | singlestage | performance list"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ link_libraries(simdjson-internal-flags test-data simdjson-windows-headers)
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/add_cpp_test.cmake)
|
||||
add_subdirectory(dom)
|
||||
add_subdirectory(ondemand)
|
||||
add_subdirectory(singlestage)
|
||||
|
||||
|
||||
# All remaining tests link with simdjson proper
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# All remaining tests link with simdjson proper
|
||||
link_libraries(simdjson)
|
||||
include_directories(..)
|
||||
add_subdirectory(compilation_failure_tests)
|
||||
add_cpp_test(singlestage_log_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_log_error_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_tostring_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_active_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_array_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_array_error_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_compilation_tests LABELS singlestage acceptance per_implementation)
|
||||
# add_cpp_test(singlestage_document_stream_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_error_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_error_location_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_json_pointer_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_key_string_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_misc_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_number_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_number_in_string_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_object_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_object_error_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_ordering_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_parse_api_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_readme_examples LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_scalar_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_twitter_tests LABELS singlestage acceptance per_implementation)
|
||||
add_cpp_test(singlestage_wrong_type_error_tests LABELS singlestage acceptance per_implementation)
|
||||
# add_cpp_test(singlestage_iterate_many_csv LABELS singlestage acceptance per_implementation)
|
||||
|
||||
if(HAVE_POSIX_FORK AND HAVE_POSIX_WAIT) # assert tests use fork and wait, which aren't on MSVC
|
||||
add_cpp_test(singlestage_assert_out_of_order_values LABELS assert per_implementation explicitonly singlestage)
|
||||
endif()
|
||||
|
||||
# Copy the simdjson dll into the tests directory
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
add_custom_command(TARGET singlestage_parse_api_tests POST_BUILD # Adds a post-build event
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake -E copy_if_different..."
|
||||
"$<TARGET_FILE:simdjson>" # <--this is in-file
|
||||
"$<TARGET_FILE_DIR:singlestage_parse_api_tests>") # <--this is out-file path
|
||||
endif(MSVC AND BUILD_SHARED_LIBS)
|
||||
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# This directory contains files aimed to verify that constructs that
|
||||
# are supposed to fail at compile time, indeed do so.
|
||||
# To prevent bit rot, the same source file is compiled twice with
|
||||
# the macro COMPILATION_TEST_USE_FAILING_CODE set to 0 or 1.
|
||||
#
|
||||
|
||||
# adds a compilation test. Two targets are created, one expected to
|
||||
# succeed compilation and one that is expected to fail.
|
||||
function(add_dual_compile_test TEST_NAME)
|
||||
add_cpp_test(${TEST_NAME}_should_compile SOURCES ${TEST_NAME}.cpp COMPILE_ONLY LABELS singlestage no_mingw)
|
||||
add_cpp_test(${TEST_NAME}_should_not_compile SOURCES ${TEST_NAME}.cpp COMPILE_ONLY WILL_FAIL LABELS singlestage acceptance no_mingw)
|
||||
target_compile_definitions(${TEST_NAME}_should_not_compile PRIVATE COMPILATION_TEST_USE_FAILING_CODE=1)
|
||||
endfunction(add_dual_compile_test)
|
||||
|
||||
|
||||
add_dual_compile_test(singlestage_iterate_char_star)
|
||||
add_dual_compile_test(singlestage_iterate_string_view)
|
||||
add_dual_compile_test(singlestage_iterate_temporary_buffer)
|
||||
add_dual_compile_test(singlestage_first_second_access)
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
auto json = "1"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
if(error) { return EXIT_FAILURE; }
|
||||
simdjson_result<singlestage::value> query = doc.at_pointer("/");
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
if(query.second == simdjson::SUCCESS) {
|
||||
std::cout << "success" << std::endl;
|
||||
std::cout << query.first << std::endl;
|
||||
}
|
||||
#else
|
||||
singlestage::value val;
|
||||
error = query.get(val);
|
||||
if(error == simdjson::SUCCESS) {
|
||||
std::cout << "success" << std::endl;
|
||||
std::cout << val << std::endl;
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
singlestage::parser parser;
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
const char* json;
|
||||
auto doc = parser.iterate(json, strlen(json));
|
||||
#else
|
||||
auto json = "1"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
#endif
|
||||
int64_t value;
|
||||
auto error = doc.get(value);
|
||||
if (error) { exit(1); }
|
||||
std::cout << value << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
singlestage::parser parser;
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
auto json = std::string_view("1");
|
||||
auto doc = parser.iterate(json);
|
||||
#else
|
||||
auto json = "1"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
#endif
|
||||
int64_t value;
|
||||
auto error = doc.get(value);
|
||||
if (error) { exit(1); }
|
||||
std::cout << value << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <iostream>
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
int main() {
|
||||
singlestage::parser parser;
|
||||
#if COMPILATION_TEST_USE_FAILING_CODE
|
||||
auto doc = parser.iterate("1"_padded);
|
||||
#else
|
||||
auto json = "1"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
#endif
|
||||
int64_t value;
|
||||
auto error = doc.get(value);
|
||||
if (error) { exit(1); }
|
||||
std::cout << value << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace active_tests {
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool parser_child() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const padded_string json = R"({ "parent": {"child1": {"name": "John"} , "child2": {"name": "Daniel"}} })"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
singlestage::object parent = doc["parent"];
|
||||
{
|
||||
singlestage::object c1 = parent["child1"];
|
||||
if(std::string_view(c1["name"]) != "John") { return false; }
|
||||
}
|
||||
{
|
||||
singlestage::object c2 = parent["child2"];
|
||||
if(std::string_view(c2["name"]) != "Daniel") { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parser_doc_correct() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const padded_string json = R"({ "key1": 1, "key2":2, "key3": 3 })"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
singlestage::object root_object = doc.get_object();
|
||||
int64_t k1 = root_object["key1"];
|
||||
int64_t k2 = root_object["key2"];
|
||||
int64_t k3 = root_object["key3"];
|
||||
return (k1 == 1) && (k2 == 2) && (k3 == 3);
|
||||
}
|
||||
|
||||
bool parser_doc_limits() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const padded_string json = R"({ "key1": 1, "key2":2, "key3": 3 })"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
int64_t k1 = doc["key1"];
|
||||
try {
|
||||
int64_t k2 = doc["key2"];
|
||||
(void) k2;
|
||||
} catch (simdjson::simdjson_error &) {
|
||||
return true; // we expect to fail.
|
||||
}
|
||||
(void) k1;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
parser_child() &&
|
||||
parser_doc_correct() &&
|
||||
// parser_doc_limits() && // Failure is dependent on build type here ...
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace active_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, active_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace array_error_tests {
|
||||
using namespace std;
|
||||
|
||||
template<typename V, typename T>
|
||||
bool assert_iterate(T array, V *expected, size_t N, simdjson::error_code *expected_error, size_t N2) {
|
||||
/**
|
||||
* We use printouts because the assert_iterate is abstract and hard to
|
||||
* understand intuitively.
|
||||
*/
|
||||
std::cout << " --- assert_iterate ";
|
||||
size_t count = 0;
|
||||
for (auto elem : std::forward<T>(array)) {
|
||||
std::cout << "-"; std::cout.flush();
|
||||
V actual{};
|
||||
auto actual_error = elem.get(actual);
|
||||
if (count >= N) {
|
||||
if (count >= (N+N2)) {
|
||||
std::cerr << "FAIL: Extra error reported: " << actual_error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "[ expect: " << expected_error[count - N] << " ]"; std::cout.flush();
|
||||
ASSERT_ERROR(actual_error, expected_error[count - N]);
|
||||
} else {
|
||||
std::cout << "[ expect: SUCCESS ]"; std::cout.flush();
|
||||
ASSERT_SUCCESS(actual_error);
|
||||
std::cout << "{ expect value : "<< expected[count] << " }"; std::cout.flush();
|
||||
|
||||
ASSERT_EQUAL(actual, expected[count]);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, N+N2);
|
||||
std::cout << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename V, size_t N, size_t N2, typename T>
|
||||
bool assert_iterate(T &array, V (&&expected)[N], simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate<V, T&>(array, expected, N, expected_error, N2);
|
||||
}
|
||||
|
||||
template<size_t N2, typename T>
|
||||
bool assert_iterate(T &array, simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate<int64_t, T&>(array, nullptr, 0, expected_error, N2);
|
||||
}
|
||||
|
||||
template<typename V, size_t N, typename T>
|
||||
bool assert_iterate(T &array, V (&&expected)[N]) {
|
||||
return assert_iterate<V, T&&>(array, expected, N, nullptr, 0);
|
||||
}
|
||||
|
||||
template<typename V, size_t N, size_t N2, typename T>
|
||||
bool assert_iterate(T &&array, V (&&expected)[N], simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate<V, T&&>(std::forward<T>(array), expected, N, expected_error, N2);
|
||||
}
|
||||
|
||||
template<size_t N2, typename T>
|
||||
bool assert_iterate(T &&array, simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate<int64_t, T&&>(std::forward<T>(array), nullptr, 0, expected_error, N2);
|
||||
}
|
||||
|
||||
template<typename V, size_t N, typename T>
|
||||
bool assert_iterate(T &&array, V (&&expected)[N]) {
|
||||
return assert_iterate<V, T&&>(std::forward<T>(array), expected, N, nullptr, 0);
|
||||
}
|
||||
|
||||
bool top_level_array_iterate_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing comma", "[1 1]", assert_iterate(doc, { int64_t(1) }, { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", "[1,,1]", assert_iterate(doc, { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", "[,]", assert_iterate(doc, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", "[,,]", assert_iterate(doc, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool top_level_array_iterate_unclosed_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("unclosed extra comma", "[,", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", "[1 ", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed extra comma", "[,,", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", "[1,", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", "[1", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", "[", assert_iterate(doc, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool array_iterate_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing comma", R"({ "a": [1 1] })", assert_iterate(doc["a"], { int64_t(1) }, { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", R"({ "a": [1,,1] })", assert_iterate(doc["a"], { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", R"({ "a": [1,,] })", assert_iterate(doc["a"], { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", R"({ "a": [,] })", assert_iterate(doc["a"], { INCORRECT_TYPE, TAPE_ERROR}));
|
||||
SINGLESTAGE_SUBTEST("extra comma ", R"({ "a": [,,] })", assert_iterate(doc["a"], { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool array_iterate_unclosed_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("unclosed extra comma", R"({ "a": [,)", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed extra comma", R"({ "a": [,,)", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", R"({ "a": [1 )", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
// TODO These pass the user values that may run past the end of the buffer if they aren't careful
|
||||
// In particular, if the padding is decorated with the wrong values, we could cause overrun!
|
||||
SINGLESTAGE_SUBTEST("unclosed ", R"({ "a": [1,)", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", R"({ "a": [1)", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed ", R"({ "a": [)", assert_iterate(doc["a"], { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool array_iterate_incomplete_error() {
|
||||
TEST_START();
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1] )", assert_iterate(doc.get_array().at(0), { int64_t(1) }, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1,])", assert_iterate(doc.get_array().at(0), { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1])", assert_iterate(doc.get_array().at(0), { int64_t(1) }, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [])", assert_iterate(doc.get_array().at(0), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
#else
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1] )", assert_iterate(doc.get_array().at(0), { int64_t(1) }));
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1,])", assert_iterate(doc.get_array().at(0), { int64_t(1) }, { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("unclosed after array", R"([ [1])", assert_iterate(doc.get_array().at(0), { int64_t(1) }));
|
||||
#endif
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||
bool out_of_order_array_iteration_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ [ 1, 2 ] ])"_padded;
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto arr : doc) {
|
||||
for (auto subelement : arr) { ASSERT_SUCCESS(subelement); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto element : doc) {
|
||||
singlestage::value arr;
|
||||
ASSERT_SUCCESS( element.get(arr) );
|
||||
for (auto subelement : arr) { ASSERT_SUCCESS(subelement); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<array>", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto element : doc) {
|
||||
auto arr = element.get_array();
|
||||
for (auto subelement : arr) { ASSERT_SUCCESS(subelement); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("array", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto element : doc) {
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS( element.get(arr) );
|
||||
for (auto subelement : arr) { ASSERT_SUCCESS(subelement); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_top_level_array_iteration_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ 1, 2 ])"_padded;
|
||||
SUBTEST("simdjson_result<document>", test_singlestage_doc(json, [&](auto arr) {
|
||||
for (auto element : arr) { ASSERT_SUCCESS(element); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("document", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::document arr;
|
||||
ASSERT_SUCCESS( std::move(doc).get(arr) );
|
||||
for (auto element : arr) { ASSERT_SUCCESS(element); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<array>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::array> arr = doc.get_array();
|
||||
for (auto element : arr) { ASSERT_SUCCESS(element); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("array", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS( doc.get(arr) );
|
||||
for (auto element : arr) { ASSERT_SUCCESS(element); }
|
||||
ASSERT_ITERATE_ERROR( arr, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_DEVELOPMENT_CHECKS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
top_level_array_iterate_error() &&
|
||||
top_level_array_iterate_unclosed_error() &&
|
||||
array_iterate_error() &&
|
||||
array_iterate_unclosed_error() &&
|
||||
array_iterate_incomplete_error() &&
|
||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||
out_of_order_array_iteration_error() &&
|
||||
out_of_order_top_level_array_iteration_error() &&
|
||||
#endif
|
||||
true;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, array_error_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,875 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace array_tests {
|
||||
using namespace std;
|
||||
using simdjson::singlestage::json_type;
|
||||
bool issue1977() {
|
||||
TEST_START();
|
||||
auto json = R"([1, 2] foo ])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS(doc.get_array().get(array));
|
||||
for (auto values : array) {
|
||||
ASSERT_SUCCESS(values);
|
||||
}
|
||||
ASSERT_FALSE(doc.at_end());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue1588() {
|
||||
TEST_START();
|
||||
const auto json = R"({
|
||||
"nodes" : [
|
||||
{
|
||||
"rotation" : [
|
||||
0.16907575726509094,
|
||||
0.7558803558349609,
|
||||
-0.27217137813568115,
|
||||
0.570947527885437
|
||||
],
|
||||
"translation" : [
|
||||
4.076245307922363,
|
||||
5.903861999511719,
|
||||
-1.0054539442062378
|
||||
]
|
||||
},
|
||||
{
|
||||
"camera" : 0,
|
||||
"rotation" : [
|
||||
-0.7071067690849304,
|
||||
0,
|
||||
0,
|
||||
0.7071067690849304
|
||||
]
|
||||
},
|
||||
{
|
||||
"children" : [
|
||||
1
|
||||
],
|
||||
"translation" : [
|
||||
7.358891487121582,
|
||||
4.958309173583984,
|
||||
6.925790786743164
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh" : 1,
|
||||
"scale" : [
|
||||
4.7498908042907715,
|
||||
4.7498908042907715,
|
||||
4.7498908042907715
|
||||
]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
// we query 'rotation', 'scale', 'translation' in sequence
|
||||
const bool expected_value[][3] = { {true, false, true},
|
||||
{true, false, false}, {false, false, true}, {false, true, false} };
|
||||
|
||||
SUBTEST("singlestage::issue1588::sequence", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( doc_result["nodes"].get(array) );
|
||||
|
||||
size_t i=0;
|
||||
for (auto value : array) {
|
||||
singlestage::object current_object;
|
||||
ASSERT_SUCCESS( value.get_object().get(current_object) );
|
||||
simdjson::singlestage::array rotation;
|
||||
if(expected_value[i][0]) {
|
||||
ASSERT_SUCCESS( current_object["rotation"].get(rotation) );
|
||||
} else {
|
||||
ASSERT_ERROR( current_object["rotation"].get(rotation), NO_SUCH_FIELD );
|
||||
}
|
||||
simdjson::singlestage::array scale;
|
||||
if(expected_value[i][1]) {
|
||||
ASSERT_SUCCESS( current_object["scale"].get(scale) );
|
||||
} else {
|
||||
ASSERT_ERROR( current_object["scale"].get(scale), NO_SUCH_FIELD );
|
||||
}
|
||||
simdjson::singlestage::array translation;
|
||||
if(expected_value[i][2]) {
|
||||
ASSERT_SUCCESS( current_object["translation"].get(translation) );
|
||||
} else {
|
||||
ASSERT_ERROR( current_object["translation"].get(translation), NO_SUCH_FIELD );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i, 4);
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::issue1588::originalcode", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
int count_nodes = 0;
|
||||
simdjson::singlestage::array doc_nodes;
|
||||
auto error = doc_result["nodes"].get(doc_nodes);
|
||||
ASSERT_SUCCESS( error );
|
||||
for (auto node_iterator : doc_nodes) {
|
||||
singlestage::object node_obj;
|
||||
ASSERT_SUCCESS( node_iterator.get_object().get(node_obj) );
|
||||
simdjson::singlestage::array rotation;
|
||||
std::cout << "checking rotation" << std::endl;
|
||||
if(expected_value[count_nodes][0]) {
|
||||
ASSERT_SUCCESS( node_obj["rotation"].get(rotation) );
|
||||
} else {
|
||||
ASSERT_ERROR( node_obj["rotation"].get(rotation), NO_SUCH_FIELD );
|
||||
}
|
||||
|
||||
simdjson::singlestage::array scale;
|
||||
std::cout << "checking scale" << std::endl;
|
||||
if(expected_value[count_nodes][1]) {
|
||||
ASSERT_SUCCESS( node_obj["scale"].get(scale) );
|
||||
} else {
|
||||
ASSERT_ERROR( node_obj["scale"].get(scale), NO_SUCH_FIELD );
|
||||
}
|
||||
|
||||
simdjson::singlestage::array translation;
|
||||
std::cout << "checking translation" << std::endl;
|
||||
if (!error) { std::cout << "translation!\n"; }
|
||||
if(expected_value[count_nodes][2]) {
|
||||
ASSERT_SUCCESS( node_obj["translation"].get(translation) );
|
||||
} else {
|
||||
ASSERT_ERROR( node_obj["translation"].get(translation), NO_SUCH_FIELD );
|
||||
}
|
||||
|
||||
++count_nodes;
|
||||
}
|
||||
ASSERT_EQUAL(count_nodes, 4);
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1876() {
|
||||
TEST_START();
|
||||
auto json = R"( [] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS(doc.count_elements().get(count));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
|
||||
ASSERT_EQUAL(count, 0);
|
||||
for (auto element : arr) {
|
||||
double value;
|
||||
ASSERT_SUCCESS(element.get_double().get(value));
|
||||
std::cout << value << std::endl;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_complex_array_count() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto cars_json = R"( { "zero":[], "test":[ { "val1":1, "val2":2 }, { "val1":1, "val2":2 } ] } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(cars_json).get(doc));
|
||||
singlestage::array firstmyarray;
|
||||
singlestage::array secondmyarray;
|
||||
ASSERT_SUCCESS(doc.find_field("zero").get_array().get(firstmyarray));
|
||||
size_t count{0};
|
||||
ASSERT_SUCCESS(firstmyarray.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 0);
|
||||
size_t new_count{0};
|
||||
for(simdjson_unused auto elem: firstmyarray) { new_count++; }
|
||||
ASSERT_EQUAL(new_count, 0);
|
||||
ASSERT_SUCCESS(doc.find_field("test").get_array().get(secondmyarray));
|
||||
ASSERT_SUCCESS(secondmyarray.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 2);
|
||||
new_count = 0;
|
||||
for(simdjson_unused auto elem: secondmyarray) { new_count++; }
|
||||
ASSERT_EQUAL(count, new_count);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_sub_array_count() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto key_value_json = R"( { "test":[ 1,2,3], "joe": [1,2] } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(key_value_json).get(doc));
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||
singlestage::value v;
|
||||
ASSERT_SUCCESS(doc.find_field("test").get(v));
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS(v.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 3);
|
||||
ASSERT_SUCCESS(doc.find_field("joe").get(v));
|
||||
ASSERT_SUCCESS(v.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 2);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_array_count() {
|
||||
TEST_START();
|
||||
const auto json = R"([ 1, 10, 100 ])"_padded;
|
||||
const vector<uint64_t> expected_value = { 1, 10, 100 };
|
||||
|
||||
SUBTEST("singlestage::count_elements", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get_array().get(array) );
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS( array.count_elements().get(count) );
|
||||
ASSERT_EQUAL(count, expected_value.size());
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::count_elements_and_decode", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS( array.count_elements().get(count) );
|
||||
ASSERT_EQUAL(count, expected_value.size());
|
||||
size_t i = 0;
|
||||
std::vector<uint64_t> receiver(count);
|
||||
for (auto value : array) {
|
||||
uint64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected_value[i]);
|
||||
receiver[i] = actual;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool iterate_empty_array_count() {
|
||||
TEST_START();
|
||||
const auto json = R"([])"_padded;
|
||||
|
||||
SUBTEST("singlestage::count_elements", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get_array().get(array) );
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS( array.count_elements().get(count) );
|
||||
ASSERT_EQUAL(count, 0);
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::count_elements_and_decode", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS( array.count_elements().get(count) );
|
||||
ASSERT_EQUAL(count, 0);
|
||||
size_t i = 0;
|
||||
std::vector<uint64_t> receiver(count);
|
||||
for (auto value : array) {
|
||||
uint64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i, 0);
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_bad_array_count() {
|
||||
TEST_START();
|
||||
const auto badjson = R"([ 1, 10 100 ])"_padded;
|
||||
|
||||
|
||||
SUBTEST("singlestage::count_elements", test_singlestage_doc(badjson, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
size_t count{};
|
||||
auto e = array.count_elements().get(count);
|
||||
if( e != TAPE_ERROR) {
|
||||
std::cout << e << "\n";
|
||||
std::cout << "expected: " << TAPE_ERROR << "\n";
|
||||
std::cout << "count = " << count << "\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool iterate_document_array_count() {
|
||||
TEST_START();
|
||||
auto empty = R"( [] )"_padded;
|
||||
SUBTEST("singlestage::empty_doc_array", test_singlestage_doc(empty, [&](auto doc_result) {
|
||||
size_t count{};
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.count_elements().get(count) );
|
||||
ASSERT_EQUAL( count, 0 );
|
||||
return true;
|
||||
}));
|
||||
auto basic = R"( [-1.234, 100000000000000, null, [1,2,3], {"t":true, "f":false}] )"_padded;
|
||||
SUBTEST("singlestage::basic_doc_array", test_singlestage_doc(basic, [&](auto doc_result) {
|
||||
size_t count{};
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.count_elements().get(count) );
|
||||
ASSERT_EQUAL( count, 5 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool iterate_bad_document_array_count() {
|
||||
TEST_START();
|
||||
padded_string bad_jsons[2] = {R"( [1, 10 1000] )"_padded, R"( [1.23, 2.34 )"_padded};
|
||||
std::string names[2] = {"missing_comma", "missing_bracket"};
|
||||
simdjson::error_code errors[2] = {TAPE_ERROR, INCOMPLETE_ARRAY_OR_OBJECT};
|
||||
size_t count{0};
|
||||
|
||||
for (auto name : names) {
|
||||
SUBTEST("singlestage::" + name, test_singlestage_doc(bad_jsons[count], [&](auto doc_result) {
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_ERROR(doc_result.count_elements(), errors[count]);
|
||||
return true;
|
||||
}));
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 2);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool iterate_document_array() {
|
||||
TEST_START();
|
||||
const auto json = R"([ 1, 10, 100 ])"_padded;
|
||||
const uint64_t expected_value[] = { 1, 10, 100 };
|
||||
|
||||
SUBTEST("singlestage::array", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
|
||||
size_t i = 0;
|
||||
for (auto value : array) {
|
||||
int64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected_value[i]);
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i*sizeof(int64_t), sizeof(expected_value));
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("singlestage::array-document-rewind", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
|
||||
size_t i = 0;
|
||||
for (auto value : array) { (void)value; i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
std::vector<int64_t> container(i); // container of size 'i'.
|
||||
|
||||
doc_result.rewind();
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
i = 0;
|
||||
for (auto value : array) {
|
||||
int64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
container[i] = actual;
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i * sizeof(int64_t), sizeof(expected_value));
|
||||
for(size_t j = 0; j < sizeof(expected_value)/sizeof(int64_t); j++) {
|
||||
ASSERT_EQUAL(container[j], expected_value[j]);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::array-rewind", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
|
||||
size_t i = 0;
|
||||
for (auto value : array) { (void)value; i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
std::vector<int64_t> container(i); // container of size 'i'.
|
||||
|
||||
array.reset();
|
||||
i = 0;
|
||||
for (auto value : array) {
|
||||
int64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
container[i] = actual;
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i * sizeof(int64_t), sizeof(expected_value));
|
||||
for(size_t j = 0; j < sizeof(expected_value)/sizeof(int64_t); j++) {
|
||||
ASSERT_EQUAL(container[j], expected_value[j]);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::array>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::array> array = doc_result.get_array();
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
size_t i=0;
|
||||
for (simdjson_unused auto value : array) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_RESULT( doc.type(), json_type::array );
|
||||
size_t i=0;
|
||||
for (simdjson_unused auto value : doc) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
size_t i=0;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
for (simdjson_unused auto value : doc_result) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool empty_rewind() {
|
||||
TEST_START();
|
||||
const auto json = R"( [] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
for(simdjson_unused auto i : arr) {
|
||||
TEST_FAIL("should be empty?");
|
||||
}
|
||||
arr.reset();
|
||||
for(simdjson_unused auto i : arr) {
|
||||
TEST_FAIL("should be empty?");
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool count_empty(simdjson::singlestage::array arr) {
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS(arr.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 0);
|
||||
bool is_empty;
|
||||
ASSERT_SUCCESS(arr.is_empty().get(is_empty));
|
||||
ASSERT_TRUE(is_empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool issue1742() {
|
||||
TEST_START();
|
||||
auto json = R"( {
|
||||
"code": 0,
|
||||
"method": "subscribe",
|
||||
"result": {
|
||||
"instrument_name": "DAI_USDC",
|
||||
"subscription": "trade.DAI_USDC",
|
||||
"channel": "trade",
|
||||
"data": [
|
||||
[1,2,3,4]
|
||||
]
|
||||
}
|
||||
} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
simdjson::singlestage::array data;
|
||||
ASSERT_SUCCESS(doc["result"]["data"].get_array().get(data));
|
||||
for (auto d : data) {
|
||||
simdjson::singlestage::array arr;
|
||||
ASSERT_SUCCESS(d.get_array().get(arr));
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS(arr.count_elements().get(count));
|
||||
ASSERT_EQUAL(count, 4);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool value_to_array(simdjson::singlestage::value val) {
|
||||
singlestage::json_type t;
|
||||
ASSERT_SUCCESS(val.type().get(t));
|
||||
ASSERT_EQUAL(t, singlestage::json_type::array);
|
||||
simdjson::singlestage::array arr;
|
||||
ASSERT_SUCCESS(val.get_array().get(arr));
|
||||
if(count_empty(arr) != true) { return false; }
|
||||
return true;
|
||||
}
|
||||
bool empty_rewind_convoluted() {
|
||||
TEST_START();
|
||||
const auto json = R"( [] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS(doc.get_value().get(val));
|
||||
if(!value_to_array(val)) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool value_to_array_except(simdjson::singlestage::value val) {
|
||||
singlestage::json_type t = val.type();
|
||||
ASSERT_EQUAL(t, singlestage::json_type::array);
|
||||
if(count_empty(simdjson::singlestage::array(val)) != true) { return false; }
|
||||
return true;
|
||||
}
|
||||
bool empty_rewind_convoluted_with_exceptions() {
|
||||
TEST_START();
|
||||
const auto json = R"( [] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS(doc.get_value().get(val));
|
||||
if(value_to_array_except(val) != true) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
bool iterate_array() {
|
||||
TEST_START();
|
||||
const auto json = R"( [ [ 1, 10, 100 ] ] )"_padded;
|
||||
const uint64_t expected_value[] = { 1, 10, 100 };
|
||||
|
||||
SUBTEST("singlestage::array", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
bool found = false;
|
||||
for (simdjson_result<singlestage::value> array_result : doc_result) {
|
||||
ASSERT_TRUE(!found); found = true;
|
||||
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( array_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( array_result.get(array) );
|
||||
|
||||
size_t i=0;
|
||||
for (auto value : array) {
|
||||
int64_t actual{};
|
||||
ASSERT_SUCCESS( value.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected_value[i]);
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
}
|
||||
ASSERT_TRUE(found);
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("simdjson_result<singlestage::array>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
bool found = false;
|
||||
for (simdjson_result<singlestage::value> array_result : doc_result) {
|
||||
ASSERT_TRUE(!found); found = true;
|
||||
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( array_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( array_result.get(array) );
|
||||
|
||||
size_t i=0;
|
||||
for (simdjson_unused auto value : array) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
}
|
||||
ASSERT_TRUE(found);
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
bool found = false;
|
||||
for (simdjson_result<singlestage::value> array_result : doc_result) {
|
||||
ASSERT_TRUE(!found); found = true;
|
||||
|
||||
singlestage::value array;
|
||||
ASSERT_SUCCESS( std::move(array_result).get(array) );
|
||||
ASSERT_RESULT( array.type(), json_type::array );
|
||||
size_t i=0;
|
||||
for (simdjson_unused auto value : array) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
}
|
||||
ASSERT_TRUE(found);
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
bool found = false;
|
||||
for (simdjson_result<singlestage::value> array_result : doc_result) {
|
||||
ASSERT_TRUE(!found); found = true;
|
||||
|
||||
size_t i=0;
|
||||
ASSERT_RESULT( array_result.type(), json_type::array );
|
||||
for (simdjson_unused auto value : array_result) { int64_t actual; ASSERT_SUCCESS( value.get(actual) ); ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
}
|
||||
ASSERT_TRUE(found);
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_array_partial_children() {
|
||||
TEST_START();
|
||||
auto json = R"(
|
||||
[
|
||||
0,
|
||||
[],
|
||||
{},
|
||||
{ "x": 3, "y": 33 },
|
||||
{ "x": 4, "y": 44 },
|
||||
{ "x": 5, "y": 55 },
|
||||
{ "x": 6, "y": 66 },
|
||||
[ 7, 77, 777 ],
|
||||
[ 8, 88, 888 ],
|
||||
{ "a": [ { "b": [ 9, 99 ], "c": 999 }, 9999 ], "d": 99999 },
|
||||
10
|
||||
]
|
||||
)"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
size_t i = 0;
|
||||
for (auto value : doc_result) {
|
||||
ASSERT_SUCCESS(value);
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
std::cout << " - After ignoring empty scalar ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
std::cout << " - After ignoring empty array ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
std::cout << " - After ignoring empty object ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
// Break after using first value in child object
|
||||
case 3: {
|
||||
for (auto child_field : value.get_object()) {
|
||||
singlestage::raw_json_string k;
|
||||
ASSERT_SUCCESS( child_field.key().get(k) );
|
||||
ASSERT_EQUAL(k, "x");
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_field.value().get(x) );
|
||||
ASSERT_EQUAL(x, 3);
|
||||
break; // Break after the first value
|
||||
}
|
||||
std::cout << " - After using first value in child object ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Break without using first value in child object
|
||||
case 4: {
|
||||
for (auto child_field : value.get_object()) {
|
||||
singlestage::raw_json_string k;
|
||||
ASSERT_SUCCESS( child_field.key().get(k) );
|
||||
ASSERT_EQUAL(k, "x");
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Only look up one field in child object
|
||||
case 5: {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( value["x"].get(x) );
|
||||
ASSERT_EQUAL( x, 5 );
|
||||
std::cout << " - After looking up one field in child object ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Only look up one field in child object, but don't use it
|
||||
case 6: {
|
||||
ASSERT_SUCCESS( value["x"] );
|
||||
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Break after first value in child array
|
||||
case 7: {
|
||||
for (auto child_value : value) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_value.get(x) );
|
||||
ASSERT_EQUAL( x, 7 );
|
||||
break;
|
||||
}
|
||||
std::cout << " - After using first value in child array ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Break without using first value in child array
|
||||
case 8: {
|
||||
for (auto child_value : value) {
|
||||
ASSERT_SUCCESS(child_value);
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Break out of multiple child loops
|
||||
case 9: {
|
||||
for (auto child1 : value.get_object()) {
|
||||
for (auto child2 : child1.value().get_array()) {
|
||||
for (auto child3 : child2.get_object()) {
|
||||
for (auto child4 : child3.value().get_array()) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child4.get(x) );
|
||||
ASSERT_EQUAL( x, 9 );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Test the actual value
|
||||
case 10: {
|
||||
uint64_t actual_value;
|
||||
ASSERT_SUCCESS( value.get(actual_value) );
|
||||
ASSERT_EQUAL( actual_value, 10 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQUAL( i, 11 ); // Make sure we found all the keys we expected
|
||||
return true;
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool iterate_empty_array() {
|
||||
TEST_START();
|
||||
auto json = "[]"_padded;
|
||||
SUBTEST("singlestage::array", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
for (simdjson_unused auto value : array) { TEST_FAIL("Unexpected value"); }
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::array>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::array> array_result = doc_result.get_array();
|
||||
for (simdjson_unused auto value : array_result) { TEST_FAIL("Unexpected value"); }
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
for (simdjson_unused auto value : doc) { TEST_FAIL("Unexpected value"); }
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
for (simdjson_unused auto value : doc_result) { TEST_FAIL("Unexpected value"); }
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::array-document-rewind", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
|
||||
size_t i = 0;
|
||||
for (auto value : array) { (void) value; i++; }
|
||||
ASSERT_EQUAL(i, 0);
|
||||
|
||||
doc_result.rewind();
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
i = 0;
|
||||
for (auto value : array) { (void) value; i++; }
|
||||
ASSERT_EQUAL(i, 0);
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::array-rewind", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::array array;
|
||||
ASSERT_RESULT( doc_result.type(), json_type::array );
|
||||
ASSERT_SUCCESS( doc_result.get(array) );
|
||||
|
||||
size_t i = 0;
|
||||
for (auto value : array) { (void) value; i++; }
|
||||
ASSERT_EQUAL(i, 0);
|
||||
|
||||
array.reset();
|
||||
i = 0;
|
||||
for (auto value : array) { (void) value; i++; }
|
||||
ASSERT_EQUAL(i, 0);
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool iterate_array_exception() {
|
||||
TEST_START();
|
||||
auto json = R"([ 1, 10, 100 ])"_padded;
|
||||
const uint64_t expected_value[] = { 1, 10, 100 };
|
||||
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
size_t i=0;
|
||||
for (int64_t actual : doc_result) { ASSERT_EQUAL(actual, expected_value[i]); i++; }
|
||||
ASSERT_EQUAL(i*sizeof(uint64_t), sizeof(expected_value));
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_empty_object_exception() {
|
||||
TEST_START();
|
||||
auto json = R"({})"_padded;
|
||||
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
for (simdjson_unused singlestage::field field : doc_result.get_object()) {
|
||||
TEST_FAIL("Unexpected field");
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool iterate_empty_array_exception() {
|
||||
TEST_START();
|
||||
auto json = "[]"_padded;
|
||||
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
for (simdjson_unused singlestage::value value : doc_result) { TEST_FAIL("Unexpected value"); }
|
||||
return true;
|
||||
}));
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue1977() &&
|
||||
issue1876() &&
|
||||
issue1742() &&
|
||||
empty_rewind_convoluted() &&
|
||||
empty_rewind() &&
|
||||
iterate_empty_array_count() &&
|
||||
iterate_sub_array_count() &&
|
||||
iterate_complex_array_count() &&
|
||||
iterate_bad_array_count() &&
|
||||
iterate_array_count() &&
|
||||
issue1588() &&
|
||||
iterate_array() &&
|
||||
iterate_document_array_count() &&
|
||||
iterate_bad_document_array_count() &&
|
||||
iterate_document_array() &&
|
||||
iterate_empty_array() &&
|
||||
iterate_array_partial_children() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
empty_rewind_convoluted_with_exceptions() &&
|
||||
iterate_array_exception() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace dom_api_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, array_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include "simdjson.h"
|
||||
|
||||
|
||||
// We get spurious "maybe used uninitialized" warnings under GCC 12.
|
||||
using namespace simdjson;
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#if __GNUC__ >= 12
|
||||
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This ensures the compiler can't rearrange them into the proper order (which causes it to work!)
|
||||
simdjson_never_inline bool check_point(simdjson_result<singlestage::value> xval, simdjson_result<singlestage::value> yval) {
|
||||
// Verify the expected release behavior
|
||||
uint64_t x, y;
|
||||
if (!xval.get(x)) { return false; }
|
||||
if (!yval.get(y)) { return false; }
|
||||
std::cout << x << "," << y << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_check_point() {
|
||||
auto json = R"(
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2 3
|
||||
)"_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
return check_point(doc["x"], doc["y"]);
|
||||
}
|
||||
|
||||
// Run a test function in a fork and check whether it exited with an assert signal
|
||||
template<typename F>
|
||||
bool assert_test(const F& f) {
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
std::cerr << "fork failed" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
//
|
||||
// This code runs in the fork (so we run the test function)
|
||||
//
|
||||
bool succeeded = f();
|
||||
exit(succeeded ? 0 : 1);
|
||||
}
|
||||
|
||||
//
|
||||
// This code runs in the original executable (so we wait for the fork and check the exit code)
|
||||
//
|
||||
int exit_code = 0;
|
||||
if (waitpid(pid, &exit_code, 0) == pid_t(-1)) {
|
||||
std::cerr << "waitpid failed: " << std::string_view(strerror(errno)) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Test passes if the child exited with an assert signal
|
||||
return WIFSIGNALED(exit_code);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
// To verify that the program asserts (which sends a signal), we fork a new process and use wait()
|
||||
// to check the resulting error code. If it's a signal error code, we consider the
|
||||
// test to have passed.
|
||||
// From https://stackoverflow.com/a/33694733
|
||||
|
||||
bool succeeded = true;
|
||||
#ifndef NDEBUG
|
||||
succeeded |= assert_test(test_check_point);
|
||||
#endif
|
||||
return succeeded ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include <set>
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
// bogus functions for compilation tests
|
||||
void process1(int ) {}
|
||||
void process2(int ) {}
|
||||
void process3(int ) {}
|
||||
|
||||
// Do not run this, it is only meant to compile
|
||||
void compilation_test_1() {
|
||||
const padded_string bogus = ""_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(bogus);
|
||||
for (singlestage::object my_object : doc["mykey"]) {
|
||||
for (auto field : my_object) {
|
||||
if (field.key() == "key_value1") { process1(field.value()); }
|
||||
else if (field.key() == "key_value2") { process2(field.value()); }
|
||||
else if (field.key() == "key_value3") { process3(field.value()); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not run this, it is only meant to compile
|
||||
void compilation_test_2() {
|
||||
const padded_string bogus = ""_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(bogus);
|
||||
std::set<std::string_view> default_users;
|
||||
singlestage::array tweets = doc["statuses"].get_array();
|
||||
for (auto tweet_value : tweets) {
|
||||
auto tweet = tweet_value.get_object();
|
||||
singlestage::object user = tweet["user"].get_object();
|
||||
std::string_view screen_name = user["screen_name"].get_string();
|
||||
bool default_profile = user["default_profile"].get_bool();
|
||||
if (default_profile) { default_users.insert(screen_name); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Do not run this, it is only meant to compile
|
||||
void compilation_test_3() {
|
||||
const padded_string bogus = ""_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(bogus);
|
||||
singlestage::array tweets;
|
||||
if(! doc["statuses"].get(tweets)) { return; }
|
||||
for (auto tweet_value : tweets) {
|
||||
auto tweet = tweet_value.get_object();
|
||||
for (auto field : tweet) {
|
||||
std::string_view key = field.unescaped_key().value();
|
||||
std::cout << "key = " << key << std::endl;
|
||||
std::string_view val = std::string_view(field.value());
|
||||
std::cout << "value (assuming it is a string) = " << val << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,844 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace document_stream_tests {
|
||||
|
||||
template <typename T>
|
||||
bool process_doc(T &docref) {
|
||||
int64_t val{};
|
||||
ASSERT_SUCCESS(docref.at_pointer("/4").get(val));
|
||||
ASSERT_EQUAL(val, 5);
|
||||
return true;
|
||||
}
|
||||
bool truncated_utf8() {
|
||||
TEST_START();
|
||||
// truncated UTF-8
|
||||
auto json = "\"document1\" \xC3"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
auto oderror = parser.iterate_many(json).get(stream);
|
||||
if (oderror) {
|
||||
std::cerr << "singlestage iterate_many error: " << oderror << std::endl;
|
||||
return false;
|
||||
}
|
||||
int document_index = 0;
|
||||
auto i = stream.begin();
|
||||
for (; i != stream.end(); ++i) {
|
||||
singlestage::document_reference doc;
|
||||
auto err = (*i).get(doc);
|
||||
document_index++;
|
||||
// With the fallback routine, we might detect a 'document' since
|
||||
// it does not do UTF-8 validation in stage one, but it will do
|
||||
// so when we access the document.
|
||||
if(err == SUCCESS) {
|
||||
singlestage::json_type t;
|
||||
err = doc.type().get(t);
|
||||
}
|
||||
if((err == SUCCESS) && (document_index != 1)) {
|
||||
std::cerr << "Only the first document should be valid." << std::endl;
|
||||
return false;
|
||||
}
|
||||
if((err != SUCCESS) && (document_index != 2)) {
|
||||
std::cerr << "singlestage iterate_many error: " << err << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(document_index < 1) {
|
||||
std::cerr << "singlestage should have accessed at least one document" << std::endl;
|
||||
return false;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue1729() {
|
||||
// This example is not a good application of iterate_many since there is
|
||||
// a single JSON document.
|
||||
TEST_START();
|
||||
auto json = R"({
|
||||
"t": 5649,
|
||||
"ng": 5,
|
||||
"lu": 4086,
|
||||
"g": [{
|
||||
"t": "Temps",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"Low Temp",
|
||||
"High Temp",
|
||||
"Smooth Avg"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
80.48750305,
|
||||
80.82499694,
|
||||
80.65625
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Pump Status",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"Pump",
|
||||
"Thermal",
|
||||
"Light"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Lux",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 4,
|
||||
"l": [
|
||||
"Value",
|
||||
"Smooth",
|
||||
"Low",
|
||||
"High"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow"
|
||||
],
|
||||
"d": [
|
||||
2274.62939453,
|
||||
2277.45947265,
|
||||
4050,
|
||||
4500
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Temp Diff",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 4,
|
||||
"l": [
|
||||
"dFarenheit",
|
||||
"sum",
|
||||
"Low",
|
||||
"High"
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan",
|
||||
"yellow"
|
||||
],
|
||||
"d": [
|
||||
0,
|
||||
0,
|
||||
0.5,
|
||||
10
|
||||
]
|
||||
},
|
||||
{
|
||||
"t": "Power",
|
||||
"xvy": 0,
|
||||
"pd": 60,
|
||||
"sz": 3,
|
||||
"l": [
|
||||
"watts (est. light) ",
|
||||
"watts (1.9~gpm) ",
|
||||
"watts (1gpm) "
|
||||
],
|
||||
"c": [
|
||||
"green",
|
||||
"orange",
|
||||
"cyan"
|
||||
],
|
||||
"d": [
|
||||
181.78063964,
|
||||
114.88922882,
|
||||
59.35943603
|
||||
]
|
||||
}
|
||||
]
|
||||
})"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
auto oderror = parser.iterate_many(json).get(stream);
|
||||
if (oderror) {
|
||||
std::cerr << "singlestage iterate_many error: " << oderror << std::endl;
|
||||
return false;
|
||||
}
|
||||
auto i = stream.begin();
|
||||
for (; i != stream.end(); ++i) {
|
||||
singlestage::document_reference doc;
|
||||
auto err = (*i).get(doc);
|
||||
if(err != SUCCESS) {
|
||||
std::cerr << "singlestage iterate_many error: " << err << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1977() {
|
||||
TEST_START();
|
||||
std::string json = R"( 1111 })";
|
||||
singlestage::parser odparser;
|
||||
singlestage::document_stream odstream;
|
||||
ASSERT_SUCCESS(odparser.iterate_many(json).get(odstream));
|
||||
|
||||
auto i = odstream.begin();
|
||||
for (; i != odstream.end(); ++i) {
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
ASSERT_TRUE(i.current_index() == 0);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1683() {
|
||||
TEST_START();
|
||||
std::string json = R"([1,2,3,4,5]
|
||||
[1,2,3,4,5]
|
||||
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
|
||||
[1,2,3,4,5])";
|
||||
|
||||
singlestage::parser odparser;
|
||||
singlestage::document_stream odstream;
|
||||
|
||||
// iterate_many all at once
|
||||
auto oderror = odparser.iterate_many(json, 50).get(odstream);
|
||||
if (oderror) { std::cerr << "singlestage iterate_many error: " << oderror << std::endl; return false; }
|
||||
|
||||
size_t currindex = 0;
|
||||
auto i = odstream.begin();
|
||||
for (; i != odstream.end(); ++i) {
|
||||
singlestage::document_reference doc;
|
||||
auto err = (*i).get(doc);
|
||||
if(err == SUCCESS) { if(!process_doc(doc)) {return false; } }
|
||||
currindex = i.current_index();
|
||||
if (err == simdjson::CAPACITY) {
|
||||
ASSERT_EQUAL(currindex, 24);
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), 305);
|
||||
break;
|
||||
} else if (err) {
|
||||
TEST_FAIL(std::string("singlestage: error accessing jsonpointer: ") + simdjson::error_message(err));
|
||||
}
|
||||
}
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), 305);
|
||||
|
||||
// iterate line-by-line
|
||||
std::stringstream ss(json);
|
||||
std::string oneline;
|
||||
oneline.reserve(json.size() + SIMDJSON_PADDING);
|
||||
while (getline(ss, oneline)) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(odparser.iterate(oneline).get(doc));
|
||||
if( ! process_doc(doc) ) { return false; }
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_document_iteration() {
|
||||
TEST_START();
|
||||
auto json = R"([1,[1,2]] {"a":1,"b":2} {"o":{"1":1,"2":2}} [1,2,3])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
std::string_view expected[4] = {"[1,[1,2]]", "{\"a\":1,\"b\":2}", "{\"o\":{\"1\":1,\"2\":2}}", "[1,2,3]"};
|
||||
size_t counter{0};
|
||||
for(auto doc : stream) {
|
||||
ASSERT_TRUE(counter < 4);
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS(to_json_string(doc).get(view));
|
||||
ASSERT_EQUAL(view, expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter, 4);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_document_iteration_multiple_batches() {
|
||||
TEST_START();
|
||||
auto json = R"([1,[1,2]] {"a":1,"b":2} {"o":{"1":1,"2":2}} [1,2,3])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json,32).get(stream));
|
||||
std::string_view expected[4] = {"[1,[1,2]]", "{\"a\":1,\"b\":2}", "{\"o\":{\"1\":1,\"2\":2}}", "[1,2,3]"};
|
||||
size_t counter{0};
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_TRUE(counter < 4);
|
||||
ASSERT_EQUAL(i.source(), expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter, 4);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_document_iteration_with_parsing() {
|
||||
TEST_START();
|
||||
auto json = R"([1,[1,2]] {"a":1,"b":2} {"o":{"1":1,"2":2}} [1,2,3])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
std::string_view expected[4] = {"[1,[1,2]]", "{\"a\":1,\"b\":2}", "{\"o\":{\"1\":1,\"2\":2}}", "[1,2,3]"};
|
||||
size_t counter{0};
|
||||
auto i = stream.begin();
|
||||
int64_t x;
|
||||
|
||||
ASSERT_EQUAL(i.source(),expected[counter++]);
|
||||
ASSERT_SUCCESS( (*i).at_pointer("/1/1").get(x) );
|
||||
ASSERT_EQUAL(x,2);
|
||||
++i;
|
||||
|
||||
ASSERT_EQUAL(i.source(),expected[counter++]);
|
||||
simdjson_result<singlestage::document_reference> xxx = *i;
|
||||
ASSERT_SUCCESS( xxx.find_field("a").get(x) );
|
||||
ASSERT_EQUAL(x,1);
|
||||
++i;
|
||||
|
||||
ASSERT_EQUAL(i.source(),expected[counter++]);
|
||||
ASSERT_SUCCESS( (*i).at_pointer("/o/2").get(x) );
|
||||
ASSERT_EQUAL(x,2);
|
||||
++i;
|
||||
|
||||
ASSERT_EQUAL(i.source(),expected[counter++]);
|
||||
ASSERT_SUCCESS( (*i).at_pointer("/2").get(x) );
|
||||
ASSERT_EQUAL(x,3);
|
||||
++i;
|
||||
|
||||
if (i != stream.end()) { return false; }
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool atoms_json() {
|
||||
TEST_START();
|
||||
auto json = R"(5 true 20.3 "string" )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
|
||||
std::string_view expected[4] = {"5", "true", "20.3", "\"string\""};
|
||||
size_t counter{0};
|
||||
for (auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_EQUAL(i.source(), expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter,4);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool doc_index() {
|
||||
TEST_START();
|
||||
auto json = R"({"z":5} {"1":1,"2":2,"4":4} [7, 10, 9] [15, 11, 12, 13] [154, 110, 112, 1311])"_padded;
|
||||
std::string_view expected[5] = {R"({"z":5})",R"({"1":1,"2":2,"4":4})","[7, 10, 9]","[15, 11, 12, 13]","[154, 110, 112, 1311]"};
|
||||
size_t expected_indexes[5] = {0, 9, 29, 44, 65};
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
size_t counter{0};
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_TRUE(counter < 5);
|
||||
ASSERT_EQUAL(i.current_index(), expected_indexes[counter]);
|
||||
ASSERT_EQUAL(i.source(), expected[counter]);
|
||||
counter++;
|
||||
}
|
||||
ASSERT_EQUAL(counter, 5);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool doc_index_multiple_batches() {
|
||||
TEST_START();
|
||||
auto json = R"({"z":5} {"1":1,"2":2,"4":4} [7, 10, 9] [15, 11, 12, 13] [154, 110, 112, 1311])"_padded;
|
||||
std::string_view expected[5] = {R"({"z":5})",R"({"1":1,"2":2,"4":4})","[7, 10, 9]","[15, 11, 12, 13]","[154, 110, 112, 1311]"};
|
||||
size_t expected_indexes[5] = {0, 9, 29, 44, 65};
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
size_t counter{0};
|
||||
ASSERT_SUCCESS(parser.iterate_many(json,32).get(stream));
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_TRUE(counter < 5);
|
||||
ASSERT_EQUAL(i.current_index(), expected_indexes[counter]);
|
||||
ASSERT_EQUAL(i.source(), expected[counter]);
|
||||
counter++;
|
||||
}
|
||||
ASSERT_EQUAL(counter, 5);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool source_test() {
|
||||
TEST_START();
|
||||
auto json = R"([1,[1,2]] {"a":1,"b":2} {"o":{"1":1,"2":2}} [1,2,3] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
std::string_view expected[4] = {"[1,[1,2]]", "{\"a\":1,\"b\":2}", "{\"o\":{\"1\":1,\"2\":2}}", "[1,2,3]"};
|
||||
size_t counter{0};
|
||||
for (auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_EQUAL(i.source(), expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter,4);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool truncated() {
|
||||
TEST_START();
|
||||
// The last JSON document is intentionally truncated.
|
||||
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2 )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
|
||||
size_t counter{0};
|
||||
for (auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
counter++;
|
||||
}
|
||||
size_t truncated = stream.truncated_bytes();
|
||||
ASSERT_EQUAL(truncated, 6);
|
||||
ASSERT_EQUAL(counter,2);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool truncated_complete_docs() {
|
||||
TEST_START();
|
||||
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
|
||||
size_t counter{0};
|
||||
for (auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
counter++;
|
||||
}
|
||||
size_t truncated = stream.truncated_bytes();
|
||||
ASSERT_EQUAL(truncated, 0);
|
||||
ASSERT_EQUAL(counter,3);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool truncated_unclosed_string() {
|
||||
TEST_START();
|
||||
// The last JSON document is intentionally truncated.
|
||||
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} "intentionally unclosed string )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
// We use a window of json.size() though any large value would do.
|
||||
ASSERT_SUCCESS( parser.iterate_many(json).get(stream) );
|
||||
size_t counter{0};
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
counter++;
|
||||
}
|
||||
size_t truncated = stream.truncated_bytes();
|
||||
ASSERT_EQUAL(counter,2);
|
||||
ASSERT_EQUAL(truncated,32);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool truncated_unclosed_string_in_object() {
|
||||
// The last JSON document is intentionally truncated.
|
||||
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS( parser.iterate_many(json).get(stream) );
|
||||
size_t counter{0};
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
counter++;
|
||||
}
|
||||
size_t truncated = stream.truncated_bytes();
|
||||
ASSERT_EQUAL(counter,2);
|
||||
ASSERT_EQUAL(truncated,39);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool small_window() {
|
||||
TEST_START();
|
||||
std::vector<char> input;
|
||||
input.push_back('[');
|
||||
for(size_t i = 1; i < 1024; i++) {
|
||||
input.push_back('1');
|
||||
input.push_back(i < 1023 ? ',' : ']');
|
||||
}
|
||||
auto json = simdjson::padded_string(input.data(),input.size());
|
||||
singlestage::parser parser;
|
||||
size_t window_size{1024}; // deliberately too small
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS( parser.iterate_many(json, window_size).get(stream) );
|
||||
auto i = stream.begin();
|
||||
ASSERT_ERROR(i.error(), CAPACITY);
|
||||
ASSERT_EQUAL(stream.truncated_bytes(), json.length());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool large_window() {
|
||||
TEST_START();
|
||||
#if SIZE_MAX > 17179869184
|
||||
auto json = R"({"error":[],"result":{"token":"xxx"}}{"error":[],"result":{"token":"xxx"}})"_padded;
|
||||
singlestage::parser parser;
|
||||
uint64_t window_size{17179869184}; // deliberately too big
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS( parser.iterate_many(json, size_t(window_size)).get(stream) );
|
||||
auto i = stream.begin();
|
||||
ASSERT_ERROR(i.error(),CAPACITY);
|
||||
#endif
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool test_leading_spaces() {
|
||||
TEST_START();
|
||||
auto input = R"( [1,1] [1,2] [1,3] [1,4] [1,5] [1,6] [1,7] [1,8] [1,9] [1,10] [1,11] [1,12] [1,13] [1,14] [1,15] )"_padded;;
|
||||
size_t count{0};
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(input, 32).get(stream));
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_SUCCESS(i.error());
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,15);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool test_crazy_leading_spaces() {
|
||||
TEST_START();
|
||||
auto input = R"( [1,1] [1,2] [1,3] [1,4] [1,5] [1,6] [1,7] [1,8] [1,9] [1,10] [1,11] [1,12] [1,13] [1,14] [1,15] )"_padded;;
|
||||
size_t count{0};
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(input, 32).get(stream));
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_SUCCESS(i.error());
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,15);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool adversarial_single_document() {
|
||||
TEST_START();
|
||||
auto json = R"({"f[)"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
size_t count{0};
|
||||
for (auto doc : stream) {
|
||||
(void)doc;
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,0);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool adversarial_single_document_array() {
|
||||
TEST_START();
|
||||
auto json = R"(["this is an unclosed string ])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
size_t count{0};
|
||||
for (auto doc : stream) {
|
||||
(void)doc;
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,0);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_stream_test() {
|
||||
TEST_START();
|
||||
fflush(NULL);
|
||||
const size_t n_records = 100;
|
||||
std::string data;
|
||||
std::vector<char> buf(1024);
|
||||
// Generating data
|
||||
for (size_t i = 0; i < n_records; ++i) {
|
||||
size_t n = snprintf(buf.data(),
|
||||
buf.size(),
|
||||
"{\"id\": %zu, \"name\": \"name%zu\", \"gender\": \"%s\", "
|
||||
"\"ete\": {\"id\": %zu, \"name\": \"eventail%zu\"}}",
|
||||
i, i, (i % 2) ? "homme" : "femme", i % 10, i % 10);
|
||||
if (n >= buf.size()) { abort(); }
|
||||
data += std::string(buf.data(), n);
|
||||
}
|
||||
|
||||
for(size_t batch_size = 1000; batch_size < 2000; batch_size += (batch_size>1050?10:1)) {
|
||||
fflush(NULL);
|
||||
simdjson::padded_string str(data);
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
size_t count{0};
|
||||
ASSERT_SUCCESS( parser.iterate_many(str, batch_size).get(stream) );
|
||||
for (auto doc : stream) {
|
||||
int64_t keyid{};
|
||||
ASSERT_SUCCESS( doc["id"].get(keyid) );
|
||||
ASSERT_EQUAL( keyid, int64_t(count) );
|
||||
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,n_records);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1668() {
|
||||
TEST_START();
|
||||
auto json = R"([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100])"_padded;
|
||||
|
||||
singlestage::parser odparser;
|
||||
singlestage::document_stream odstream;
|
||||
ASSERT_SUCCESS( odparser.iterate_many(json.data(), json.length(), 50).get(odstream) );
|
||||
for (auto doc: odstream) {
|
||||
singlestage::value val;
|
||||
ASSERT_ERROR(doc.at_pointer("/40").get(val), CAPACITY);
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), json.length());
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1668_long() {
|
||||
TEST_START();
|
||||
auto json = R"([1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100])"_padded;
|
||||
|
||||
singlestage::parser odparser;
|
||||
singlestage::document_stream odstream;
|
||||
size_t counter{0};
|
||||
ASSERT_SUCCESS( odparser.iterate_many(json.data(), json.length(), 50).get(odstream) );
|
||||
for (auto doc: odstream) {
|
||||
if(counter < 6) {
|
||||
int64_t val{};
|
||||
ASSERT_SUCCESS(doc.at_pointer("/4").get(val));
|
||||
ASSERT_EQUAL(val, 5);
|
||||
} else {
|
||||
singlestage::value val;
|
||||
ASSERT_ERROR(doc.at_pointer("/4").get(val), CAPACITY);
|
||||
// We left 293 bytes unprocessed.
|
||||
ASSERT_EQUAL(odstream.truncated_bytes(), 293);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_stream_utf8_test() {
|
||||
TEST_START();
|
||||
fflush(NULL);
|
||||
const size_t n_records = 100;
|
||||
std::string data;
|
||||
std::vector<char> buf(1024);
|
||||
// Generating data
|
||||
for (size_t i = 0; i < n_records; ++i) {
|
||||
size_t n = snprintf(buf.data(),
|
||||
buf.size(),
|
||||
"{\"id\": %zu, \"name\": \"name%zu\", \"gender\": \"%s\", "
|
||||
"\"\xC3\xA9t\xC3\xA9\": {\"id\": %zu, \"name\": \"\xC3\xA9ventail%zu\"}}",
|
||||
i, i, (i % 2) ? "\xE2\xBA\x83" : "\xE2\xBA\x95", i % 10, i % 10);
|
||||
if (n >= buf.size()) { abort(); }
|
||||
data += std::string(buf.data(), n);
|
||||
}
|
||||
|
||||
for(size_t batch_size = 1000; batch_size < 2000; batch_size += (batch_size>1050?10:1)) {
|
||||
fflush(NULL);
|
||||
simdjson::padded_string str(data);
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
size_t count{0};
|
||||
ASSERT_SUCCESS( parser.iterate_many(str, batch_size).get(stream) );
|
||||
for (auto doc : stream) {
|
||||
int64_t keyid{};
|
||||
ASSERT_SUCCESS( doc["id"].get(keyid) );
|
||||
ASSERT_EQUAL( keyid, int64_t(count) );
|
||||
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL( count, n_records )
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool stress_data_race() {
|
||||
TEST_START();
|
||||
// Correct JSON.
|
||||
auto input = R"([1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] )"_padded;;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(input, 32).get(stream));
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
ASSERT_SUCCESS(i.error());
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool stress_data_race_with_error() {
|
||||
TEST_START();
|
||||
#if SIMDJSON_THREAD_ENABLED
|
||||
std::cout << "ENABLED" << std::endl;
|
||||
#endif
|
||||
// Intentionally broken
|
||||
auto input = R"([1,23] [1,23] [1,23] [1,23 [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] [1,23] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(input, 32).get(stream));
|
||||
size_t count{0};
|
||||
for(auto i = stream.begin(); i != stream.end(); ++i) {
|
||||
auto error = i.error();
|
||||
if(count <= 3) {
|
||||
ASSERT_SUCCESS(error);
|
||||
} else {
|
||||
ASSERT_ERROR(error,TAPE_ERROR);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool fuzzaccess() {
|
||||
TEST_START();
|
||||
// Issue 38801 in oss-fuzz
|
||||
auto json = "\xff \n~~\n{}"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream docs;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(docs));
|
||||
size_t bool_count = 0;
|
||||
size_t total_count = 0;
|
||||
for (auto doc : docs) {
|
||||
total_count++;
|
||||
bool b;
|
||||
if(doc.get_bool().get(b) == SUCCESS) { bool_count +=b; }
|
||||
// If we don't access the document at all, other than get_bool(),
|
||||
// then some simdjson kernels will allow you to iterate through
|
||||
// 3 'documents'. By asking for the type, we make the iteration
|
||||
// terminate after the first 'document'.
|
||||
singlestage::json_type t;
|
||||
if(doc.type().get(t) != SUCCESS) { break; }
|
||||
}
|
||||
return (bool_count == 0) && (total_count == 1);
|
||||
}
|
||||
|
||||
bool string_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( "a string" badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_string().get(view));
|
||||
ASSERT_EQUAL(view,"a string");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool uint64_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_uint64().get(x));
|
||||
ASSERT_EQUAL(x,133);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool int64_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_int64().get(x));
|
||||
ASSERT_EQUAL(x,133);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool double_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
double x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_double().get(x));
|
||||
ASSERT_EQUAL(x,133);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool bool_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( true badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
bool x;
|
||||
ASSERT_SUCCESS((*doc.begin()).get_bool().get(x));
|
||||
ASSERT_EQUAL(x,true);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool null_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( null badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json).get(doc));
|
||||
bool n;
|
||||
ASSERT_SUCCESS((*doc.begin()).is_null().get(n));
|
||||
ASSERT_EQUAL(n,true);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue1977() &&
|
||||
string_with_trailing() &&
|
||||
uint64_with_trailing() &&
|
||||
int64_with_trailing() &&
|
||||
bool_with_trailing() &&
|
||||
null_with_trailing() &&
|
||||
truncated_utf8() &&
|
||||
issue1729() &&
|
||||
fuzzaccess() &&
|
||||
issue1683() &&
|
||||
issue1668() &&
|
||||
issue1668_long() &&
|
||||
simple_document_iteration() &&
|
||||
simple_document_iteration_multiple_batches() &&
|
||||
simple_document_iteration_with_parsing() &&
|
||||
atoms_json() &&
|
||||
doc_index() &&
|
||||
doc_index_multiple_batches() &&
|
||||
source_test() &&
|
||||
truncated() &&
|
||||
truncated_complete_docs() &&
|
||||
truncated_unclosed_string() &&
|
||||
small_window() &&
|
||||
large_window() &&
|
||||
test_leading_spaces() &&
|
||||
test_crazy_leading_spaces() &&
|
||||
adversarial_single_document() &&
|
||||
adversarial_single_document_array() &&
|
||||
document_stream_test() &&
|
||||
document_stream_utf8_test() &&
|
||||
stress_data_race() &&
|
||||
stress_data_race_with_error() &&
|
||||
true;
|
||||
}
|
||||
} // document_stream_tests
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
return test_main(argc, argv, document_stream_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace error_location_tests {
|
||||
|
||||
bool array() {
|
||||
TEST_START();
|
||||
auto json = R"( [1,2,3] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::vector<char> expected = {'1','2','3'};
|
||||
std::vector<int64_t> expected_values = {1,2,3};
|
||||
size_t count{0};
|
||||
for (auto value : doc) {
|
||||
int64_t i;
|
||||
const char* c;
|
||||
// Must call current_location first because get_int64() will consume values
|
||||
ASSERT_SUCCESS(doc.current_location().get(c));
|
||||
ASSERT_EQUAL(*c, expected[count]);
|
||||
ASSERT_SUCCESS(value.get_int64().get(i));
|
||||
ASSERT_EQUAL(i, expected_values[count]);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,3);
|
||||
ASSERT_ERROR(doc.current_location(), OUT_OF_BOUNDS);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a":1, "b":2, "c":3} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::vector<char> expected = {'1','2','3'};
|
||||
std::vector<int64_t> expected_values = {1,2,3};
|
||||
size_t count{0};
|
||||
for (auto field : doc.get_object()) {
|
||||
int64_t i;
|
||||
const char* c;
|
||||
// Must call current_location first because get_int64() will consume values
|
||||
ASSERT_SUCCESS(doc.current_location().get(c));
|
||||
ASSERT_EQUAL(*c,expected[count]);
|
||||
ASSERT_SUCCESS(field.value().get(i));
|
||||
ASSERT_EQUAL(i,expected_values[count]);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count,3);
|
||||
ASSERT_ERROR(doc.current_location(), OUT_OF_BOUNDS);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool json_pointer() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a": [1,2,[3,4,5]], "b": {"c": [1.2, 2.3]}} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
uint64_t i;
|
||||
ASSERT_SUCCESS(doc.at_pointer("/a/2/1").get(i));
|
||||
ASSERT_EQUAL(i, 4);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
std::string expected = ",5]], \"b\": {\"c\": [1.2, 2.3]}} ";
|
||||
ASSERT_EQUAL(std::string(ptr, expected.size()), expected);
|
||||
double d;
|
||||
ASSERT_SUCCESS(doc.at_pointer("/b/c/1").get(d));
|
||||
ASSERT_EQUAL(d, 2.3);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
expected = "]}} ";
|
||||
ASSERT_EQUAL(std::string(ptr, expected.size()), expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool json_pointer_with_errors() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a": [1,2,[3 4,5]], "b": {"c": [1.2., 2.3]}} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
double d;
|
||||
ASSERT_ERROR(doc.at_pointer("/b/c/0").get(d), NUMBER_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
std::string expected = "1.2., 2.3]}} ";
|
||||
ASSERT_EQUAL(std::string(ptr, expected.size()), expected);
|
||||
uint64_t i;
|
||||
ASSERT_ERROR(doc.at_pointer("/a/2/1").get(i), TAPE_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
expected = "4,5]], \"b\": {\"c\": [1.2., 2.3]}} ";
|
||||
ASSERT_EQUAL(std::string(ptr, expected.size()), expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool broken_json1() {
|
||||
TEST_START();
|
||||
auto json = " \xc3\x94\xc3\xb8\xe2\x84\xa6{\"a\":1, 3} "_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
const char * ptr;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc["a"], INCORRECT_TYPE);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(std::string(ptr, 18), "\xc3\x94\xc3\xb8\xe2\x84\xa6{\"a\":1, 3} ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool broken_json2() {
|
||||
TEST_START();
|
||||
auto json = R"( [[[]] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
singlestage::array arr;
|
||||
const char * ptr;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
ASSERT_ERROR(arr.count_elements(), TAPE_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(std::string(ptr - 2,2), "] ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool broken_json3() {
|
||||
TEST_START();
|
||||
auto json = R"( [1 1.23, 2] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
size_t count{0};
|
||||
const char * ptr;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
for (auto val : doc) {
|
||||
if (count == 1) {
|
||||
ASSERT_ERROR(val, TAPE_ERROR);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(std::string(ptr, strlen("1.23, 2] ")), "1.23, 2] ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool broken_json4() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a":1, 3.5, "b":5} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
const char * ptr;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc["b"], TAPE_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(std::string(ptr, strlen("3.5, \"b\":5} ")), "3.5, \"b\":5} ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool incomplete_json() {
|
||||
TEST_START();
|
||||
auto json = R"( [1,2,3 )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
for (auto val : doc) {
|
||||
ASSERT_ERROR(val, INCOMPLETE_ARRAY_OR_OBJECT);
|
||||
}
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(std::string(ptr, strlen("[1,2,3 ")), "[1,2,3 ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool boolean_error() {
|
||||
TEST_START();
|
||||
auto json = R"( [tru, fals] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
for (auto val : doc) {
|
||||
bool b;
|
||||
ASSERT_ERROR(val.get(b), INCORRECT_TYPE);
|
||||
}
|
||||
ASSERT_ERROR(doc.current_location(), OUT_OF_BOUNDS);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool no_such_field() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a":5, "b":4} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc["c"], NO_SUCH_FIELD);
|
||||
ASSERT_ERROR(doc.current_location(), OUT_OF_BOUNDS);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object_with_no_such_field() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a":5, "b":4} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
uint64_t i;
|
||||
ASSERT_SUCCESS(doc["a"].get(i));
|
||||
ASSERT_EQUAL(i, 5);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, ", \"b\":4} ");
|
||||
ASSERT_ERROR(doc["c"], NO_SUCH_FIELD);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, ", \"b\":4} ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool number_parsing_error() {
|
||||
TEST_START();
|
||||
auto json = R"( [13.34.514] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
double d;
|
||||
ASSERT_ERROR(doc.at_pointer("/0").get_double().get(d), NUMBER_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, "13.34.514] ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool number_parsing_root_error() {
|
||||
TEST_START();
|
||||
auto json = R"( 13.34.514 )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
const char * ptr;
|
||||
double d;
|
||||
ASSERT_ERROR(doc.get_double().get(d), NUMBER_ERROR);
|
||||
ASSERT_SUCCESS(doc.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, "13.34.514 ");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool current_location_in_value() {
|
||||
TEST_START();
|
||||
auto json = R"( {"a": {"b": "c"}} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
simdjson_result<singlestage::value> a = doc["a"];
|
||||
ASSERT_SUCCESS(a);
|
||||
const char * ptr;
|
||||
ASSERT_SUCCESS(a.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, R"({"b": "c"}} )");
|
||||
simdjson_result<singlestage::value> b = a["b"];
|
||||
ASSERT_SUCCESS(b);
|
||||
ASSERT_SUCCESS(b.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, R"("c"}} )");
|
||||
double d;
|
||||
ASSERT_ERROR(b.get_double().get(d), INCORRECT_TYPE);
|
||||
ASSERT_SUCCESS(b.current_location().get(ptr));
|
||||
ASSERT_EQUAL(ptr, R"("c"}} )");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return array() &&
|
||||
object() &&
|
||||
json_pointer() &&
|
||||
json_pointer_with_errors() &&
|
||||
broken_json1() &&
|
||||
broken_json2() &&
|
||||
broken_json3() &&
|
||||
broken_json4() &&
|
||||
incomplete_json() &&
|
||||
boolean_error() &&
|
||||
no_such_field() &&
|
||||
object_with_no_such_field() &&
|
||||
number_parsing_error() &&
|
||||
number_parsing_root_error() &&
|
||||
current_location_in_value() &&
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace error_location_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, error_location_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace error_tests {
|
||||
using namespace std;
|
||||
|
||||
bool badbadjson() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json_string = R"({
|
||||
"main": "therain"_"in_spain"_
|
||||
})"_padded;
|
||||
singlestage::document document;
|
||||
auto error = parser.iterate(json_string).get(document);
|
||||
if(error != simdjson::SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
singlestage::object obj;
|
||||
error = document.get_object().get(obj);
|
||||
if(error != simdjson::SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
std::string_view name_value{};
|
||||
error = obj["name"].get_string().get(name_value);
|
||||
ASSERT_ERROR(error,TAPE_ERROR);
|
||||
// Check for "main" field
|
||||
std::string_view main_value{};
|
||||
error = obj["main"].get_string().get(main_value);
|
||||
ASSERT_ERROR(error,TAPE_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool badbadjson2() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json_string = R"({
|
||||
"main": "therain"_"in_spain"_
|
||||
})"_padded;
|
||||
singlestage::document document;
|
||||
auto error = parser.iterate(json_string).get(document);
|
||||
if(error != simdjson::SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
singlestage::object obj;
|
||||
error = document.get_object().get(obj);
|
||||
if(error != simdjson::SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string_view main_value{};
|
||||
error = obj["main"].get_string().get(main_value);
|
||||
ASSERT_ERROR(error, simdjson::SUCCESS);
|
||||
std::string_view name_value{};
|
||||
error = obj["name"].get_string().get(name_value);
|
||||
ASSERT_ERROR(error,TAPE_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1834() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = "[[]"_padded;
|
||||
json.data()[json.size()] = ']';
|
||||
auto doc = parser.iterate(json);
|
||||
size_t cnt{};
|
||||
auto error = doc.count_elements().get(cnt);
|
||||
return error != simdjson::SUCCESS;
|
||||
}
|
||||
bool issue1834_2() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = "{\"a\":{}"_padded;
|
||||
json.data()[json.size()] = '}';
|
||||
auto doc = parser.iterate(json);
|
||||
size_t cnt{};
|
||||
auto error = doc.count_fields().get(cnt);
|
||||
return error != simdjson::SUCCESS;
|
||||
}
|
||||
bool empty_document_error() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = ""_padded;
|
||||
ASSERT_ERROR( parser.iterate(json), EMPTY );
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool raw_json_string_error() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
singlestage::raw_json_string rawjson;
|
||||
ASSERT_ERROR( doc.get_raw_json_string().get(rawjson), INCORRECT_TYPE );
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool raw_json_string_except() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
try {
|
||||
singlestage::raw_json_string rawjson = doc.get_raw_json_string();
|
||||
(void)rawjson;
|
||||
TEST_FAIL("Should have thrown an exception!")
|
||||
} catch(simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), INCORRECT_TYPE);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
}
|
||||
bool raw_json_string_except_with_io() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = "{\"haha\":{\"df2\":3.5, \"df3\": \"fd\"}}"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
try {
|
||||
auto rawjson = doc.get_raw_json_string();
|
||||
std::cout << rawjson;
|
||||
TEST_FAIL("Should have thrown an exception!")
|
||||
} catch(simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), INCORRECT_TYPE);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
bool parser_max_capacity() {
|
||||
TEST_START();
|
||||
singlestage::parser parser(1); // max_capacity set to 1 byte
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
auto error = parser.iterate(json);
|
||||
ASSERT_ERROR(error,CAPACITY);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool simple_error_example() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"({"bad number":3.14.1 })"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
double x;
|
||||
ASSERT_ERROR( doc["bad number"].get_double().get(x), NUMBER_ERROR );
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool simple_error_example_except() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"({"bad number":3.14.1 })"_padded;
|
||||
try {
|
||||
singlestage::document doc = parser.iterate(json);
|
||||
double x = doc["bad number"].get_double();
|
||||
TEST_FAIL("should throw got: "+std::to_string(x))
|
||||
} catch(simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), NUMBER_ERROR);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool get_fail_then_succeed_bool() {
|
||||
TEST_START();
|
||||
auto json = R"({ "val" : true })"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> val = doc["val"];
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS( doc["val"].get(val) );
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
json = R"(true)"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](simdjson_result<singlestage::document> val) {
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_SUCCESS( val.get_bool());
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::document val;
|
||||
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_SUCCESS( val.get_bool() );
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, false );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool get_fail_then_succeed_null() {
|
||||
TEST_START();
|
||||
auto json = R"({ "val" : null })"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> val = doc["val"];
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS( doc["val"].get(val) );
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
json = R"(null)"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](simdjson_result<singlestage::document> val) {
|
||||
// Get everything that can fail in both forward and backwards order
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::document val;
|
||||
ASSERT_SUCCESS( std::move(doc).get(val) ); // Get everything that can fail in both forward and backwards order
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_object(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_int64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_uint64(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_double(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_string(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_array(), INCORRECT_TYPE );
|
||||
ASSERT_ERROR( val.get_bool(), INCORRECT_TYPE );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( val.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
TEST_SUCCEED();
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool invalid_type() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("]", "]", doc.type().error() == TAPE_ERROR);
|
||||
SINGLESTAGE_SUBTEST("}", "}", doc.type().error() == TAPE_ERROR);
|
||||
SINGLESTAGE_SUBTEST(":", ":", doc.type().error() == TAPE_ERROR);
|
||||
SINGLESTAGE_SUBTEST(",", ",", doc.type().error() == TAPE_ERROR);
|
||||
SINGLESTAGE_SUBTEST("+", "+", doc.type().error() == TAPE_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
badbadjson() &&
|
||||
badbadjson2() &&
|
||||
issue1834() &&
|
||||
issue1834_2() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
raw_json_string_except() &&
|
||||
raw_json_string_except_with_io() &&
|
||||
#endif
|
||||
raw_json_string_error() &&
|
||||
empty_document_error() &&
|
||||
parser_max_capacity() &&
|
||||
get_fail_then_succeed_bool() &&
|
||||
get_fail_then_succeed_null() &&
|
||||
invalid_type() &&
|
||||
simple_error_example() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
simple_error_example_except() &&
|
||||
#endif
|
||||
true;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, error_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace iterate_many_csv_tests {
|
||||
using namespace std;
|
||||
|
||||
bool normal() {
|
||||
TEST_START();
|
||||
auto json = R"( 1, 2, 3, 4, "a", "b", "c", {"hello": "world"} , [1, 2, 3])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc_stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json, json.size(), true).get(doc_stream));
|
||||
|
||||
for (auto doc : doc_stream)
|
||||
{
|
||||
ASSERT_SUCCESS(doc);
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool small_batch_size() {
|
||||
TEST_START();
|
||||
auto json = R"( 1, 2, 3, 4, "a", "b", "c", {"hello": "world"} , [1, 2, 3])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc_stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json, 32, true).get(doc_stream));
|
||||
|
||||
for (auto doc : doc_stream)
|
||||
{
|
||||
ASSERT_SUCCESS(doc);
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool trailing_comma() {
|
||||
TEST_START();
|
||||
auto json = R"(1,)"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc_stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json, json.size(), true).get(doc_stream));
|
||||
|
||||
for (auto doc : doc_stream)
|
||||
{
|
||||
ASSERT_SUCCESS(doc);
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool check_parsed_values() {
|
||||
TEST_START();
|
||||
|
||||
auto json = R"( 1 , "a" , [100, 1] , {"hello" : "world"} , )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc_stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json, json.size(), true).get(doc_stream));
|
||||
|
||||
auto begin = doc_stream.begin();
|
||||
auto end = doc_stream.end();
|
||||
int cnt = 0;
|
||||
auto it = begin;
|
||||
for (; it != end && cnt < 4; ++it, ++cnt) {
|
||||
auto doc = *it;
|
||||
switch (cnt)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int64_t actual;
|
||||
ASSERT_SUCCESS(doc.get_int64().get(actual));
|
||||
ASSERT_EQUAL(actual, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
std::string_view sv;
|
||||
ASSERT_SUCCESS(doc.get_string().get(sv));
|
||||
ASSERT_EQUAL(sv, "a");
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
std::vector<int64_t> expected{100, 1};
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
size_t element_count;
|
||||
ASSERT_SUCCESS(arr.count_elements().get(element_count));
|
||||
ASSERT_EQUAL(element_count, 2);
|
||||
int i = 0;
|
||||
for (auto a : arr)
|
||||
{
|
||||
int64_t actual;
|
||||
ASSERT_SUCCESS(a.get(actual));
|
||||
ASSERT_EQUAL(actual, expected[i++]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||
std::string_view sv;
|
||||
obj.find_field("hello").get(sv);
|
||||
ASSERT_EQUAL(sv, "world");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TEST_FAIL("Too many cases")
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQUAL(cnt, 4);
|
||||
ASSERT_TRUE(!(it != end));
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool leading_comma() {
|
||||
TEST_START();
|
||||
auto json = R"(,1)"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document_stream doc_stream;
|
||||
ASSERT_SUCCESS(parser.iterate_many(json, json.size(), true).get(doc_stream));
|
||||
|
||||
try {
|
||||
auto begin = doc_stream.begin();
|
||||
auto end = doc_stream.end();
|
||||
for (auto it = begin; it != end; ++it) {}
|
||||
} catch (simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), TAPE_ERROR);
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool run() {
|
||||
return normal() &&
|
||||
small_batch_size() &&
|
||||
trailing_comma() &&
|
||||
check_parsed_values() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
leading_comma() &&
|
||||
#endif
|
||||
true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, iterate_many_csv_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
#include <string>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace json_pointer_tests {
|
||||
const padded_string TEST_JSON = R"(
|
||||
{
|
||||
"/~01abc": [
|
||||
0,
|
||||
{
|
||||
"\\\" 0": [
|
||||
"value0",
|
||||
"value1"
|
||||
]
|
||||
}
|
||||
],
|
||||
"0": "0 ok",
|
||||
"01": "01 ok",
|
||||
"": "empty ok",
|
||||
"arr": []
|
||||
}
|
||||
)"_padded;
|
||||
|
||||
const padded_string TEST_RFC_JSON = R"(
|
||||
{
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
}
|
||||
)"_padded;
|
||||
|
||||
bool run_success_test(const padded_string & json,std::string_view json_pointer,std::string expected) {
|
||||
TEST_START();
|
||||
std::cout <<":"<< json_pointer<<std::endl;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
singlestage::value val;
|
||||
std::string_view actual;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(val));
|
||||
ASSERT_SUCCESS(simdjson::to_json_string(val).get(actual));
|
||||
ASSERT_EQUAL(actual,expected);
|
||||
// We want to see if the value is usable besides to_json_string.
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(val));
|
||||
singlestage::json_type type;
|
||||
ASSERT_SUCCESS(val.type().get(type));
|
||||
switch (type) {
|
||||
case singlestage::json_type::array:
|
||||
ASSERT_SUCCESS(val.get_array().error());
|
||||
break;
|
||||
case singlestage::json_type::object:
|
||||
ASSERT_SUCCESS(val.get_object().error());
|
||||
break;
|
||||
case singlestage::json_type::number:
|
||||
ASSERT_SUCCESS(val.get_double().error());
|
||||
break;
|
||||
case singlestage::json_type::string:
|
||||
ASSERT_SUCCESS(val.get_string().error());
|
||||
break;
|
||||
case singlestage::json_type::boolean:
|
||||
ASSERT_SUCCESS(val.get_bool().error());
|
||||
break;
|
||||
case singlestage::json_type::null:
|
||||
ASSERT_SUCCESS(val.is_null().error());
|
||||
break;
|
||||
default:
|
||||
TEST_FAIL("unexpected type");
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run_failure_test(const padded_string & json,std::string_view json_pointer,error_code expected) {
|
||||
TEST_START();
|
||||
std::cout << "json_pointer: " << json_pointer << std::endl;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_EQUAL(doc.at_pointer(json_pointer).error(),expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool demo_test() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document cars;
|
||||
double x;
|
||||
ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
|
||||
ASSERT_SUCCESS(cars.at_pointer("/0/tire_pressure/1").get(x));
|
||||
ASSERT_EQUAL(x,39.9);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool demo_relative_path() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document cars;
|
||||
std::vector<double> measured;
|
||||
ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
|
||||
for (auto car_element : cars) {
|
||||
double x;
|
||||
ASSERT_SUCCESS(car_element.at_pointer("/tire_pressure/1").get(x));
|
||||
measured.push_back(x);
|
||||
}
|
||||
|
||||
std::vector<double> expected = {39.9, 31, 30};
|
||||
if (measured != expected) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_as_scalar() {
|
||||
TEST_START();
|
||||
auto number_json = R"( 1 )"_padded;
|
||||
auto null_json = R"( null )"_padded;
|
||||
auto string_json = R"( "a" )"_padded;
|
||||
auto true_json = R"( true )"_padded;
|
||||
auto false_json = R"( false )"_padded;
|
||||
auto object_json = R"( {} )"_padded;
|
||||
auto array_json = R"( {} )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
singlestage::value val;
|
||||
bool is_scalar;
|
||||
std::cout << " checking number"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(number_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking null"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(null_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking string"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(string_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking false"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(false_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking true"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(true_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_TRUE(is_scalar);
|
||||
ASSERT_ERROR(doc.at_pointer("").get(val), simdjson::SCALAR_DOCUMENT_AS_VALUE);
|
||||
std::cout << " checking object"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(object_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_FALSE(is_scalar);
|
||||
ASSERT_SUCCESS(doc.at_pointer("").get(val));
|
||||
std::cout << " checking array"<< std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(array_json).get(doc));
|
||||
ASSERT_SUCCESS(doc.is_scalar().get(is_scalar));
|
||||
ASSERT_FALSE(is_scalar);
|
||||
ASSERT_SUCCESS(doc.at_pointer("").get(val));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool many_json_pointers() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document cars;
|
||||
std::vector<double> measured;
|
||||
ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
double x;
|
||||
std::string json_pointer = std::string("/") + std::to_string(i) + std::string("/tire_pressure/1");
|
||||
ASSERT_SUCCESS(cars.at_pointer(json_pointer).get(x));
|
||||
measured.push_back(x);
|
||||
}
|
||||
|
||||
std::vector<double> expected = {39.9, 31, 30};
|
||||
if (measured != expected) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool run_broken_tests() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
singlestage::value v;
|
||||
std::string_view val;
|
||||
|
||||
auto invalid_escape_key = R"( {"hello": [0,1,2,3], "te\est": "foo", "bool": true, "num":1234, "success":"yes"} )"_padded;
|
||||
auto invalid_escape_value = R"( {"hello": [0,1,2,3], "test": "fo\eo", "bool": true, "num":1234, "success":"yes"} )"_padded;
|
||||
auto invalid_escape_value_at_jp = R"( {"hello": [0,1,2,3], "test": "foo", "bool": true, "num":1234, "success":"y\es"} )"_padded;
|
||||
auto unclosed_object = R"( {"test": "foo", "bool": true, "num":1234, "success":"yes" )"_padded;
|
||||
auto missing_bracket_before = R"( {"hello": [0,1,2,3, "test": "foo", "bool": true, "num":1234, "success":"yes"} )"_padded;
|
||||
auto missing_bracket_after = R"( {"test": "foo", "bool": true, "num":1234, "success":"yes", "hello":[0,1,2,3} )"_padded;
|
||||
|
||||
std::string json_pointer = "/success";
|
||||
std::cout << "\t- invalid_escape_key" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(invalid_escape_key).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(val));
|
||||
std::cout << "\t- invalid_escape_value" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(invalid_escape_value).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(val));
|
||||
std::cout << "\t- invalid_escape_value_at_jp_nomat" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(invalid_escape_value_at_jp).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(v));
|
||||
std::cout << "\t- invalid_escape_value_at_jp" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(invalid_escape_value_at_jp).get(doc));
|
||||
ASSERT_ERROR(doc.at_pointer(json_pointer).get(val), simdjson::STRING_ERROR);
|
||||
std::cout << "\t- unclosed_object" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(unclosed_object).get(doc));
|
||||
ASSERT_ERROR(doc.at_pointer(json_pointer).get(val), simdjson::INCOMPLETE_ARRAY_OR_OBJECT);
|
||||
std::cout << "\t- missing_bracket_before" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(missing_bracket_before).get(doc));
|
||||
ASSERT_ERROR(doc.at_pointer(json_pointer).get(val), simdjson::TAPE_ERROR);
|
||||
std::cout << "\t- missing_bracket_after" << std::endl;
|
||||
ASSERT_SUCCESS(parser.iterate(missing_bracket_after).get(doc));
|
||||
ASSERT_SUCCESS(doc.at_pointer(json_pointer).get(val));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool many_json_pointers_object_array() {
|
||||
TEST_START();
|
||||
auto dogcatpotato = R"( { "dog" : [1,2,3], "cat" : [5, 6, 7], "potato" : [1234]})"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(dogcatpotato).get(doc));
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS(obj.at_pointer("/dog/1").get(x));
|
||||
ASSERT_EQUAL(x, 2);
|
||||
ASSERT_SUCCESS(obj.at_pointer("/potato/0").get(x));
|
||||
ASSERT_EQUAL(x, 1234);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool many_json_pointers_object() {
|
||||
TEST_START();
|
||||
auto cfoofoo2 = R"( { "c" :{ "foo": { "a": [ 10, 20, 30 ] }}, "d": { "foo2": { "a": [ 10, 20, 30 ] }} , "e": 120 })"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS(obj.at_pointer("/c/foo/a/1").get(x));
|
||||
ASSERT_EQUAL(x, 20);
|
||||
ASSERT_SUCCESS(obj.at_pointer("/d/foo2/a/2").get(x));
|
||||
ASSERT_EQUAL(x, 30);
|
||||
ASSERT_SUCCESS(obj.at_pointer("/e").get(x));
|
||||
ASSERT_EQUAL(x, 120);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool many_json_pointers_array() {
|
||||
TEST_START();
|
||||
auto cfoofoo2 = R"( [ 111, 2, 3, { "foo": { "a": [ 10, 20, 33 ] }}, { "foo2": { "a": [ 10, 20, 30 ] }}, 1001 ])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(cfoofoo2).get(doc));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS(arr.at_pointer("/3/foo/a/1").get(x));
|
||||
ASSERT_EQUAL(x, 20);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
struct car_type {
|
||||
std::string make;
|
||||
std::string model;
|
||||
uint64_t year;
|
||||
std::vector<double> tire_pressure;
|
||||
car_type(std::string_view _make, std::string_view _model, uint64_t _year,
|
||||
std::vector<double>&& _tire_pressure) :
|
||||
make{_make}, model{_model}, year(_year), tire_pressure(_tire_pressure) {}
|
||||
};
|
||||
|
||||
bool json_pointer_invalidation() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
singlestage::document cars;
|
||||
std::vector<double> measured;
|
||||
ASSERT_SUCCESS(parser.iterate(cars_json).get(cars));
|
||||
std::vector<car_type> content;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
singlestage::object obj;
|
||||
std::string json_pointer = std::string("/") + std::to_string(i);
|
||||
// Each successive at_pointer call invalidates
|
||||
// previously parsed values, strings, objects and array.
|
||||
ASSERT_SUCCESS(cars.at_pointer(json_pointer).get(obj));
|
||||
// We materialize the object.
|
||||
std::string_view make;
|
||||
ASSERT_SUCCESS(obj["make"].get(make));
|
||||
std::string_view model;
|
||||
ASSERT_SUCCESS(obj["model"].get(model));
|
||||
uint64_t year;
|
||||
ASSERT_SUCCESS(obj["year"].get(year));
|
||||
// We materialize the array.
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(obj["tire_pressure"].get(arr));
|
||||
std::vector<double> values;
|
||||
for(auto x : arr) {
|
||||
double value_double;
|
||||
ASSERT_SUCCESS(x.get(value_double));
|
||||
values.push_back(value_double);
|
||||
}
|
||||
content.emplace_back(make, model, year, std::move(values));
|
||||
}
|
||||
std::string expected[] = {"Toyota", "Kia", "Toyota"};
|
||||
int i = 0;
|
||||
for (car_type c : content) {
|
||||
std::cout << c.make << " " << c.model << " " << c.year << "\n";
|
||||
ASSERT_EQUAL(expected[i++], c.make);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool json_pointer_invalidation_exceptions() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
|
||||
singlestage::parser parser;
|
||||
std::vector<double> measured;
|
||||
singlestage::document cars = parser.iterate(cars_json);
|
||||
std::vector<car_type> content;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string json_pointer = std::string("/") + std::to_string(i);
|
||||
// Each successive at_pointer call invalidates
|
||||
// previously parsed values, strings, objects and array.
|
||||
singlestage::object obj(cars.at_pointer(json_pointer).get_object());
|
||||
// We materialize the object.
|
||||
std::string_view make = obj["make"];
|
||||
std::string_view model = obj["model"];
|
||||
uint64_t year(obj["year"]);
|
||||
// We materialize the array.
|
||||
singlestage::array arr(obj["tire_pressure"].get_array());
|
||||
std::vector<double> values;
|
||||
for(auto x : arr) {
|
||||
double value_double(x.get_double());
|
||||
values.push_back(value_double);
|
||||
}
|
||||
content.emplace_back(make, model, year, std::move(values));
|
||||
}
|
||||
std::string expected[] = {"Toyota", "Kia", "Toyota"};
|
||||
for (car_type c : content) {
|
||||
std::cout << c.make << " " << c.model << " " << c.year << "\n";
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
json_pointer_invalidation_exceptions() &&
|
||||
#endif
|
||||
many_json_pointers_array() &&
|
||||
many_json_pointers_object() &&
|
||||
many_json_pointers_object_array() &&
|
||||
run_broken_tests() &&
|
||||
json_pointer_invalidation() &&
|
||||
demo_test() &&
|
||||
demo_relative_path() &&
|
||||
run_success_test(TEST_RFC_JSON,"/foo",R"(["bar", "baz"])") &&
|
||||
run_success_test(TEST_RFC_JSON,"/foo/0",R"("bar")") &&
|
||||
run_success_test(TEST_RFC_JSON,"/",R"(0)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/a~1b",R"(1)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/c%d",R"(2)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/e^f",R"(3)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/g|h",R"(4)") &&
|
||||
run_success_test(TEST_RFC_JSON,R"(/i\\j)",R"(5)") &&
|
||||
run_success_test(TEST_RFC_JSON,R"(/k\"l)",R"(6)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/ ",R"(7)") &&
|
||||
run_success_test(TEST_RFC_JSON,"/m~0n",R"(8)") &&
|
||||
run_success_test(TEST_RFC_JSON,"",R"({
|
||||
"foo": ["bar", "baz"],
|
||||
"": 0,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
" ": 7,
|
||||
"m~n": 8
|
||||
})") &&
|
||||
run_success_test(TEST_JSON, "", R"({
|
||||
"/~01abc": [
|
||||
0,
|
||||
{
|
||||
"\\\" 0": [
|
||||
"value0",
|
||||
"value1"
|
||||
]
|
||||
}
|
||||
],
|
||||
"0": "0 ok",
|
||||
"01": "01 ok",
|
||||
"": "empty ok",
|
||||
"arr": []
|
||||
})") &&
|
||||
run_success_test(TEST_JSON, R"(/~1~001abc)", R"([
|
||||
0,
|
||||
{
|
||||
"\\\" 0": [
|
||||
"value0",
|
||||
"value1"
|
||||
]
|
||||
}
|
||||
])") &&
|
||||
run_success_test(TEST_JSON, R"(/~1~001abc/1)", R"({
|
||||
"\\\" 0": [
|
||||
"value0",
|
||||
"value1"
|
||||
]
|
||||
})") &&
|
||||
run_success_test(TEST_JSON, R"(/~1~001abc/1/\\\" 0)", R"([
|
||||
"value0",
|
||||
"value1"
|
||||
])") &&
|
||||
run_success_test(TEST_JSON, R"(/~1~001abc/1/\\\" 0/0)", "\"value0\"") &&
|
||||
run_success_test(TEST_JSON, R"(/~1~001abc/1/\\\" 0/1)", "\"value1\"") &&
|
||||
run_success_test(TEST_JSON, "/arr", R"([])") &&
|
||||
run_success_test(TEST_JSON, "/0", "\"0 ok\"") &&
|
||||
run_success_test(TEST_JSON, "/01", "\"01 ok\"") &&
|
||||
run_success_test(TEST_JSON, "", R"({
|
||||
"/~01abc": [
|
||||
0,
|
||||
{
|
||||
"\\\" 0": [
|
||||
"value0",
|
||||
"value1"
|
||||
]
|
||||
}
|
||||
],
|
||||
"0": "0 ok",
|
||||
"01": "01 ok",
|
||||
"": "empty ok",
|
||||
"arr": []
|
||||
})") &&
|
||||
run_failure_test(TEST_JSON, R"(/~1~001abc/1/\\\" 0/2)", INDEX_OUT_OF_BOUNDS) &&
|
||||
run_failure_test(TEST_JSON, "/arr/0", INDEX_OUT_OF_BOUNDS) &&
|
||||
run_failure_test(TEST_JSON, "~1~001abc", INVALID_JSON_POINTER) &&
|
||||
run_failure_test(TEST_JSON, "/~01abc", NO_SUCH_FIELD) &&
|
||||
run_failure_test(TEST_JSON, "/~1~001abc/01", INVALID_JSON_POINTER) &&
|
||||
run_failure_test(TEST_JSON, "/~1~001abc/", INVALID_JSON_POINTER) &&
|
||||
run_failure_test(TEST_JSON, "/~1~001abc/-", INDEX_OUT_OF_BOUNDS) &&
|
||||
many_json_pointers() &&
|
||||
document_as_scalar() &&
|
||||
true;
|
||||
}
|
||||
} // json_pointer_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, json_pointer_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace key_string_tests {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool parser_key_value() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const padded_string json = R"({ "1": "1", "2": "2", "3": "3", "abc": "abc", "\u0075": "\u0075" })"_padded;
|
||||
auto doc = parser.iterate(json);
|
||||
for(auto field : doc.get_object()) {
|
||||
std::string_view keyv = field.unescaped_key();
|
||||
std::string_view valuev = field.value();
|
||||
if(keyv != valuev) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
parser_key_value() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace key_string_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, key_string_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#define SIMDJSON_VERBOSE_LOGGING 1
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace log_error_tests {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool tape_error()
|
||||
{
|
||||
TEST_START();
|
||||
auto json = R"( {"a", "hello"} )"_padded;
|
||||
singlestage::parser parser;
|
||||
try {
|
||||
singlestage::document doc = parser.iterate(json);
|
||||
std::cout << doc["a"] << std::endl;
|
||||
TEST_FAIL("Should have thrown an exception!")
|
||||
} catch (simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), TAPE_ERROR);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool no_such_field()
|
||||
{
|
||||
TEST_START();
|
||||
auto json = R"( {"a": "hello"} )"_padded;
|
||||
singlestage::parser parser;
|
||||
try {
|
||||
singlestage::document doc = parser.iterate(json);
|
||||
std::cout << doc["missing_key"] << std::endl;
|
||||
TEST_FAIL("Should have thrown an exception!")
|
||||
} catch (simdjson_error& e) {
|
||||
ASSERT_ERROR(e.error(), NO_SUCH_FIELD);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run()
|
||||
{
|
||||
SIMDJSON_PUSH_DISABLE_WARNINGS
|
||||
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
||||
std::string str = "SIMDJSON_LOG_LEVEL=ERROR";
|
||||
putenv(str.data());
|
||||
bool rc =
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
tape_error() &&
|
||||
no_such_field() &&
|
||||
#endif // #if SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
SIMDJSON_POP_DISABLE_WARNINGS
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, log_error_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#define SIMDJSON_VERBOSE_LOGGING 1
|
||||
#include "simdjson.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
|
||||
int main() {
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc = parser.iterate(cars_json);
|
||||
std::vector<std::string> container;
|
||||
for(singlestage::object o : doc) {
|
||||
container.emplace_back(std::string_view(o["make"]));
|
||||
}
|
||||
std::cout << "---" << std::endl;
|
||||
for(std::string& m : container) {
|
||||
std::cout << m << std::endl;
|
||||
}
|
||||
#endif // #if SIMDJSON_EXCEPTIONS
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,631 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace misc_tests {
|
||||
using namespace std;
|
||||
bool issue1981_success() {
|
||||
auto error_phrase = R"(false)"_padded;
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(error_phrase).get(doc));
|
||||
bool b;
|
||||
ASSERT_SUCCESS( doc.get_bool().get(b));
|
||||
ASSERT_FALSE(b);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1981_failure() {
|
||||
auto error_phrase = R"(falseA)"_padded;
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(error_phrase).get(doc));
|
||||
bool b;
|
||||
ASSERT_ERROR( doc.get_bool().get(b), INCORRECT_TYPE);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool replacement_char() {
|
||||
auto fun_phrase = R"( ["I \u2665 Unicode. Even broken \ud800 Unicode." ])"_padded;
|
||||
std::string_view expected_fun = "I \xe2\x99\xa5 Unicode. Even broken \xef\xbf\xbd Unicode.";
|
||||
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(fun_phrase).get(doc));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS( doc.get_array().get(arr));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS( arr.at(0).get_string(true).get(view));
|
||||
ASSERT_EQUAL(view, expected_fun);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool wobbly_tests() {
|
||||
auto lone_surrogate = R"( "\ud800" )"_padded;
|
||||
std::string_view expected_lone = "\xed\xa0\x80";
|
||||
|
||||
|
||||
auto fun_phrase = R"( ["I \u2665 Unicode. Even broken \ud800 Unicode." ])"_padded;
|
||||
std::string_view expected_fun = "I \xe2\x99\xa5 Unicode. Even broken \xed\xa0\x80 Unicode.";
|
||||
|
||||
auto insane_url = R"({"input": "http://example.com/\uDC00\uD834\uDF06\uDC00"} )"_padded;
|
||||
std::string_view expected_insane = "http://example.com/\xED\xB0\x80\xF0\x9D\x8C\x86\xED\xB0\x80";
|
||||
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(lone_surrogate).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS( doc.get_wobbly_string().get(view));
|
||||
ASSERT_EQUAL(view, expected_lone);
|
||||
|
||||
ASSERT_SUCCESS(parser.iterate(fun_phrase).get(doc));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS( doc.get_array().get(arr));
|
||||
ASSERT_SUCCESS( arr.at(0).get_wobbly_string().get(view));
|
||||
ASSERT_EQUAL(view, expected_fun);
|
||||
|
||||
ASSERT_SUCCESS(parser.iterate(insane_url).get(doc));
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( doc.get_object().get(obj));
|
||||
ASSERT_SUCCESS( obj["input"].get_wobbly_string().get(view));
|
||||
|
||||
ASSERT_EQUAL(view, expected_insane);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool test_get_value() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string json = R"({"a":[[1,null,3.0],["a","b",true],[10000000000,2,3]]})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS(doc.get_value().get(val));
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(val.get_object().get(obj));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(obj["a"].get_array().get(arr));
|
||||
size_t count{};
|
||||
ASSERT_SUCCESS(arr.count_elements().get(count));
|
||||
ASSERT_EQUAL(3,count);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1661a() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"":],"global-groups":[[]}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::value global_groups;
|
||||
ASSERT_SUCCESS(doc["global-groups"].get(global_groups));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global_groups.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::array);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool doc_ref() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"":2,"v":[]})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::document_reference ref(doc);
|
||||
singlestage::value arr;
|
||||
ASSERT_SUCCESS(ref["v"].get(arr));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(arr.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::array);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue_uffff() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"( "wow:\uFFFF" )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS( doc.get_string().get(view));
|
||||
ASSERT_EQUAL(view, "wow:\xef\xbf\xbf");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue_backslash() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"( "sc:\\./" )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS( doc.get_string().get(view));
|
||||
ASSERT_EQUAL(view, "sc:\\./");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1870() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"("\uDC00")"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_ERROR( doc.get_string().get(view), STRING_ERROR );
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
// Test a surrogate pair with the low surrogate out of range
|
||||
bool issue1894() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"("\uD888\u1234")"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_ERROR(doc.get_string().get(view), STRING_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1894toolarge() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"("\uD888\uE000")"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_ERROR(doc.get_string().get(view), STRING_ERROR);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
// Test the smallest surrogate pair, largest surrogate pair, and a surrogate pair in range.
|
||||
bool issue1894success() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"("\uD888\uDC00\uD800\uDC00\uDBFF\uDFFF")"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS(doc.get_string().get(view));
|
||||
ASSERT_EQUAL(view, "\xf0\xb2\x80\x80\xf0\x90\x80\x80\xf4\x8f\xbf\xbf");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1660() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_object(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1660_with_bool() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_bool(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1660_with_uint64() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_uint64(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1660_with_int64() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_int64(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1660_with_double() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_double(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1660_with_null() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS(shadowable.is_null().get(is_null_value));
|
||||
ASSERT_TRUE(!is_null_value);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool issue1660_with_string() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"globals":{"a":{"shadowable":[}}}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object globals;
|
||||
ASSERT_SUCCESS(doc["globals"].get(globals));
|
||||
for (auto global_field : globals) {
|
||||
singlestage::value global;
|
||||
ASSERT_SUCCESS(global_field.value().get(global));
|
||||
singlestage::json_type global_type;
|
||||
ASSERT_SUCCESS(global.type().get(global_type));
|
||||
ASSERT_EQUAL(global_type, singlestage::json_type::object);
|
||||
singlestage::object global_object;
|
||||
ASSERT_SUCCESS(global.get(global_object));
|
||||
singlestage::value shadowable;
|
||||
ASSERT_SUCCESS(global_object["shadowable"].get(shadowable));
|
||||
ASSERT_ERROR(shadowable.get_string(), INCORRECT_TYPE);
|
||||
singlestage::value badvalue;
|
||||
auto error = global_object["writable"].get(badvalue);
|
||||
if(error == SUCCESS) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool is_alive_root_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"([1,2,3)"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
size_t count{0};
|
||||
for(simdjson_unused simdjson_result<singlestage::value> val : doc) {
|
||||
ASSERT_ERROR(val.error(), INCOMPLETE_ARRAY_OR_OBJECT);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool is_alive_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"a":[1,2,3})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.get_object().get(obj));
|
||||
singlestage::array internal_arr;
|
||||
ASSERT_SUCCESS(obj["a"].get_array().get(internal_arr));
|
||||
size_t count{0};
|
||||
for(simdjson_unused simdjson_result<singlestage::value> val : internal_arr) {
|
||||
if(count < 3) {
|
||||
ASSERT_SUCCESS(val.error());
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
} else {
|
||||
ASSERT_ERROR(val.error(), TAPE_ERROR);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 4);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool is_alive_root_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"a":1)"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
singlestage::object obj;
|
||||
ASSERT_ERROR(doc.get_object().get(obj), INCOMPLETE_ARRAY_OR_OBJECT);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool is_alive_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"([{"a":1])"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS(doc.at(0).get_object().get(obj));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
size_t count{0};
|
||||
for(simdjson_unused simdjson_result<singlestage::field> val : obj) {
|
||||
if(count == 0) {
|
||||
ASSERT_SUCCESS(val.error());
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
}
|
||||
if(count == 1) {
|
||||
ASSERT_ERROR(val.error(), TAPE_ERROR);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 2);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue1661() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"({"":],"global-groups":[[]}})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::object global_groups;
|
||||
ASSERT_ERROR(doc["global-groups"].get(global_groups), INCORRECT_TYPE);
|
||||
singlestage::object globals;
|
||||
auto error = doc["globals"].get(globals);
|
||||
if(error == SUCCESS) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
simdjson_warn_unused bool big_integer() {
|
||||
TEST_START();
|
||||
simdjson::singlestage::parser parser;
|
||||
simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
|
||||
simdjson::singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
simdjson::singlestage::object o;
|
||||
ASSERT_SUCCESS(doc.get_object().get(o));
|
||||
string_view token;
|
||||
ASSERT_SUCCESS(o["value"].raw_json_token().get(token));
|
||||
ASSERT_EQUAL(token, "12321323213213213213213213213211223");
|
||||
return true;
|
||||
}
|
||||
simdjson_warn_unused bool big_integer_in_string() {
|
||||
TEST_START();
|
||||
simdjson::singlestage::parser parser;
|
||||
simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
|
||||
simdjson::singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
simdjson::singlestage::object o;
|
||||
ASSERT_SUCCESS(doc.get_object().get(o));
|
||||
string_view token;
|
||||
ASSERT_SUCCESS(o["value"].raw_json_token().get(token));
|
||||
ASSERT_EQUAL(token, "\"12321323213213213213213213213211223\"");
|
||||
return true;
|
||||
}
|
||||
simdjson_warn_unused bool test_raw_json_token(string_view json, string_view expected_token, int expected_start_index = 0) {
|
||||
string title("'");
|
||||
title.append(json.data(), json.length());
|
||||
title += std::string("'");
|
||||
padded_string json_padded = json;
|
||||
SUBTEST(title, test_singlestage_doc(json_padded, [&](auto doc) {
|
||||
string_view token;
|
||||
ASSERT_SUCCESS( doc.raw_json_token().get(token) );
|
||||
ASSERT_EQUAL( token, expected_token );
|
||||
// Validate the text is inside the original buffer
|
||||
ASSERT_EQUAL( reinterpret_cast<const void*>(token.data()), reinterpret_cast<const void*>(&json_padded.data()[expected_start_index]));
|
||||
return true;
|
||||
}));
|
||||
|
||||
// Test values
|
||||
auto json_in_hash = string(R"({"a":)");
|
||||
json_in_hash.append(json.data(), json.length());
|
||||
json_in_hash += std::string("}");
|
||||
json_padded = json_in_hash;
|
||||
title = std::string("'");
|
||||
title.append(json_in_hash.data(), json_in_hash.length());
|
||||
title += std::string("'");
|
||||
SUBTEST(title, test_singlestage_doc(json_padded, [&](auto doc) {
|
||||
string_view token;
|
||||
ASSERT_SUCCESS( doc["a"].raw_json_token().get(token) );
|
||||
ASSERT_EQUAL( token, expected_token );
|
||||
// Validate the text is inside the original buffer
|
||||
// Adjust for the {"a":
|
||||
ASSERT_EQUAL( reinterpret_cast<const void*>(token.data()), reinterpret_cast<const void*>(&json_padded.data()[5+expected_start_index]));
|
||||
return true;
|
||||
}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool raw_json_token() {
|
||||
TEST_START();
|
||||
return
|
||||
test_raw_json_token("{}", "{") &&
|
||||
test_raw_json_token("{ }", "{ ") &&
|
||||
test_raw_json_token("{ \n }", "{ \n ") &&
|
||||
test_raw_json_token(" \n { \n } \n ", "{ \n ", 3) &&
|
||||
test_raw_json_token("[]", "[") &&
|
||||
test_raw_json_token("1", "1") &&
|
||||
test_raw_json_token(" \n 1 \n ", "1 \n ", 3) &&
|
||||
test_raw_json_token("-123.456e-789", "-123.456e-789") &&
|
||||
test_raw_json_token(" \n -123.456e-789 \n ", "-123.456e-789 \n ", 3) &&
|
||||
test_raw_json_token("true", "true") &&
|
||||
test_raw_json_token("false", "false") &&
|
||||
test_raw_json_token("null", "null") &&
|
||||
test_raw_json_token("blah2", "blah2") &&
|
||||
test_raw_json_token("true false", "true ") &&
|
||||
test_raw_json_token("true \n false", "true \n ") &&
|
||||
true;
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
issue1981_success() &&
|
||||
issue1981_failure() &&
|
||||
replacement_char() &&
|
||||
wobbly_tests() &&
|
||||
issue_uffff() &&
|
||||
issue_backslash() &&
|
||||
issue1870() &&
|
||||
issue1894() &&
|
||||
issue1894toolarge() &&
|
||||
issue1894success() &&
|
||||
is_alive_root_array() &&
|
||||
is_alive_root_object() &&
|
||||
is_alive_array() &&
|
||||
is_alive_object() &&
|
||||
test_get_value() &&
|
||||
issue1660_with_uint64() &&
|
||||
issue1660_with_int64() &&
|
||||
issue1660_with_double() &&
|
||||
issue1660_with_null() &&
|
||||
issue1660_with_string() &&
|
||||
issue1660_with_bool() &&
|
||||
issue1661a() &&
|
||||
issue1660() &&
|
||||
issue1661() &&
|
||||
big_integer_in_string() &&
|
||||
big_integer() &&
|
||||
raw_json_token() &&
|
||||
doc_ref() &&
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace twitter_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, misc_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
#include <string>
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace number_in_string_tests {
|
||||
const padded_string CRYPTO_JSON = R"(
|
||||
{
|
||||
"ticker":{
|
||||
"base":"BTC",
|
||||
"target":"USD",
|
||||
"price":"443.7807865468",
|
||||
"volume":"31720.1493969300",
|
||||
"change":"Infinity",
|
||||
"markets":[
|
||||
{
|
||||
"market":"bitfinex",
|
||||
"price":"447.5000000000",
|
||||
"volume":"10559.5293639000"
|
||||
},
|
||||
{
|
||||
"market":"bitstamp",
|
||||
"price":"448.5400000000",
|
||||
"volume":"11628.2880079300"
|
||||
},
|
||||
{
|
||||
"market":"btce",
|
||||
"price":"432.8900000000",
|
||||
"volume":"8561.0563600000"
|
||||
}
|
||||
]
|
||||
},
|
||||
"timestamp":1399490941,
|
||||
"timestampstr":"1399490941"
|
||||
}
|
||||
)"_padded;
|
||||
|
||||
bool in_document_int64() {
|
||||
TEST_START();
|
||||
auto json = R"( "-11232321" )"_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
int64_t result;
|
||||
ASSERT_SUCCESS(doc.get_int64_in_string().get(result));
|
||||
ASSERT_EQUAL(result,-11232321);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool in_document_uint64() {
|
||||
TEST_START();
|
||||
auto json = R"( "11232321" )"_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
uint64_t result;
|
||||
ASSERT_SUCCESS(doc.get_uint64_in_string().get(result));
|
||||
ASSERT_EQUAL(result,11232321);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool in_document_double() {
|
||||
TEST_START();
|
||||
auto json = R"( "11232321.12" )"_padded;
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
double result;
|
||||
ASSERT_SUCCESS(doc.get_double_in_string().get(result));
|
||||
ASSERT_EQUAL(result,11232321.12);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
// bool stream_of_pure_int64() {
|
||||
// TEST_START();
|
||||
// auto json = R"( 1 2 3 )"_padded;
|
||||
|
||||
// singlestage::parser parser;
|
||||
// singlestage::document_stream stream;
|
||||
// ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
// int document_index = 0;
|
||||
// for (auto doc : stream) {
|
||||
// document_index++;
|
||||
// int64_t result;
|
||||
// ASSERT_SUCCESS(doc.get_int64().get(result));
|
||||
// ASSERT_EQUAL(result,document_index);
|
||||
// }
|
||||
// ASSERT_EQUAL(3,document_index);
|
||||
// TEST_SUCCEED();
|
||||
// }
|
||||
|
||||
// bool stream_of_direct_int64() {
|
||||
// TEST_START();
|
||||
// auto json = R"( "1" "2" "3" )"_padded;
|
||||
|
||||
// singlestage::parser parser;
|
||||
// singlestage::document_stream stream;
|
||||
// ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
// int document_index = 0;
|
||||
// for (auto doc : stream) {
|
||||
// document_index++;
|
||||
// int64_t result;
|
||||
// ASSERT_SUCCESS(doc.get_int64_in_string().get(result));
|
||||
// ASSERT_EQUAL(result,document_index);
|
||||
// }
|
||||
// ASSERT_EQUAL(3,document_index);
|
||||
// TEST_SUCCEED();
|
||||
// }
|
||||
|
||||
// bool stream_of_int64() {
|
||||
// TEST_START();
|
||||
// auto json = R"( ["1"] ["2"] ["3"] )"_padded;
|
||||
|
||||
// singlestage::parser parser;
|
||||
// singlestage::document_stream stream;
|
||||
// ASSERT_SUCCESS(parser.iterate_many(json).get(stream));
|
||||
// int document_index = 0;
|
||||
// for (auto doc : stream) {
|
||||
// document_index++;
|
||||
// int64_t result;
|
||||
// ASSERT_SUCCESS(doc.get_array().at(0).get_int64_in_string().get(result));
|
||||
// ASSERT_EQUAL(result,document_index);
|
||||
// }
|
||||
// ASSERT_EQUAL(3,document_index);
|
||||
// TEST_SUCCEED();
|
||||
// }
|
||||
|
||||
bool array_double() {
|
||||
TEST_START();
|
||||
auto json = R"(["1.2","2.3","-42.3","2.43442e3", "-1.234e3"])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<double> expected = {1.2, 2.3, -42.3, 2434.42, -1234};
|
||||
double d;
|
||||
for (auto value : doc) {
|
||||
ASSERT_SUCCESS(value.get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool array_int() {
|
||||
TEST_START();
|
||||
auto json = R"(["1", "2", "-3", "1000", "-7844", "-9223372036854775807", "9223372036854775807"])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<int64_t> expected = {1, 2, -3, 1000, -7844, INT64_C(-9223372036854775807), INT64_C(9223372036854775807) };
|
||||
int64_t i;
|
||||
for (auto value : doc) {
|
||||
ASSERT_SUCCESS(value.get_int64_in_string().get(i));
|
||||
ASSERT_EQUAL(i,expected[counter++]);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool array_unsigned() {
|
||||
TEST_START();
|
||||
auto json = R"(["1", "2", "24", "9000", "156934", "10588030077111859193", "18446744073709551615"])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<uint64_t> expected = {1, 2, 24, 9000, 156934, UINT64_C(10588030077111859193), UINT64_C(18446744073709551615)};
|
||||
uint64_t u;
|
||||
for (auto value : doc) {
|
||||
ASSERT_SUCCESS(value.get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,expected[counter++]);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object() {
|
||||
TEST_START();
|
||||
auto json = R"({"a":"1.2", "b":"-2.342e2", "c":"22", "d":"-112358", "e":"1080", "f":"123456789", "g":"10588030077111859193"})"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::vector<double> expected = {1.2, -234.2, 22, -112358, 1080, 123456789};
|
||||
double d;
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
// Doubles
|
||||
ASSERT_SUCCESS(doc.find_field("a").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("b").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
// Integers
|
||||
ASSERT_SUCCESS(doc.find_field("c").get_int64_in_string().get(i));
|
||||
ASSERT_EQUAL(i,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("d").get_int64_in_string().get(i));
|
||||
ASSERT_EQUAL(i,expected[counter++]);
|
||||
// Unsigned integers
|
||||
ASSERT_SUCCESS(doc.find_field("e").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("f").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.find_field("g").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u, UINT64_C(10588030077111859193));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool docs() {
|
||||
TEST_START();
|
||||
auto double_doc = R"( "-1.23e1" )"_padded;
|
||||
auto int_doc = R"( "-243" )"_padded;
|
||||
auto uint_doc = R"( "212213" )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
double d;
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
// Double
|
||||
ASSERT_SUCCESS(parser.iterate(double_doc).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,-12.3);
|
||||
// Integer
|
||||
ASSERT_SUCCESS(parser.iterate(int_doc).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_int64_in_string().get(i));
|
||||
ASSERT_EQUAL(i,-243);
|
||||
// Unsigned integer
|
||||
ASSERT_SUCCESS(parser.iterate(uint_doc).get(doc));
|
||||
ASSERT_SUCCESS(doc.get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,212213);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool number_parsing_error() {
|
||||
TEST_START();
|
||||
auto json = R"( ["13.06.54", "1.0e", "2e3r4,,."])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::string expected[3] = {"13.06.54", "1.0e", "2e3r4,,."};
|
||||
for (auto value : doc) {
|
||||
double d;
|
||||
std::string_view view;
|
||||
ASSERT_ERROR(value.get_double_in_string().get(d),NUMBER_ERROR);
|
||||
ASSERT_SUCCESS(value.get_string().get(view));
|
||||
ASSERT_EQUAL(view,expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter,3);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool incorrect_type_error() {
|
||||
TEST_START();
|
||||
auto json = R"( ["e", "i", "pi", "one", "zero"])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
size_t counter{0};
|
||||
std::string expected[5] = {"e", "i", "pi", "one", "zero"};
|
||||
for (auto value : doc) {
|
||||
double d;
|
||||
std::string_view view;
|
||||
ASSERT_ERROR(value.get_double_in_string().get(d),INCORRECT_TYPE);
|
||||
ASSERT_SUCCESS(value.get_string().get(view));
|
||||
ASSERT_EQUAL(view,expected[counter++]);
|
||||
}
|
||||
ASSERT_EQUAL(counter,5);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool json_pointer_test() {
|
||||
TEST_START();
|
||||
auto json = R"( ["12.34", { "a":["3","5.6"], "b":{"c":"1.23e1"} }, ["1", "3.5"] ])"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::vector<double> expected = {12.34, 5.6, 12.3, 1, 3.5};
|
||||
size_t counter{0};
|
||||
double d;
|
||||
ASSERT_SUCCESS(doc.at_pointer("/0").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.at_pointer("/1/a/1").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.at_pointer("/1/b/c").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.at_pointer("/2/0").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_SUCCESS(doc.at_pointer("/2/1").get_double_in_string().get(d));
|
||||
ASSERT_EQUAL(d,expected[counter++]);
|
||||
ASSERT_EQUAL(counter,5);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool crypto_timestamp() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(CRYPTO_JSON).get(doc));
|
||||
uint64_t u;
|
||||
ASSERT_SUCCESS(doc.at_pointer("/timestampstr").get_uint64_in_string().get(u));
|
||||
ASSERT_EQUAL(u,1399490941);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool crypto_market() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(CRYPTO_JSON).get(doc));
|
||||
singlestage::array markets;
|
||||
ASSERT_SUCCESS(doc.find_field("ticker").find_field("markets").get_array().get(markets));
|
||||
std::string_view expected_views[3] = {"bitfinex", "bitstamp", "btce"};
|
||||
double expected_prices[3] = {447.5, 448.54, 432.89};
|
||||
double expected_volumes[3] = {10559.5293639, 11628.28800793, 8561.05636};
|
||||
size_t counter{0};
|
||||
for (auto value : markets) {
|
||||
std::string_view view;
|
||||
double price;
|
||||
double volume;
|
||||
ASSERT_SUCCESS(value.find_field("market").get_string().get(view));
|
||||
ASSERT_EQUAL(view,expected_views[counter]);
|
||||
ASSERT_SUCCESS(value.find_field("price").get_double_in_string().get(price));
|
||||
ASSERT_EQUAL(price,expected_prices[counter]);
|
||||
ASSERT_SUCCESS(value.find_field("volume").get_double_in_string().get(volume));
|
||||
ASSERT_EQUAL(volume,expected_volumes[counter]);
|
||||
counter++;
|
||||
}
|
||||
ASSERT_EQUAL(counter,3);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool crypto_infinity() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(CRYPTO_JSON).get(doc));
|
||||
singlestage::value value;
|
||||
double d;
|
||||
std::string_view view;
|
||||
ASSERT_SUCCESS(doc.find_field("ticker").find_field("change").get(value));
|
||||
ASSERT_ERROR(value.get_double_in_string().get(d), INCORRECT_TYPE);
|
||||
ASSERT_SUCCESS(value.get_string().get(view));
|
||||
ASSERT_EQUAL(view,"Infinity");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return stream_of_pure_int64() &&
|
||||
stream_of_direct_int64() &&
|
||||
stream_of_int64() &&
|
||||
in_document_int64() &&
|
||||
in_document_uint64() &&
|
||||
in_document_double() &&
|
||||
array_double() &&
|
||||
array_int() &&
|
||||
array_unsigned() &&
|
||||
object() &&
|
||||
docs() &&
|
||||
number_parsing_error() &&
|
||||
incorrect_type_error() &&
|
||||
json_pointer_test() &&
|
||||
crypto_timestamp() &&
|
||||
crypto_market() &&
|
||||
crypto_infinity() &&
|
||||
true;
|
||||
}
|
||||
} // number_in_string_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, number_in_string_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
#include <cmath>
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace number_tests {
|
||||
|
||||
bool small_integers() {
|
||||
TEST_START();
|
||||
for (int64_t m = 10; m < 20; m++) {
|
||||
for (int64_t i = -1024; i < 1024; i++) {
|
||||
if(!test_singlestage<int64_t>(std::to_string(i),
|
||||
[&](int64_t actual) {
|
||||
ASSERT_EQUAL(actual, i);
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
} // if
|
||||
} // for i
|
||||
} // for m
|
||||
return true;
|
||||
}
|
||||
|
||||
bool powers_of_two() {
|
||||
TEST_START();
|
||||
|
||||
// converts the double "expected" to a padded string
|
||||
auto format_into_padded=[](const double expected) -> padded_string
|
||||
{
|
||||
std::vector<char> buf(1024);
|
||||
const auto n = std::snprintf(buf.data(),
|
||||
buf.size(),
|
||||
"%.*e",
|
||||
std::numeric_limits<double>::max_digits10 - 1,
|
||||
expected);
|
||||
const auto nz=static_cast<size_t>(n);
|
||||
if (n<0 || nz >= buf.size()) { std::abort(); }
|
||||
return padded_string(buf.data(), nz);
|
||||
};
|
||||
|
||||
for (int i = -1075; i < 1024; ++i) {// large negative values should be zero.
|
||||
const double expected = std::pow(2, i);
|
||||
const auto buf=format_into_padded(expected);
|
||||
std::fflush(nullptr);
|
||||
if(!test_singlestage<double>(buf,
|
||||
[&](double actual) {
|
||||
if(actual!=expected) {
|
||||
std::cerr << "JSON '" << buf << " parsed to ";
|
||||
std::fprintf( stderr," %18.18g instead of %18.18g\n", actual, expected); // formatting numbers is easier with printf
|
||||
SIMDJSON_SHOW_DEFINE(FLT_EVAL_METHOD);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
} // if
|
||||
} // for i
|
||||
return true;
|
||||
}
|
||||
|
||||
static const double testing_power_of_ten[] = {
|
||||
1e-307, 1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299,
|
||||
1e-298, 1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290,
|
||||
1e-289, 1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281,
|
||||
1e-280, 1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272,
|
||||
1e-271, 1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263,
|
||||
1e-262, 1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254,
|
||||
1e-253, 1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245,
|
||||
1e-244, 1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236,
|
||||
1e-235, 1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227,
|
||||
1e-226, 1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218,
|
||||
1e-217, 1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209,
|
||||
1e-208, 1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200,
|
||||
1e-199, 1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191,
|
||||
1e-190, 1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182,
|
||||
1e-181, 1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173,
|
||||
1e-172, 1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164,
|
||||
1e-163, 1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155,
|
||||
1e-154, 1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146,
|
||||
1e-145, 1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137,
|
||||
1e-136, 1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128,
|
||||
1e-127, 1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119,
|
||||
1e-118, 1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110,
|
||||
1e-109, 1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101,
|
||||
1e-100, 1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92,
|
||||
1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83,
|
||||
1e-82, 1e-81, 1e-80, 1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74,
|
||||
1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65,
|
||||
1e-64, 1e-63, 1e-62, 1e-61, 1e-60, 1e-59, 1e-58, 1e-57, 1e-56,
|
||||
1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47,
|
||||
1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40, 1e-39, 1e-38,
|
||||
1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29,
|
||||
1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
|
||||
1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11,
|
||||
1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2,
|
||||
1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
||||
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16,
|
||||
1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25,
|
||||
1e26, 1e27, 1e28, 1e29, 1e30, 1e31, 1e32, 1e33, 1e34,
|
||||
1e35, 1e36, 1e37, 1e38, 1e39, 1e40, 1e41, 1e42, 1e43,
|
||||
1e44, 1e45, 1e46, 1e47, 1e48, 1e49, 1e50, 1e51, 1e52,
|
||||
1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59, 1e60, 1e61,
|
||||
1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69, 1e70,
|
||||
1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
|
||||
1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88,
|
||||
1e89, 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97,
|
||||
1e98, 1e99, 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106,
|
||||
1e107, 1e108, 1e109, 1e110, 1e111, 1e112, 1e113, 1e114, 1e115,
|
||||
1e116, 1e117, 1e118, 1e119, 1e120, 1e121, 1e122, 1e123, 1e124,
|
||||
1e125, 1e126, 1e127, 1e128, 1e129, 1e130, 1e131, 1e132, 1e133,
|
||||
1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 1e140, 1e141, 1e142,
|
||||
1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151,
|
||||
1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 1e160,
|
||||
1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169,
|
||||
1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178,
|
||||
1e179, 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187,
|
||||
1e188, 1e189, 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196,
|
||||
1e197, 1e198, 1e199, 1e200, 1e201, 1e202, 1e203, 1e204, 1e205,
|
||||
1e206, 1e207, 1e208, 1e209, 1e210, 1e211, 1e212, 1e213, 1e214,
|
||||
1e215, 1e216, 1e217, 1e218, 1e219, 1e220, 1e221, 1e222, 1e223,
|
||||
1e224, 1e225, 1e226, 1e227, 1e228, 1e229, 1e230, 1e231, 1e232,
|
||||
1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, 1e240, 1e241,
|
||||
1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, 1e250,
|
||||
1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259,
|
||||
1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268,
|
||||
1e269, 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277,
|
||||
1e278, 1e279, 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286,
|
||||
1e287, 1e288, 1e289, 1e290, 1e291, 1e292, 1e293, 1e294, 1e295,
|
||||
1e296, 1e297, 1e298, 1e299, 1e300, 1e301, 1e302, 1e303, 1e304,
|
||||
1e305, 1e306, 1e307, 1e308};
|
||||
|
||||
|
||||
|
||||
bool powers_of_ten() {
|
||||
TEST_START();
|
||||
std::vector<char> buf(1024);
|
||||
|
||||
const bool is_pow_correct{1e-308 == std::pow(10,-308)};
|
||||
const int start_point = is_pow_correct ? -10000 : -307;
|
||||
if(!is_pow_correct) {
|
||||
std::cout << "On your system, the pow function is busted. Sorry about that. " << std::endl;
|
||||
}
|
||||
for (int i = start_point; i <= 308; ++i) {// large negative values should be zero.
|
||||
const size_t n = std::snprintf(buf.data(), buf.size(), "1e%d", i);
|
||||
if (n >= buf.size()) { std::abort(); }
|
||||
std::fflush(nullptr);
|
||||
const double expected = ((i >= -307) ? testing_power_of_ten[i + 307]: std::pow(10, i));
|
||||
|
||||
if(!test_singlestage<double>(padded_string(buf.data(), n), [&](double actual) {
|
||||
if(actual!=expected) {
|
||||
std::cerr << "JSON '" << buf.data() << " parsed to ";
|
||||
std::fprintf( stderr," %18.18g instead of %18.18g\n", actual, expected); // formatting numbers is easier with printf
|
||||
SIMDJSON_SHOW_DEFINE(FLT_EVAL_METHOD);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
return false;
|
||||
} // if
|
||||
} // for i
|
||||
return true;
|
||||
}
|
||||
|
||||
void github_issue_1273() {
|
||||
padded_string bad(std::string_view("0.0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000122978293824"));
|
||||
simdjson::singlestage::parser parser;
|
||||
simdjson_unused auto blah=parser.iterate(bad);
|
||||
double x;
|
||||
simdjson_unused auto blah2=blah.get(x);
|
||||
}
|
||||
|
||||
bool issue_1898() {
|
||||
TEST_START();
|
||||
padded_string negative_zero_string(std::string_view("-1e-999"));
|
||||
simdjson::singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(negative_zero_string).get(doc));
|
||||
double x;
|
||||
ASSERT_SUCCESS(doc.get(x));
|
||||
// should be minus 0
|
||||
ASSERT_TRUE(std::signbit(x));
|
||||
ASSERT_TRUE(x == -0);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool old_crashes() {
|
||||
TEST_START();
|
||||
github_issue_1273();
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool is_alive_root_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"([1,2,3)"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_alive());
|
||||
size_t count{0};
|
||||
for(simdjson_unused simdjson_result<singlestage::value> val : doc) {
|
||||
ASSERT_ERROR(val.error(), INCOMPLETE_ARRAY_OR_OBJECT);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
ASSERT_FALSE(doc.is_alive());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool get_number_tests() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
padded_string docdata = R"([1.0, 3, 1, 3.1415,-13231232,9999999999999999999,-9223372036854775807,-9223372036854775808])"_padded;
|
||||
singlestage::number_type expectedtypes[] = {singlestage::number_type::floating_point_number,
|
||||
singlestage::number_type::signed_integer,
|
||||
singlestage::number_type::signed_integer,
|
||||
singlestage::number_type::floating_point_number,
|
||||
singlestage::number_type::signed_integer,
|
||||
singlestage::number_type::unsigned_integer,
|
||||
singlestage::number_type::signed_integer,
|
||||
singlestage::number_type::signed_integer
|
||||
};
|
||||
bool is_negative[] = {false, false, false, false, true, false, true, true};
|
||||
bool is_integer[] = {false, true, true, false, true, true, true, true};
|
||||
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
singlestage::array arr;
|
||||
ASSERT_SUCCESS(doc.get_array().get(arr));
|
||||
size_t counter{0};
|
||||
for(simdjson_result<singlestage::value> valr : arr) {
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS(valr.get(val));
|
||||
singlestage::number_type nt{};
|
||||
ASSERT_SUCCESS(val.get_number_type().get(nt));
|
||||
ASSERT_EQUAL(expectedtypes[counter], nt);
|
||||
singlestage::number num;
|
||||
ASSERT_SUCCESS(val.get_number().get(num));
|
||||
ASSERT_EQUAL(is_negative[counter], val.is_negative());
|
||||
bool intvalue{};
|
||||
ASSERT_SUCCESS(val.is_integer().get(intvalue));
|
||||
ASSERT_EQUAL(is_integer[counter], intvalue);
|
||||
singlestage::number_type t = num.get_number_type();
|
||||
ASSERT_EQUAL(expectedtypes[counter], t);
|
||||
switch(t) {
|
||||
case singlestage::number_type::signed_integer:
|
||||
ASSERT_TRUE(num.is_int64());
|
||||
break;
|
||||
case singlestage::number_type::unsigned_integer:
|
||||
ASSERT_TRUE(num.is_uint64());
|
||||
break;
|
||||
case singlestage::number_type::floating_point_number:
|
||||
ASSERT_TRUE(num.is_double());
|
||||
break;
|
||||
}
|
||||
if(counter == 0) {
|
||||
ASSERT_EQUAL(num.get_double(), 1.0);
|
||||
ASSERT_EQUAL((double)num, 1.0);
|
||||
} else if(counter == 1) {
|
||||
ASSERT_EQUAL(num.get_int64(), 3);
|
||||
ASSERT_EQUAL((int64_t)num, 3);
|
||||
} else if(counter == 2) {
|
||||
ASSERT_EQUAL(num.get_int64(), 1);
|
||||
ASSERT_EQUAL((int64_t)num, 1);
|
||||
} else if(counter == 3) {
|
||||
ASSERT_EQUAL(num.get_double(), 3.1415);
|
||||
ASSERT_EQUAL((double)num, 3.1415);
|
||||
} else if(counter == 4) {
|
||||
ASSERT_EQUAL(num.get_int64(), -13231232);
|
||||
ASSERT_EQUAL((int64_t)num, -13231232);
|
||||
} else if(counter == 5) {
|
||||
ASSERT_EQUAL(num.get_uint64(), UINT64_C(9999999999999999999));
|
||||
ASSERT_EQUAL((uint64_t)num, UINT64_C(9999999999999999999));
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool issue1878() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto json = R"(123_abc)"_padded;
|
||||
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_int64().error(), NUMBER_ERROR);
|
||||
}
|
||||
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_int64().error(), TRAILING_CONTENT);
|
||||
}
|
||||
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_uint64().error(), NUMBER_ERROR);
|
||||
}
|
||||
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_uint64().error(), TRAILING_CONTENT);
|
||||
}
|
||||
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_double().error(), NUMBER_ERROR);
|
||||
}
|
||||
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_double().error(), TRAILING_CONTENT);
|
||||
}
|
||||
for (char ch : {'_', '%', 'z', '&', '\\', '/', '*'}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_number().error(), NUMBER_ERROR);
|
||||
}
|
||||
for (char ch : {'[', ']', '{', '}', ',', ' '}) {
|
||||
json.data()[3] = ch;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.get_number().error(), TRAILING_CONTENT);
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool get_root_number_tests() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
padded_string docdata;
|
||||
singlestage::number number;
|
||||
singlestage::number_type nt{};
|
||||
|
||||
bool intvalue{};
|
||||
|
||||
docdata = R"(1.0)"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_FALSE(doc.is_negative());
|
||||
ASSERT_SUCCESS(doc.get_number_type().get(nt));
|
||||
ASSERT_EQUAL(nt, singlestage::number_type::floating_point_number);
|
||||
ASSERT_SUCCESS(doc.is_integer().get(intvalue));
|
||||
ASSERT_SUCCESS(doc.get_number().get(number));
|
||||
ASSERT_FALSE(intvalue);
|
||||
ASSERT_EQUAL(number.get_number_type(), singlestage::number_type::floating_point_number);
|
||||
ASSERT_EQUAL(number.get_double(), 1.0);
|
||||
|
||||
docdata = R"(-3.132321)"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_TRUE(doc.is_negative());
|
||||
ASSERT_SUCCESS(doc.get_number_type().get(nt));
|
||||
ASSERT_EQUAL(nt, singlestage::number_type::floating_point_number);
|
||||
ASSERT_SUCCESS(doc.is_integer().get(intvalue));
|
||||
ASSERT_SUCCESS(doc.get_number().get(number));
|
||||
ASSERT_FALSE(intvalue);
|
||||
ASSERT_EQUAL(number.get_number_type(), singlestage::number_type::floating_point_number);
|
||||
ASSERT_EQUAL(number.get_double(), -3.132321);
|
||||
|
||||
docdata = R"(1233)"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_FALSE(doc.is_negative());
|
||||
ASSERT_SUCCESS(doc.get_number_type().get(nt));
|
||||
ASSERT_EQUAL(nt, singlestage::number_type::signed_integer);
|
||||
ASSERT_SUCCESS(doc.is_integer().get(intvalue));
|
||||
ASSERT_SUCCESS(doc.get_number().get(number));
|
||||
ASSERT_TRUE(intvalue);
|
||||
ASSERT_EQUAL(number.get_number_type(), singlestage::number_type::signed_integer);
|
||||
ASSERT_EQUAL(number.get_int64(), 1233);
|
||||
|
||||
docdata = R"(9999999999999999999)"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
ASSERT_FALSE(doc.is_negative());
|
||||
ASSERT_SUCCESS(doc.get_number_type().get(nt));
|
||||
ASSERT_EQUAL(nt, singlestage::number_type::unsigned_integer);
|
||||
ASSERT_SUCCESS(doc.is_integer().get(intvalue));
|
||||
ASSERT_SUCCESS(doc.get_number().get(number));
|
||||
ASSERT_TRUE(intvalue);
|
||||
ASSERT_EQUAL(number.get_number_type(), singlestage::number_type::unsigned_integer);
|
||||
ASSERT_EQUAL(number.get_uint64(), UINT64_C(9999999999999999999));
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool issue2017() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
padded_string docdata = R"({"score":0.8825149536132812})"_padded;
|
||||
ASSERT_SUCCESS(parser.iterate(docdata).get(doc));
|
||||
double score;
|
||||
ASSERT_SUCCESS(doc["score"].get_double().get(score));
|
||||
ASSERT_EQUAL(score, 0.8825149536132812);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return issue2017() &&
|
||||
issue_1898() &&
|
||||
issue1878() &&
|
||||
get_root_number_tests() &&
|
||||
get_number_tests()&&
|
||||
small_integers() &&
|
||||
powers_of_two() &&
|
||||
powers_of_ten() &&
|
||||
old_crashes();
|
||||
}
|
||||
|
||||
} // namespace number_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, number_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,573 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace object_error_tests {
|
||||
using namespace std;
|
||||
|
||||
template<typename V, typename T>
|
||||
bool assert_iterate_object(T &&object, const char **expected_key, V *expected, size_t N, simdjson::error_code *expected_error, size_t N2) {
|
||||
size_t count = 0;
|
||||
for (auto field : object) {
|
||||
V actual{};
|
||||
auto actual_error = field.value().get(actual);
|
||||
if (count >= N) {
|
||||
ASSERT((count - N) < N2, "Extra error reported");
|
||||
ASSERT_ERROR(actual_error, expected_error[count - N]);
|
||||
} else {
|
||||
ASSERT_SUCCESS(actual_error);
|
||||
ASSERT_EQUAL(field.key().value_unsafe(), expected_key[count]);
|
||||
ASSERT_EQUAL(actual, expected[count]);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, N+N2);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename V, size_t N, size_t N2, typename T>
|
||||
bool assert_iterate_object(T &&object, const char *(&&expected_key)[N], V (&&expected)[N], simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate_object<V, T>(std::forward<T>(object), expected_key, expected, N, expected_error, N2);
|
||||
}
|
||||
|
||||
template<size_t N2, typename T>
|
||||
bool assert_iterate_object(T &&object, simdjson::error_code (&&expected_error)[N2]) {
|
||||
return assert_iterate_object<int64_t, T>(std::forward<T>(object), nullptr, nullptr, 0, expected_error, N2);
|
||||
}
|
||||
|
||||
template<typename V, size_t N, typename T>
|
||||
bool assert_iterate_object(T &&object, const char *(&&expected_key)[N], V (&&expected)[N]) {
|
||||
return assert_iterate_object<V, T>(std::forward<T>(object), expected_key, expected, N, nullptr, 0);
|
||||
}
|
||||
|
||||
bool object_iterate_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing colon", R"({ "a" 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("missing key ", R"({ : 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("missing value", R"({ "a": , "b": 2 })", assert_iterate_object(doc.get_object(), { INCORRECT_TYPE, TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("missing comma", R"({ "a": 1 "b": 2 })", assert_iterate_object(doc.get_object(), { "a" }, { int64_t(1) }, { TAPE_ERROR }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_iterate_wrong_key_type_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ 1: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ true: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ false: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ null: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ []: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ {}: 1, "b": 2 })", assert_iterate_object(doc.get_object(), { TAPE_ERROR }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_iterate_unclosed_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": 1, )", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": 1 )", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": )", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a" )", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ )", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_iterate_incomplete_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "x": { "a": 1, })", assert_iterate_object(doc.get_object(), { "a" }, { int64_t(1) }, { TAPE_ERROR }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "x": { "a": 1 })", assert_iterate_object(doc.get_object(), { "a" }, { int64_t(1) }, { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "x": { "a": })", assert_iterate_object(doc.get_object(), { INCORRECT_TYPE, INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "x": { "a" })", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "x": { })", assert_iterate_object(doc.get_object(), { INCOMPLETE_ARRAY_OR_OBJECT }));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object_lookup_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing colon", R"({ "a" 1, "b": 2 })", assert_error(doc["a"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("missing key ", R"({ : 1, "b": 2 })", assert_error(doc["a"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("missing value", R"({ "a": , "b": 2 })", assert_success(doc["a"]));
|
||||
SINGLESTAGE_SUBTEST("missing comma", R"({ "a": 1 "b": 2 })", assert_success(doc["a"]));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_lookup_unclosed_error() {
|
||||
TEST_START();
|
||||
#if SIMDJSON_CHECK_EOF
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": )", assert_error(doc["a"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
#else
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": )", assert_error(doc["a"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
#endif
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a" )", assert_error(doc["a"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ )", assert_error(doc["a"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object_lookup_miss_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing colon", R"({ "a" 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("missing key ", R"({ : 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("missing value", R"({ "a": , "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("missing comma", R"({ "a": 1 "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_lookup_miss_wrong_key_type_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ 1: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ true: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ false: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ null: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ []: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
SINGLESTAGE_SUBTEST("wrong key type", R"({ {}: 1, "b": 2 })", assert_error(doc["b"], TAPE_ERROR));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_lookup_miss_unclosed_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": 1, )", assert_error(doc["b"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
// TODO These next two pass the user a value that may run past the end of the buffer if they aren't careful.
|
||||
// In particular, if the padding is decorated with the wrong values, we could cause overrun!
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": 1 )", assert_error(doc["b"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a": )", assert_error(doc["b"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ "a" )", assert_error(doc["b"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
SINGLESTAGE_SUBTEST("unclosed", R"({ )", assert_error(doc["b"], INCOMPLETE_ARRAY_OR_OBJECT));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool object_lookup_miss_next_error() {
|
||||
TEST_START();
|
||||
SINGLESTAGE_SUBTEST("missing comma", R"({ "a": 1 "b": 2 })", ([&]() {
|
||||
auto obj = doc.get_object();
|
||||
return assert_result(obj["a"], int64_t(1)) && assert_error(obj["b"], TAPE_ERROR);
|
||||
})());
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||
bool out_of_order_object_iteration_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 1, "y": 2 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto element : doc) {
|
||||
auto obj = element.get_object();
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
ASSERT_ITERATE_ERROR( obj, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
for (auto element : doc) {
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
ASSERT_ITERATE_ERROR( obj, OUT_OF_ORDER_ITERATION );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_top_level_object_iteration_error() {
|
||||
TEST_START();
|
||||
auto json = R"({ "x": 1, "y": 2 })"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
auto obj = doc.get_object();
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
ASSERT_ITERATE_ERROR( obj, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( doc.get(obj) );
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
ASSERT_ITERATE_ERROR( obj, OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_index_child_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 1, "y": 2 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element.get_object();
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj["x"], OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj["x"], OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element;
|
||||
ASSERT_SUCCESS( obj["x"] );
|
||||
}
|
||||
ASSERT_ERROR( obj["x"], OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
ASSERT_SUCCESS( obj["x"] );
|
||||
}
|
||||
ASSERT_ERROR( obj["x"], OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_index_sibling_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 0, "y": 2 }, { "x": 1, "y": 4 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element.get_object();
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj["x"].get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj["x"].get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( element.get_object().get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj["x"].get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj["x"].get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element;
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj["x"].get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj["x"].get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::value obj;
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj["x"].get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj["x"].get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field_child_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 1, "y": 2 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element.get_object();
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element;
|
||||
ASSERT_SUCCESS( obj.find_field("x") );
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
ASSERT_SUCCESS( obj.find_field("x") );
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field_sibling_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 0, "y": 2 }, { "x": 1, "y": 4 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element.get_object();
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj.find_field("x").get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( element.get_object().get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj.find_field("x").get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element;
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj.find_field("x").get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::value obj;
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj.find_field("x").get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field_unordered_child_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 1, "y": 2 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element.get_object();
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field_unordered("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
for (auto field : obj) { ASSERT_SUCCESS(field); }
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field_unordered("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> obj;
|
||||
for (auto element : doc) {
|
||||
obj = element;
|
||||
ASSERT_SUCCESS( obj.find_field_unordered("x") );
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field_unordered("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value obj;
|
||||
for (auto element : doc) {
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
ASSERT_SUCCESS( obj.find_field_unordered("x") );
|
||||
}
|
||||
ASSERT_ERROR( obj.find_field_unordered("x"), OUT_OF_ORDER_ITERATION );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field_unordered_sibling_error() {
|
||||
TEST_START();
|
||||
auto json = R"([ { "x": 0, "y": 2 }, { "x": 1, "y": 4 } ])"_padded;
|
||||
SUBTEST("simdjson_result<object>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::object> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element.get_object();
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj.find_field_unordered("x").get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field_unordered("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("object", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::object last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( element.get_object().get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj.find_field_unordered("x").get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field_unordered("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("simdjson_result<value>", test_singlestage_doc(json, [&](auto doc) {
|
||||
simdjson_result<singlestage::value> last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
auto obj = element;
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS(obj.find_field_unordered("x").get(x));
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field_unordered("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("value", test_singlestage_doc(json, [&](auto doc) {
|
||||
singlestage::value last_obj;
|
||||
uint64_t i = 0;
|
||||
for (auto element : doc) {
|
||||
singlestage::value obj;
|
||||
ASSERT_SUCCESS( element.get(obj) );
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( obj.find_field_unordered("x").get(x) );
|
||||
ASSERT_EQUAL(x, i);
|
||||
if (i > 0) {
|
||||
ASSERT_ERROR(last_obj.find_field_unordered("x").get(x), OUT_OF_ORDER_ITERATION);
|
||||
break;
|
||||
}
|
||||
last_obj = obj;
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool run() {
|
||||
return
|
||||
object_iterate_error() &&
|
||||
object_iterate_wrong_key_type_error() &&
|
||||
object_iterate_unclosed_error() &&
|
||||
object_lookup_error() &&
|
||||
object_lookup_unclosed_error() &&
|
||||
object_lookup_miss_error() &&
|
||||
object_lookup_miss_unclosed_error() &&
|
||||
object_lookup_miss_wrong_key_type_error() &&
|
||||
object_lookup_miss_next_error() &&
|
||||
#ifdef SIMDJSON_DEVELOPMENT_CHECKS
|
||||
out_of_order_object_iteration_error() &&
|
||||
out_of_order_top_level_object_iteration_error() &&
|
||||
out_of_order_object_index_child_error() &&
|
||||
out_of_order_object_index_sibling_error() &&
|
||||
out_of_order_object_find_field_child_error() &&
|
||||
out_of_order_object_find_field_sibling_error() &&
|
||||
out_of_order_object_find_field_unordered_child_error() &&
|
||||
out_of_order_object_find_field_unordered_sibling_error() &&
|
||||
#endif
|
||||
true;
|
||||
}
|
||||
} // namespace object_error_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, object_error_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace object_tests {
|
||||
using namespace std;
|
||||
using simdjson::singlestage::json_type;
|
||||
|
||||
bool object_find_field_unordered() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc_result.get(object) );
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::object>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::object> object;
|
||||
object = doc_result.get_object();
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_object_find_field_unordered() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( doc.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( doc.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( doc.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( doc_result.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc_result.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc_result.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( doc_result.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( doc_result.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool value_object_find_field_unordered() {
|
||||
TEST_START();
|
||||
auto json = R"({ "outer": { "a": 1, "b": 2, "c/d": 3 } })"_padded;
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::value object;
|
||||
ASSERT_SUCCESS( doc_result.find_field_unordered("outer").get(object) );
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::value> object = doc_result.find_field_unordered("outer");
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field_unordered("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object.find_field_unordered("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object.find_field_unordered("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object_find_field() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc_result.get(object) );
|
||||
|
||||
ASSERT_EQUAL( object.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( object.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( object.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::object>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::object> object;
|
||||
object = doc_result.get_object();
|
||||
|
||||
ASSERT_EQUAL( object.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( object.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( object.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_object_find_field() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( doc.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( doc.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( doc.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( doc_result.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc_result.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc_result.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( doc_result.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( doc_result.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool value_object_find_field() {
|
||||
TEST_START();
|
||||
auto json = R"({ "outer": { "a": 1, "b": 2, "c/d": 3 } })"_padded;
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::value object;
|
||||
ASSERT_SUCCESS( doc_result.find_field("outer").get(object) );
|
||||
ASSERT_EQUAL( object.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( object.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( object.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::value> object = doc_result.find_field("outer");
|
||||
ASSERT_EQUAL( object.find_field("a").get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object.find_field("b").get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object.find_field("c/d").get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_ERROR( object.find_field("a"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( object.find_field("d"), NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
object_find_field_unordered() &&
|
||||
document_object_find_field_unordered() &&
|
||||
value_object_find_field_unordered() &&
|
||||
object_find_field() &&
|
||||
document_object_find_field() &&
|
||||
value_object_find_field() &&
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace object_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, object_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace object_tests {
|
||||
using namespace std;
|
||||
using simdjson::singlestage::json_type;
|
||||
|
||||
bool object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc_result.get(object) );
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::object>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::object> object;
|
||||
object = doc_result.get_object();
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( doc["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( doc["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( doc["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( doc_result["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( doc_result["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( doc_result["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( doc_result["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( doc_result["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool value_object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "outer": { "a": 1, "b": 2, "c/d": 3 } })"_padded;
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::value object;
|
||||
ASSERT_SUCCESS( doc_result["outer"].get(object) );
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::value> object = doc_result["outer"];
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_EQUAL( object["b"].get_uint64().value_unsafe(), 2 );
|
||||
ASSERT_EQUAL( object["c/d"].get_uint64().value_unsafe(), 3 );
|
||||
|
||||
ASSERT_EQUAL( object["a"].get_uint64().value_unsafe(), 1 );
|
||||
ASSERT_ERROR( object["d"], NO_SUCH_FIELD );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool document_nested_object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "x": { "y": { "z": 2 } } }})"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( doc_result["x"]["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( doc["x"]["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool nested_object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "x": { "y": { "z": 2 } } }})"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::object>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::object> object = doc_result.get_object();
|
||||
ASSERT_EQUAL( object["x"]["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc_result.get(object) );
|
||||
ASSERT_EQUAL( object["x"]["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool value_nested_object_index() {
|
||||
TEST_START();
|
||||
auto json = R"({ "x": { "y": { "z": 2 } } }})"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
simdjson_result<singlestage::value> x = doc_result["x"];
|
||||
ASSERT_EQUAL( x["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::value x;
|
||||
ASSERT_SUCCESS( doc_result["x"].get(x) );
|
||||
ASSERT_EQUAL( x["y"]["z"].get_uint64().value_unsafe(), 2 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool object_index_partial_children() {
|
||||
TEST_START();
|
||||
auto json = R"(
|
||||
{
|
||||
"scalar_ignore": 0,
|
||||
"empty_array_ignore": [],
|
||||
"empty_object_ignore": {},
|
||||
"object_break": { "x": 3, "y": 33 },
|
||||
"object_break_unused": { "x": 4, "y": 44 },
|
||||
"object_index": { "x": 5, "y": 55 },
|
||||
"object_index_unused": { "x": 6, "y": 66 },
|
||||
"array_break": [ 7, 77, 777 ],
|
||||
"array_break_unused": [ 8, 88, 888 ],
|
||||
"quadruple_nested_break": { "a": [ { "b": [ 9, 99 ], "c": 999 }, 9999 ], "d": 99999 },
|
||||
"actual_value": 10
|
||||
}
|
||||
)"_padded;
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc_result.get(object) );
|
||||
|
||||
ASSERT_SUCCESS( object["scalar_ignore"] );
|
||||
std::cout << " - After ignoring empty scalar ..." << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( object["empty_array_ignore"] );
|
||||
std::cout << " - After ignoring empty array ..." << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( object["empty_object_ignore"] );
|
||||
std::cout << " - After ignoring empty object ..." << std::endl;
|
||||
|
||||
// Break after using first value in child object
|
||||
{
|
||||
auto value = object["object_break"];
|
||||
for (auto [ child_field, error ] : value.get_object()) {
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(child_field.key(), "x");
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_field.value().get(x) );
|
||||
ASSERT_EQUAL(x, 3);
|
||||
break; // Break after the first value
|
||||
}
|
||||
std::cout << " - After using first value in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break without using first value in child object
|
||||
{
|
||||
auto value = object["object_break_unused"];
|
||||
for (auto [ child_field, error ] : value.get_object()) {
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(child_field.key(), "x");
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Only look up one field in child object
|
||||
{
|
||||
auto value = object["object_index"];
|
||||
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( value["x"].get(x) );
|
||||
ASSERT_EQUAL( x, 5 );
|
||||
std::cout << " - After looking up one field in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Only look up one field in child object, but don't use it
|
||||
{
|
||||
auto value = object["object_index_unused"];
|
||||
|
||||
ASSERT_SUCCESS( value["x"] );
|
||||
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break after first value in child array
|
||||
{
|
||||
auto value = object["array_break"];
|
||||
|
||||
for (auto child_value : value) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_value.get(x) );
|
||||
ASSERT_EQUAL( x, 7 );
|
||||
break;
|
||||
}
|
||||
std::cout << " - After using first value in child array ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break without using first value in child array
|
||||
{
|
||||
auto value = object["array_break_unused"];
|
||||
|
||||
for (auto child_value : value) {
|
||||
ASSERT_SUCCESS(child_value);
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break out of multiple child loops
|
||||
{
|
||||
auto value = object["quadruple_nested_break"];
|
||||
for (auto child1 : value.get_object()) {
|
||||
for (auto child2 : child1.value().get_array()) {
|
||||
for (auto child3 : child2.get_object()) {
|
||||
for (auto child4 : child3.value().get_array()) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child4.get(x) );
|
||||
ASSERT_EQUAL( x, 9 );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
|
||||
}
|
||||
|
||||
// Test the actual value
|
||||
{
|
||||
auto value = object["actual_value"];
|
||||
uint64_t actual_value;
|
||||
ASSERT_SUCCESS( value.get(actual_value) );
|
||||
ASSERT_EQUAL( actual_value, 10 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_SUCCESS( doc_result["scalar_ignore"] );
|
||||
std::cout << " - After ignoring empty scalar ..." << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( doc_result["empty_array_ignore"] );
|
||||
std::cout << " - After ignoring empty array ..." << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( doc_result["empty_object_ignore"] );
|
||||
std::cout << " - After ignoring empty doc_result ..." << std::endl;
|
||||
|
||||
// Break after using first value in child object
|
||||
{
|
||||
auto value = doc_result["object_break"];
|
||||
for (auto [ child_field, error ] : value.get_object()) {
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(child_field.key(), "x");
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_field.value().get(x) );
|
||||
ASSERT_EQUAL(x, 3);
|
||||
break; // Break after the first value
|
||||
}
|
||||
std::cout << " - After using first value in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break without using first value in child object
|
||||
{
|
||||
auto value = doc_result["object_break_unused"];
|
||||
for (auto [ child_field, error ] : value.get_object()) {
|
||||
ASSERT_SUCCESS(error);
|
||||
ASSERT_EQUAL(child_field.key(), "x");
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Only look up one field in child object
|
||||
{
|
||||
auto value = doc_result["object_index"];
|
||||
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( value["x"].get(x) );
|
||||
ASSERT_EQUAL( x, 5 );
|
||||
std::cout << " - After looking up one field in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Only look up one field in child object, but don't use it
|
||||
{
|
||||
auto value = doc_result["object_index_unused"];
|
||||
|
||||
ASSERT_SUCCESS( value["x"] );
|
||||
std::cout << " - After looking up (but not using) one field in child object ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break after first value in child array
|
||||
{
|
||||
auto value = doc_result["array_break"];
|
||||
|
||||
for (auto child_value : value) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child_value.get(x) );
|
||||
ASSERT_EQUAL( x, 7 );
|
||||
break;
|
||||
}
|
||||
std::cout << " - After using first value in child array ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break without using first value in child array
|
||||
{
|
||||
auto value = doc_result["array_break_unused"];
|
||||
|
||||
for (auto child_value : value) {
|
||||
ASSERT_SUCCESS(child_value);
|
||||
break;
|
||||
}
|
||||
std::cout << " - After reaching (but not using) first value in child array ..." << std::endl;
|
||||
}
|
||||
|
||||
// Break out of multiple child loops
|
||||
{
|
||||
auto value = doc_result["quadruple_nested_break"];
|
||||
for (auto child1 : value.get_object()) {
|
||||
for (auto child2 : child1.value().get_array()) {
|
||||
for (auto child3 : child2.get_object()) {
|
||||
for (auto child4 : child3.value().get_array()) {
|
||||
uint64_t x;
|
||||
ASSERT_SUCCESS( child4.get(x) );
|
||||
ASSERT_EQUAL( x, 9 );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::cout << " - After breaking out of quadruply-nested arrays and objects ..." << std::endl;
|
||||
}
|
||||
|
||||
// Test the actual value
|
||||
{
|
||||
auto value = doc_result["actual_value"];
|
||||
uint64_t actual_value;
|
||||
ASSERT_SUCCESS( value.get(actual_value) );
|
||||
ASSERT_EQUAL( actual_value, 10 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool object_index_exception() {
|
||||
TEST_START();
|
||||
auto json = R"({ "a": 1, "b": 2, "c/d": 3})"_padded;
|
||||
SUBTEST("singlestage::object", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::object object = doc_result;
|
||||
|
||||
ASSERT_EQUAL( uint64_t(object["a"]), 1 );
|
||||
ASSERT_EQUAL( uint64_t(object["b"]), 2 );
|
||||
ASSERT_EQUAL( uint64_t(object["c/d"]), 3 );
|
||||
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool nested_object_index_exception() {
|
||||
TEST_START();
|
||||
auto json = R"({ "x": { "y": { "z": 2 } } }})"_padded;
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
ASSERT_EQUAL( uint64_t(doc_result["x"]["y"]["z"]), 2 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
object_index() &&
|
||||
document_object_index() &&
|
||||
value_object_index() &&
|
||||
nested_object_index() &&
|
||||
document_nested_object_index() &&
|
||||
value_nested_object_index() &&
|
||||
object_index_partial_children() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
object_index_exception() &&
|
||||
nested_object_index_exception() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace object_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, object_tests::run);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace ordering_tests {
|
||||
using namespace std;
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
auto json = "{\"coordinates\":[{\"x\":1.1,\"y\":2.2,\"z\":3.3}]}"_padded;
|
||||
|
||||
bool in_order_object_index() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
x += double(point_object["x"]);
|
||||
y += double(point_object["y"]);
|
||||
z += double(point_object["z"]);
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool in_order_object_find_field_unordered() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
x += double(point_object.find_field_unordered("x"));
|
||||
y += double(point_object.find_field_unordered("y"));
|
||||
z += double(point_object.find_field_unordered("z"));
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool in_order_object_find_field() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
x += double(point_object.find_field("x"));
|
||||
y += double(point_object.find_field("y"));
|
||||
z += double(point_object.find_field("z"));
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool out_of_order_object_index() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
z += double(point_object["z"]);
|
||||
x += double(point_object["x"]);
|
||||
y += double(point_object["y"]);
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field_unordered() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
z += double(point_object.find_field_unordered("z"));
|
||||
x += double(point_object.find_field_unordered("x"));
|
||||
y += double(point_object.find_field_unordered("y"));
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool out_of_order_object_find_field() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (singlestage::object point_object : doc["coordinates"]) {
|
||||
z += double(point_object.find_field("z"));
|
||||
ASSERT_ERROR( point_object.find_field("x"), NO_SUCH_FIELD );
|
||||
ASSERT_ERROR( point_object.find_field("y"), NO_SUCH_FIELD );
|
||||
}
|
||||
return (x == 0) && (y == 0) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool foreach_object_field_lookup() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
double x{0};
|
||||
double y{0};
|
||||
double z{0};
|
||||
for (auto point_object : doc["coordinates"]) {
|
||||
for (auto field : point_object.get_object()) {
|
||||
if (field.key() == "z") { z += double(field.value()); }
|
||||
else if (field.key() == "x") { x += double(field.value()); }
|
||||
else if (field.key() == "y") { y += double(field.value()); }
|
||||
}
|
||||
}
|
||||
return (x == 1.1) && (y == 2.2) && (z == 3.3);
|
||||
}
|
||||
|
||||
bool use_values_out_of_order_after_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto doc = parser.iterate(json);
|
||||
simdjson_result<singlestage::value> x{}, y{}, z{};
|
||||
for (auto point_object : doc["coordinates"]) {
|
||||
x = point_object["x"];
|
||||
y = point_object["y"];
|
||||
z = point_object["z"];
|
||||
}
|
||||
return (double(x) == 1.1) && (double(z) == 3.3) && (double(y) == 2.2);
|
||||
}
|
||||
|
||||
bool use_object_multiple_times_out_of_order() {
|
||||
TEST_START();
|
||||
singlestage::parser parser{};
|
||||
auto json2 = "{\"coordinates\":{\"x\":1.1,\"y\":2.2,\"z\":3.3}}"_padded;
|
||||
auto doc = parser.iterate(json2);
|
||||
auto x = doc["coordinates"]["x"];
|
||||
auto y = doc["coordinates"]["y"];
|
||||
auto z = doc["coordinates"]["z"];
|
||||
return (double(x) == 1.1) && (double(z) == 3.3) && (double(y) == 2.2);
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
in_order_object_index() &&
|
||||
in_order_object_find_field_unordered() &&
|
||||
in_order_object_find_field() &&
|
||||
out_of_order_object_index() &&
|
||||
out_of_order_object_find_field_unordered() &&
|
||||
out_of_order_object_find_field() &&
|
||||
foreach_object_field_lookup() &&
|
||||
use_values_out_of_order_after_array() &&
|
||||
use_object_multiple_times_out_of_order() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace ordering_tests
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, ordering_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace parse_api_tests {
|
||||
using namespace std;
|
||||
|
||||
const padded_string BASIC_JSON = "[1,2,3]"_padded;
|
||||
const padded_string BASIC_NDJSON = "[1,2,3]\n[4,5,6]"_padded;
|
||||
const padded_string EMPTY_NDJSON = ""_padded;
|
||||
|
||||
|
||||
bool parser_iterate_empty() {
|
||||
TEST_START();
|
||||
FILE *p;
|
||||
// Of course, we could just call iterate on the empty string, but
|
||||
// we want to test the whole process.
|
||||
const char *const tmpfilename = "emptysinglestage.txt";
|
||||
if((p = fopen(tmpfilename, "w")) != nullptr) {
|
||||
fclose(p);
|
||||
auto json = padded_string::load(tmpfilename);
|
||||
singlestage::document doc;
|
||||
singlestage::parser parser;
|
||||
auto error = parser.iterate(json).get(doc);
|
||||
remove(tmpfilename);
|
||||
if(error != simdjson::EMPTY) {
|
||||
std::cerr << "Was expecting empty but got " << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::cout << "Warning: I could not create temporary file " << tmpfilename << std::endl;
|
||||
std::cout << "We omit testing the empty file case." << std::endl;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_iterate() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(BASIC_JSON);
|
||||
ASSERT_SUCCESS( doc.get_array() );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parser_iterate_padded() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const char json_str[] = "12\0 ";// 64 bytes of padding
|
||||
ASSERT_EQUAL(sizeof(json_str), 66);
|
||||
ASSERT_EQUAL(strlen(json_str), 2);
|
||||
|
||||
{
|
||||
cout << "- char*" << endl;
|
||||
auto doc = parser.iterate(json_str, strlen(json_str), sizeof(json_str));
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- uint8_t*" << endl;
|
||||
const uint8_t* json = reinterpret_cast<const uint8_t*>(json_str);
|
||||
auto doc = parser.iterate(json, strlen(json_str), sizeof(json_str));
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- string_view" << endl;
|
||||
std::string_view json(json_str);
|
||||
auto doc = parser.iterate(json, sizeof(json_str));
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- string" << endl;
|
||||
std::string json = "12";
|
||||
json.reserve(json.length() + SIMDJSON_PADDING);
|
||||
auto doc = parser.iterate(json);
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_iterate_padded_string_view() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
const char json_str[] = "12\0 "; // 64 bytes of padding
|
||||
ASSERT_EQUAL(sizeof(json_str), 66);
|
||||
ASSERT_EQUAL(strlen(json_str), 2);
|
||||
|
||||
{
|
||||
cout << "- padded_string_view(string_view)" << endl;
|
||||
padded_string_view json(std::string_view(json_str), sizeof(json_str));
|
||||
auto doc = parser.iterate(json);
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- padded_string_view(char*)" << endl;
|
||||
auto doc = parser.iterate(padded_string_view(json_str, strlen(json_str), sizeof(json_str)));
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- padded_string_view(string)" << endl;
|
||||
std::string json = "12";
|
||||
json.reserve(json.length() + SIMDJSON_PADDING);
|
||||
auto doc = parser.iterate(padded_string_view(json));
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
{
|
||||
cout << "- padded_string_view(string_view(char*))" << endl;
|
||||
padded_string_view json(json_str, sizeof(json_str));
|
||||
auto doc = parser.iterate(json);
|
||||
ASSERT_SUCCESS( doc.get_double() );
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_iterate_insufficient_padding() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
constexpr char json_str[] = "12\0 "; // 63 bytes of padding
|
||||
ASSERT_EQUAL(sizeof(json_str), 65);
|
||||
ASSERT_EQUAL(strlen(json_str), 2);
|
||||
ASSERT_EQUAL(padded_string_view(json_str, strlen(json_str), sizeof(json_str)).padding(), 63);
|
||||
ASSERT_EQUAL(SIMDJSON_PADDING, 64);
|
||||
|
||||
{
|
||||
cout << "- char*, 63 padding" << endl;
|
||||
ASSERT_ERROR( parser.iterate(json_str, strlen(json_str), sizeof(json_str)), INSUFFICIENT_PADDING );
|
||||
cout << "- char*, 0 padding" << endl;
|
||||
ASSERT_ERROR( parser.iterate(json_str, strlen(json_str), strlen(json_str)), INSUFFICIENT_PADDING );
|
||||
}
|
||||
|
||||
{
|
||||
std::string_view json(json_str);
|
||||
cout << "- string_view, 63 padding" << endl;
|
||||
ASSERT_ERROR( parser.iterate(json, sizeof(json_str)), INSUFFICIENT_PADDING );
|
||||
cout << "- string_view, 0 padding" << endl;
|
||||
ASSERT_ERROR( parser.iterate(json, strlen(json_str)), INSUFFICIENT_PADDING );
|
||||
}
|
||||
|
||||
{
|
||||
std::string json = "12";
|
||||
json.shrink_to_fit();
|
||||
cout << "- string, 0 padding" << endl;
|
||||
ASSERT_ERROR( parser.iterate(json), INSUFFICIENT_PADDING );
|
||||
// It's actually kind of hard to allocate "just enough" capacity, since the string tends
|
||||
// to grow more than you tell it to.
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool parser_iterate_exception() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(BASIC_JSON);
|
||||
simdjson_unused singlestage::array array = doc;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool parser_document_reuse() {
|
||||
TEST_START();
|
||||
singlestage::document doc;
|
||||
// A document spans about 40 bytes. Nevertheless, some users
|
||||
// would rather reuse them.
|
||||
std::cout << sizeof(doc) << std::endl;
|
||||
auto json = R"({"key": "value"})"_padded;
|
||||
auto jsonbad = R"({"key": "value")"_padded; // deliberaty broken
|
||||
auto jsonunclosedstring = "{\"coordinates:[{\"x\":1.1,\"y\":2.2,\"z\":3.3}]}"_padded;
|
||||
std::string_view output;
|
||||
|
||||
singlestage::parser parser;
|
||||
std::cout << "correct document (1)" << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
|
||||
ASSERT_SUCCESS(simdjson::to_json_string(doc).get(output));
|
||||
std::cout << output << std::endl;
|
||||
|
||||
std::cout << "correct document (2)" << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
for(singlestage::field field : doc.get_object() ) {
|
||||
std::cout << "field: " << field.key() << std::endl;
|
||||
}
|
||||
std::cout << "unclosed string document " << std::endl;
|
||||
simdjson::error_code error;
|
||||
if((error = parser.iterate(jsonunclosedstring).get(doc)) == SUCCESS) {
|
||||
// fallback kernel:
|
||||
ASSERT_EQUAL( doc.get_object().find_field("coordinates").error(), TAPE_ERROR );
|
||||
} else {
|
||||
// regular kernels:
|
||||
ASSERT_EQUAL( error, UNCLOSED_STRING );
|
||||
}
|
||||
|
||||
std::cout << "truncated document " << std::endl;
|
||||
ASSERT_SUCCESS( parser.iterate(jsonbad).get(doc) );
|
||||
ASSERT_EQUAL( simdjson::to_json_string(doc).get(output), TAPE_ERROR );
|
||||
|
||||
std::cout << "correct document with new doc" << std::endl;
|
||||
singlestage::document doc2;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc2) );
|
||||
for(singlestage::field field : doc2.get_object() ) {
|
||||
std::cout << "field: " << field.key() << std::endl;
|
||||
}
|
||||
std::cout << "correct document (3): " << doc.to_debug_string() << std::endl;
|
||||
|
||||
std::cout << "correct document (3)" << std::endl;
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
std::cout << doc.to_debug_string() << std::endl;
|
||||
for(singlestage::field field : doc.get_object() ) {
|
||||
std::cout << "field: " << field.key() << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "unclosed string document " << std::endl;
|
||||
ASSERT_SUCCESS( parser.iterate(jsonbad).get(doc) );
|
||||
ASSERT_EQUAL( simdjson::to_json_string(doc).get(output), TAPE_ERROR );
|
||||
|
||||
// next two lines are terrible code.
|
||||
doc.~document();
|
||||
doc = singlestage::document();
|
||||
//
|
||||
|
||||
std::cout << "correct document (4)" << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(output) );
|
||||
std::cout << output << std::endl;
|
||||
|
||||
std::cout << "unclosed string document " << std::endl;
|
||||
|
||||
if((error = parser.iterate(jsonunclosedstring).get(doc)) == SUCCESS) {
|
||||
// fallback kernel:
|
||||
ASSERT_EQUAL( doc.get_object().find_field("coordinates").error(), TAPE_ERROR );
|
||||
} else {
|
||||
// regular kernels:
|
||||
ASSERT_EQUAL( error, UNCLOSED_STRING );
|
||||
}
|
||||
|
||||
|
||||
// next two lines are terrible code.
|
||||
doc.~document();
|
||||
doc = singlestage::document();
|
||||
//
|
||||
std::cout << "correct document (5)" << std::endl;
|
||||
|
||||
ASSERT_SUCCESS( parser.iterate(json).get(doc) );
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(output) );
|
||||
std::cout << output << std::endl;
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return parser_iterate_empty() &&
|
||||
parser_iterate() &&
|
||||
parser_iterate_padded() &&
|
||||
parser_iterate_padded_string_view() &&
|
||||
parser_iterate_insufficient_padding() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
parser_document_reuse() &&
|
||||
parser_iterate_exception() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, parse_api_tests::run);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace scalar_tests {
|
||||
using namespace std;
|
||||
using simdjson::singlestage::json_type;
|
||||
|
||||
template<typename T> json_type expected_json_type();
|
||||
template<> json_type expected_json_type<std::string_view>() { return json_type::string; }
|
||||
template<> json_type expected_json_type<double>() { return json_type::number; }
|
||||
template<> json_type expected_json_type<uint64_t>() { return json_type::number; }
|
||||
template<> json_type expected_json_type<int64_t>() { return json_type::number; }
|
||||
template<> json_type expected_json_type<bool>() { return json_type::boolean; }
|
||||
|
||||
template<typename T>
|
||||
bool test_scalar_value(const padded_string &json, const T &expected, bool test_twice=true) {
|
||||
std::cout << "- JSON: " << json << endl;
|
||||
SUBTEST( "simdjson_result<document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
T actual{};
|
||||
ASSERT_RESULT( doc_result.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( doc_result.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( doc_result.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
ASSERT_RESULT( doc_result.type(), expected_json_type<T>() );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST( "document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
T actual{};
|
||||
ASSERT_RESULT( doc.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( doc.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( doc.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
ASSERT_RESULT( doc.type(), expected_json_type<T>() );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
{
|
||||
padded_string whitespace_json = std::string(json) + " ";
|
||||
std::cout << "- JSON: " << whitespace_json << endl;
|
||||
SUBTEST( "simdjson_result<document>", test_singlestage_doc(whitespace_json, [&](auto doc_result) {
|
||||
T actual{};
|
||||
ASSERT_RESULT( doc_result.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( doc_result.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( doc_result.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
ASSERT_RESULT( doc_result.type(), expected_json_type<T>() );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
SUBTEST( "document", test_singlestage_doc(whitespace_json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
T actual{};
|
||||
ASSERT_RESULT( doc.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( doc.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( doc.get(actual) );
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
ASSERT_RESULT( doc.type(), expected_json_type<T>() );
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
padded_string array_json = std::string("[") + std::string(json) + "]";
|
||||
std::cout << "- JSON: " << array_json << endl;
|
||||
SUBTEST( "simdjson_result<value>", test_singlestage_doc(array_json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (simdjson_result<singlestage::value> val_result : doc_result) {
|
||||
T actual{};
|
||||
ASSERT_RESULT( val_result.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( val_result.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( val_result.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
ASSERT_RESULT( val_result.type(), expected_json_type<T>() );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
return true;
|
||||
}));
|
||||
SUBTEST( "value", test_singlestage_doc(array_json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (simdjson_result<singlestage::value> val_result : doc_result) {
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS( val_result.get(val) );
|
||||
T actual{};
|
||||
ASSERT_RESULT( val.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( val.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( val.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
ASSERT_RESULT( val.type(), expected_json_type<T>() );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
padded_string whitespace_array_json = std::string("[") + std::string(json) + " ]";
|
||||
std::cout << "- JSON: " << whitespace_array_json << endl;
|
||||
|
||||
SUBTEST( "simdjson_result<value>", test_singlestage_doc(whitespace_array_json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (simdjson_result<singlestage::value> val_result : doc_result) {
|
||||
T actual{};
|
||||
ASSERT_RESULT( val_result.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( val_result.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( val_result.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
ASSERT_RESULT( val_result.type(), expected_json_type<T>() );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
return true;
|
||||
}));
|
||||
|
||||
SUBTEST( "value", test_singlestage_doc(whitespace_array_json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (simdjson_result<singlestage::value> val_result : doc_result) {
|
||||
singlestage::value val;
|
||||
ASSERT_SUCCESS( val_result.get(val) );
|
||||
T actual{};
|
||||
ASSERT_RESULT( val.type(), expected_json_type<T>() );
|
||||
ASSERT_SUCCESS( val.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
// Test it twice (scalars can be retrieved more than once)
|
||||
if (test_twice) {
|
||||
ASSERT_SUCCESS( val.get(actual) );
|
||||
ASSERT_EQUAL(actual, expected);
|
||||
ASSERT_RESULT( val_result.type(), expected_json_type<T>() );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool string_value() {
|
||||
TEST_START();
|
||||
// We can't retrieve a small string twice because it will blow out the string buffer
|
||||
if (!test_scalar_value(R"("hi")"_padded, std::string_view("hi"), false)) { return false; }
|
||||
// ... unless the document is big enough to have a big string buffer :)
|
||||
if (!test_scalar_value(R"("hi" )"_padded, std::string_view("hi"))) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool numeric_values() {
|
||||
TEST_START();
|
||||
if (!test_scalar_value<int64_t> ("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value<uint64_t>("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value<double> ("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value<int64_t> ("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value<uint64_t>("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value<double> ("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value<int64_t> ("-1"_padded, -1)) { return false; }
|
||||
if (!test_scalar_value<double> ("-1"_padded, -1)) { return false; }
|
||||
if (!test_scalar_value<double> ("1.1"_padded, 1.1)) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool boolean_values() {
|
||||
TEST_START();
|
||||
if (!test_scalar_value<bool> ("true"_padded, true)) { return false; }
|
||||
if (!test_scalar_value<bool> ("false"_padded, false)) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool null_value() {
|
||||
TEST_START();
|
||||
auto json = "null"_padded;
|
||||
SUBTEST("singlestage::document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( doc.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::document>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( doc_result.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
return true;
|
||||
}));
|
||||
json = "[null]"_padded;
|
||||
SUBTEST("singlestage::value", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (auto value_result : doc_result) {
|
||||
singlestage::value value;
|
||||
ASSERT_SUCCESS( value_result.get(value) );
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( value.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL( count, 1 );
|
||||
return true;
|
||||
}));
|
||||
SUBTEST("simdjson_result<singlestage::value>", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (auto value_result : doc_result) {
|
||||
bool is_null_value;
|
||||
ASSERT_SUCCESS( value_result.is_null().get(is_null_value) );
|
||||
ASSERT_EQUAL( is_null_value, true );
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL( count, 1 );
|
||||
return true;
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
template<typename T>
|
||||
bool test_scalar_value_exception(const padded_string &json, const T &expected) {
|
||||
std::cout << "- JSON: " << json << endl;
|
||||
SUBTEST( "document", test_singlestage_doc(json, [&](auto doc_result) {
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( std::move(doc_result).get(doc) );
|
||||
ASSERT_EQUAL( expected, T(doc) );
|
||||
return true;
|
||||
}));
|
||||
padded_string array_json = std::string("[") + std::string(json) + "]";
|
||||
std::cout << "- JSON: " << array_json << endl;
|
||||
SUBTEST( "value", test_singlestage_doc(array_json, [&](auto doc_result) {
|
||||
int count = 0;
|
||||
for (T actual : doc_result) {
|
||||
ASSERT_EQUAL( actual, expected );
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQUAL(count, 1);
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool string_value_exception() {
|
||||
TEST_START();
|
||||
return test_scalar_value_exception(R"("hi")"_padded, std::string_view("hi"));
|
||||
}
|
||||
|
||||
bool numeric_values_exception() {
|
||||
TEST_START();
|
||||
if (!test_scalar_value_exception<int64_t> ("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value_exception<uint64_t>("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value_exception<double> ("0"_padded, 0)) { return false; }
|
||||
if (!test_scalar_value_exception<int64_t> ("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value_exception<uint64_t>("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value_exception<double> ("1"_padded, 1)) { return false; }
|
||||
if (!test_scalar_value_exception<int64_t> ("-1"_padded, -1)) { return false; }
|
||||
if (!test_scalar_value_exception<double> ("-1"_padded, -1)) { return false; }
|
||||
if (!test_scalar_value_exception<double> ("1.1"_padded, 1.1)) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool boolean_values_exception() {
|
||||
TEST_START();
|
||||
if (!test_scalar_value_exception<bool> ("true"_padded, true)) { return false; }
|
||||
if (!test_scalar_value_exception<bool> ("false"_padded, false)) { return false; }
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool string_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( "a string" badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
std::string_view view;
|
||||
ASSERT_ERROR(doc.get_string().get(view), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool uint64_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
uint64_t x;
|
||||
ASSERT_ERROR(doc.get_uint64().get(x), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool int64_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
int64_t x;
|
||||
ASSERT_ERROR(doc.get_int64().get(x), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool double_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( 133 badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
double x;
|
||||
ASSERT_ERROR(doc.get_double().get(x), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool bool_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( true badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
bool x;
|
||||
ASSERT_ERROR(doc.get_bool().get(x), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool null_with_trailing() {
|
||||
TEST_START();
|
||||
auto json = R"( null badstuff )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
ASSERT_ERROR(doc.is_null(), TRAILING_CONTENT);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool nully() {
|
||||
TEST_START();
|
||||
auto json = R"( nully )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS(parser.iterate(json).get(doc));
|
||||
bool x;
|
||||
ASSERT_SUCCESS(doc.is_null().get(x));
|
||||
ASSERT_TRUE(!x);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
nully() &&
|
||||
string_with_trailing() &&
|
||||
uint64_with_trailing() &&
|
||||
int64_with_trailing() &&
|
||||
bool_with_trailing() &&
|
||||
null_with_trailing() &&
|
||||
string_value() &&
|
||||
numeric_values() &&
|
||||
boolean_values() &&
|
||||
null_value() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
string_value_exception() &&
|
||||
numeric_values_exception() &&
|
||||
boolean_values_exception() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace scalar_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, scalar_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "simdjson.h"
|
||||
|
||||
|
||||
/**
|
||||
* What follows is merely a compilation test to verify
|
||||
* https://github.com/simdjson/simdjson/issues/1768
|
||||
* It deliberately resides before any namespace declaration
|
||||
* within this file.
|
||||
*/
|
||||
namespace issue1768 {
|
||||
template <typename T> void print(const T &a) { std::cout << a; }
|
||||
} // namespace NA
|
||||
|
||||
void issue1768_test() {
|
||||
simdjson::singlestage::object obj;
|
||||
issue1768::print(obj);
|
||||
}
|
||||
/**
|
||||
* End of 1768 compilation check.
|
||||
*/
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
#include "test_singlestage.h"
|
||||
namespace tostring_tests {
|
||||
const char *test_files[] = {
|
||||
TWITTER_JSON, TWITTER_TIMELINE_JSON, REPEAT_JSON, CANADA_JSON,
|
||||
MESH_JSON, APACHE_JSON, GSOC_JSON};
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool issue1607() {
|
||||
TEST_START();
|
||||
auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
singlestage::parser parser;
|
||||
singlestage::document doc = parser.iterate(silly_json);
|
||||
std::string_view expected = R"("result")";
|
||||
std::string_view result = simdjson::to_json_string(doc["test"]);
|
||||
std::cout << "'"<< result << "'" << std::endl;
|
||||
ASSERT_EQUAL(result, expected);
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool minify_demo() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(silly_json).get(doc) );
|
||||
std::cout << simdjson::to_json_string(doc["test"]) << std::endl;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool minify_demo2() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(silly_json).get(doc) );
|
||||
std::cout << std::string_view(doc["test"]) << std::endl;
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
bool car_example() {
|
||||
TEST_START();
|
||||
auto cars_json = R"( [
|
||||
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
|
||||
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
|
||||
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
|
||||
] )"_padded;
|
||||
std::vector<std::string_view> arrays;
|
||||
// We are going to collect string_view instances which point inside the `cars_json` string
|
||||
// and are therefore valid as long as `cars_json` remains in scope.
|
||||
{
|
||||
singlestage::parser parser;
|
||||
for (singlestage::object car : parser.iterate(cars_json)) {
|
||||
if(uint64_t(car["year"]) > 2000) { // Pick the recent cars only!
|
||||
arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We can now convert to a JSON string:
|
||||
std::ostringstream oss;
|
||||
oss << "[";
|
||||
for(size_t i = 0; i < arrays.size(); i++) {
|
||||
if(i>0) { oss << ","; }
|
||||
oss << arrays[i];
|
||||
}
|
||||
oss << "]";
|
||||
auto json_string = oss.str();
|
||||
ASSERT_EQUAL(json_string, "[[ 40.1, 39.9, 37.7, 40.4 ],[ 30.1, 31.0, 28.6, 28.7 ]]");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The general idea of these tests if that if you take a JSON file,
|
||||
* load it, then convert it into a string, then parse that, and
|
||||
* convert it again into a second string, then the two strings should
|
||||
* be identifical. If not, then something was lost or added in the
|
||||
* process.
|
||||
*/
|
||||
|
||||
bool load_to_string(const char *filename) {
|
||||
simdjson::singlestage::parser parser;
|
||||
std::cout << "Loading " << filename << std::endl;
|
||||
simdjson::padded_string docdata;
|
||||
auto error = simdjson::padded_string::load(filename).get(docdata);
|
||||
if (error) {
|
||||
std::cerr << "could not load " << filename << " got " << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "file loaded: " << docdata.size() << " bytes." << std::endl;
|
||||
simdjson::singlestage::document doc;
|
||||
auto silly_json = R"( { "test": "result" } )"_padded;
|
||||
|
||||
error = parser.iterate(silly_json).get(doc);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "serializing once." << std::endl;
|
||||
std::string_view serial1 = simdjson::to_json_string(doc);
|
||||
error = parser.iterate(serial1, serial1.size() + simdjson::SIMDJSON_PADDING).get(doc);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "serializing twice." << std::endl;
|
||||
std::string_view serial2 = simdjson::to_json_string(doc);
|
||||
bool match = (serial1 == serial2);
|
||||
if (match) {
|
||||
std::cout << "Parsing to_string and calling to_string again results in the "
|
||||
"same content. "
|
||||
<< "Got " << serial1.size() << " bytes." << std::endl;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
bool minify_test() {
|
||||
TEST_START();
|
||||
for (size_t i = 0; i < sizeof(test_files) / sizeof(test_files[0]); i++) {
|
||||
bool ok = load_to_string(test_files[i]);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool load_to_string_exceptionless(const char *filename) {
|
||||
simdjson::singlestage::parser parser;
|
||||
std::cout << "Loading " << filename << std::endl;
|
||||
simdjson::padded_string docdata;
|
||||
auto error = simdjson::padded_string::load(filename).get(docdata);
|
||||
if (error) {
|
||||
std::cerr << "could not load " << filename << " got " << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "file loaded: " << docdata.size() << " bytes." << std::endl;
|
||||
simdjson::singlestage::document doc;
|
||||
error = parser.iterate(docdata).get(doc);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "serializing once." << std::endl;
|
||||
std::string_view serial1;
|
||||
error = simdjson::to_json_string(doc).get(serial1);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
error = parser.iterate(serial1, serial1.size() + simdjson::SIMDJSON_PADDING).get(doc);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "serializing twice." << std::endl;
|
||||
std::string_view serial2;
|
||||
error = simdjson::to_json_string(doc).get(serial2);
|
||||
if (error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
bool match = (serial1 == serial2);
|
||||
if (match) {
|
||||
std::cout << "Parsing to_string and calling to_string again results in the "
|
||||
"same content. "
|
||||
<< "Got " << serial1.size() << " bytes." << std::endl;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
bool minify_exceptionless_test() {
|
||||
TEST_START();
|
||||
for (size_t i = 0; i < sizeof(test_files) / sizeof(test_files[0]); i++) {
|
||||
bool ok = load_to_string_exceptionless(test_files[i]);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"({})"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc));
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({})");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool empty_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"([])"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc));
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"([])");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool single_digit_document() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"(9)"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"(9)");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool single_string_document() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"("")"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"("")");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool at_start_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( [111,2,3,5] )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( doc.get_array().get(array) );
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
|
||||
ASSERT_EQUAL(serial, "[111,2,3,5]");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool at_start_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc.get_object().get(object) );
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool in_middle_array() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( [111,{"a":1},3,5] )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( doc.get_array().get(array) );
|
||||
auto i = array.begin();
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS( (*i).get_int64().get(x) );
|
||||
ASSERT_EQUAL(x, 111);
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
|
||||
ASSERT_EQUAL(serial, "[111,{\"a\":1},3,5]");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, "[111,{\"a\":1},3,5]");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool at_middle_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc.get_object().get(object) );
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS(object["b"].get_int64().get(x));
|
||||
ASSERT_EQUAL(x,2);
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool at_middle_object_just_key() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc.get_object().get(object) );
|
||||
singlestage::value x;
|
||||
ASSERT_SUCCESS(object["b"].get(x));
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
bool at_end_object() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( {"a":1, "b":2, "c": 3 } )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( doc.get_object().get(object) );
|
||||
int64_t x;
|
||||
ASSERT_ERROR(object["bcc"].get_int64().get(x), NO_SUCH_FIELD);
|
||||
std::string_view serial;
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"a":1, "b":2, "c": 3 })");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool at_array_end() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
std::string_view serial;
|
||||
auto arr_json = R"( [111,2,3,5] )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( doc.get_array().get(array) );
|
||||
auto i = array.begin();
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS( (*i).get_int64().get(x) );
|
||||
ASSERT_EQUAL(x, 111);
|
||||
++i;
|
||||
ASSERT_SUCCESS( (*i).get_int64().get(x) );
|
||||
ASSERT_EQUAL(x, 2);
|
||||
++i;
|
||||
ASSERT_SUCCESS( (*i).get_int64().get(x) );
|
||||
ASSERT_EQUAL(x, 3);
|
||||
++i;
|
||||
ASSERT_SUCCESS( (*i).get_int64().get(x) );
|
||||
ASSERT_EQUAL(x, 5);
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
|
||||
ASSERT_EQUAL(serial, "[111,2,3,5]");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, "[111,2,3,5]");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool complex_case() {
|
||||
TEST_START();
|
||||
singlestage::parser parser;
|
||||
auto arr_json = R"( {"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]} )"_padded;
|
||||
singlestage::document doc;
|
||||
ASSERT_SUCCESS( parser.iterate(arr_json).get(doc) );
|
||||
singlestage::object obj;
|
||||
ASSERT_SUCCESS( doc.get_object().get(obj) );
|
||||
singlestage::array array;
|
||||
ASSERT_SUCCESS( obj["objects"].get_array().get(array) );
|
||||
std::string_view serial;
|
||||
for(auto v : array) {
|
||||
singlestage::object object;
|
||||
ASSERT_SUCCESS( v.get_object().get(object) );
|
||||
int64_t x;
|
||||
ASSERT_SUCCESS(object["id"].get_int64().get(x));
|
||||
if(x / 2 * 2 != x) {
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(object).get(serial));
|
||||
ASSERT_EQUAL(serial, "{\"id\":"+std::to_string(x)+"}");
|
||||
}
|
||||
}
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(array).get(serial));
|
||||
ASSERT_EQUAL(serial, R"([{"id":1}, {"id":2}, {"id":3}])");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(obj).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]})");
|
||||
ASSERT_SUCCESS( simdjson::to_json_string(doc).get(serial));
|
||||
ASSERT_EQUAL(serial, R"({"array":[1,2,3], "objects":[{"id":1}, {"id":2}, {"id":3}]})");
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool run() {
|
||||
return
|
||||
empty_object() &&
|
||||
empty_array() &&
|
||||
single_digit_document() &&
|
||||
single_string_document() &&
|
||||
complex_case() &&
|
||||
at_start_object() &&
|
||||
at_middle_object() &&
|
||||
at_middle_object_just_key() &&
|
||||
at_end_object() &&
|
||||
at_start_array() &&
|
||||
in_middle_array() &&
|
||||
at_array_end() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
issue1607() &&
|
||||
minify_demo() &&
|
||||
minify_demo2() &&
|
||||
minify_test() &&
|
||||
car_example() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
minify_exceptionless_test() &&
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace tostring_tests
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, tostring_tests::run);
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
#include <set>
|
||||
#include "simdjson.h"
|
||||
#include "test_singlestage.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
namespace twitter_tests {
|
||||
using namespace std;
|
||||
|
||||
bool twitter_count() {
|
||||
TEST_START();
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
uint64_t count;
|
||||
ASSERT_SUCCESS( doc_result["search_metadata"]["count"].get(count) );
|
||||
ASSERT_EQUAL( count, 100 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
bool twitter_example() {
|
||||
TEST_START();
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
singlestage::parser parser;
|
||||
auto doc = parser.iterate(json);
|
||||
for (singlestage::object tweet : doc["statuses"]) {
|
||||
uint64_t id = tweet["id"];
|
||||
std::string_view text = tweet["text"];
|
||||
std::string_view screen_name = tweet["user"]["screen_name"];
|
||||
uint64_t retweets = tweet["retweet_count"];
|
||||
uint64_t favorites = tweet["favorite_count"];
|
||||
(void) id;
|
||||
(void) text;
|
||||
(void) retweets;
|
||||
(void) favorites;
|
||||
(void) screen_name;
|
||||
}
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool twitter_default_profile() {
|
||||
TEST_START();
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
// Print users with a default profile.
|
||||
set<string_view> default_users;
|
||||
for (auto tweet : doc_result["statuses"]) {
|
||||
auto user = tweet["user"].get_object();
|
||||
|
||||
// We have to get the screen name before default_profile because it appears first
|
||||
std::string_view screen_name;
|
||||
ASSERT_SUCCESS( user["screen_name"].get(screen_name) );
|
||||
|
||||
bool default_profile{};
|
||||
ASSERT_SUCCESS( user["default_profile"].get(default_profile) );
|
||||
if (default_profile) {
|
||||
default_users.insert(screen_name);
|
||||
}
|
||||
}
|
||||
ASSERT_EQUAL( default_users.size(), 86 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool twitter_image_sizes() {
|
||||
TEST_START();
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
// Print image names and sizes
|
||||
set<pair<uint64_t, uint64_t>> image_sizes;
|
||||
for (auto tweet : doc_result["statuses"]) {
|
||||
auto media = tweet["entities"]["media"];
|
||||
if (!media.error()) {
|
||||
for (auto image : media) {
|
||||
uint64_t id_val;
|
||||
std::string_view id_string;
|
||||
ASSERT_SUCCESS( image["id"].get(id_val) );
|
||||
ASSERT_SUCCESS( image["id_str"].get(id_string) );
|
||||
std::cout << "id = " << id_val << std::endl;
|
||||
std::cout << "id_string = " << id_string << std::endl;
|
||||
|
||||
for (auto size : image["sizes"].get_object()) {
|
||||
std::string_view size_key;
|
||||
ASSERT_SUCCESS( size.unescaped_key().get(size_key) );
|
||||
std::cout << "Type of image size = " << size_key << std::endl;
|
||||
|
||||
uint64_t width, height;
|
||||
ASSERT_SUCCESS( size.value()["w"].get(width) );
|
||||
ASSERT_SUCCESS( size.value()["h"].get(height) );
|
||||
image_sizes.insert(make_pair(width, height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_EQUAL( image_sizes.size(), 15 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool twitter_count_exception() {
|
||||
TEST_START();
|
||||
padded_string json;
|
||||
ASSERT_SUCCESS( padded_string::load(TWITTER_JSON).get(json) );
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
uint64_t count = doc_result["search_metadata"]["count"];
|
||||
ASSERT_EQUAL( count, 100 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
bool twitter_default_profile_exception() {
|
||||
TEST_START();
|
||||
padded_string json = padded_string::load(TWITTER_JSON);
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
// Print users with a default profile.
|
||||
set<string_view> default_users;
|
||||
for (auto tweet : doc_result["statuses"]) {
|
||||
singlestage::object user = tweet["user"];
|
||||
|
||||
// We have to get the screen name before default_profile because it appears first
|
||||
std::string_view screen_name = user["screen_name"];
|
||||
if (user["default_profile"]) {
|
||||
default_users.insert(screen_name);
|
||||
}
|
||||
}
|
||||
ASSERT_EQUAL( default_users.size(), 86 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
/*
|
||||
* Fun fact: id and id_str can differ:
|
||||
* 505866668485386240 and 505866668485386241.
|
||||
* Presumably, it is because doubles are used
|
||||
* at some point in the process and the number
|
||||
* 505866668485386241 cannot be represented as a double.
|
||||
* (not our fault)
|
||||
*/
|
||||
bool twitter_image_sizes_exception() {
|
||||
TEST_START();
|
||||
padded_string json = padded_string::load(TWITTER_JSON);
|
||||
ASSERT_TRUE(test_singlestage_doc(json, [&](auto doc_result) {
|
||||
// Print image names and sizes
|
||||
set<pair<uint64_t, uint64_t>> image_sizes;
|
||||
for (auto tweet : doc_result["statuses"]) {
|
||||
auto media = tweet["entities"]["media"];
|
||||
if (!media.error()) {
|
||||
for (auto image : media) {
|
||||
std::cout << "id = " << uint64_t(image["id"]) << std::endl;
|
||||
std::cout << "id_string = " << std::string_view(image["id_str"]) << std::endl;
|
||||
for (auto size : image["sizes"].get_object()) {
|
||||
std::cout << "Type of image size = " << std::string_view(size.unescaped_key()) << std::endl;
|
||||
// NOTE: the uint64_t is required so that each value is actually parsed before the pair is created
|
||||
image_sizes.insert(make_pair<uint64_t,uint64_t>(size.value()["w"], size.value()["h"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_EQUAL( image_sizes.size(), 15 );
|
||||
return true;
|
||||
}));
|
||||
TEST_SUCCEED();
|
||||
}
|
||||
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
|
||||
bool run() {
|
||||
return
|
||||
twitter_count() &&
|
||||
twitter_default_profile() &&
|
||||
twitter_image_sizes() &&
|
||||
#if SIMDJSON_EXCEPTIONS
|
||||
twitter_count_exception() &&
|
||||
twitter_example() &&
|
||||
twitter_default_profile_exception() &&
|
||||
twitter_image_sizes_exception() &&
|
||||
#endif // SIMDJSON_EXCEPTIONS
|
||||
true;
|
||||
}
|
||||
|
||||
} // namespace twitter_tests
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return test_main(argc, argv, twitter_tests::run);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user