mirror of
https://github.com/nlohmann/json.git
synced 2026-11-04 03:39:22 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74a96a0bbb |
No files matched your search
@@ -116,6 +116,10 @@ inline void copy_short(CharType* dst, const CharType* src, const std::size_t len
|
||||
/// the number of characters an empty vector is grown to by output_vector_sink
|
||||
constexpr std::size_t min_vector_sink_capacity = 64;
|
||||
|
||||
/// the number of characters output_vector_sink makes writable ahead of its
|
||||
/// position at a time: 64 KiB of the vector's capacity, not all of it
|
||||
constexpr std::size_t vector_sink_window = 65536;
|
||||
|
||||
/// @brief non-virtual output sink writing into a std::vector
|
||||
///
|
||||
/// This sink is not part of the virtual output_adapter_protocol hierarchy: it is
|
||||
@@ -129,7 +133,8 @@ constexpr std::size_t min_vector_sink_capacity = 64;
|
||||
/// encoding them: insert() is an out-of-line call into a routine that can insert
|
||||
/// anywhere, and resize() is one as well with libstdc++. The sink therefore keeps
|
||||
/// its own write position: it grows the vector geometrically ahead of the
|
||||
/// position and copies each write to it, so a write is a capacity check and a
|
||||
/// position (making @ref vector_sink_window characters of it writable at a
|
||||
/// time) and copies each write to it, so a write is a capacity check and a
|
||||
/// short copy. The destructor shrinks the vector to the bytes actually written,
|
||||
/// also when a write throws; shrinking a vector never allocates. The sink owns
|
||||
/// that trim, so it can be moved but not copied, and the vector must not be used
|
||||
@@ -277,9 +282,17 @@ class output_vector_sink
|
||||
// reallocate for every few bytes
|
||||
const std::size_t written = position();
|
||||
const std::size_t needed = written + length;
|
||||
v->resize((std::max)(min_vector_sink_capacity, needed <= v->capacity()
|
||||
? v->capacity()
|
||||
: (std::max)(needed, v->capacity() * 2)));
|
||||
const std::size_t capacity = (std::max)(min_vector_sink_capacity, needed <= v->capacity()
|
||||
? v->capacity()
|
||||
: (std::max)(needed, v->capacity() * 2));
|
||||
v->reserve(capacity);
|
||||
// resize() zeroes the characters it adds. Zeroing all of a doubled
|
||||
// capacity, megabytes of a fresh allocation, at once faults in its
|
||||
// pages and evicts them from the cache before the writer gets there,
|
||||
// so its stores miss again; a window ahead of the position is still
|
||||
// cached when they come (the binary writers on a long array of
|
||||
// numbers: 4-26 % faster on x86, 1-2.5 % on Apple M1)
|
||||
v->resize((std::min)(capacity, (std::max)(needed, written + vector_sink_window)));
|
||||
cursor = v->data() + written;
|
||||
limit = v->data() + v->size();
|
||||
}
|
||||
|
||||
Generated
+17
-4
@@ -27491,6 +27491,10 @@ inline void copy_short(CharType* dst, const CharType* src, const std::size_t len
|
||||
/// the number of characters an empty vector is grown to by output_vector_sink
|
||||
constexpr std::size_t min_vector_sink_capacity = 64;
|
||||
|
||||
/// the number of characters output_vector_sink makes writable ahead of its
|
||||
/// position at a time: 64 KiB of the vector's capacity, not all of it
|
||||
constexpr std::size_t vector_sink_window = 65536;
|
||||
|
||||
/// @brief non-virtual output sink writing into a std::vector
|
||||
///
|
||||
/// This sink is not part of the virtual output_adapter_protocol hierarchy: it is
|
||||
@@ -27504,7 +27508,8 @@ constexpr std::size_t min_vector_sink_capacity = 64;
|
||||
/// encoding them: insert() is an out-of-line call into a routine that can insert
|
||||
/// anywhere, and resize() is one as well with libstdc++. The sink therefore keeps
|
||||
/// its own write position: it grows the vector geometrically ahead of the
|
||||
/// position and copies each write to it, so a write is a capacity check and a
|
||||
/// position (making @ref vector_sink_window characters of it writable at a
|
||||
/// time) and copies each write to it, so a write is a capacity check and a
|
||||
/// short copy. The destructor shrinks the vector to the bytes actually written,
|
||||
/// also when a write throws; shrinking a vector never allocates. The sink owns
|
||||
/// that trim, so it can be moved but not copied, and the vector must not be used
|
||||
@@ -27652,9 +27657,17 @@ class output_vector_sink
|
||||
// reallocate for every few bytes
|
||||
const std::size_t written = position();
|
||||
const std::size_t needed = written + length;
|
||||
v->resize((std::max)(min_vector_sink_capacity, needed <= v->capacity()
|
||||
? v->capacity()
|
||||
: (std::max)(needed, v->capacity() * 2)));
|
||||
const std::size_t capacity = (std::max)(min_vector_sink_capacity, needed <= v->capacity()
|
||||
? v->capacity()
|
||||
: (std::max)(needed, v->capacity() * 2));
|
||||
v->reserve(capacity);
|
||||
// resize() zeroes the characters it adds. Zeroing all of a doubled
|
||||
// capacity, megabytes of a fresh allocation, at once faults in its
|
||||
// pages and evicts them from the cache before the writer gets there,
|
||||
// so its stores miss again; a window ahead of the position is still
|
||||
// cached when they come (the binary writers on a long array of
|
||||
// numbers: 4-26 % faster on x86, 1-2.5 % on Apple M1)
|
||||
v->resize((std::min)(capacity, (std::max)(needed, written + vector_sink_window)));
|
||||
cursor = v->data() + written;
|
||||
limit = v->data() + v->size();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ std::vector<json> test_values()
|
||||
large_payloads.push_back(json::binary(std::vector<std::uint8_t>(static_cast<std::size_t>(100 * i), static_cast<std::uint8_t>(i))));
|
||||
}
|
||||
|
||||
// several times vector_sink_window characters in every format: the vector
|
||||
// sink makes the capacity it grows to writable a window at a time
|
||||
json many_windows = json::array();
|
||||
for (std::uint64_t i = 0; i < 30000; ++i)
|
||||
{
|
||||
many_windows.push_back((i * 0x9E3779B97F4A7C15u) >> 1u);
|
||||
}
|
||||
|
||||
return
|
||||
{
|
||||
json(nullptr), json(true), json(false),
|
||||
@@ -61,7 +69,7 @@ std::vector<json> test_values()
|
||||
json::array(), json::object(),
|
||||
json::array({1, 2, 3}), json({{"a", 1}, {"b", nullptr}}),
|
||||
json({{"nested", {{"deep", json::array({1, "two", 3.0, nullptr})}}}}),
|
||||
big_array, big_object, large_payloads,
|
||||
big_array, big_object, large_payloads, many_windows,
|
||||
json::binary(std::vector<std::uint8_t>(5000, 0x42))
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user