A particularly satisfying patch to Oak today, ec3a188a. It simplifies implementations of the standard library's str.startsWith?
and str.endsWith?
.
Before, these functions compared both strings byte-by-byte, short-circuiting the loop if any mismatch was found. This was theoretically more efficient than comparing an entire substring to the given substring, because of the short-circuiting possibility. But in practice, the overhead of the extra VM ops when evaluating such iteration negated any gains.
Now, these functions create substrings of the original string that should equal the given prefix or suffix, and do a single, simple string comparison delegated to the underlying runtime. As a bonus, these one-line implementations are very simple and easy on the eyes.
fn startsWith?(s, prefix) s |> slice(0, len(prefix)) = prefix
fn endsWith?(s, suffix) s |> slice(len(s) - len(suffix)) = suffix
Especially on long inputs, the efficiency gain is significant:
Benchmark 1: oak input.oak (old implementation)
Time (mean ± σ): 3.197 s ± 0.010 s [User: 3.792 s, System: 0.200 s]
Range (min … max): 3.179 s … 3.214 s 10 runs
Benchmark 2: ./oak input.oak (new implementation)
Time (mean ± σ): 2.141 s ± 0.024 s [User: 2.539 s, System: 0.144 s]
Range (min … max): 2.117 s … 2.187 s 10 runs
Summary
'./oak input.oak' ran
1.49 ± 0.02 times faster than 'oak input.oak'