Skip to content

Releases: stephenberry/glaze

v4.2.3

26 Dec 20:37
Compare
Choose a tag to compare

Improvements

Fixes

  • Fixed glz::merge with empty objects in #1519 (thanks @SenseOnline)
  • Fixed enum string read for vector of pairs in concatenate mode by @sjanel in #1525

In Development

  • REPE conformance for registry errors in #1526

Full Changelog: v4.2.2...v4.2.3

v4.2.2

18 Dec 15:45
Compare
Choose a tag to compare

Slice support for glz::read_jmespath

std::vector<int> data{0,1,2,3,4,5,6,7,8,9};
std::string buffer{};
expect(not glz::write_json(data, buffer));

std::vector<int> slice{};
expect(not glz::read_jmespath<"[0:5]">(slice, buffer));
expect(slice.size() == 5);
expect(slice[0] == 0);
expect(slice[1] == 1);
expect(slice[2] == 2);
expect(slice[3] == 3);
expect(slice[4] == 4);

Pre-compute JMESPath run-time expressions

The run-time version of glz::read_jmespath also now takes in a const jmespath_expression&. This allows a jmespath_expression to be "compiled" once in the code and reused for much better runtime performance. This caches the tokenization.

Person child{};
// A runtime expression can be pre-computed and saved for more efficient lookups
glz::jmespath_expression expression{"family.children[0]"};
expect(not glz::read_jmespath(expression, child, buffer));
expect(child.first_name == "Lilly");

Note that this still works:

expect(not glz::read_jmespath("family.children[0]", child, buffer));

by @stephenberry in #1510

Fixes

  • Include missing version header that could cause segfaults with GCC in #1508 (Many thanks to @hs-vc)

Full Changelog: v4.2.1...v4.2.2

v4.2.1

17 Dec 17:31
Compare
Choose a tag to compare

First steps for compile-time and run-time JMESPath query support

v4.2.0 neutered the partial_read option, due to its complexity and confusing behavior (and to make it faster). This release brings another approach to partial reading that is far more extensible, by utilizing the JMESPath query specification.

More JMESPath support will be added in the future, but this release brings both compile-time and run-time JMESPath expression handling to read a value at a target location in a buffer.

Example

struct Person
{
   std::string first_name{};
   std::string last_name{};
   uint16_t age{};
};

struct Family
{
   Person father{};
   Person mother{};
   std::vector<Person> children{};
};

struct Home
{
   Family family{};
   std::string address{};
};

suite jmespath_read_at_tests = [] {
   "compile-time read_jmespath"_test = [] {
      Home home{.family = {.father = {"Gilbert", "Fox", 28},
                           .mother = {"Anne", "Fox", 30},
                           .children = {{"Lilly"}, {"Vincent"}}}};

      std::string buffer{};
      expect(not glz::write_json(home, buffer));

      std::string first_name{};
      auto ec = glz::read_jmespath<"family.father.first_name">(first_name, buffer);
      expect(not ec) << glz::format_error(ec, buffer);
      expect(first_name == "Gilbert");

      Person child{};
      expect(not glz::read_jmespath<"family.children[0]">(child, buffer));
      expect(child.first_name == "Lilly");
      expect(not glz::read_jmespath<"family.children[1]">(child, buffer));
      expect(child.first_name == "Vincent");
   };

   "run-time read_jmespath"_test = [] {
      Home home{.family = {.father = {"Gilbert", "Fox", 28},
                           .mother = {"Anne", "Fox", 30},
                           .children = {{"Lilly"}, {"Vincent"}}}};

      std::string buffer{};
      expect(not glz::write_json(home, buffer));

      std::string first_name{};
      auto ec = glz::read_jmespath("family.father.first_name", first_name, buffer);
      expect(not ec) << glz::format_error(ec, buffer);
      expect(first_name == "Gilbert");

      Person child{};
      expect(not glz::read_jmespath("family.children[0]", child, buffer));
      expect(child.first_name == "Lilly");
      expect(not glz::read_jmespath("family.children[1]", child, buffer));
      expect(child.first_name == "Vincent");
   };
};

by @stephenberry in #1509

Other Improvements

Full Changelog: v4.2.0...v4.2.1

v4.2.0

16 Dec 23:08
Compare
Choose a tag to compare

