v7.0.0 Highlights
- Cleaner compiler errors with a smaller core
glz::optswhile still allowing the same compile time customization options. - Faster integer to string serialization using larger tables, but also added
optimization_levelto remove large tables and optimize for size for small, embedded devices. - Lazy parsers for JSON and BEVE
- Much more
Breaking Changes
Options Refactoring
Several options have been renamed and moved to the inheritable options pattern:
number→string_as_number(more descriptive name)raw→unquoted(clearer semantics)write_member_functions→write_function_pointers(reflects support for all function pointer types)
Old names are preserved as deprecated aliases with clear static_assert messages guiding migration.
Core Options Size Reduction
The following options have been removed from glz::opts to reduce template instantiation sizes:
indentation_charindentation_widthnew_lines_in_arraysquoted_numstring_as_number(formerlynumber)unquoted(formerlyraw)raw_stringstructs_as_arrays
Users requiring these options should define them in custom structs that inherit from glz::opts. This change reduces compiler error verbosity and improves build performance for projects using default options.
Context Field Rename
The glz::context field indentation_level has been renamed to depth (#2207). This field tracks nesting depth during both reading (for stack overflow prevention) and writing (for indentation formatting).
New Features
Lazy JSON Parser (#2211)
Introducing glz::lazy_json, a lazy JSON parser that performs zero upfront processing. Creating a lazy_json object is O(1)—it simply stores a pointer to the buffer.
Key Features:
- On-demand parsing: Only parses bytes when accessed
- Indexed views: Build an index once in O(n) time, then achieve O(1) element retrieval
- Direct deserialization: New
read_jsonoverload accepts lazy views directly, enabling ~49% faster single-pass struct deserialization - Iterator support: Full range-based for loop compatibility for arrays and objects
When to use: Ideal for extracting a small number of fields from large JSON documents.
Basic Usage:
std::string json = R"({"name":"John","age":30,"active":true})";
auto result = glz::lazy_json(json);
if (result) {
auto& doc = *result;
auto name = doc["name"].get<std::string_view>(); // Only parses "name"
auto age = doc["age"].get<int64_t>(); // Only parses "age"
}Nested Access:
std::string json = R"({"user":{"profile":{"email":"alice@example.com"}}})";
auto result = glz::lazy_json(json);
if (result) {
auto email = (*result)["user"]["profile"]["email"].get<std::string_view>();
}Array Iteration:
std::string json = R"({"items":[{"id":1},{"id":2},{"id":3}]})";
auto result = glz::lazy_json(json);
if (result) {
int64_t sum = 0;
for (auto item : (*result)["items"]) {
if (auto id = item["id"].get<int64_t>()) {
sum += *id;
}
}
}Indexed Views for O(1) Random Access:
auto users = (*result)["users"].index(); // Build index once - O(n)
size_t count = users.size(); // O(1)
auto user500 = users[500]; // O(1) direct accessLazy BEVE Parser (#2220)
glz::lazy_beve brings the same lazy parsing capabilities to BEVE binary format:
- On-demand field access via
operator[] - Type checking methods:
is_object(),is_array(),is_string() - Value extraction through
get<T>() - Forward iterators for container traversal
- Random access indexing via
index()method - Size queries without full parsing
Query Parameter and URL Encoding Support (#2233)
New glaze/net/url.hpp header with comprehensive URL handling:
- URL encoding/decoding: Handles percent-encoding (
%20to space,+to space) - Query string parsing:
parse_urlencoded()for extractingkey=valuepairs - URL component splitting:
split_target()to separate paths from query strings - Automatic integration: HTTP router populates
request.queryautomatically - Zero-allocation options: High-performance parsing without heap allocations
BEVE Size Precomputation (#2206)
New glz::beve_size(value) function calculates exact serialization byte count without performing serialization:
glz::beve_size()for tagged serializationglz::beve_size_untagged()for untagged scenariosglz::compressed_int_size()for compressed integer encoding
Use case: Efficient pre-allocation for shared memory IPC scenarios.
BEVE Header Inspection (#2212, #2225)
Inspect BEVE buffer headers without full deserialization:
glz::beve_peek_header()returns tag, type, extension type, count, and header sizeglz::beve_peek_header_at()for inspecting headers at specific offsets- Enables pre-allocation, structure validation, and type-based routing
TOML: Array of Tables Support (#2216)
Full TOML 1.0 specification compliance for array-of-tables:
Writing:
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
name = "Nail"
sku = 284758393Reading: Parser handles [[array_name]] sections with proper nesting support.
Override: glz::inline_table<&T::member> wrapper forces inline {key = value} syntax.
Variant Custom Types (#2208)
Automatic JSON type deduction for custom types in std::variant:
std::variant<std::string, Amount> v;
glz::read_json(v, "42.5"); // Automatically parses as AmountGlaze now infers JSON types by examining the second parameter of custom read lambdas.
Static Function Pointer Support (#2223)
Function pointers are now fully supported:
- Works in
glz::metadefinitions and JSON-RPC registries - Serialization to type signature strings with
write_function_pointersenabled - Fixes stack overflow when registering JSON-RPC methods using static member functions
Improvements
Performance
Optimization Levels (#2214)
New optimization_level option for binary size vs. performance tradeoff:
- Normal (default): Large lookup tables (40KB) for maximum performance
- Size: Compact 400-byte tables, ~277KB binary savings for embedded systems
Faster Integer Serialization
Specialized itoa routines for 8/16-bit integer types provide performance improvements for these common types.
Reduced Template Instantiations (#2200)
Core template instantiation optimizations reduce compile times and binary sizes.
Security
Runtime Size Limits (#2199)
Runtime constraints for BEVE and CBOR deserialization:
struct my_context : glz::context {
size_t max_string_length = 1024;
size_t max_array_size = 100;
size_t max_map_size = 50;
};Runtime allocate_raw_pointers (#2213)
The allocate_raw_pointers option can now be set at runtime for more flexible memory allocation control.
Compatibility
Float Format Fallback (#2204)
float_format now falls back to snprintf on platforms without full std::to_chars floating-point support.
Bug Fixes
- Fixed HTTP POST body additional read issue (#2235)
- Fixed
renamed_key_sizecalculation (#2226) - Fixed BEVE string key detection and number key parsing in objects (included in #2220)
Migration Guide
Options Changes
If you use custom formatting options, update your code to inherit from glz::opts:
// Before (v6.x)
constexpr glz::opts my_opts{.indentation_width = 4};
// After (v7.0.0)
struct my_opts : glz::opts {
static constexpr uint8_t indentation_width = 4;
};Renamed Options
// Before
glz::opts{.number = true}
glz::opts{.raw = true}
glz::opts{.write_member_functions = true}
// After
struct my_opts : glz::opts { bool string_as_number = true; };
struct my_opts : glz::opts { bool unquoted = true; };
struct my_opts : glz::opts { bool write_function_pointers = true; };Full Changelog: v6.5.1...v7.0.0