Compare commits

..

7 Commits

Author SHA1 Message Date
Daniel Lemire 17cb457ffd version bump 2023-10-30 12:52:49 -04:00
Daniel Lemire 8b2af0473a skip UTF-8 BOM if present. (#2079) 2023-10-30 12:51:02 -04:00
Daniel Lemire f1bfa43385 Update ubuntu20-sani.yml 2023-10-27 20:58:54 -04:00
Daniel Lemire 29fbbee852 version bump 2023-10-27 20:57:30 -04:00
Daniel Lemire baa7d961ce Allowing users to write directly to std::optional<std::string> (#2078)
* Allowing users to write directly to std::optional<std::string>

* better fallback

* do not force the cast to std::string

* missing header

* removing abort
2023-10-27 20:56:12 -04:00
Yagiz Nizipli 6412b27c7e Merge pull request #2077 from simdjson/raw_json_on_values 2023-10-27 19:11:01 -04:00
Daniel Lemire 503da5ec83 raw_json() on values 2023-10-27 16:22:22 -04:00
26 changed files with 871 additions and 173 deletions
-1
View File
@@ -32,7 +32,6 @@ jobs:
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
ctest --output-on-failure -LE explicitonly -j
- name: Use cmake with undefined sanitizer
run: |
mkdir builddebugundefsani &&
+3 -3
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 3.4.0
VERSION 3.6.0
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "17.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "17" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "19.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "19" CACHE STRING "simdjson library soversion")
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "3.4.0"
PROJECT_NUMBER = "3.6.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+46 -4
View File
@@ -30,6 +30,7 @@ An overview of what you need to know to use simdjson, with examples.
- [Dynamic Number Types](#dynamic-number-types)
- [Raw Strings](#raw-strings)
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
- [Storing Directly into an Existing String Instance](#storing-directly-into-an-existing-string-instance)
- [Thread Safety](#thread-safety)
- [Standard Compliance](#standard-compliance)
- [Backwards Compatibility](#backwards-compatibility)
@@ -1722,13 +1723,42 @@ obj.reset(); // revise the object
uint64_t x = obj["value"]; // gives me 123
```
Storing Directly into an Existing std::string Instance
You can use `raw_json()` with the values inside an array and object. When
calling `raw_json()` on an untyped value, it acts as `raw_json()` when the
value is an array or an object. Otherwise, it acts as `raw_json_token()`.
It is useful if you do not care for the type of the value and just wants a
string representation.
```C++
auto json = R"( [1,2,"fds", {"a":1}, [1,344]] )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
size_t counter = 0;
for(auto array: doc) {
std::string_view raw = array.raw_json();
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
}
```
```C++
auto json = R"( {"key1":1,"key2":2,"key3":"fds", "key4":{"a":1}, "key5":[1,344]} )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
size_t counter = 0;
for(auto key_value: doc.get_object()) {
std::string_view raw = key_value.value().raw_json();
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
}
```
Storing Directly into an Existing String Instance
-----------------------------------------------------
The simdjson library favours the use of `std::string_view` instances because
it tends to lead to better performance due to causing fewer memory allocations.
However, they are cases where you need to store a string result in an `std::string``
instance. You can do so with a version of the `to_string()` method which takes as
instance. You can do so with a templated version of the `to_string()` method which takes as
a parameter a reference to an `std::string`.
```C++
@@ -1750,10 +1780,22 @@ The same routine can be written without exceptions handling:
if(err) { /* handle error */ }
```
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances, it does not point at data that is
within our `parser` instance. The same caveat applies: you should
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances,
it does not point at data that is within our `parser` instance. The same caveat applies: you should
only consume a JSON string once.
Because `get_string()` is a template that requires a type that can be assigned an `std::string`, you
can use it with features such as `std::optional`:
```C++
auto json = R"({ "foo1": "3.1416" } )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::optional<std::string> value;
if(doc["foo1"].get_string(value)) { /* error */ }
// value was populated with "3.1416"
```
You should be mindful of the trade-off: allocating multiple
`std::string` instances can become expensive.
+1 -2
View File
@@ -224,8 +224,7 @@ private:
* Parse the next document found in the buffer previously given to document_stream.
*
* The content should be a valid JSON document encoded as UTF-8. If there is a
* UTF-8 BOM, the caller is responsible for omitting it, UTF-8 BOM are
* discouraged.
* UTF-8 BOM, the parser skips it.
*
* You do NOT need to pre-allocate a parser. This function takes care of
* pre-allocating a capacity defined by the batch_size defined when creating the
+12 -1
View File
@@ -12,6 +12,7 @@
#include "simdjson/dom/element-inl.h"
#include <climits>
#include <cstring> /* memcmp */
namespace simdjson {
namespace dom {
@@ -120,8 +121,14 @@ inline simdjson_result<element> parser::parse_into_document(document& provided_d
_loaded_bytes_capacity = len;
}
std::memcpy(static_cast<void *>(loaded_bytes.get()), buf, len);
buf = reinterpret_cast<const uint8_t*>(loaded_bytes.get());
}
_error = implementation->parse(realloc_if_needed ? reinterpret_cast<const uint8_t*>(loaded_bytes.get()): buf, len, provided_doc);
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
buf += 3;
len -= 3;
}
_error = implementation->parse(buf, len, provided_doc);
if (_error) { return _error; }
@@ -158,6 +165,10 @@ simdjson_inline simdjson_result<element> parser::parse(const padded_string_view
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
buf += 3;
len -= 3;
}
return document_stream(*this, buf, len, batch_size);
}
inline simdjson_result<document_stream> parser::parse_many(const char *buf, size_t len, size_t batch_size) noexcept {
+4
View File
@@ -254,6 +254,8 @@ public:
* And, possibly, no document many have been parsed when the `parser.load_many(path)` function
* returned.
*
* If there is a UTF-8 BOM, the parser skips it.
*
* ### Format
*
* The file must contain a series of one or more JSON documents, concatenated into a single
@@ -346,6 +348,8 @@ public:
* cout << std::string(doc["title"]) << endl;
* }
*
* If there is a UTF-8 BOM, the parser skips it.
*
* ### Format
*
* The buffer must contain a series of one or more JSON documents, concatenated into a single
@@ -128,7 +128,8 @@ simdjson_inline simdjson_result<double> document::get_double_in_string() noexcep
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 error_code document::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_inline error_code document::get_string(string_type& receiver, bool allow_replacement) noexcept {
return get_root_value_iterator().get_root_string(receiver, true, allow_replacement);
}
simdjson_inline simdjson_result<std::string_view> document::get_wobbly_string() noexcept {
@@ -400,7 +401,8 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
if (error()) { return error(); }
return first.get_string(allow_replacement);
}
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::get_string(string_type& receiver, bool allow_replacement) noexcept {
if (error()) { return error(); }
return first.get_string(receiver, allow_replacement);
}
@@ -590,7 +592,8 @@ simdjson_inline simdjson_result<int64_t> document_reference::get_int64_in_string
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 error_code document_reference::get_string(std::string& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, false, allow_replacement); }
template <typename string_type>
simdjson_inline error_code document_reference::get_string(string_type& receiver, bool allow_replacement) noexcept { return doc->get_root_value_iterator().get_root_string(receiver, 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); }
@@ -727,7 +730,8 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
if (error()) { return error(); }
return first.get_string(allow_replacement);
}
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document_reference>::get_string(string_type& receiver, bool allow_replacement) noexcept {
if (error()) { return error(); }
return first.get_string(receiver, allow_replacement);
}
+8 -4
View File
@@ -113,7 +113,8 @@ public:
*
* @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
*/
simdjson_inline error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
/**
* Cast this JSON value to a string.
*
@@ -638,7 +639,8 @@ public:
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 error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, 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;
@@ -708,7 +710,8 @@ public:
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 error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept;
@@ -781,7 +784,8 @@ public:
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 error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept;
@@ -241,8 +241,7 @@ private:
* Parse the next document found in the buffer previously given to document_stream.
*
* The content should be a valid JSON document encoded as UTF-8. If there is a
* UTF-8 BOM, the caller is responsible for omitting it, UTF-8 BOM are
* discouraged.
* UTF-8 BOM, the parser skips it.
*
* You do NOT need to pre-allocate a parser. This function takes care of
* pre-allocating a capacity defined by the batch_size defined when creating the
@@ -46,6 +46,8 @@ simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capa
simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(padded_string_view json) & noexcept {
if (json.padding() < SIMDJSON_PADDING) { return INSUFFICIENT_PADDING; }
json.remove_utf8_bom();
// Allocate if needed
if (capacity() < json.length() || !string_buf) {
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
@@ -96,6 +98,8 @@ simdjson_warn_unused simdjson_inline simdjson_result<document> parser::iterate(c
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; }
json.remove_utf8_bom();
// Allocate if needed
if (capacity() < json.length()) {
SIMDJSON_TRY( allocate(json.length(), max_depth()) );
@@ -108,6 +112,10 @@ simdjson_warn_unused simdjson_inline simdjson_result<json_iterator> parser::iter
inline simdjson_result<document_stream> parser::iterate_many(const uint8_t *buf, size_t len, size_t batch_size, bool allow_comma_separated) noexcept {
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
if((len >= 3) && (std::memcmp(buf, "\xEF\xBB\xBF", 3) == 0)) {
buf += 3;
len -= 3;
}
if(allow_comma_separated && batch_size < len) { batch_size = len; }
return document_stream(*this, buf, len, batch_size, allow_comma_separated);
}
+2 -1
View File
@@ -59,7 +59,7 @@ public:
* 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.
* document. If there is a UTF-8 BOM, the parser skips it.
*
* ### IMPORTANT: Validate what you use
*
@@ -188,6 +188,7 @@ public:
* arrays or objects) MUST be separated with ASCII whitespace.
*
* The characters inside a JSON document, and between JSON documents, must be valid Unicode (UTF-8).
* If there is a UTF-8 BOM, the parser skips it.
*
* The documents must not exceed batch_size bytes (by default 1MB) or they will fail to parse.
* Setting batch_size to excessively large or excessively small values may impact negatively the
+29 -2
View File
@@ -47,7 +47,8 @@ simdjson_inline simdjson_result<raw_json_string> value::get_raw_json_string() no
simdjson_inline simdjson_result<std::string_view> value::get_string(bool allow_replacement) noexcept {
return iter.get_string(allow_replacement);
}
simdjson_inline error_code value::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_inline error_code value::get_string(string_type& receiver, bool allow_replacement) noexcept {
return iter.get_string(receiver, allow_replacement);
}
simdjson_inline simdjson_result<std::string_view> value::get_wobbly_string() noexcept {
@@ -196,6 +197,26 @@ 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<std::string_view> value::raw_json() noexcept {
json_type t;
SIMDJSON_TRY(type().get(t));
switch (t)
{
case json_type::array: {
ondemand::array array;
SIMDJSON_TRY(get_array().get(array));
return array.raw_json();
}
case json_type::object: {
ondemand::object object;
SIMDJSON_TRY(get_object().get(object));
return object.raw_json();
}
default:
return raw_json_token();
}
}
simdjson_inline simdjson_result<const char *> value::current_location() noexcept {
return iter.json_iter().current_location();
}
@@ -322,7 +343,8 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
if (error()) { return error(); }
return first.get_string(allow_replacement);
}
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_inline error_code simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::get_string(string_type& receiver, bool allow_replacement) noexcept {
if (error()) { return error(); }
return first.get_string(receiver, allow_replacement);
}
@@ -426,6 +448,11 @@ simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLE
return first.raw_json_token();
}
simdjson_inline simdjson_result<std::string_view> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::raw_json() noexcept {
if (error()) { return error(); }
return first.raw_json();
}
simdjson_inline simdjson_result<const char *> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::current_location() noexcept {
if (error()) { return error(); }
return first.current_location();
+17 -2
View File
@@ -148,7 +148,8 @@ public:
*
* @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS.
*/
simdjson_inline error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
/**
* Cast this JSON value to a "wobbly" string.
@@ -492,9 +493,21 @@ public:
* - true
* - false
* - null
*
* See also value::raw_json().
*/
simdjson_inline std::string_view raw_json_token() noexcept;
/**
* Get a string_view pointing at this value in the JSON document.
* If this element is an array or an object, it consumes the array or the object
* and returns a string_view instance corresponding to the
* array as represented in JSON. It points inside the original document.
* If this element is a scalar (string, number, Boolean, null), it returns what
* raw_json_token() would return.
*/
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
/**
* Returns the current location in the document if in bounds.
*/
@@ -619,7 +632,8 @@ public:
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 error_code get_string(std::string& receiver, bool allow_replacement = false) noexcept;
template <typename string_type>
simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept;
simdjson_inline simdjson_result<std::string_view> get_wobbly_string() noexcept;
simdjson_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string> get_raw_json_string() noexcept;
simdjson_inline simdjson_result<bool> get_bool() noexcept;
@@ -712,6 +726,7 @@ public:
/** @copydoc simdjson_inline std::string_view value::raw_json_token() const noexcept */
simdjson_inline simdjson_result<std::string_view> raw_json_token() noexcept;
simdjson_inline simdjson_result<std::string_view> raw_json() noexcept;
/** @copydoc simdjson_inline simdjson_result<const char *> current_location() noexcept */
simdjson_inline simdjson_result<const char *> current_location() noexcept;
@@ -513,11 +513,12 @@ simdjson_warn_unused simdjson_inline simdjson_result<bool> value_iterator::parse
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_string(bool allow_replacement) noexcept {
return get_raw_json_string().unescape(json_iter(), allow_replacement);
}
simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(std::string& receiver, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code value_iterator::get_string(string_type& receiver, bool allow_replacement) noexcept {
std::string_view content;
auto err = get_string(allow_replacement).get(content);
if (err) { return err; }
receiver = std::string(content);
receiver = content;
return SUCCESS;
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_wobbly_string() noexcept {
@@ -643,11 +644,12 @@ simdjson_inline simdjson_result<number> value_iterator::get_root_number(bool che
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_string(bool check_trailing, bool allow_replacement) noexcept {
return get_root_raw_json_string(check_trailing).unescape(json_iter(), allow_replacement);
}
simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(std::string& receiver, bool check_trailing, bool allow_replacement) noexcept {
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code value_iterator::get_root_string(string_type& receiver, bool check_trailing, bool allow_replacement) noexcept {
std::string_view content;
auto err = get_root_string(check_trailing, allow_replacement).get(content);
if (err) { return err; }
receiver = std::string(content);
receiver = content;
return SUCCESS;
}
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> value_iterator::get_root_wobbly_string(bool check_trailing) noexcept {
@@ -296,7 +296,8 @@ public:
*/
simdjson_warn_unused simdjson_inline simdjson_result<std::string_view> get_string(bool allow_replacement) noexcept;
simdjson_warn_unused simdjson_inline error_code get_string(std::string& receiver, bool allow_replacement) noexcept;
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, 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;
@@ -313,7 +314,8 @@ public:
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 error_code get_root_string(std::string& receiver, bool check_trailing, bool allow_replacement) noexcept;
template <typename string_type>
simdjson_warn_unused simdjson_inline error_code get_root_string(string_type& receiver, 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;
+12 -1
View File
@@ -2,9 +2,10 @@
#define SIMDJSON_PADDED_STRING_VIEW_INL_H
#include "simdjson/padded_string_view.h"
#include "simdjson/error-inl.h"
#include <cstring> /* memcmp */
namespace simdjson {
inline padded_string_view::padded_string_view(const char* s, size_t len, size_t capacity) noexcept
@@ -31,6 +32,16 @@ inline size_t padded_string_view::capacity() const noexcept { return _capacity;
inline size_t padded_string_view::padding() const noexcept { return capacity() - length(); }
inline bool padded_string_view::remove_utf8_bom() noexcept {
if(length() < 3) { return false; }
if (std::memcmp(data(), "\xEF\xBB\xBF", 3) == 0) {
remove_prefix(3);
_capacity -= 3;
return true;
}
return false;
}
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson_result<padded_string_view> &s) noexcept(false) { return out << s.value(); }
#endif
+7
View File
@@ -54,6 +54,13 @@ public:
/** The number of allocated bytes. */
inline size_t capacity() const noexcept;
/**
* Remove the UTF-8 Byte Order Mark (BOM) if it exists.
*
* @return whether a BOM was found and removed
*/
inline bool remove_utf8_bom() noexcept;
/** The amount of padding on the string (capacity() - length()) */
inline size_t padding() const noexcept;
+2 -2
View File
@@ -4,7 +4,7 @@
#define SIMDJSON_SIMDJSON_VERSION_H
/** The version of simdjson being used (major.minor.revision) */
#define SIMDJSON_VERSION "3.4.0"
#define SIMDJSON_VERSION "3.6.0"
namespace simdjson {
enum {
@@ -15,7 +15,7 @@ enum {
/**
* The minor version (major.MINOR.revision) of simdjson being used.
*/
SIMDJSON_VERSION_MINOR = 4,
SIMDJSON_VERSION_MINOR = 6,
/**
* The revision (major.minor.REVISION) of simdjson being used.
*/
+1 -1
View File
@@ -1,4 +1,4 @@
/* auto-generated on 2023-10-25 19:34:52 -0400. Do not edit! */
/* auto-generated on 2023-10-30 12:51:02 -0400. Do not edit! */
/* including simdjson.cpp: */
/* begin file simdjson.cpp */
#define SIMDJSON_SRC_SIMDJSON_CPP
+537 -133
View File
File diff suppressed because it is too large Load Diff
+29 -1
View File
@@ -66,6 +66,16 @@ namespace number_tests {
return true;
}
bool bomskip() {
TEST_START();
simdjson::dom::parser parser;
simdjson::padded_string docdata = "\xEF\xBB\xBF{\"score\":0.8825149536132812}"_padded;
double score;
ASSERT_SUCCESS(parser.parse(docdata)["score"].get_double().get(score));
ASSERT_EQUAL(score, 0.8825149536132812);
TEST_SUCCEED();
}
bool issue2017() {
TEST_START();
simdjson::dom::parser parser;
@@ -386,7 +396,8 @@ namespace number_tests {
}
bool run() {
return issue2017() &&
return bomskip() &&
issue2017() &&
truncated_borderline() &&
specific_tests() &&
ground_truth() &&
@@ -1658,6 +1669,7 @@ namespace validate_tests {
}
return true;
}
bool test_validate() {
std::cout << "Running " << __func__ << std::endl;
const std::string test = R"({ "foo" : 1, "bar" : [ 1, 2, 3 ], "baz": { "a": 1, "b": 2, "c": 3 } })";
@@ -1666,6 +1678,7 @@ namespace validate_tests {
}
return true;
}
bool test_range() {
std::cout << "Running " << __func__ << std::endl;
for(size_t len = 0; len <= 128; len++) {
@@ -1683,6 +1696,7 @@ namespace validate_tests {
}
return true;
}
bool test_issue1169() {
std::cout << "Running " << __func__ << std::endl;
std::vector<uint8_t> source(64,' ');
@@ -1693,6 +1707,7 @@ namespace validate_tests {
}
return true;
}
bool test_issue1169_long() {
std::cout << "Running " << __func__ << std::endl;
for(size_t len = 1; len <= 128; len++) {
@@ -1702,6 +1717,7 @@ namespace validate_tests {
}
return true;
}
bool test_random() {
std::cout << "Running " << __func__ << std::endl;
std::vector<uint8_t> source(64,' ');
@@ -1763,6 +1779,7 @@ namespace minify_tests {
}
return true;
}
// this is meant to test buffer overflows.
bool test_various_lengths2() {
std::cout << "Running " << __func__ << std::endl;
@@ -1781,6 +1798,7 @@ namespace minify_tests {
}
return true;
}
bool test_single_quote() {
std::cout << "Running " << __func__ << std::endl;
const std::string test = "\"";
@@ -1801,12 +1819,14 @@ namespace minify_tests {
const std::string minified(R"({"foo":1,"bar":[1,2,0.11111111111111113],"baz":{"a":3.1415926535897936,"b":2,"c":3.141592653589794}})");
return check_minification(test.c_str(), test.size(), minified.c_str(), minified.size());
}
bool test_minify_array() {
std::cout << "Running " << __func__ << std::endl;
std::string test("[ 1, 2, 3]");
std::string minified("[1,2,3]");
return check_minification(test.c_str(), test.size(), minified.c_str(), minified.size());
}
bool test_minify_object() {
std::cout << "Running " << __func__ << std::endl;
std::string test(R"({ "foo " : 1, "b ar" : [ 1, 2, 3 ], "baz": { "a": 1, "b": 2, "c": 3 } })");
@@ -1849,6 +1869,7 @@ namespace format_tests {
s << doc;
return assert_minified(s);
}
bool print_minify_parser_parse() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1868,6 +1889,7 @@ namespace format_tests {
s << value;
return assert_minified(s, "1");
}
bool print_minify_element() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1887,6 +1909,7 @@ namespace format_tests {
s << array;
return assert_minified(s, "[1,2,0.11111111111111113]");
}
bool print_minify_array() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1906,6 +1929,7 @@ namespace format_tests {
s << object;
return assert_minified(s, R"({"a":3.1415926535897936,"b":2,"c":3.141592653589794})");
}
bool print_minify_object() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1925,6 +1949,7 @@ namespace format_tests {
s << parser.parse(DOCUMENT);
return assert_minified(s);
}
bool print_minify_parser_parse_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1940,6 +1965,7 @@ namespace format_tests {
s << parser.parse(DOCUMENT)["foo"];
return assert_minified(s, "1");
}
bool print_minify_element_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1956,6 +1982,7 @@ namespace format_tests {
s << value;
return assert_minified(s, "1");
}
bool print_minify_element_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
@@ -1972,6 +1999,7 @@ namespace format_tests {
s << parser.parse(DOCUMENT)["bar"].get_array();
return assert_minified(s, "[1,2,0.11111111111111113]");
}
bool print_minify_array_result_exception() {
std::cout << "Running " << __func__ << std::endl;
dom::parser parser;
+29 -1
View File
@@ -397,6 +397,33 @@ namespace document_stream_tests {
std::cout << "number of documents " << count << std::endl;
return count == 1;
}
bool skipbom() {
std::cout << "Running " << __func__ << std::endl;
simdjson::dom::parser parser;
auto json = "\xEF\xBB\xBF{\"hello\": \"world\"}"_padded;
simdjson::dom::document_stream stream;
ASSERT_SUCCESS(parser.parse_many(json).get(stream));
size_t count = 0;
for (auto doc : stream) {
if(doc.error()) {
std::cerr << "Unexpected error: " << doc.error() << std::endl;
return false;
}
std::string expected = R"({"hello":"world"})";
simdjson::dom::element this_document;
ASSERT_SUCCESS(doc.get(this_document));
std::string answer = simdjson::minify(this_document);
if(answer != expected) {
std::cout << this_document << std::endl;
return false;
}
count += 1;
}
std::cout << "number of documents " << count << std::endl;
return count == 1;
}
#if SIMDJSON_EXCEPTIONS
bool single_document_exceptions() {
std::cout << "Running " << __func__ << std::endl;
@@ -913,7 +940,8 @@ namespace document_stream_tests {
}
bool run() {
return fuzzaccess() &&
return skipbom() &&
fuzzaccess() &&
baby_fuzzer() &&
issue1649() &&
adversarial_single_document_array() &&
@@ -322,6 +322,43 @@ namespace document_stream_tests {
TEST_SUCCEED();
}
bool skipbom() {
TEST_START();
auto json = "\xEF\xBB\xBF[1,[1,2]] {\"a\":1,\"b\":2} {\"o\":{\"1\":1,\"2\":2}} [1,2,3]"_padded;
ondemand::parser parser;
ondemand::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<ondemand::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;
@@ -803,6 +840,7 @@ namespace document_stream_tests {
bool run() {
return
skipbom() &&
issue1977() &&
string_with_trailing() &&
uint64_with_trailing() &&
+13
View File
@@ -16,6 +16,18 @@ namespace misc_tests {
ASSERT_FALSE(b);
TEST_SUCCEED();
}
bool skipbom() {
auto error_phrase = "\xEF\xBB\xBF false"_padded;
TEST_START();
ondemand::parser parser;
ondemand::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;
@@ -593,6 +605,7 @@ namespace misc_tests {
bool run() {
return
skipbom() &&
issue1981_success() &&
issue1981_failure() &&
replacement_char() &&
+53 -1
View File
@@ -1,6 +1,8 @@
#include "simdjson.h"
#include "test_ondemand.h"
#if __cpp_lib_optional >= 201606L
#include <optional>
#endif
using namespace std;
using namespace simdjson;
using error_code=simdjson::error_code;
@@ -1479,10 +1481,60 @@ bool example1958() {
}
return true;
}
bool to_optional() {
TEST_START();
auto json = R"({ "foo1": "3.1416" } )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
#if __cpp_lib_optional >= 201606L
std::optional<std::string> value;
ASSERT_SUCCESS(doc["foo1"].get_string(value));
std::cout << value.value() << std::endl;
#else
std::string value;
ASSERT_SUCCESS(doc["foo1"].get_string(value));
std::cout << value << std::endl;
#endif
TEST_SUCCEED();
}
bool value_raw_json_array() {
TEST_START();
auto json = R"( [1,2,"fds", {"a":1}, [1,344]] )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::string_view expected[] = {"1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"};
size_t counter = 0;
for(auto array: doc) {
std::string_view raw = array.raw_json();
ASSERT_EQUAL(raw, expected[counter++]);
}
TEST_SUCCEED();
}
bool value_raw_json_object() {
TEST_START();
auto json = R"( {"key1":1,"key2":2,"key3":"fds", "key4":{"a":1}, "key5":[1,344]} )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::string_view expected[] = {"1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"};
size_t counter = 0;
for(auto key_value: doc.get_object()) {
std::string_view raw = key_value.value().raw_json();
ASSERT_EQUAL(raw, expected[counter++]);
}
TEST_SUCCEED();
}
#endif
bool run() {
return true
#if SIMDJSON_EXCEPTIONS
&& to_optional()
&& value_raw_json_array() && value_raw_json_object()
&& gen_raw1() && gen_raw2() && gen_raw3()
&& at_end()
&& example1956() && example1958()