mORMot2 DailyDaily read of upstream commits

Pascal numeric parsers are rewritten around faster integer paths

The Pascal implementations behind GetExtended and GetNumericVariantFromJson now keep common integer and short-decimal inputs on tighter loops, while preserving guarded handling for long mantissas, exponents and Int64 limits. The GetExtended tests also make zero-sign normalization and several 18–20 digit fractions explicit. There is no signature migration, but applications that depend on exact numeric variant types or floating-point edge cases should validate against build 2.4.16865.

TL;DR

  • Land on build 2.4.16865 and regression-test numeric conversion code that depends on exact variant types or boundary rounding.
  • The non-Win32 Pascal GetExtended path was streamlined twice, with separate fast loops for the first 18 digits, overflow-aware continuation, fractions and exponents.
  • GetExtended now intentionally normalizes -0 and -0e400 to numeric zero on its Pascal path, following the behavior recorded by the new tests.
  • GetNumericVariantFromJson unrolls its first digits and rewrites Int64, Currency and Double selection without changing its public signature.
  • mormot.core.base adds the public MIN_INT64 constant and the TSynVarData.VPtrInt overlay member.

Upgrade advice

Take build 2.4.16865 as the complete parser sequence. No broken intermediate range is identified in the raw payload, but the four commits are tightly coupled: the final JSON parser uses MIN_INT64 introduced immediately before it. Re-run tests for -0, Int64 extrema, long decimal mantissas, Currency values with up to four fractional digits, scientific notation and invalid JSON numbers on every Delphi and FPC backend you ship.

Build2.4.16861 → 2.4.16865
Commits4
Lines+307 -204
Read2 min

4 of 4 entries · 4 commits upstream

Stories
# Entry Category Units
1 Medium JSON numeric variants get an unrolled common-digit parser GetNumericVariantFromJson now unrolls its initial digit accumulation, processes later digits in paired and overflow-aware loops, handles MIN_INT64 with an explicit sentinel, and separates fraction and exponent validation. The result phase was rewritten around positive magnitude values for varInteger, varInt64, varCurrency and varDouble, including pointer-sized zero initialization through TSynVarData.VPtrInt. Performance mormot.core.variants c88c4ad7+170-93

core: rewritten GetNumericVariantFromJson()

Impact

All Delphi and FPC callers of the public function use the new Pascal implementation. The signature and accepted JSON grammar are unchanged in the diff, but the code deciding exact integer, Currency or Double storage has been substantially replaced; consumers that inspect TVarData.VType should regression-test representative boundaries. No benchmark result is included in the payload.

Worth a look

Test the returned VType and value around 32-bit, Int64 and Currency limits, plus long mantissas and signed exponent forms.

Arnaud Bouchez · 21:15 UTC · view the commit on GitHub →

2 Medium GetExtended removes work from common integer and decimal paths The non-WIN32DELPHI GetExtended parser replaces several signed counters and temporary floating-point values with PtrUInt digit handling, returns integers and zero directly, and folds power-of-ten scaling into fewer operations. Its NAN/INF probe now reads a two-byte prefix before checking the third character. The same commit documents why the JSON numeric parser divides by exact powers for short negative exponents. Performance mormot.core.text+1 700177da+64-74

core: slightly optimized GetExtended() code

Impact

FPC and non-Win32 Delphi builds use the streamlined Pascal path; Delphi Win32 continues to use its x87 assembly implementation. The public signatures remain unchanged. The direct zero path normalizes negative zero, a behavior made explicit by the next commit’s tests.

Worth a look

Include signed zero and representative exponent boundaries in parser regression tests before upgrading.

Public API

  • GetExtendedbehaviour-changed — The Pascal path normalizes -0 and zero with an exponent to numeric zero; signatures are unchanged.

Arnaud Bouchez · 08:21 UTC · view the commit on GitHub →

3 Medium GetExtended splits fast digits from overflow-aware parsing The Pascal GetExtended implementation is rewritten again: the first 18 integer digits are accumulated without overflow checks, later digits use a guarded loop, excess significant digits are skipped while their decimal position is retained, and fractional and exponent syntax have dedicated validation. Tests add long fractional boundary cases, invalid -e1 and .e2 inputs, and the expected normalization of -0e400. Performance mormot.core.text 71129606+66-33

core: rewritten GetExtended() pascal

Impact

This is the final GetExtended implementation in the edition and it broadens regression coverage around 18–20 significant digits. It affects FPC and non-Win32 Delphi parsing performance and edge results; Delphi Win32 keeps its assembly path. No caller source change is required.

Worth a look

Re-run exact-bit conversion tests for long mantissas, subnormals and exponent limits on non-Win32 targets.

Arnaud Bouchez · 09:47 UTC · view the commit on GitHub →

4 Low MIN_INT64 and a pointer-sized variant overlay become public mormot.core.base adds MIN_INT64 beside MAX_INT64 and adds VPtrInt under the varOleInt arm of TSynVarData. TRestStorageInMemory.FindMax uses the named constant instead of low(Int64), and a GetExtended comment clarifies why its Pascal loop is not unrolled like the JSON parser. New features mormot.core.base+2 e5746e2f+7-4

core: minor refactoring including new MIN_INT64 constant

Impact

Existing ORM behavior is unchanged. Library and application code can now use a named signed 64-bit minimum and can clear or access the pointer-sized integer storage of TSynVarData directly. The additions compile according to PtrInt width on Delphi and FPC.

Public API

  • MIN_INT64added — Public constant equal to low(Int64).
  • TSynVarData.VPtrIntadded — Pointer-sized integer view added to the varOleInt overlay arm.

Arnaud Bouchez · 15:04 UTC · view the commit on GitHub →

Upstream activity commits per day · last 60 days
Commits977
Active days44/60
Busiest2026-09-30
Peak60
2026-08-15: 0 commits2026-08-16: 0 commits2026-08-17: 0 commits2026-08-18: 0 commits2026-08-19: 0 commits2026-08-20: 0 commits2026-08-21: 0 commits2026-08-22: 0 commits2026-08-23: 0 commits2026-08-24: 0 commits2026-08-25: 0 commits2026-08-26: 0 commits2026-08-27: 26 commits2026-08-28: 11 commits2026-08-29: 10 commits2026-08-30: 1 commit2026-08-31: 23 commits2026-09-01: 0 commits2026-09-02: 20 commits2026-09-03: 29 commits2026-09-04: 35 commits2026-09-05: 13 commits2026-09-06: 0 commits2026-09-07: 0 commits2026-09-08: 23 commits2026-09-09: 10 commits2026-09-10: 17 commits2026-09-11: 23 commits2026-09-12: 14 commits2026-09-13: 9 commits2026-09-14: 7 commits2026-09-15: 4 commits2026-09-16: 24 commits2026-09-17: 26 commits2026-09-18: 21 commits2026-09-19: 59 commits2026-09-20: 13 commits2026-09-21: 5 commits2026-09-22: 34 commits2026-09-23: 17 commits2026-09-24: 57 commits2026-09-25: 22 commits2026-09-26: 26 commits2026-09-27: 0 commits2026-09-28: 2 commits2026-09-29: 19 commits2026-09-30: 60 commits2026-10-01: 26 commits2026-10-02: 30 commits2026-10-03: 32 commits2026-10-04: 15 commits2026-10-05: 1 commit2026-10-06: 26 commits2026-10-07: 37 commits2026-10-08: 27 commits2026-10-09: 35 commits2026-10-10: 33 commits2026-10-11: 9 commits2026-10-12: 11 commits2026-10-13: 35 commits
2026-08-152026-10-13