Skip to content

Releases: stephenberry/glaze

v7.2.3

02 Apr 22:21

Choose a tag to compare

Improvements

BEVE

Networking

Reduce Complexity (Compile Times)

CI

MSVC Optimization

Fixes

Full Changelog: v7.2.2...v7.2.3

v7.2.2

26 Mar 14:25

Choose a tag to compare

Improvements

Fixes

Full Changelog: v7.2.1...v7.2.2

v7.2.1

15 Mar 23:41

Choose a tag to compare

Improvements

Fixes

Full Changelog: v7.2.0...v7.2.1

v7.2.0

10 Mar 01:41

Choose a tag to compare

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::meta needed, 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_enums option 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.

Improvements

  • Make stream_request buffer size configurable + update docs by @frak0d in #2354

Fixes

New Contributors

Full Changelog: v7.1.1...v7.2.0

v7.1.1

07 Mar 15:27

Choose a tag to compare

Improvements

Using a temporary scratch buffer in glz::context that will only be allocated in certain edge cases. This allows more control over memory usage and less surprises from static thread_local temporary buffers that may not get deallocated.


Fixes

New Contributors

Full Changelog: v7.1.0...v7.1.1

v7.1.0

28 Feb 23:57

Choose a tag to compare

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

26 Jan 15:29

Choose a tag to compare

Glaze v7.0.2

Highlights

  • YAML 1.2 support
  • std::expected support extended to BEVE and CBOR formats, plus std::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_executor for 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_t to int16_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_executor support
  • #2254 - JSON schema documentation fix
  • #2253 - BEVE and CBOR std::expected support
  • #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

16 Jan 16:12

Choose a tag to compare

Glaze v7.0.1

Highlights

  • Reduced binary size for embedded and size-constrained environments (use glz::size_opts and GLZ_DISABLE_ALWAYS_INLINE)
  • TOML support for std::variant and 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_size and 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::variant types 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

  • #2246 - Fix sparse enums with large values (modular_shifted hash)
  • #2245 - Reduce binary size (std_error_code.hpp, template bifurcation)
  • #2244 - Optimized digit parsing
  • #2241 - Small binary simple_float for size optimization level
  • #2240 - Generic TOML support and variant handling

v7.0.0

10 Jan 23:34

Choose a tag to compare

v7.0.0 Highlights

  • Cleaner compiler errors with a smaller core glz::opts while still allowing the same compile time customization options.
  • Faster integer to string serialization using larger tables, but also added optimization_level to 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:

  • numberstring_as_number (more descriptive name)
  • rawunquoted (clearer semantics)
  • write_member_functionswrite_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_char
  • indentation_width
  • new_lines_in_arrays
  • quoted_num
  • string_as_number (formerly number)
  • unquoted (formerly raw)
  • raw_string
  • structs_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_json overload 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 access

Lazy 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 (%20 to space, + to space)
  • Query string parsing: parse_urlencoded() for extracting key=value pairs
  • URL component splitting: split_target() to separate paths from query strings
  • Automatic integration: HTTP router populates request.query automatically
  • 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 serialization
  • glz::beve_size_untagged() for untagged scenarios
  • glz::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 size
  • glz::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 = 284758393

Reading: 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 Amount

Glaze 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::meta definitions and JSON-RPC registries
  • Serialization to type signature strings with write_function_pointers enabled
  • 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_size calculation (#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

03 Jan 19:19

Choose a tag to compare

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 prevented

Protection 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 them

By 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