Skip to content

Commit

Permalink
Reimplement quoteWith() to use less memory and improve performance
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Jan 2, 2025
1 parent d60bfd4 commit 5ed2460
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 6 deletions.
13 changes: 7 additions & 6 deletions src/public.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ function re_quote(string $pattern, array $literals = []): string {
}

function quoteWith(string $pattern, array $literals, string $delimiter, string $placeholder): string {
$result = \implode('', \array_map(
fn(string $p, ?string $v) => $p . $v,
\explode($placeholder, $pattern),
\array_map(fn(string $value) => preg_quote($value, $delimiter), $literals),
));
return $delimiter . $result . $delimiter;
$count = 0;
while (($pos = \strPos($pattern, $placeholder)) !== false) {
$quoted = \preg_quote($literals[$count], $delimiter);
$pattern = \subStr_replace($pattern, $quoted, $pos, \strLen($placeholder));
++$count;
}
return $delimiter . $pattern . $delimiter;
}
27 changes: 27 additions & 0 deletions test/Benchmark.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
namespace Test;

use PHPUnit\Framework\Assert;

class Benchmark
{
public static function run(int $iterations, callable $block): void {
$values = \array_map(
fn() => self::benchmarkSample($iterations, $block),
range(1, 10));
Assert::fail(
"Avg: " . (array_sum($values) / count($values)) . "\n" .
"Samples: " . var_export($values, true) . "\n",
);
}

private static function benchmarkSample(int $iterations, callable $block): float {
$start = \microTime(true);
foreach (range(0, $iterations) as $_) {
$block();
}
$end = \microTime(true);
\usleep(1000 * 50);
return $end - $start;
}
}
8 changes: 8 additions & 0 deletions test/QuoteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@ public function quotedValue_isQuotedWithDelimiter(): void {
public function leadingSlash_isNotNaivelyMistookForDelimitedPattern(): void {
re_test('/abc', '/abc');
}

#[Test]
public function benchmark(): void {
$this->markTestSkipped('Benchmark');
$longString = str_repeat('two', 50);
$literals = ["Three", $longString, $longString];
Benchmark::run(85 * 1000, fn() => re_quote('@ one @ two @', $literals));
}
}

0 comments on commit 5ed2460

Please sign in to comment.