function Intervals::generateIntervals
@phpstan-return array{'numeric': Interval[], 'branches': array{'names': string[], 'exclude': bool}}
Parameters
bool $stopOnFirstValidInterval:
3 calls to Intervals::generateIntervals()
- Intervals::compactConstraint in vendor/
composer/ semver/ src/ Intervals.php - Attempts to optimize a MultiConstraint
- Intervals::get in vendor/
composer/ semver/ src/ Intervals.php - Creates an array of numeric intervals and branch constraints representing a given constraint
- Intervals::haveIntersections in vendor/
composer/ semver/ src/ Intervals.php - Checks whether $a and $b have any intersection, equivalent to $a->matches($b)
File
-
vendor/
composer/ semver/ src/ Intervals.php, line 288
Class
- Intervals
- Helper class generating intervals from constraints
Namespace
Composer\SemverCode
private static function generateIntervals(ConstraintInterface $constraint, $stopOnFirstValidInterval = false) {
if ($constraint instanceof MatchAllConstraint) {
return array(
'numeric' => array(
new Interval(Interval::fromZero(), Interval::untilPositiveInfinity()),
),
'branches' => Interval::anyDev(),
);
}
if ($constraint instanceof MatchNoneConstraint) {
return array(
'numeric' => array(),
'branches' => array(
'names' => array(),
'exclude' => false,
),
);
}
if ($constraint instanceof Constraint) {
return self::generateSingleConstraintIntervals($constraint);
}
if (!$constraint instanceof MultiConstraint) {
throw new \UnexpectedValueException('The constraint passed in should be an MatchAllConstraint, Constraint or MultiConstraint instance, got ' . \get_class($constraint) . '.');
}
$constraints = $constraint->getConstraints();
$numericGroups = array();
$constraintBranches = array();
foreach ($constraints as $c) {
$res = self::get($c);
$numericGroups[] = $res['numeric'];
$constraintBranches[] = $res['branches'];
}
if ($constraint->isDisjunctive()) {
$branches = Interval::noDev();
foreach ($constraintBranches as $b) {
if ($b['exclude']) {
if ($branches['exclude']) {
// disjunctive constraint, so only exclude what's excluded in all constraints
// !=a,!=b || !=b,!=c => !=b
$branches['names'] = array_intersect($branches['names'], $b['names']);
}
else {
// disjunctive constraint so exclude all names which are not explicitly included in the alternative
// (==b || ==c) || !=a,!=b => !=a
$branches['exclude'] = true;
$branches['names'] = array_diff($b['names'], $branches['names']);
}
}
else {
if ($branches['exclude']) {
// disjunctive constraint so exclude all names which are not explicitly included in the alternative
// !=a,!=b || (==b || ==c) => !=a
$branches['names'] = array_diff($branches['names'], $b['names']);
}
else {
// disjunctive constraint, so just add all the other branches
// (==a || ==b) || ==c => ==a || ==b || ==c
$branches['names'] = array_merge($branches['names'], $b['names']);
}
}
}
}
else {
$branches = Interval::anyDev();
foreach ($constraintBranches as $b) {
if ($b['exclude']) {
if ($branches['exclude']) {
// conjunctive, so just add all branch names to be excluded
// !=a && !=b => !=a,!=b
$branches['names'] = array_merge($branches['names'], $b['names']);
}
else {
// conjunctive, so only keep included names which are not excluded
// (==a||==c) && !=a,!=b => ==c
$branches['names'] = array_diff($branches['names'], $b['names']);
}
}
else {
if ($branches['exclude']) {
// conjunctive, so only keep included names which are not excluded
// !=a,!=b && (==a||==c) => ==c
$branches['names'] = array_diff($b['names'], $branches['names']);
$branches['exclude'] = false;
}
else {
// conjunctive, so only keep names that are included in both
// (==a||==b) && (==a||==c) => ==a
$branches['names'] = array_intersect($branches['names'], $b['names']);
}
}
}
}
$branches['names'] = array_unique($branches['names']);
if (\count($numericGroups) === 1) {
return array(
'numeric' => $numericGroups[0],
'branches' => $branches,
);
}
$borders = array();
foreach ($numericGroups as $group) {
foreach ($group as $interval) {
$borders[] = array(
'version' => $interval->getStart()
->getVersion(),
'operator' => $interval->getStart()
->getOperator(),
'side' => 'start',
);
$borders[] = array(
'version' => $interval->getEnd()
->getVersion(),
'operator' => $interval->getEnd()
->getOperator(),
'side' => 'end',
);
}
}
$opSortOrder = self::$opSortOrder;
usort($borders, function ($a, $b) use ($opSortOrder) {
$order = version_compare($a['version'], $b['version']);
if ($order === 0) {
return $opSortOrder[$a['operator']] - $opSortOrder[$b['operator']];
}
return $order;
});
$activeIntervals = 0;
$intervals = array();
$index = 0;
$activationThreshold = $constraint->isConjunctive() ? \count($numericGroups) : 1;
$start = null;
foreach ($borders as $border) {
if ($border['side'] === 'start') {
$activeIntervals++;
}
else {
$activeIntervals--;
}
if (!$start && $activeIntervals >= $activationThreshold) {
$start = new Constraint($border['operator'], $border['version']);
}
elseif ($start && $activeIntervals < $activationThreshold) {
// filter out invalid intervals like > x - <= x, or >= x - < x
if (version_compare($start->getVersion(), $border['version'], '=') && ($start->getOperator() === '>' && $border['operator'] === '<=' || $start->getOperator() === '>=' && $border['operator'] === '<')) {
unset($intervals[$index]);
}
else {
$intervals[$index] = new Interval($start, new Constraint($border['operator'], $border['version']));
$index++;
if ($stopOnFirstValidInterval) {
break;
}
}
$start = null;
}
}
return array(
'numeric' => $intervals,
'branches' => $branches,
);
}