Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Intervals.php

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

ConstraintInterface

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\Semver

Code

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();
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal