PageRenderTime 42ms CodeModel.GetById 9ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Composer/DependencyResolver/Decisions.php

https://github.com/skug/composer
PHP | 197 lines | 148 code | 35 blank | 14 comment | 16 complexity | 8204f0eda42c6c3f33f179c62b50f390 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\DependencyResolver;
  12. /**
  13. * Stores decisions on installing, removing or keeping packages
  14. *
  15. * @author Nils Adermann <naderman@naderman.de>
  16. */
  17. class Decisions implements \Iterator, \Countable
  18. {
  19. const DECISION_LITERAL = 0;
  20. const DECISION_REASON = 1;
  21. protected $pool;
  22. protected $decisionMap;
  23. protected $decisionQueue = array();
  24. public function __construct($pool)
  25. {
  26. $this->pool = $pool;
  27. if (version_compare(PHP_VERSION, '5.3.4', '>=')) {
  28. $this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1);
  29. } else {
  30. $this->decisionMap = array_fill(0, $this->pool->getMaxId() + 1, 0);
  31. }
  32. }
  33. public function decide($literal, $level, $why)
  34. {
  35. $this->addDecision($literal, $level);
  36. $this->decisionQueue[] = array(
  37. self::DECISION_LITERAL => $literal,
  38. self::DECISION_REASON => $why,
  39. );
  40. }
  41. public function satisfy($literal)
  42. {
  43. $packageId = abs($literal);
  44. return (
  45. $literal > 0 && $this->decisionMap[$packageId] > 0 ||
  46. $literal < 0 && $this->decisionMap[$packageId] < 0
  47. );
  48. }
  49. public function conflict($literal)
  50. {
  51. $packageId = abs($literal);
  52. return (
  53. ($this->decisionMap[$packageId] > 0 && $literal < 0) ||
  54. ($this->decisionMap[$packageId] < 0 && $literal > 0)
  55. );
  56. }
  57. public function decided($literalOrPackageId)
  58. {
  59. return $this->decisionMap[abs($literalOrPackageId)] != 0;
  60. }
  61. public function undecided($literalOrPackageId)
  62. {
  63. return $this->decisionMap[abs($literalOrPackageId)] == 0;
  64. }
  65. public function decidedInstall($literalOrPackageId)
  66. {
  67. return $this->decisionMap[abs($literalOrPackageId)] > 0;
  68. }
  69. public function decisionLevel($literalOrPackageId)
  70. {
  71. return abs($this->decisionMap[abs($literalOrPackageId)]);
  72. }
  73. public function decisionRule($literalOrPackageId)
  74. {
  75. $packageId = abs($literalOrPackageId);
  76. foreach ($this->decisionQueue as $i => $decision) {
  77. if ($packageId === abs($decision[self::DECISION_LITERAL])) {
  78. return $decision[self::DECISION_REASON];
  79. }
  80. }
  81. return null;
  82. }
  83. public function atOffset($queueOffset)
  84. {
  85. return $this->decisionQueue[$queueOffset];
  86. }
  87. public function validOffset($queueOffset)
  88. {
  89. return $queueOffset >= 0 && $queueOffset < count($this->decisionQueue);
  90. }
  91. public function lastReason()
  92. {
  93. return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_REASON];
  94. }
  95. public function lastLiteral()
  96. {
  97. return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_LITERAL];
  98. }
  99. public function reset()
  100. {
  101. while ($decision = array_pop($this->decisionQueue)) {
  102. $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
  103. }
  104. }
  105. public function resetToOffset($offset)
  106. {
  107. while (count($this->decisionQueue) > $offset + 1) {
  108. $decision = array_pop($this->decisionQueue);
  109. $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
  110. }
  111. }
  112. public function revertLast()
  113. {
  114. $this->decisionMap[abs($this->lastLiteral())] = 0;
  115. array_pop($this->decisionQueue);
  116. }
  117. public function count()
  118. {
  119. return count($this->decisionQueue);
  120. }
  121. public function rewind()
  122. {
  123. end($this->decisionQueue);
  124. }
  125. public function current()
  126. {
  127. return current($this->decisionQueue);
  128. }
  129. public function key()
  130. {
  131. return key($this->decisionQueue);
  132. }
  133. public function next()
  134. {
  135. return prev($this->decisionQueue);
  136. }
  137. public function valid()
  138. {
  139. return false !== current($this->decisionQueue);
  140. }
  141. public function isEmpty()
  142. {
  143. return count($this->decisionQueue) === 0;
  144. }
  145. protected function addDecision($literal, $level)
  146. {
  147. $packageId = abs($literal);
  148. $previousDecision = $this->decisionMap[$packageId];
  149. if ($previousDecision != 0) {
  150. $literalString = $this->pool->literalToString($literal);
  151. $package = $this->pool->literalToPackage($literal);
  152. throw new SolverBugException(
  153. "Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."."
  154. );
  155. }
  156. if ($literal > 0) {
  157. $this->decisionMap[$packageId] = $level;
  158. } else {
  159. $this->decisionMap[$packageId] = -$level;
  160. }
  161. }
  162. }