Breaking Partial Read Changes (Faster/Cleaner)

  • The option partial_read_nested has been removed, to simplify partial reading and bring better performance. If the option partial_read is true, then short circuiting will occur after the deepest value is read. This ensures that a true "partial" read occurs and post-read skipping is not necessary.
    • If you only want to read certain fields in a struct and perform this multiple times within a larger object, then use glz::skip or set error_on_unknown_keys = false. Either of these approaches will skip keys you don't care about.
  • The local metadata for static constexpr auto partial_read = true; will now be ignored. You must explicitly use glz::opts{.partial_read = true} in the Glaze options for partial reading.
    • The local meta parameter was a poor design choice, because we want to separate serialization logic from options, so that the same glz::meta information can be used with various options. It also complicated the code/API.

Tip

When setting up partial reading, it is best to just include the parts of the deepest structure you care about and the parent structures to that location. This ensures the most efficient traversal to the fields of interest and the least amount of C++ struct writing.

The documentation for partial reading has been updated here: [Partial Read](https://github.com/stephenberry/glaze/blob/main/docs/partial-read.md)

by @stephenberry in #1502

Improvements

  • Faster string skipping with SWAR in #1499

Full Changelog: v4.1.0...v4.2.0

v4.1.0

14 Dec 15:03
Compare
Choose a tag to compare

Improvements

  • Update to fast_float v7.0.0 in #1488
  • Adding example_json for newcomers to Glaze in #1490
  • Document glz::convert_struct in #1491
  • Faster skipping in #1495

New Reflection Feature

  • glz::for_each_field in #1497
struct test_type
{
   int32_t int1{};
   int64_t int2{};
};

test_type var{42, 43};

glz::for_each_field(var, [](auto& field) { field += 1; });

expect(var.int1 == 43);
expect(var.int2 == 44);

In Development (Breaking Changes)

glz::mustache has been renamed to glz::stencil along with all other associated names. The decision was made to make a more optimal approach that does not conform strictly to the mustache specification, with the long term goal of adding compile time options that satisfy full compliance. The more generally useful string interpolation will be named stencil and not automatically escape HTML characters.

Full Changelog: v4.0.3...v4.1.0

v4.0.3

12 Dec 15:40
Compare
Choose a tag to compare

Improvements

  • Support for nullable value types in #1460
    • This adds support for optional like types that cannot provide an operator bool() because that operator is reserved for some other action. This adds a nullable_value_t concept that only checks for value() and has_value().
  • Adding glz::convert_struct for reflection conversion in #1472
  • Faster glz::validate_json in #1478
  • Use constructible_from rather than convertible to string_view in #1486
  • Cleanup and minor optimizations by @stephenberry in #1461, #1462, #1464, #1475, #1479

Fixes

  • Fix issue with variants of 1 type and tags in #1485
  • validate_skipped for glz::validate_jsonc in #1476

In Development

  • Improvements to glz::async_map in #1465
  • async_map -> shared_async_map in #1469

Full Changelog: v4.0.2...v4.0.3

v4.0.2

02 Dec 14:51
Compare
Choose a tag to compare

Improvements

  • Faster JSON object reading in some cases in #1442
  • Simplified JSON read code in #1449
  • Adding title for json schema when writing variants in #1451

Fixes

  • Fixed volatile bug by @stephenberry in #1440
  • Handling for escaped string reading (at least for column wise CSV) in #1446
  • Avoiding _umul128, fallback to umul128_generic in MSYS2/MINGW32 by @jalius in #1453
  • Eigen check for get_member to avoid invocable branch in #1458

In Development

  • Asio improvementsin #1444
  • Use a single vector for async_map and support atomic (non-movable) types directly in #1456

Full Changelog: v4.0.1...v4.0.2

v4.0.1

13 Nov 20:55
Compare
Choose a tag to compare

Improvements

  • Integer assignment support for glz::json_t by @stephenberry in #1425
  • Using a compile time linear search for partial writing index finding in #1427

Fixes

  • Fix extra comma when unknown writer is empty in #1435
  • Fix number parsing for glz::raw_json by @stephenberry in #1432

In Development

  • Fix for asio_client call with no parameters in #1424
  • Fix invalid notify check on response rather than request in #1430
  • glz::async_map: using proxy rather than allocating unique_ptr in #1433

Full Changelog: v4.0.0...v4.0.1

v4.0.0

31 Oct 14:43
Compare
Choose a tag to compare

Glaze 4.0

This release brings a number of bug fixes with very few API breaking changes. The primary breaking change is a new integer parsing algorithm that is faster and rejects decimals and negative exponents to avoid implicit data loss.

New Integer Parsing Logic

When parsing integer types such as uint16_t or int64_t, Glaze will now reject decimal values and negative exponents, so a value such as 1.37 would produce a parse_number_failure. This is important for avoiding implicit data loss. Developers often need to handle these conversions in various ways. Sometimes it is better to round (with various methodologies), other times truncate, and other times use the ceiling. It is recommended to use floating point types if you do not know if you will be receiving decimal values. A glz::custom lambda in your meta can be used to invisibly convert a parsed floating point value into an integer if you do not wish to do this elsewhere.

We are open to requests for additional integer parsing options, but don't want to add complexity to Glaze unless there is a concrete need. So, please open an issue if this change causes problems.

By narrowing the definition of what it means to parse an integer in Glaze it will allow us to perform variant type deduction on integer vs floating point types. So, we will be able to parse either into an integer or a float in a variant. This has been requested a few times and would allow interfaces to avoid data loss with large integers and floating point decimal values simultaneously.

In summary, this change in integer parsing provides the benefits:

  • Faster integer parsing
  • No implicit data loss
  • Disambiguation of integers and floats in JSON parsing to support dual integer/float types in variants and full numeric integrity

Positive exponents are still handled for integer parsing, such as 1e9, which can save space and be easier to read than 1000000000.

This release has no effect on integer serialization. Round-tripping in Glaze has not been affected.

Breaking Changes

  • String support for std::array<char, N> in #1247
    std::array<char, N> is now treated as a string type rather than an array of single character strings.

  • Roundtrip support for vector<pair>, better concatenate option support, and BEVE support for these in #1418
    When reading in a vector<pair> type objects are by default expected to be concatenated (as they are for output). The concatenate option must be set to false to read in a non-concatenated vector of pairs. Now both the concatenate = true and concatenate = false conditions properly roundtrip for both JSON and BEVE.

Improvements

  • json_t assignment operators and string_view constructor in #1412
  • Support for std::atomic in #1364
  • Use clang format 18.1 in #1374
  • Use jkj::dragonbox::to_decimal_ex for faster floating point serialization in #1392
  • Adding roundtrip format agnostic testing in #1380
  • Type "cls" or "clear" to bring the command line menu (glz::cli_menu) to the front in #1409

Fixes

  • Removing lots of noexcept qualifiers to allow exceptions to propagate when Glaze is used with exceptions enabled in #1420
  • Unknown fields fix with entirely null first object in #1367
  • [Concept update] string_t with resize also needs to have .data() by @sjanel in #1372
  • Support empty input NDJSON in #1381
  • Fix JSON RPC documentation link to json-rpc.cpp source by @pentatonick in #1385
  • Support reading into a const pointer to a member in #1387
  • Fix JSON parsing from arrays to set like types with custom structs by @sjanel in #1394
  • Put fast_float and dragonbox into glz namespace by @amosbird in #1398
  • Naming more things beve instead of binary in #1399
  • Using GLZ_ macro prefix for third party dependencies by @stephenberry in #1403
  • Add missing include inside of threadpool.hpp by @X-rays5 in #1413

Active Development (use at your own risk)

  • New binary REPE v1.0 spec implementation (repe::registry) in #1336
  • Capture functions by reference in repe::registry by @stephenberry in #1396
  • Removing repe::registry auto-locking in #1415

Full Changelog: v3.6.2...v4.0.0

v3.6.2

04 Oct 18:17
Compare
Choose a tag to compare

New AVX2 SIMD optimizations (faster string writing on some platforms)

The CMake now has the option glaze_ENABLE_AVX2. This will attempt to use AVX2 SIMD instructions in some cases to improve performance, as long as the system you are configuring on supports it. Set this option to OFF to disable the AVX2 instruction set, such as if you are cross-compiling for Arm. And, if you aren't using CMake the macro GLZ_USE_AVX2 enables the feature if defined.

Improvements

Fixes

  • Allow NDJSON in the skip_array requires statement. by @Haatschii in #1357

Full Changelog: v3.6.1...v3.6.2