mirror of
https://github.com/nlohmann/json.git
synced 2026-10-25 15:28:54 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea3dca202b |
No files matched your search
@@ -55,10 +55,7 @@ validate with overload 2 first, if the original vector must survive a failed loa
|
||||
|
||||
## Exceptions
|
||||
|
||||
On a big-endian target, throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) -- the same
|
||||
exception [`save()`](save.md#exceptions) throws there, since the image format is little-endian only.
|
||||
|
||||
Otherwise throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
|
||||
Throws [`parse_error.116`](../../home/exceptions.md#jsonexceptionparse_error116) if `image` is not one
|
||||
`save()` could have written, or fails the requested `check`:
|
||||
|
||||
| message | when |
|
||||
@@ -95,6 +92,9 @@ are checked once, however many nodes refer to it.
|
||||
|
||||
## Notes
|
||||
|
||||
**Little-endian targets only.** On a big-endian target, `load()` does not exist, just like
|
||||
[`save()`](save.md#notes): the image format is little-endian, so a call fails to compile.
|
||||
|
||||
### `image_check` { #image_check }
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -31,9 +31,6 @@ Throws [`type_error.320`](../../home/exceptions.md#jsonexceptiontype_error320) i
|
||||
[discarded](is_discarded.md) -- a default-constructed document, or one a failed [`parse()`](parse.md)/
|
||||
[`read()`](read.md) with `allow_exceptions == false` left discarded.
|
||||
|
||||
On a big-endian target, throws `type_error.320` with a different message instead: the image format is little-endian
|
||||
only (see [Notes](#notes)).
|
||||
|
||||
Throws [`out_of_range.416`](../../home/exceptions.md#jsonexceptionout_of_range416) if the node count, the text, or
|
||||
the decoded strings of the image would individually reach 4 GiB -- the same 32-bit offsets
|
||||
[`parse()`](parse.md#exceptions) and, for edits, [`set`](set.md)/[`push_back`](push_back.md) are already limited to.
|
||||
@@ -44,9 +41,6 @@ the decoded strings of the image would individually reach 4 GiB -- the same 32-b
|
||||
[json.exception.type_error.320] cannot save a discarded json_document
|
||||
```
|
||||
```
|
||||
[json.exception.type_error.320] json_document images need a little-endian target
|
||||
```
|
||||
```
|
||||
[json.exception.out_of_range.416] images of 4 GiB or more are not supported by json_document
|
||||
```
|
||||
|
||||
@@ -70,9 +64,9 @@ else -- see [`load`'s Exceptions](load.md#exceptions).
|
||||
the *same* build on the *same* (little-endian) machine -- not as a long-term storage format. Keep the original
|
||||
JSON text if you need to read a saved document back with a future library version.
|
||||
|
||||
**Little-endian only.** The image is written as raw little-endian bytes, with no byte-swapping. `save()` (and
|
||||
[`load`](load.md)) throw `type_error.320` on a big-endian target rather than silently produce bytes a big-endian
|
||||
reader could not interpret correctly.
|
||||
**Little-endian targets only.** The image is written as raw little-endian bytes, with no byte-swapping. On a
|
||||
big-endian target, `save()` and [`load`](load.md) do not exist: a call fails to compile rather than produce bytes a
|
||||
big-endian reader could not interpret correctly.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -354,9 +354,10 @@ validation entirely, for an image trusted as much as the process's own memory. S
|
||||
!!! warning "Experimental"
|
||||
|
||||
The image format is versioned but not yet stable, and may change in an incompatible way before it is declared
|
||||
stable. It is little-endian only, and tied to the library build that wrote it -- use it to cache a document or to
|
||||
hand one to another process running the *same* build, not as a long-term storage format; keep the original JSON
|
||||
text if a saved document needs to be readable by a future library version.
|
||||
stable. It is little-endian only (on big-endian targets, `save()` and `load()` do not exist), and tied to the
|
||||
library build that wrote it -- use it to cache a document or to hand one to another process running the *same*
|
||||
build, not as a long-term storage format; keep the original JSON text if a saved document needs to be readable by
|
||||
a future library version.
|
||||
|
||||
The idea of a document you can read without parsing comes from zero-copy formats such as
|
||||
[FlatBuffers](https://github.com/google/flatbuffers) and [YaFF](https://github.com/yandex/yaff); the check
|
||||
|
||||
@@ -853,17 +853,12 @@ from JSON text.
|
||||
|
||||
[`basic_json_document::save()`](../api/basic_json_document/save.md) cannot write an
|
||||
[image](../features/json_view.md#images) of a [discarded](../api/basic_json_document/is_discarded.md) document.
|
||||
[`save()`](../api/basic_json_document/save.md) and [`load()`](../api/basic_json_document/load.md) also throw this
|
||||
exception on a big-endian target, since the image format is little-endian only.
|
||||
|
||||
!!! failure "Example messages"
|
||||
|
||||
```
|
||||
[json.exception.type_error.320] cannot save a discarded json_document
|
||||
```
|
||||
```
|
||||
[json.exception.type_error.320] json_document images need a little-endian target
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ enum class exception_id : int
|
||||
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
|
||||
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
|
||||
document_binary_value = 319, ///< a binary value is stored in a json_document
|
||||
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
|
||||
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
|
||||
discarded_value_used = 321, ///< a discarded value is used
|
||||
// out_of_range
|
||||
array_index_out_of_range = 401, ///< an array index is out of range
|
||||
|
||||
@@ -182,12 +182,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
|
||||
}
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
|
||||
/// the document as an image
|
||||
inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
const std::size_t arena_size = d.arena_size;
|
||||
std::vector<node> compacted;
|
||||
std::string text_tail;
|
||||
@@ -243,6 +241,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
*o = 0;
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// the parts of a number token that the checks need
|
||||
struct number_token
|
||||
@@ -663,13 +662,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
|
||||
/// Read an image into d. The text and the decoded strings stay in the image;
|
||||
/// the nodes are copied (so that they are aligned, and edits can change them).
|
||||
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
if (image == nullptr || size < sizeof(image_header))
|
||||
{
|
||||
throw_invalid_image("too short");
|
||||
@@ -738,6 +735,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
|
||||
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
|
||||
d.discarded = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
|
||||
@@ -1182,6 +1182,10 @@ class basic_json_document
|
||||
/// how load() checks an image (full, bounds, or none)
|
||||
using image_check = detail::view::image_check;
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
// (the image format is little-endian: big-endian targets have no save()
|
||||
// and load(), so that a call fails to compile instead of always throwing)
|
||||
|
||||
/// The document as an image that load() reads without parsing: the node
|
||||
/// index, the text, and the decoded strings. An edited document is
|
||||
/// written in its current state (floats that are not finite become null,
|
||||
@@ -1223,6 +1227,7 @@ class basic_json_document
|
||||
detail::view::load_image(*d.m_data, d.m_data->owned_image.data(), d.m_data->owned_image.size(), check);
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////
|
||||
// edits //
|
||||
|
||||
Generated
+1
-1
@@ -5565,7 +5565,7 @@ enum class exception_id : int
|
||||
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
|
||||
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
|
||||
document_binary_value = 319, ///< a binary value is stored in a json_document
|
||||
document_image_unsupported = 320, ///< a json_document image cannot be saved or loaded (discarded document, big-endian target)
|
||||
document_image_unsupported = 320, ///< a discarded json_document cannot be saved as an image
|
||||
discarded_value_used = 321, ///< a discarded value is used
|
||||
// out_of_range
|
||||
array_index_out_of_range = 401, ///< an array index is out of range
|
||||
|
||||
Generated
+9
-6
@@ -5007,12 +5007,10 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v
|
||||
}
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no save() elsewhere)
|
||||
/// the document as an image
|
||||
inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
const std::size_t arena_size = d.arena_size;
|
||||
std::vector<node> compacted;
|
||||
std::string text_tail;
|
||||
@@ -5068,6 +5066,7 @@ inline std::vector<std::uint8_t> save_image(const document_data& d)
|
||||
*o = 0;
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// the parts of a number token that the checks need
|
||||
struct number_token
|
||||
@@ -5488,13 +5487,11 @@ inline bool check_image(const node* nodes, std::size_t count, const unsigned cha
|
||||
throw_parse_error(exception_id::invalid_document_image, concat("invalid json_document image: ", what));
|
||||
}
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN // (the image format is little-endian: no load() elsewhere)
|
||||
/// Read an image into d. The text and the decoded strings stay in the image;
|
||||
/// the nodes are copied (so that they are aligned, and edits can change them).
|
||||
inline void load_image(document_data& d, const std::uint8_t* image, std::size_t size, image_check check)
|
||||
{
|
||||
#if !NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
throw_type_error(exception_id::document_image_unsupported, "json_document images need a little-endian target"); // LCOV_EXCL_LINE
|
||||
#endif
|
||||
if (image == nullptr || size < sizeof(image_header))
|
||||
{
|
||||
throw_invalid_image("too short");
|
||||
@@ -5563,6 +5560,7 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t
|
||||
std::vector<std::uint32_t>().swap(d.large_objects); // (only needed while building)
|
||||
d.discarded = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
@@ -8911,6 +8909,10 @@ class basic_json_document
|
||||
/// how load() checks an image (full, bounds, or none)
|
||||
using image_check = detail::view::image_check;
|
||||
|
||||
#if NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
// (the image format is little-endian: big-endian targets have no save()
|
||||
// and load(), so that a call fails to compile instead of always throwing)
|
||||
|
||||
/// The document as an image that load() reads without parsing: the node
|
||||
/// index, the text, and the decoded strings. An edited document is
|
||||
/// written in its current state (floats that are not finite become null,
|
||||
@@ -8952,6 +8954,7 @@ class basic_json_document
|
||||
detail::view::load_image(*d.m_data, d.m_data->owned_image.data(), d.m_data->owned_image.size(), check);
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////
|
||||
// edits //
|
||||
|
||||
@@ -28,11 +28,25 @@ using nlohmann::detail::view::node;
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <test_data.hpp>
|
||||
|
||||
namespace json_view_image_test
|
||||
{
|
||||
// whether a document type has save() and load() (only on little-endian targets)
|
||||
template<typename T, typename = void>
|
||||
struct has_save : std::false_type {};
|
||||
template<typename T>
|
||||
struct has_save<T, decltype(static_cast<void>(std::declval<const T&>().save()))> : std::true_type {};
|
||||
template<typename T, typename = void>
|
||||
struct has_load : std::false_type {};
|
||||
template<typename T>
|
||||
struct has_load<T, decltype(static_cast<void>(T::load(std::declval<const std::vector<std::uint8_t>&>())))> : std::true_type {};
|
||||
} // namespace json_view_image_test
|
||||
|
||||
#if !(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
|
||||
namespace
|
||||
@@ -171,6 +185,9 @@ std::uint32_t rng()
|
||||
|
||||
TEST_CASE("json_view images: round trips")
|
||||
{
|
||||
static_assert(json_view_image_test::has_save<json_document>::value && json_view_image_test::has_load<json_document>::value, "save() and load() on a little-endian target");
|
||||
static_assert(json_view_image_test::has_save<ordered_json_editable_document>::value && json_view_image_test::has_load<ordered_json_editable_document>::value, "save() and load() on a little-endian target");
|
||||
|
||||
SECTION("small documents")
|
||||
{
|
||||
for (const char* text :
|
||||
@@ -1275,8 +1292,12 @@ TEST_CASE("json_view images: damaged images")
|
||||
|
||||
TEST_CASE("json_view images: big-endian targets")
|
||||
{
|
||||
// the image format is little-endian: save() and load() do not exist here
|
||||
static_assert(!json_view_image_test::has_save<json_document>::value, "no save() on a big-endian target");
|
||||
static_assert(!json_view_image_test::has_load<json_document>::value, "no load() on a big-endian target");
|
||||
static_assert(!json_view_image_test::has_save<json_editable_document>::value, "no save() on a big-endian target");
|
||||
const json_document d = json_document::parse("[1]");
|
||||
CHECK_THROWS_WITH_AS(d.save(), "[json.exception.type_error.320] json_document images need a little-endian target", json::type_error&);
|
||||
CHECK(d.root().size() == 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user