function Intervals::compactConstraint
Attempts to optimize a MultiConstraint
When merging MultiConstraints together they can get very large, this will compact it by looking at the real intervals covered by all the constraints and then creates a new constraint containing only the smallest amount of rules to match the same intervals.
Return value
4 calls to Intervals::compactConstraint()
- Plugin::process in vendor/
phpstan/ extension-installer/ src/ Plugin.php - PoolBuilder::markPackageNameForLoading in vendor/
composer/ composer/ src/ Composer/ DependencyResolver/ PoolBuilder.php - PoolOptimizer::expandDisjunctiveMultiConstraints in vendor/
composer/ composer/ src/ Composer/ DependencyResolver/ PoolOptimizer.php - ValidatingArrayLoader::load in vendor/
composer/ composer/ src/ Composer/ Package/ Loader/ ValidatingArrayLoader.php - @inheritDoc
File
-
vendor/
composer/ semver/ src/ Intervals.php, line 139
Class
- Intervals
- Helper class generating intervals from constraints
Namespace
Composer\SemverCode
public static function compactConstraint(ConstraintInterface $constraint) {
if (!$constraint instanceof MultiConstraint) {
return $constraint;
}
$intervals = self::generateIntervals($constraint);
$constraints = array();
$hasNumericMatchAll = false;
if (\count($intervals['numeric']) === 1 && (string) $intervals['numeric'][0]->getStart() === (string) Interval::fromZero() && (string) $intervals['numeric'][0]->getEnd() === (string) Interval::untilPositiveInfinity()) {
$constraints[] = $intervals['numeric'][0]->getStart();
$hasNumericMatchAll = true;
}
else {
$unEqualConstraints = array();
for ($i = 0, $count = \count($intervals['numeric']); $i < $count; $i++) {
$interval = $intervals['numeric'][$i];
// if current interval ends with < N and next interval begins with > N we can swap this out for != N
// but this needs to happen as a conjunctive expression together with the start of the current interval
// and end of next interval, so [>=M, <N] || [>N, <P] => [>=M, !=N, <P] but M/P can be skipped if
// they are zero/+inf
if ($interval->getEnd()
->getOperator() === '<' && $i + 1 < $count) {
$nextInterval = $intervals['numeric'][$i + 1];
if ($interval->getEnd()
->getVersion() === $nextInterval->getStart()
->getVersion() && $nextInterval->getStart()
->getOperator() === '>') {
// only add a start if we didn't already do so, can be skipped if we're looking at second
// interval in [>=M, <N] || [>N, <P] || [>P, <Q] where unEqualConstraints currently contains
// [>=M, !=N] already and we only want to add !=P right now
if (\count($unEqualConstraints) === 0 && (string) $interval->getStart() !== (string) Interval::fromZero()) {
$unEqualConstraints[] = $interval->getStart();
}
$unEqualConstraints[] = new Constraint('!=', $interval->getEnd()
->getVersion());
continue;
}
}
if (\count($unEqualConstraints) > 0) {
// this is where the end of the following interval of a != constraint is added as explained above
if ((string) $interval->getEnd() !== (string) Interval::untilPositiveInfinity()) {
$unEqualConstraints[] = $interval->getEnd();
}
// count is 1 if entire constraint is just one != expression
if (\count($unEqualConstraints) > 1) {
$constraints[] = new MultiConstraint($unEqualConstraints, true);
}
else {
$constraints[] = $unEqualConstraints[0];
}
$unEqualConstraints = array();
continue;
}
// convert back >= x - <= x intervals to == x
if ($interval->getStart()
->getVersion() === $interval->getEnd()
->getVersion() && $interval->getStart()
->getOperator() === '>=' && $interval->getEnd()
->getOperator() === '<=') {
$constraints[] = new Constraint('==', $interval->getStart()
->getVersion());
continue;
}
if ((string) $interval->getStart() === (string) Interval::fromZero()) {
$constraints[] = $interval->getEnd();
}
elseif ((string) $interval->getEnd() === (string) Interval::untilPositiveInfinity()) {
$constraints[] = $interval->getStart();
}
else {
$constraints[] = new MultiConstraint(array(
$interval->getStart(),
$interval->getEnd(),
), true);
}
}
}
$devConstraints = array();
if (0 === \count($intervals['branches']['names'])) {
if ($intervals['branches']['exclude']) {
if ($hasNumericMatchAll) {
return new MatchAllConstraint();
}
// otherwise constraint should contain a != operator and already cover this
}
}
else {
foreach ($intervals['branches']['names'] as $branchName) {
if ($intervals['branches']['exclude']) {
$devConstraints[] = new Constraint('!=', $branchName);
}
else {
$devConstraints[] = new Constraint('==', $branchName);
}
}
// excluded branches, e.g. != dev-foo are conjunctive with the interval, so
// > 2.0 != dev-foo must return a conjunctive constraint
if ($intervals['branches']['exclude']) {
if (\count($constraints) > 1) {
return new MultiConstraint(array_merge(array(
new MultiConstraint($constraints, false),
), $devConstraints), true);
}
if (\count($constraints) === 1 && (string) $constraints[0] === (string) Interval::fromZero()) {
if (\count($devConstraints) > 1) {
return new MultiConstraint($devConstraints, true);
}
return $devConstraints[0];
}
return new MultiConstraint(array_merge($constraints, $devConstraints), true);
}
// otherwise devConstraints contains a list of == operators for branches which are disjunctive with the
// rest of the constraint
$constraints = array_merge($constraints, $devConstraints);
}
if (\count($constraints) > 1) {
return new MultiConstraint($constraints, false);
}
if (\count($constraints) === 1) {
return $constraints[0];
}
return new MatchNoneConstraint();
}