diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-19 23:45:37 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-19 23:45:37 +0900 |
| commit | 95bb4d31909367597f71e8e0c90e008d25945dd3 (patch) | |
| tree | c3fac2f9e6bd9718c17358d56b017aa5b4bc4dd2 /crates/shirabe-php-src/src/standard/versioning.rs | |
| parent | 0800c90a7ec0bc7a3d4c13063dfe6d2298a557bc (diff) | |
| download | php-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>
Diffstat (limited to 'crates/shirabe-php-src/src/standard/versioning.rs')
| -rw-r--r-- | crates/shirabe-php-src/src/standard/versioning.rs | 28 |
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) |
