github stephenberry/glaze v7.7.0

latest releases: v9.0.0, v8.4.0, v8.3.0...
4 months ago

Compilation-time improvements

This release prioritizes compile time costs. Three subsystems that were previously pulled in transitively by glaze.hpp are now opt-in. If your code uses jmespath, msgpack, or recorder, you must add an explicit include.

Breaking: required includes

jmespath is now opt-in

include/glaze/json/jmespath.hpp is no longer bundled by glaze.hpp or glaze/json.hpp.

#include <glaze/json/jmespath.hpp>

msgpack is now opt-in

glaze/msgpack.hpp is no longer included by the glaze.hpp aggregate header, matching the existing CBOR convention.

#include <glaze/msgpack.hpp>

recorder is now opt-in

glaze/record/recorder.hpp is no longer included by the glaze.hpp aggregate header. This also severs the transitive glaze/csv.hpp chain that recorder pulled into every TU.

#include <glaze/record/recorder.hpp>

glaze/json/generic.hpp split with generic_fwd.hpp

Following the same convention as glaze/forward.hpp: widely-included user headers can now reference glz::generic via the lightweight forward-only glaze/json/generic_fwd.hpp, deferring the full read/write machinery to the TUs that serialize.

Other compilation-time cleanup

A broader pass on header weight and instantiation cost:

  • New glaze/forward.hpp with no Glaze dependencies (just <cstdint>). Users who want to specialize glz::meta, glz::to<Format, T>, glz::from<Format, T>, or construct glz::custom_t in widely-included user headers can now include only this and defer the full <glaze/glaze.hpp> include to the TUs that call read/write.

  • <atomic> / <bitset> / <complex> includes in core/common.hpp are now gated on GLZ_REFLECTION26 (the only code that needed them).

  • unique_per_length_info no longer instantiates std::ranges::sort per N. Measured: glz::make_keys_info<20> instantiation drops from 45.1 ms to 26.0 ms with -ftime-trace.

  • boxed<T> inside glz::schema no longer drags std::unique_ptr<T> and std::default_delete<T> instantiations into every TU that includes schema.hpp.

  • Compilation time optimization and cleanup by @stephenberry in #2527

  • Reduce always inline usage for jsonb and bson by @stephenberry in #2572

  • perf(progress_bar): build status string with glz::to_chars + memcpy by @stephenberry in #2573

TOML: nullables, nested tables, and inline-mode cascading

This release lands four independent TOML fixes that together close most of the long-standing round-trip gaps in the parser and writer.

Inline tables and nullables (read)

The struct reader's inline-table branch now returns after parse_toml_object_members consumes the closing }. Without this, the surrounding , or } of the enclosing inline table was misparsed as the start of a new key, producing unknown_key errors on perfectly valid documents:

a = 1
inline_data = { key1 = "value1", key2 = 100 }
b = 2

Nullable support is now broadly available for both TOML and YAML, including nested nullable tables and nullable arrays. nullable_emplace is consolidated as the single emplacement point.

  • toml: fix inline tables parsing, support for nullables by @makekryl in #2561
  • toml: fix reading nested nullable tables and nullable arrays by @makekryl in #2576

Arrays with newlines (read)

Multi-line arrays were rejected when the parser hit a newline mid-array. They are now accepted, matching the TOML spec.

Map fields and cascade inline mode through nested writers (write)

Struct fields of std::map type now emit as inline tables (items = { key = value, ... }) so the output is well-formed TOML in any nesting position. Previously they flowed through the scalar writer and produced output that could not be read back.

Inline mode now cascades through every nested writer: write_inline_value is the single dispatch point for any value written inside an inline context, and write_inline_object, write_inline_map, the array writer's write_element, the tuple/glaze_array writer, and the struct writer's PASS 1 scalar path all route through it. As a result, struct fields of vector<struct>, vector<map<...>>, optional<map>, optional<struct>, variant<...struct...>, or tuple<struct, ...> can no longer leak multi-line struct dumps or [[...]] headers inside [ ... ] or { ... }.

  • Fix TOML serialization of map fields and cascade inline mode through nested writers by @stephenberry in #2544

Native JSON support for sys_days and year_month_day

std::chrono::year_month_day had no JSON specialization at all, and std::chrono::sys_days round-tripped as a full datetime. Users had to write a glz::custom lambda with std::chrono::parse to handle simple date fields, which trips compiler bugs on GCC/MSVC. Both now work directly:

struct Holiday {
    std::chrono::year_month_day date;
    std::string name;
};

Holiday h{2024y/6/15, "midsummer"};
glz::write_json(h);  // {"date":"2024-06-15","name":"midsummer"}

sys_days writes the same "YYYY-MM-DD" shape and accepts either form on read (a full datetime is floored to its UTC date).

Breaking change: write_json(sys_days{...}) used to produce "2024-06-15T00:00:00Z". It now produces "2024-06-15". Readers accept both, so upgrading on the read side is safe; producers that emit the new shape break older readers that strictly require a time component.

Safety: years outside [0000, 9999] now fail to serialize with error_code::constraint_violated instead of silently emitting wrap-around digits. This guard also covers the pre-existing system_time_point writer.

HTTP: structured glz_write_error from response::body<Opts>

When glz::write failed inside response::body<Opts>(value), the response body was reset to a hardcoded literal {"error":"glz::write_json error"}. Two issues: the underlying error_ctx (code + custom message) was discarded, and the literal was appended to any partial payload the failed write had already pushed, producing malformed JSON like {"name":"abc{"error":"glz::write_json error"}.

Now the body is cleared before writing the error and a small structured value is serialized:

{"error":"glaze write failure","code":42,"message":"<custom_error_message from error_ctx>"}
  • fix(http): emit structured glz_write_error from response::body<Opts> on serialization failure by @genisis0x in #2565

CMake: glaze_INSTALL option

When consumed as a subproject (e.g. via FetchContent), glaze was unconditionally registering its install() and CPack rules into the parent project, causing glaze artifacts to appear in downstream installers without the consumer opting in.

A new glaze_INSTALL option defaults to ${PROJECT_IS_TOP_LEVEL}. Top-level builds keep the install rules; subproject builds skip them by default. Consumers who want the cascade can set glaze_INSTALL=ON. CMAKE_SKIP_INSTALL_RULES is still honored.

  • cmake: add glaze_INSTALL option, default to PROJECT_IS_TOP_LEVEL by @stephenberry in #2578

Cleanup

Full Changelog: v7.6.0...v7.7.0

Don't miss a new glaze release

NewReleases is sending notifications on new releases.