mirror of
https://github.com/nlohmann/json.git
synced 2026-10-18 12:08:12 +00:00
Address the review of the json_view object index and SIMD scan
From gregmarr's review of #5628: - Docs and comments say that the hash index is one of the object's keys. - object_index.hpp: conditional_static_cast for the hash, "slot" for the table position, no flag for a degenerate table, and a static_assert that the smallest indexed object is larger than the probe window. - scan.hpp unrolls with NLOHMANN_VIEW_REPEAT_FIRST_8/SECOND_8. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
16 files changed
+54
-48
No files matched your search
@@ -77,8 +77,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
|
||||
@@ -35,8 +35,8 @@ No-throw guarantee: this function never throws exceptions.
|
||||
1. Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) with a JSON pointer.
|
||||
|
||||
@@ -28,7 +28,8 @@ No-throw guarantee: this function never throws exceptions.
|
||||
Linear in the number of members: unlike the lookup functions, `count()` does not stop at the first match, because it
|
||||
has to count every member with the key. Members are compared one after another, in document order. Each comparison
|
||||
first checks the key's length -- already known from the index, without reading the key bytes -- before comparing its
|
||||
content.
|
||||
content. The hash index of the keys of objects with 128 or more members does not help here, since every member
|
||||
is visited.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ No-throw guarantee: this function never throws exceptions.
|
||||
Linear in the number of members: as for [`ordered_json`](../ordered_json.md), members are compared one after another,
|
||||
in document order, stopping at the first match. Each comparison first checks the key's length
|
||||
-- already known from the index, without reading the key bytes -- before comparing its content.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time on
|
||||
average.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -83,8 +83,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
another, in document order, stopping at the first match. Each comparison first checks the
|
||||
key's length -- already known from the index, without reading the key bytes -- before comparing its content, so a
|
||||
key of a different length than `key` is rejected without touching the source text.
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in `idx`: elements are skipped one at a time from the first one, since they are not a fixed size in the
|
||||
index (unlike `BasicJsonType`'s array, which is random-access).
|
||||
3. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
@@ -116,7 +116,7 @@ document.
|
||||
member in order and so keep the *last* value for a repeated key, so `#!cpp v["a"]` and
|
||||
`#!cpp v.materialize()["a"]` can differ. To get the value `parse()` would give, use
|
||||
[`materialize()`](materialize.md) or iterate the members with [`items()`](items.md) and keep the last match.
|
||||
The hash index of a larger object (128 members or more) leads to the first member of a key as well.
|
||||
The key hash index of a larger object (128 members or more) leads to the first member of a key as well.
|
||||
[`begin()`](begin.md)/[`end()`](end.md) and [`items()`](items.md) iterate over *all* members, including
|
||||
duplicates, in document order. See [Duplicate keys](../../features/json_view.md#duplicate-keys) and
|
||||
[`size()`](size.md#notes).
|
||||
|
||||
@@ -70,8 +70,8 @@ None of these exceptions carry a [`JSON_DIAGNOSTICS`](../macros/json_diagnostics
|
||||
1. Linear in the number of members: as for [`operator[]`](operator[].md#complexity), members are compared one after
|
||||
another, in document order, stopping at the first match. Plus the complexity of converting
|
||||
the found member to `T` (see [`get`](get.md)).
|
||||
Objects with 128 or more members get a hash index while parsing, so that a lookup in them takes constant time
|
||||
on average.
|
||||
Objects with 128 or more members get a hash index of their keys while parsing, so that a lookup in them takes
|
||||
constant time on average.
|
||||
2. Linear in the number of reference tokens of `ptr` and, for each token, in the number of members of the object at
|
||||
that level or the index into the array -- as for the [`operator[]`](operator[].md#complexity) and
|
||||
[`at`](at.md#complexity) overloads that take a JSON pointer. Plus the complexity of converting the resolved value
|
||||
|
||||
@@ -180,7 +180,7 @@ document: `#!cpp auto v = json_document::parse(text).root();` does not compile.
|
||||
|
||||
**Why the first?** A lookup can stop as soon as it finds a match. Returning the last member would force every lookup
|
||||
to scan all members of the object, even when the key is found at the very first one: this made lookups in small
|
||||
objects 1.6 to 3.4 times slower. The hash index of objects with 128 members or more leads to the first member of a
|
||||
objects 1.6 to 3.4 times slower. The hash index of the keys of objects with 128 members or more leads to the first member of a
|
||||
key as well. Other zero-copy parsers that index the source text, such as yyjson and simdjson, also return the first
|
||||
member. RFC 8259 only says that names within an object SHOULD be unique and that the behavior of a receiver that sees
|
||||
duplicates is unpredictable, so neither choice is wrong.
|
||||
|
||||
@@ -196,7 +196,7 @@ packet-beta
|
||||
|-------|---------|------------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 0 | `kind` | `uint8_t` | the type, numbered as [`value_t`](../api/basic_json/value_t.md): 0 null, 1 object, 2 array, 3 string, 4 boolean, 5 signed integer, 6 unsigned integer, 7 float |
|
||||
| 1 | `flags` | `uint8_t` | bits 0-1: where a string's bytes are (0: the source text, 1: the buffer of decoded strings, for strings with escapes); bit 2: the value of a boolean |
|
||||
| 2-3 | `extra` | `uint16_t` | numbers: the number of integer digits (low byte) and fraction digits (high byte), 255 for more; objects: the number of their hash index (1-based), or 0; otherwise 0 |
|
||||
| 2-3 | `extra` | `uint16_t` | numbers: the number of integer digits (low byte) and fraction digits (high byte), 255 for more; objects: the number of their key hash index (1-based), or 0; otherwise 0 |
|
||||
| 4-7 | `off` | `uint32_t` | where the value starts: the first byte after a string's opening quote (or its position in the buffer of decoded strings), the first byte of a number or literal, the bracket of an array or object |
|
||||
| 8-11 | `len` | `uint32_t` | strings: the length after decoding; floats and literals: the length of the token; arrays and objects: the number of elements |
|
||||
| 12-15 | `next` | `uint32_t` | arrays and objects: the number of nodes of the subtree, including the node itself |
|
||||
@@ -212,7 +212,7 @@ packet-beta
|
||||
step from element to element this way and skip whole subtrees in constant time.
|
||||
- **Offsets** are 32 bits wide, so a document is limited to 4294967279 bytes, 4 GiB minus 16 bytes (a margin below
|
||||
2^32 for positions one scanner step past the end of the text; `out_of_range.416`).
|
||||
- **Large objects** (128 members or more) get a hash index after parsing
|
||||
- **Large objects** (128 members or more) get a hash index for their keys after parsing
|
||||
([`detail/view/object_index.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/view/object_index.hpp)):
|
||||
an open-addressing table whose slots hold the distance from the object's node to a key's node, so that a lookup does
|
||||
not compare every key. Of duplicate keys the table leads to the first, as a linear search does. The object's `extra`
|
||||
|
||||
Reference in new issue
Block a user