You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
4.9 KiB
PHTML

<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\DependencyResolver;
/**
* Stores decisions on installing, removing or keeping packages
*
* @author Nils Adermann <naderman@naderman.de>
*/
class Decisions implements \Iterator, \Countable
{
const DECISION_LITERAL = 0;
const DECISION_REASON = 1;
protected $pool;
protected $decisionMap;
protected $decisionQueue = array();
public function __construct($pool)
{
$this->pool = $pool;
if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
$this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
} else {
$this->decisionMap = array_fill(0, $this->pool->getMaxId() + 1, 0);
}
}
public function decide($literal, $level, $why)
{
$this->addDecision($literal, $level);
$this->decisionQueue[] = array(
self::DECISION_LITERAL => $literal,
self::DECISION_REASON => $why,
);
}
public function satisfy($literal)
{
$packageId = abs($literal);
return (
$literal > 0 && $this->decisionMap[$packageId] > 0 ||
$literal < 0 && $this->decisionMap[$packageId] < 0
);
}
public function conflict($literal)
{
$packageId = abs($literal);
return (
($this->decisionMap[$packageId] > 0 && $literal < 0) ||
($this->decisionMap[$packageId] < 0 && $literal > 0)
);
}
public function decided($literalOrPackageId)
{
return $this->decisionMap[abs($literalOrPackageId)] != 0;
}
public function undecided($literalOrPackageId)
{
return $this->decisionMap[abs($literalOrPackageId)] == 0;
}
public function decidedInstall($literalOrPackageId)
{
return $this->decisionMap[abs($literalOrPackageId)] > 0;
}
public function decisionLevel($literalOrPackageId)
{
return abs($this->decisionMap[abs($literalOrPackageId)]);
}
public function decisionRule($literalOrPackageId)
{
$packageId = abs($literalOrPackageId);
foreach ($this->decisionQueue as $i => $decision) {
if ($packageId === abs($decision[self::DECISION_LITERAL])) {
return $decision[self::DECISION_REASON];
}
}
return null;
}
public function atOffset($queueOffset)
{
return $this->decisionQueue[$queueOffset];
}
public function validOffset($queueOffset)
{
return $queueOffset >= 0 && $queueOffset < count($this->decisionQueue);
}
public function lastReason()
{
return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_REASON];
}
public function lastLiteral()
{
return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_LITERAL];
}
public function reset()
{
while ($decision = array_pop($this->decisionQueue)) {
$this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
}
}
public function resetToOffset($offset)
{
while (count($this->decisionQueue) > $offset + 1) {
$decision = array_pop($this->decisionQueue);
$this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
}
}
public function revertLast()
{
$this->decisionMap[abs($this->lastLiteral())] = 0;
array_pop($this->decisionQueue);
}
public function count()
{
return count($this->decisionQueue);
}
public function rewind()
{
end($this->decisionQueue);
}
public function current()
{
return current($this->decisionQueue);
}
public function key()
{
return key($this->decisionQueue);
}
public function next()
{
return prev($this->decisionQueue);
}
public function valid()
{
return false !== current($this->decisionQueue);
}
public function isEmpty()
{
return count($this->decisionQueue) === 0;
}
protected function addDecision($literal, $level)
{
$packageId = abs($literal);
$previousDecision = $this->decisionMap[$packageId];
if ($previousDecision != 0) {
$literalString = $this->pool->literalToString($literal);
$package = $this->pool->literalToPackage($literal);
throw new SolverBugException(
"Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."."
);
}
if ($literal > 0) {
$this->decisionMap[$packageId] = $level;
} else {
$this->decisionMap[$packageId] = -$level;
}
}
}