Commit Graph
12807 Commits
Author SHA1 Message Date
Barna Kovacs 01ff4a5ec2 Reuse the top non-empty list descriptor (#15785)
Avoid rebuilding and hashing the canonical non-empty list top leaf when the tail is term().

Assisted-by: Codex:GPT-5
2026-08-23 18:21:10 +02:00
José Valim 63a7a054ce Remove none clauses if there are non empty clauses, closes #15777 2026-08-22 12:00:55 +02:00
José Valim 583150d002 Extract domain computation into a separate function 2026-08-22 12:00:55 +02:00
José Valim 6e05add26b Extract clause grouping into a separate function 2026-08-22 12:00:55 +02:00
Dino Kovač 4f0c820624 Add DateTime add/4 and shift_zone/3 UTC fast path (#15779) 2026-08-22 10:02:25 +02:00
Daniel KukulaandClaude Opus 5 11b7f08b0b Trim trailing whitespace without slicing per step (#15780)
trim_trailing/1 walked the string with binary_part/3, which allocated the
three byte lookahead plus a fresh prefix on every step even though every
prefix but the last one is discarded, and paid one allocation even when
there was nothing to trim.

Carry the position instead and slice once at the end. The six one-byte
whitespace codepoints, which are the common case, now need no lookahead at
all, so the lookahead tables only hold the multi-byte ones.

Dispatching on the byte with :binary.at/2 instead of matching the string is
what makes the common path free. Matching turns the argument into a match
context, and a clause returning the string unchanged then has to materialize
it again, which is the allocation we are trying to avoid.

Measured on OTP 29, ns/op and words allocated per call:

                          before        after
  100B, nothing to trim   47.6 / 8w    16.0 / 0w
  1KB, nothing to trim    47.4 / 8w    16.2 / 0w
  100B + one space        73.2 / 21w   41.4 / 5w
  100B + four spaces     104.4 / 34w   83.2 / 5w
  100B + NBSP             71.8 / 21w   60.9 / 13w
  100B + 64 spaces       754.8 / 294w 887.8 / 5w

Trimming every line of lib/elixir/lib/kernel.ex drops from 0.442ms to
0.134ms, and 2000 lines ending in a newline from 0.282ms to 0.094ms.

The trade-off is the last row. The old code advanced up to three bytes per
iteration through the lookahead table where this one advances one byte at a
time, so runs longer than about five whitespace bytes lose time, 15% to 20%
on a 64 byte run. Allocation on that run goes from O(n) to O(1), and long
trailing runs are rare next to lines ending in a single newline or in
nothing at all.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 00:57:08 +02:00
Thomas Cioppettini 30af9521cf Remove duplicate pattern compilation in Unicode data processing (#15776)
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: Thomas Cioppettini <544875+tomciopp@users.noreply.github.com>
2026-08-21 09:14:19 +02:00
Daniel Kukula 5d605debe1 Fix base64 swar singleton false positive (#15773) 2026-08-21 09:13:59 +02:00
Hasan mohamed 345507aca9 Fix type checker crash on non-returning for ... into: expression (#15747) (#15770) 2026-08-20 22:39:18 +02:00
Thomas Cioppettini c4b42ddbbe Add unit fast paths to Calendar.ISO.iso_days_to_unit/2 (#15771)
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: Thomas Cioppettini <544875+tomciopp@users.noreply.github.com>
2026-08-20 22:35:19 +02:00
Barna Kovacs 15572f54c1 Remove redundant list construction in String.replace (#15769) 2026-08-20 15:05:07 +02:00
José Valim fee29461cb Update docs logo 2026-08-20 14:20:40 +02:00
Daniel Kukula 4616a06f73 Optimize Macro.classify_atom (#15768)
Atoms made exclusively of ASCII letters, numbers and underscores, beginning
with a lowercase letter or underscore and optionally ending with ? or !, are
always identifiers, and only atoms prefixed by "Elixir" are candidates for
aliases. Recognizing both directly on the binary avoids building a charlist
and running the unicode aware identifier tokenizer, which dominates the cost
of classifying keyword list, map and struct keys when inspecting them.
2026-08-19 19:26:59 +02:00
Daniel Kukula 6cde8680ab Remove intermediate list in elixir_interpolation hex_to_int (#15767) 2026-08-18 17:36:38 +02:00
Thomas Cioppettini cb5fb8e2e0 perf: Copy file mode with chmod instead of stat and write_stat (#15754) 2026-08-18 17:26:11 +02:00
Daniel Kukula 11e920f9e4 Fast path for unescape_char/2 (#15766) 2026-08-18 17:25:48 +02:00
Thomas Cioppettini 02124013de Replace protocol dispatch with arithmetic in Access.slice/1 (#15764)
Assisted-by: Claude Code:claude-fable-5

Signed-off-by: Thomas Cioppettini <544875+tomciopp@users.noreply.github.com>
2026-08-16 21:24:13 +02:00
Barna Kovacs 11d2adf0ce Optimize Time.compare/2 (#15763) 2026-08-16 14:08:20 +02:00
Barna Kovacs c62216d7cb Optimize Date.compare/2 (#15762) 2026-08-16 13:27:02 +02:00
José Valim 9417808a56 Shift by unit in more occasions 2026-08-16 12:45:46 +02:00
Thomas Cioppettini 2db772efa6 perf: Add exact fast paths to Calendar.ISO.add_day_fraction_to_iso_days (#15759) 2026-08-16 12:24:12 +02:00
Thomas Cioppettini 82196d2bd9 fix: Range.disjoint?/2 for ranges beyond float precision (#15760) 2026-08-16 08:42:59 +02:00
Thomas Cioppettini 99b6970093 perf: Remove unused length computation in List.myers_difference (#15753) 2026-08-16 08:40:48 +02:00
Thomas Cioppettini f3a86d828b perf: Avoid intermediate charlist in String.downcase/upcase with :ascii (#15755) 2026-08-16 08:40:26 +02:00
Thomas Cioppettini 5b682995bf perf: Avoid copying the list in List.pop_at/3 for out-of-bounds indexes (#15756) 2026-08-16 08:28:59 +02:00
Thomas Cioppettini a6e7663f8f perf: Add accumulator free fast paths to Macro.prewalk/2 and postwalk/2 (#15758) 2026-08-16 08:27:52 +02:00
Thomas Cioppettini cf7e87a637 perf: Skip no-op microsecond step in Calendar.ISO shift functions (#15752) 2026-08-16 08:19:44 +02:00
Barna Kovacs a704e91133 Precompute ANSI escape sequences at compile time (#15749)
Assisted-by: Antigravity:Gemini-3.7-Flash
2026-08-14 17:38:18 +02:00
Eric Meadows-Jönsson a357d19110 Optimize comparison of parsed versions (#15748) 2026-08-14 07:06:30 -07:00
Thomas Cioppettini 7c4552c156 Avoid system_info call on every regex operation (#15745) 2026-08-14 13:16:24 +02:00
Alexander Gubarev bc7844c26c Fix Date.to_iso8601/2 loses :format with custom calendar (#15740) 2026-08-13 21:39:28 +02:00
Barna Kovacs f67cbf14a6 Optimize URI.append_query field access (#15741) 2026-08-13 21:03:00 +02:00
Andrea Leopardi a89dcdc865 Improve Enum.min_max* specs (#15739) 2026-08-13 10:44:35 +02:00
Alexander Gubarev c929e885bb Fix struct key malformed error message (#15735) 2026-08-12 23:46:03 +02:00
Alexander Gubarev 7bf65189db Fix Task.yield_many/2 waits too long or forever when :limit exceeds task count (#15737) 2026-08-12 20:51:46 +02:00
Nelson Vides f316902a80 Optimize URI.encode_www_form/1 and RFC 3986 query encoding (#15736)
Both encoders were built on a binary comprehension whose body calls
`percent/2` through a captured predicate:

    for <<byte <- string>>, into: "" do
      case percent(byte, &char_unreserved?/1) do
        "%20" -> "+"
        percent -> percent
      end
    end

`for ... into: ""` over a binary generator compiles to a native Erlang
bitstring comprehension, so the comprehension itself is fine, but in the
body it pays per byte a `make_fun3` to build the captured predicate, a
call to `percent/2` plus an indirect call through it, a freshly
allocated one- or three-byte binary that is discarded immediately, an
`is_eq_exact` against the literal "%20", and a runtime-sized
`bs_create_bin` to append the result.

Rewrite it as a tail-recursive loop that writes the escape straight into
the accumulator. The unreserved test moves into a `defguardp` so it
inlines instead of going through a closure, `+` is handled by its own
clause rather than by comparing the produced binary against "%20", and
the appended segments have compile-time-known sizes.
2026-08-12 18:31:55 +02:00
José Valim b911bb0380 Raise when | is used in guards, closes #15734 2026-08-12 07:42:25 +02:00
José Valim 6ef6f78206 Properly escape unicode codepoints above ASCII range 2026-08-11 17:10:23 +02:00
José Valim 024beb1bfc Update design-anti-patterns.md 2026-08-10 14:21:53 +02:00
Mikhail Nekrashevich 44085d4347 Escape C1 control characters with Unicode escapes (#15726)
Assisted-by: Codex:GPT-5
2026-08-09 09:21:22 +02:00
makoto-developer 0bd52d4a7e Only use do-end blocks when every trailing keyword is a block keyword (#15725) 2026-08-08 09:05:26 +02:00
Daniel Kukula 48c515f994 Remove accumulator from parse_digits, reuse all_digits? function (#15722) 2026-08-07 20:23:14 +02:00
Daniel Kukula 81fb10eec8 Remove accumulator from parse_microsecond, use binary_part (#15723) 2026-08-07 20:22:11 +02:00
Alexander Gubarev 8b584147e8 Validate microseconds in Time.from_seconds_after_midnight/3 (#15721) 2026-08-07 18:09:37 +02:00
Jonatan Männchen 5e7cb9a707 Add Path.safe_join/2 (#15720) 2026-08-07 15:57:22 +02:00
José Valim 2971952edc Fix escaping of literal interpolated strings, closes #15718 2026-08-07 12:28:51 +02:00
José Valim 309bb8a875 Unpack guard operations from all modules 2026-08-07 12:28:51 +02:00
Daniel Kukula e697189e3b Remove intermediate list in float parse (#15719) 2026-08-07 10:33:00 +02:00
makoto-developer 79cf2ffa15 Fix System.stacktrace arity in the table of deprecations (#15713) 2026-08-04 08:34:01 +02:00
makoto-developer d5f4d491c9 Fix Kernel.SpecialForms references in Macro.Env docs (#15712) 2026-08-03 10:38:50 +02:00