diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-19 23:45:38 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-19 23:45:38 +0900 |
| commit | 325c75b58c05e9ef8fed51c05609dfc2bfed112d (patch) | |
| tree | d96f79864ebf51a164da50c4dd0d062c3fd70a6b | |
| parent | 95bb4d31909367597f71e8e0c90e008d25945dd3 (diff) | |
| download | php-shirabe-325c75b58c05e9ef8fed51c05609dfc2bfed112d.tar.gz php-shirabe-325c75b58c05e9ef8fed51c05609dfc2bfed112d.tar.zst php-shirabe-325c75b58c05e9ef8fed51c05609dfc2bfed112d.zip | |
perf(semver): memoize MultiConstraint's string form
composer/semver memoizes MultiConstraint::__toString() into $this->string, but
the port recomputed it on every call. On `require laravel/laravel` that meant
837k stringifications visiting 1.7M child constraints, all of them feeding the
CompilingMatcher and Intervals cache keys.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| -rw-r--r-- | crates/shirabe-semver/src/constraint/multi_constraint.rs | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/crates/shirabe-semver/src/constraint/multi_constraint.rs b/crates/shirabe-semver/src/constraint/multi_constraint.rs index 4e9b8cf5..30c2edd6 100644 --- a/crates/shirabe-semver/src/constraint/multi_constraint.rs +++ b/crates/shirabe-semver/src/constraint/multi_constraint.rs @@ -4,11 +4,13 @@ use crate::constraint::AnyConstraint; use crate::constraint::Bound; use crate::constraint::MatchAllConstraint; use shirabe_php_shim::CmpOp; +use std::sync::OnceLock; #[derive(Debug, Clone)] pub struct MultiConstraint { pub(crate) constraints: Vec<AnyConstraint>, pub(crate) pretty_string: Option<String>, + string: OnceLock<String>, pub(crate) conjunctive: bool, } @@ -28,6 +30,7 @@ impl MultiConstraint { Self { constraints, pretty_string, + string: OnceLock::new(), conjunctive, } } @@ -251,8 +254,11 @@ impl MultiConstraint { impl std::fmt::Display for MultiConstraint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let parts: Vec<String> = self.constraints.iter().map(|c| c.to_string()).collect(); - let sep = if self.conjunctive { " " } else { " || " }; - write!(f, "[{}]", parts.join(sep)) + let string = self.string.get_or_init(|| { + let parts: Vec<String> = self.constraints.iter().map(|c| c.to_string()).collect(); + let sep = if self.conjunctive { " " } else { " || " }; + format!("[{}]", parts.join(sep)) + }); + f.write_str(string) } } |
