aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util/filesystem.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-18 15:03:55 +0900
committernsfisis <nsfisis@gmail.com>2026-07-18 15:54:27 +0900
commit91692846909ed191addb7ec1c34aad11392ab88b (patch)
tree7c477055e432fd43a98e5dddc016e07dcfc67f60 /crates/shirabe/src/util/filesystem.rs
parent4ae58baf8618f5fe916ba2a69faaca93514134ce (diff)
downloadphp-shirabe-91692846909ed191addb7ec1c34aad11392ab88b.tar.gz
php-shirabe-91692846909ed191addb7ec1c34aad11392ab88b.tar.zst
php-shirabe-91692846909ed191addb7ec1c34aad11392ab88b.zip
perf(regex): eliminate per-call clone overhead in preg_* dispatch
regex::Regex::clone() does not share the underlying meta engine's search-cache pool, so every fresh clone pays a ~10us warmup cost on its first use. Two changes together eliminate this across nearly all preg_* call sites: - A php_regex! macro resolves PHP-style patterns to a per-call-site &'static regex::Regex (via regex-macro's LazyLock), applied at the majority of call sites throughout the codebase. - Call sites still passing dynamic pattern strings go through PATTERN_CACHE, which now stores Arc<(Regex, bool)> and hands out Arc::clone()s instead of cloning the Regex itself. PregPattern::resolve() returns a ResolvedPattern enum (Arc or 'static reference) rather than an owned Regex, so neither path ever clones the Regex proper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/util/filesystem.rs')
-rw-r--r--crates/shirabe/src/util/filesystem.rs32
1 files changed, 19 insertions, 13 deletions
diff --git a/crates/shirabe/src/util/filesystem.rs b/crates/shirabe/src/util/filesystem.rs
index d21a0e7d..b92bee94 100644
--- a/crates/shirabe/src/util/filesystem.rs
+++ b/crates/shirabe/src/util/filesystem.rs
@@ -11,9 +11,9 @@ use shirabe_php_shim::{
basename, chdir, clearstatcache, clearstatcache2, copy, dirname, error_get_last, explode,
fclose, feof, file_exists, file_get_contents, file_put_contents, fileatime, filemtime,
filesize, fopen, fread, function_exists, fwrite, implode, is_dir, is_file, is_link,
- is_readable, lstat, mkdir, rename, rmdir, rtrim, str_contains, str_repeat, str_replace,
- str_starts_with, strlen, strpos, strtoupper, strtr, substr, substr_count, symlink, touch,
- unlink, usleep, var_export,
+ is_readable, lstat, mkdir, php_regex, rename, rmdir, rtrim, str_contains, str_repeat,
+ str_replace, str_starts_with, strlen, strpos, strtoupper, strtr, substr, substr_count, symlink,
+ touch, unlink, usleep, var_export,
};
use std::path::Path;
@@ -227,7 +227,7 @@ impl Filesystem {
return Ok(Some(true));
}
- if Preg::is_match3("{^(?:[a-z]:)?[/\\\\]+$}i", directory, None) {
+ if Preg::is_match3(php_regex!("{^(?:[a-z]:)?[/\\\\]+$}i"), directory, None) {
return Err(RuntimeException {
message: format!("Aborting an attempted deletion of {}, this was probably not intended, if it is a real use case please report it.", directory),
code: 0,
@@ -592,7 +592,7 @@ impl Filesystem {
let mut common_path = to.clone();
while strpos(&format!("{}/", from), &format!("{}/", common_path)) != Some(0)
&& "/" != common_path
- && !Preg::is_match3("{^[A-Z]:/?$}i", &common_path, None)
+ && !Preg::is_match3(php_regex!("{^[A-Z]:/?$}i"), &common_path, None)
{
common_path = strtr(&dirname(&common_path), "\\", "/");
}
@@ -649,7 +649,7 @@ impl Filesystem {
let mut common_path = to.clone();
while strpos(&format!("{}/", from), &format!("{}/", common_path)) != Some(0)
&& "/" != common_path
- && !Preg::is_match3("{^[A-Z]:/?$}i", &common_path, None)
+ && !Preg::is_match3(php_regex!("{^[A-Z]:/?$}i"), &common_path, None)
&& "." != common_path
{
common_path = strtr(&dirname(&common_path), "\\", "/");
@@ -756,7 +756,7 @@ impl Filesystem {
String,
> = indexmap::IndexMap::new();
if Preg::is_match3(
- "{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix",
+ php_regex!("{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix"),
&path,
Some(&mut prefix_match),
) {
@@ -785,7 +785,7 @@ impl Filesystem {
// ensure c: is normalized to C:
prefix = Preg::replace_callback(
- "{(^|://)[a-z]:$}i",
+ php_regex!("{(^|://)[a-z]:$}i"),
|m: &indexmap::IndexMap<
shirabe_external_packages::composer::pcre::CaptureKey,
String,
@@ -808,7 +808,7 @@ impl Filesystem {
/// And other possible unforeseen disasters, see https://github.com/composer/composer/pull/9422
pub fn trim_trailing_slash(path: &str) -> String {
let mut path = path.to_string();
- if !Preg::is_match3("{^[/\\\\]+$}", &path, None) {
+ if !Preg::is_match3(php_regex!("{^[/\\\\]+$}"), &path, None) {
path = rtrim(&path, Some("/\\"));
}
@@ -821,14 +821,16 @@ impl Filesystem {
// on linux as file:////foo (which would be a network path \\foo on windows) will resolve to /foo which could be a local path
if Platform::is_windows() {
return Preg::is_match3(
- "{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\\.\\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i",
+ php_regex!(
+ "{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\\.\\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i"
+ ),
path,
None,
);
}
Preg::is_match3(
- "{^(file://|/|/?[a-z]:[\\\\/]|\\.\\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i",
+ php_regex!("{^(file://|/|/?[a-z]:[\\\\/]|\\.\\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i"),
path,
None,
)
@@ -837,10 +839,14 @@ impl Filesystem {
pub fn get_platform_path(path: &str) -> String {
let mut path = path.to_string();
if Platform::is_windows() {
- path = Preg::replace("{^(?:file:///([a-z]):?/)}i", "file://$1:/", &path);
+ path = Preg::replace(
+ php_regex!("{^(?:file:///([a-z]):?/)}i"),
+ "file://$1:/",
+ &path,
+ );
}
- Preg::replace("{^file://}i", "", &path)
+ Preg::replace(php_regex!("{^file://}i"), "", &path)
}
/// Cross-platform safe version of is_readable()