Releases: stephenberry/glaze
v7.2.3
Improvements
BEVE
- Support for BEVE aligned typed arrays by @stephenberry in #2400
- Support skipping BEVE extensions by @stephenberry in #2426
Networking
- HTTP Client Chunked Support by @stephenberry in #2414
- max_response_body_size for http client by @stephenberry in #2418
- HTTP read until connection closed support by @stephenberry in #2421
Reduce Complexity (Compile Times)
- Remove make_static by @stephenberry in #2429
- Drop custom from_chars for constexpr use, required in C++23 by @stephenberry in #2430
CI
- Update deprecated CI dependencies by @annihilatorq in #2416
- fedora ci test timeout by @stephenberry in #2396
MSVC Optimization
- Remove MSVC guard for unique_per_length_info by @stephenberry in #2431
Fixes
- Suppress bad clang warnings by @stephenberry in #2427
- internal linkage for constexpr variables for module use by @stephenberry in #2428
Full Changelog: v7.2.2...v7.2.3
v7.2.2
Improvements
- error_on_missing_array_elements option by @stephenberry in #2381
- Glaze vs Boost.Beast HTTP server benchmarks and optimizations by @stephenberry in #2384
- custom optional support by @stephenberry in #2390
- Add clang-cl CI workflow by @annihilatorq in #2395
- Make REST router more like a map and allow overwriting routes by @stephenberry in #2403
Fixes
- YAML fix for generic_u64 and generic_i64 by @stephenberry in #2382
- format_context to support specifying YAML in opts format field by @stephenberry in #2383
- glz::patch support for all glz::generic_ types by @stephenberry in #2387
- Avoid erroring on nullable value types by @stephenberry in #2394
- Fix GNU-style flag passing to MSVC frontend by @annihilatorq in #2391
- Nullable value write skipping by @stephenberry in #2398
Full Changelog: v7.2.1...v7.2.2
v7.2.1
Improvements
- C++26 support to reflect C Arrays by @stephenberry in #2360
- Increase strictness of time_point parsing by @stephenberry in #2365
- Support string_as_number option with std::string_view and arrays of char by @stephenberry in #2372
- Propagate Opts into lazy_json read_into by @stephenberry in #2371
- Better error messages for unknown variant type by @stephenberry in #2377
Fixes
- Use ensure_space for always_null_t JSON by @stephenberry in #2363
- Accept ISO 8601 format strings without timezone information by @stephenberry in #2364
- Finalize read_into context for partial reading with lazy_json by @stephenberry in #2373
- Minor cleanup of includes and use std::unreachable by @stephenberry in #2375
Full Changelog: v7.2.0...v7.2.1
v7.2.0
C++26 Reflection Support!
Glaze now supports P2996 "Reflection for C++26". This unlocks capabilities that aren't possible with older compile-time reflection:
- Non-aggregate types — classes with constructors, virtual functions, and inheritance just work
- Automatic enum serialization — no
glz::metaneeded, enums serialize to strings automatically - Unlimited struct members — no 128-member cap
- Private member access — reflect on all members regardless of access specifiers
- Standardized — no compiler-specific hacks, built on
std::meta
// Classes with constructors — just works with P2996
class User {
public:
std::string name;
int age;
User() = default;
User(std::string n, int a) : name(std::move(n)), age(a) {}
};
User u{"Alice", 30};
auto json = glz::write_json(u).value_or("error");
// {"name":"Alice","age":30}
// Enums serialize as strings — no glz::meta required
enum class Color { Red, Green, Blue };
Color c = Color::Green;
struct reflect_enums_opts : glz::opts {
bool reflect_enums = true;
};
auto color_json = glz::write<reflect_enums_opts{}>(c).value_or("error");
// "Green"Note that the
reflect_enumsoption has been added to avoid a breaking change for how Glaze default serializes enums as their numerical equivalent.
Supported compilers: GCC 16+ (-std=c++26 -freflection) and Bloomberg clang-p2996. See the C++26 reflection documentation for setup and details.
- C++26 Reflection by @stephenberry in #2217
Improvements
Fixes
- YAML fix for unindented sequence under a known key by @stephenberry in #2357
- Fix YAML double-quoted \xXX being interpreted as a byte instead of a codepoint by @nghiaho310pf in #2359
- YAML Fixes and Improvements by @stephenberry in #2358
New Contributors
- @nghiaho310pf made their first contribution in #2359
- @frak0d made their first contribution in #2354
Full Changelog: v7.1.1...v7.2.0
v7.1.1
Improvements
- Reduced static thread_local use by @stephenberry in #2344
Using a temporary scratch buffer in
glz::contextthat will only be allocated in certain edge cases. This allows more control over memory usage and less surprises fromstatic thread_localtemporary buffers that may not get deallocated.
- ImprovedTOML 1.1 compliance and unit tests in #2341
- Implement
skip_read_constraintoption by @eoan-ermine in #2339 - JSON schema value support by @stephenberry in #2350
- Value type variant schema support by @stephenberry in #2351
Fixes
- Fixed unit tests for MSVC by @stephenberry in #2343
- Fixed enum hashed-lookup bounds check on truncated JSON strings by @huangminghuang in #2345
- Fixed json_shema handling for glz::modify by @stephenberry in #2347
- YAML skip unindented sequences properly by @stephenberry in #2355
New Contributors
- @eoan-ermine made their first contribution in #2339
Full Changelog: v7.1.0...v7.1.1
v7.1.0
Glaze v7.1.0
This release focuses on YAML maturity, networking reliability, container/generic behavior, and platform compatibility.
Important
glz::generic now supports different underlying map types, but now defaults to a faster, ordered map, which preserves insertion order rather than sorting lexicographically. This ensures proper round tripping for unsorted JSON objects. See documentation for more details: https://stephenberry.github.io/glaze/generic-json
YAML Maturity
YAML support received major hardening and coverage improvements, including parser correctness, conformance, roundtrip behavior, and generic integration.
Related pull requests: #2289, #2293, #2297, #2298, #2300, #2302, #2305, #2317, #2324, #2335.
Networking Improvements
HTTP/WebSocket behavior was improved across TLS support, handshake compatibility, CPU efficiency, and server internals.
Related pull requests: #2260, #2284, #2292, #2321, #2322, #2323.
Generic and Container Behavior
Runtime generic behavior and ordered container support were improved, including insertion-order preservation and additional integer generic access support.
Related pull requests: #2318, #2325, #2334.
Platform and Toolchain Compatibility
Compatibility and CI coverage improved for MSVC and ARM targets, along with sanitizer/toolchain robustness fixes.
Related pull requests: #2273, #2288, #2303, #2304, #2309, #2336, #2337.
Core Improvements and Fixes
Core quality improvements include SIMD/reflection work and correctness fixes around key handling and string conversion behavior.
Related pull requests: #2270, #2281, #2290, #2329.
Full Changelog
v7.0.2
Glaze v7.0.2
Highlights
- YAML 1.2 support
std::expectedsupport extended to BEVE and CBOR formats, plusstd::expected<void, E>handling in JSON- Enum hashing improvements for writing with graceful fallbacks when perfect hashing fails and a two-element fast path
- HTTP server/client flexibility via
asio::any_io_executorfor shared event loops - Further binary size reduction in the simple float module (~76% smaller lookup tables)
YAML Support (#2243)
Glaze now includes a YAML 1.2 Core Schema reader and writer. All types with existing glz::meta specializations work automatically with YAML -- no additional boilerplate required.
#include <glaze/yaml.hpp>
struct my_struct {
std::string name;
int age;
std::vector<std::string> tags;
};
my_struct obj{"Alice", 30, {"developer", "musician"}};
// Write YAML
std::string yaml;
glz::write_yaml(obj, yaml);
// name: Alice
// age: 30
// tags:
// - developer
// - musician
// Read YAML
my_struct parsed{};
glz::read_yaml(parsed, yaml);Features:
- Block style and flow style collections
- Double-quoted, single-quoted, and plain scalars
- Literal (
|) and folded (>) block scalars with chomping modifiers - Hex (
0x), octal (0o), and binary (0b) integer literals - Special values:
.inf,-.inf,.nan,null,~ - YAML Core Schema tags (
!!str,!!int,!!float,!!bool,!!null,!!seq,!!map) - Document markers (
---and...) std::variant,std::optional,std::unique_ptr,std::shared_ptr, enum, tuple, and pair support- File I/O helpers:
glz::read_file_yaml/glz::write_file_yaml - Configurable options:
indent_width,flow_style,skip_null_members,error_on_unknown_keys
YAML is not included in the main glaze/glaze.hpp header to avoid unnecessary compile-time cost. Include glaze/yaml.hpp explicitly.
See the YAML documentation for full details.
std::expected Support
std::expected<void, E> in JSON (#2251)
std::expected<void, E> is now handled correctly in JSON serialization and deserialization:
std::expected<void, int> val{}; // success
std::string json;
glz::write_json(val, json);
// json: "{}"
std::expected<void, int> err = std::unexpected(42);
glz::write_json(err, json);
// json: {"unexpected":42}BEVE and CBOR Support (#2253)
std::expected<T, E> (including std::expected<void, E>) is now fully supported in both BEVE and CBOR formats, using the same {"unexpected": error} encoding convention as JSON.
Enum Hashing Improvements
Fallback When Hashing Fails (#2263)
Previously, enums with adversarial value distributions could cause a compile error if the perfect hash seed search failed. The library now gracefully falls back:
- N <= 16 values: linear search
- N > 16 values: binary search through a compile-time sorted array
This also fixes a potential out-of-bounds read when parsing standalone enum strings at the end of input.
HTTP Server/Client Executor Support (#2258)
glz::http_server and glz::http_client can now be constructed with an asio::any_io_executor, allowing integration into an existing ASIO application with a shared event loop.
// Use an existing executor
asio::io_context my_context;
glz::http_server server{my_context.get_executor()};
// Or let glaze create its own (default, backward-compatible)
glz::http_server server{};The legacy constructor accepting std::shared_ptr<asio::io_context> is preserved for backward compatibility.
Binary Size Optimization
Simple Float Table Reduction (#2248)
The simple_float module's power-of-5 lookup tables were reduced by ~76%:
- Table range narrowed from [-64, +64] to [-16, +16] (covers typical JSON numbers)
- Table storage split into separate arrays for better alignment
- Exponent type downsized from
int32_ttoint16_t - Total table size reduced from ~2.5KB to ~594 bytes
Numbers with exponents outside [-16, +16] fall back to binary exponentiation.
Pull Requests
- #2264 - Two element ID optimization
- #2263 - Enum search fallback when hashing fails
- #2258 - HTTP server/client
asio::any_io_executorsupport - #2254 - JSON schema documentation fix
- #2253 - BEVE and CBOR
std::expectedsupport - #2251 -
std::expected<void, E>JSON support - #2248 - Simple float table reduction
- #2243 - YAML support
Full Changelog: v7.0.1...v7.0.2
v7.0.1
Glaze v7.0.1
Highlights
- Reduced binary size for embedded and size-constrained environments (use
glz::size_optsandGLZ_DISABLE_ALWAYS_INLINE) - TOML support for
std::variantand generic types (glz::generic, maps) - Optimized floating-point parsing
- Fixed sparse enums with large values (#2246)
Binary Size Optimization
This release focuses heavily on reducing binary size for embedded systems and size-constrained environments.
std::error_code Integration Moved to Optional Header
The unused std::error_code integration has been moved from the core headers to a separate optional header:
#include <glaze/core/std_error_code.hpp>This reduces binary size by ~34KB for users who don't need std::error_code compatibility. The overhead came from the global error_category variable with std::error_category vtable, which forced a DATA segment with page alignment overhead.
Breaking Change: If your code uses glz::error_category, glz::make_error_code(), or relies on implicit conversion from glz::error_code to std::error_code, you must now explicitly include the header:
#include <glaze/core/std_error_code.hpp>Size-Optimized Float Parsing (simple_float.hpp)
A new compact floating-point parsing and serialization module achieves ~21-25KB savings compared to the full dragonbox/fast_float implementations:
- Maintains strict JSON compliance
- Verified to roundtrip with all of Glaze's floating point algorithms, so no changes occur when switching from
glz::opts_sizeand peak performance algorithms
This is automatically used when serializing/deserializing with glz::opts_size.
TOML Improvements
Variant and Generic Type Support (#2240)
Full TOML serialization support for:
std::varianttypes with automatic type detection- Generic types:
glz::generic,glz::generic_i64,glz::generic_u64 - Map types:
std::map,std::unordered_map
std::variant<int, double, std::string> value = 3.14;
std::string toml;
glz::write<glz::TOML>(value, toml);
// toml: "3.14"Features:
- Automatic type detection from TOML syntax (quoted strings, booleans, arrays, objects, floats, integers)
- Dotted keys and table sections within map contexts
- Path-based nested map navigation for type safety
Bug Fixes
Sparse Enums with Large Values (#2246)
Fixed compilation failure for enums with values that share common power-of-2 factors:
enum class SparseEnum : int {
Zero = 0,
FourHundredMillion = 400000000 // Previously failed to compile
};The issue occurred because values like 0 and 400000000 (both divisible by 2^10) would hash to the same bucket with standard modular hashing, causing "Failed to find perfect hash seed for enum" errors.
Solution: Added a new modular_shifted hash strategy that removes common trailing zeros before hashing. The compiler automatically selects this strategy when standard modular hashing fails.
Pull Requests
v7.0.0
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
v6.5.1
Security Enhancements
BEVE/CBOR DoS Protection (#2194)
Binary formats like BEVE and CBOR encode length headers indicating how many elements follow. Previously, a malicious actor could craft a message claiming billions of elements but containing minimal data, causing memory exhaustion before validation.
Glaze now validates length headers against remaining buffer size before any memory allocation:
// Malicious buffer claiming 1 billion strings but containing only a few bytes
std::vector<std::string> result;
auto ec = glz::read_beve(result, malicious_buffer);
// ec.ec == glz::error_code::invalid_length
// No memory was allocated - attack preventedProtection applies to strings, typed arrays, generic arrays, and maps/objects.
User-Configurable Allocation Limits (#2195)
New compile-time options for stricter memory control:
struct secure_opts : glz::opts
{
uint32_t format = glz::BEVE;
size_t max_string_length = 1024; // Max 1KB per string
size_t max_array_size = 10000; // Max 10,000 elements per array
size_t max_map_size = 1000; // Max 1,000 entries per map
};
auto ec = glz::read<secure_opts{}>(obj, buffer);New glz::max_length wrapper for per-field limits:
template <>
struct glz::meta<UserInput>
{
using T = UserInput;
static constexpr auto value = object(
"username", glz::max_length<&T::username, 64>, // Max 64 chars
"scores", glz::max_length<&T::scores, 100> // Max 100 elements
);
};See Security Documentation for best practices.
New Features
Bounded Buffer Overflow Detection (#2189)
Writing to fixed-size buffers (like std::array or std::span) now returns error_code::buffer_overflow instead of undefined behavior when capacity is exceeded:
std::array<char, 32> buffer{};
auto ec = glz::write_json(large_object, buffer);
if (ec.ec == glz::error_code::buffer_overflow) {
// Handle insufficient buffer space
}allocate_raw_pointers Option (#2196)
New compile-time option to allow allocating memory for null raw pointers during deserialization:
struct alloc_opts : glz::opts {
bool allocate_raw_pointers = true;
};
std::vector<MyStruct*> vec;
auto ec = glz::read<alloc_opts{}>(vec, json);
// vec now contains allocated pointers - caller must delete themBy default, Glaze refuses to allocate raw pointers to prevent memory leaks. See Nullable Types for details.
Compatibility
iOS Support for Older Versions (#2197)
Added compatibility guards for std::to_chars/std::from_chars floating-point support, which is unavailable on iOS < 16.3. This affects only float128_t serialization; regular float and double types use Glaze's built-in implementation and work on all iOS versions.
Build
- Removed old Boost::system linkage (#2193)
Full Changelog: v6.5.0...v6.5.1