aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-19 23:45:37 +0900
committernsfisis <nsfisis@gmail.com>2026-08-19 23:45:37 +0900
commit95bb4d31909367597f71e8e0c90e008d25945dd3 (patch)
treec3fac2f9e6bd9718c17358d56b017aa5b4bc4dd2
parent0800c90a7ec0bc7a3d4c13063dfe6d2298a557bc (diff)
downloadphp-shirabe-95bb4d31909367597f71e8e0c90e008d25945dd3.tar.gz
php-shirabe-95bb4d31909367597f71e8e0c90e008d25945dd3.tar.zst
php-shirabe-95bb4d31909367597f71e8e0c90e008d25945dd3.zip
perf(php-src): stop collecting version tokens into vectors
php_version_compare canonicalized both operands into a Vec<&str> and copied the canonicalized bytes a second time through from_utf8_lossy().into_owned(). Walk the split iterators directly and move the Vec<u8> into the String, which takes the per-call allocation count from six down to two. Splits are only ever inserted at ASCII digit boundaries, so the buffer is always valid UTF-8. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
-rw-r--r--crates/shirabe-php-src/src/standard/versioning.rs28
1 files changed, 16 insertions, 12 deletions
diff --git a/crates/shirabe-php-src/src/standard/versioning.rs b/crates/shirabe-php-src/src/standard/versioning.rs
index 27f06309..8dadaafc 100644
--- a/crates/shirabe-php-src/src/standard/versioning.rs
+++ b/crates/shirabe-php-src/src/standard/versioning.rs
@@ -1,7 +1,7 @@
/// php-src: ext/standard/versioning.c `php_version_compare` (PHP 8.5.2)
///
/// Returns -1, 0 or 1. The original walks the canonicalized strings with destructive `.` splits
-/// and moving pointers; this splits into a `Vec<&str>` and indexes instead.
+/// and moving pointers; this walks a `split('.')` iterator over each instead.
pub fn php_version_compare(v1: &str, v2: &str) -> i32 {
if v1.is_empty() || v2.is_empty() {
return match (v1.is_empty(), v2.is_empty()) {
@@ -12,27 +12,29 @@ pub fn php_version_compare(v1: &str, v2: &str) -> i32 {
}
let c1 = canonicalize_version(v1);
let c2 = canonicalize_version(v2);
- let t1: Vec<&str> = c1.split('.').filter(|s| !s.is_empty()).collect();
- let t2: Vec<&str> = c2.split('.').filter(|s| !s.is_empty()).collect();
+ let mut t1 = c1.split('.').filter(|s| !s.is_empty());
+ let mut t2 = c2.split('.').filter(|s| !s.is_empty());
let mut compare = 0;
- let mut i = 0;
- while i < t1.len() && i < t2.len() && compare == 0 {
- compare = version_token_compare(t1[i], t2[i]);
- i += 1;
+ let mut p1 = t1.next();
+ let mut p2 = t2.next();
+ while compare == 0
+ && let (Some(a), Some(b)) = (p1, p2)
+ {
+ compare = version_token_compare(a, b);
+ p1 = t1.next();
+ p2 = t2.next();
}
if compare == 0 {
// A leftover numeric token wins; a leftover special form is compared against the implicit
// release baseline ("#", order 4).
- if i < t1.len() {
- let p = t1[i];
+ if let Some(p) = p1 {
compare = if p.as_bytes()[0].is_ascii_digit() {
1
} else {
special_form_order(p).cmp(&4) as i32
};
- } else if i < t2.len() {
- let p = t2[i];
+ } else if let Some(p) = p2 {
compare = if p.as_bytes()[0].is_ascii_digit() {
-1
} else {
@@ -72,7 +74,9 @@ fn canonicalize_version(version: &str) -> String {
q.push(ch);
}
}
- String::from_utf8_lossy(&q).into_owned()
+ // Splits are only ever inserted at ASCII digit <-> non-digit boundaries, which are always
+ // char boundaries, so a valid UTF-8 input stays valid.
+ String::from_utf8(q).expect("canonicalized version is valid UTF-8")
}
/// php-src: ext/standard/versioning.c `php_version_compare` loop body (PHP 8.5.2)