In gsub is used with a string replacement or a map that doesn't
have a default proc, we know for sure no code can cause the MatchData
to escape the `gsub` call.
In such case, we still have to allocate a new MatchData because we
don't know what is the lifetime of the backref, but for any subsequent
match we can re-use the MatchData we allocated ourselves, reducing
allocations significantly.
This partially fixes [Misc #20652], except when a block is used,
and partially reduce the performance impact of
abc0304cb2 / [Bug #17507]
```
compare-ruby: ruby 3.5.0dev (2025-02-24T09:44:57Z master 5cf146399f) +PRISM [arm64-darwin24]
built-ruby: ruby 3.5.0dev (2025-02-24T10:58:27Z gsub-elude-match da966636e9) +PRISM [arm64-darwin24]
warming up....
| |compare-ruby|built-ruby|
|:----------------|-----------:|---------:|
|escape | 3.577k| 3.697k|
| | -| 1.03x|
|escape_bin | 5.869k| 6.743k|
| | -| 1.15x|
|escape_utf8 | 3.448k| 3.738k|
| | -| 1.08x|
|escape_utf8_bin | 6.361k| 7.267k|
| | -| 1.14x|
```
Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
According to MSVC manual (*1), cl.exe can skip including a header file
when that:
- contains #pragma once, or
- starts with #ifndef, or
- starts with #if ! defined.
GCC has a similar trick (*2), but it acts more stricter (e. g. there
must be _no tokens_ outside of #ifndef...#endif).
Sun C lacked #pragma once for a looong time. Oracle Developer Studio
12.5 finally implemented it, but we cannot assume such recent version.
This changeset modifies header files so that each of them include
strictly one #ifndef...#endif. I believe this is the most portable way
to trigger compiler optimizations. [Bug #16770]
*1: https://docs.microsoft.com/en-us/cpp/preprocessor/once
*2: https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
These headers need no rewrite. Just add some minor tweaks, like
addition of #include lines. Mainly cosmetic.
TIMET_MAX_PLUS_ONE was deleted because the macro was used from only
one place (directly write expression there).
One day, I could not resist the way it was written. I finally started
to make the code clean. This changeset is the beginning of a series of
housekeeping commits. It is a simple refactoring; split internal.h into
files, so that we can divide and concur in the upcoming commits. No
lines of codes are either added or removed, except the obvious file
headers/footers. The generated binary is identical to the one before.