Standard string formatting functions cannot do without heap, unlike Delphi

Summary

In FPC, all of the RTL string formatting functions are based on top of SysUtils.Format() implementation. The problem is that Format(), by its very signature, has to use managed strings, allocating heap memory. Because of this, they are inapplicable in cases and situations when and where the heap is scarce or unavailable at all, possibly depleted, maybe even damaged.

Furthermore, this requirement is thus imposed on SysUtils.FormatBuf(), forcing it to craft new string values from the already existing and available data, making it essentially useless and also doubling its memory consumption.
https://gitlab.com/freepascal.org/fpc/source/-/blob/3c7d0cbe27aae00041c2ae53695165a828425e17/rtl/objpas/sysutils/sysstr.inc#L1203-1225

Delphi Runtime Library, by contrast, has its general implementation of string formatting in FormatBuf(), which allows any scenarios, including stack-only ones. The managed strings are hence adapted to it with code in SysUtils.FmtStr(), while Format() being just a single-line wrapper around it, because it's more efficient to repurpose an existing string for the result value than allocate a new one.

System Information

  • Compiler version: 3.2.2, trunk (3c7d0cbe)

Possible fixes

Do what Delphi does. Fixing this is necessary to resolve #41467.

It is worth noting that Delphi's approach can be improved. According to SysUtils.pas from Delphi 2010, FmtStr() guesses the size for the output buffer through trial-and-error so that it would be greater than, but not equal to, the value FormatBuf() returns. This is slow, but there is a better way - calculate the required size once from the format string, similar to calling std::snprintf() with no buffer in C/C++. Would be neat to have this in RTL as a separate public function, perhaps in StrUtils instead of SysUtils.

Edited by Dmitry D. Chernov