Skip to content

Commit

Permalink
Merge pull request #59 from gsteel/priority-queue
Browse files Browse the repository at this point in the history
Improve types for `PriorityQueue`
  • Loading branch information
Ocramius authored Jun 8, 2022
2 parents 20f0787 + 5630ec9 commit 2b93932
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 91 deletions.
69 changes: 0 additions & 69 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,75 +221,6 @@
<code>(int) $priority</code>
</RedundantCastGivenDocblockType>
</file>
<file src="src/PriorityQueue.php">
<DocblockTypeContradiction occurrences="1">
<code>null === $this-&gt;queue</code>
</DocblockTypeContradiction>
<InvalidStringClass occurrences="1">
<code>new $this-&gt;queueClass()</code>
</InvalidStringClass>
<LessSpecificReturnStatement occurrences="1">
<code>$this-&gt;queue</code>
</LessSpecificReturnStatement>
<MissingClosureReturnType occurrences="2">
<code>function ($item) {</code>
<code>function ($item) {</code>
</MissingClosureReturnType>
<MissingConstructor occurrences="1">
<code>$queue</code>
</MissingConstructor>
<MixedArgument occurrences="1">
<code>$item['priority']</code>
</MixedArgument>
<MixedArrayAccess occurrences="13">
<code>$item['data']</code>
<code>$item['data']</code>
<code>$item['data']</code>
<code>$item['data']</code>
<code>$item['data']</code>
<code>$item['data']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
<code>$item['priority']</code>
</MixedArrayAccess>
<MixedArrayOffset occurrences="1">
<code>$this-&gt;items[$key]</code>
</MixedArrayOffset>
<MixedAssignment occurrences="9">
<code>$highestPriority</code>
<code>$highestPriority</code>
<code>$item</code>
<code>$item</code>
<code>$item</code>
<code>$item</code>
<code>$item</code>
<code>$item</code>
<code>$value</code>
</MixedAssignment>
<MoreSpecificReturnType occurrences="1">
<code>SplPriorityQueue</code>
</MoreSpecificReturnType>
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>null</code>
</PossiblyNullPropertyAssignmentValue>
<PossiblyUndefinedVariable occurrences="1">
<code>$key</code>
</PossiblyUndefinedVariable>
<PropertyTypeCoercion occurrences="1">
<code>new $this-&gt;queueClass()</code>
</PropertyTypeCoercion>
<RedundantCastGivenDocblockType occurrences="2">
<code>(int) $priority</code>
<code>(string) $class</code>
</RedundantCastGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="1">
<code>null !== $this-&gt;queue</code>
</RedundantConditionGivenDocblockType>
</file>
<file src="src/SplPriorityQueue.php">
<ImplementedReturnTypeMismatch occurrences="1">
<code>void</code>
Expand Down
66 changes: 44 additions & 22 deletions src/PriorityQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
* This class aggregates items for the queue itself, but also composes an
* "inner" iterator in the form of an SplPriorityQueue object for performing
* the actual iteration.
*
* @template T
* @template TPriority of int
* @implements IteratorAggregate<array-key, T>
*/
class PriorityQueue implements Countable, IteratorAggregate, Serializable
{
Expand All @@ -39,22 +43,22 @@ class PriorityQueue implements Countable, IteratorAggregate, Serializable
/**
* Inner queue class to use for iteration
*
* @var string
* @var class-string<\SplPriorityQueue>
*/
protected $queueClass = SplPriorityQueue::class;

/**
* Actual items aggregated in the priority queue. Each item is an array
* with keys "data" and "priority".
*
* @var array
* @var list<array{data: T, priority: TPriority}>
*/
protected $items = [];

/**
* Inner queue object
*
* @var SplPriorityQueue
* @var \SplPriorityQueue<TPriority, T>|null
*/
protected $queue;

Expand All @@ -63,12 +67,13 @@ class PriorityQueue implements Countable, IteratorAggregate, Serializable
*
* Priority defaults to 1 (low priority) if none provided.
*
* @param mixed $data
* @param int $priority
* @return PriorityQueue
* @param T $data
* @param TPriority $priority
* @return $this
*/
public function insert($data, $priority = 1)
{
/** @psalm-var TPriority $priority */
$priority = (int) $priority;
$this->items[] = [
'data' => $data,
Expand Down Expand Up @@ -97,13 +102,14 @@ public function insert($data, $priority = 1)
public function remove($datum)
{
$found = false;
$key = null;
foreach ($this->items as $key => $item) {
if ($item['data'] === $datum) {
$found = true;
break;
}
}
if ($found) {
if ($found && $key !== null) {
unset($this->items[$key]);
$this->queue = null;

Expand Down Expand Up @@ -142,17 +148,19 @@ public function count()
/**
* Peek at the top node in the queue, based on priority.
*
* @return mixed
* @return T
*/
public function top()
{
return $this->getIterator()->top();
$queue = clone $this->getQueue();

return $queue->top();
}

/**
* Extract a node from the inner queue and sift up
*
* @return mixed
* @return T
*/
public function extract()
{
Expand Down Expand Up @@ -196,7 +204,7 @@ public function extract()
* retrieves the inner queue object, and clones it for purposes of
* iteration.
*
* @return SplPriorityQueue
* @return \SplPriorityQueue<TPriority, T>
*/
#[ReturnTypeWillChange]
public function getIterator()
Expand All @@ -218,7 +226,7 @@ public function serialize()
/**
* Magic method used for serializing of an instance.
*
* @return array
* @return list<array{data: T, priority: TPriority}>
*/
public function __serialize()
{
Expand All @@ -228,7 +236,7 @@ public function __serialize()
/**
* Unserialize a string into a PriorityQueue object
*
* Serialization format is compatible with {@link Laminas\Stdlib\SplPriorityQueue}
* Serialization format is compatible with {@link SplPriorityQueue}
*
* @param string $data
* @return void
Expand All @@ -243,13 +251,15 @@ public function unserialize($data)
));
}

/** @psalm-var list<array{data: T, priority: TPriority}> $toUnserialize */

$this->__unserialize($toUnserialize);
}

/**
* Magic method used to rebuild an instance.
*
* @param array $data Data array.
* @param list<array{data: T, priority: TPriority}> $data Data array.
* @return void
*/
public function __unserialize($data)
Expand All @@ -261,13 +271,18 @@ public function __unserialize($data)

/**
* Serialize to an array
*
* By default, returns only the item data, and in the order registered (not
* sorted). You may provide one of the EXTR_* flags as an argument, allowing
* the ability to return priorities or both data and priority.
*
* @param int $flag
* @return array
* @return array<array-key, mixed>
* @psalm-return ($flag is self::EXTR_DATA
* ? list<array{data: T, priority: TPriority}>
* : $flag is self::EXTR_PRIORITY
* ? list<TPriority>
* : list<T>
* )
*/
public function toArray($flag = self::EXTR_DATA)
{
Expand All @@ -292,19 +307,20 @@ public function toArray($flag = self::EXTR_DATA)
* Please see {@link getIterator()} for details on the necessity of an
* internal queue class. The class provided should extend SplPriorityQueue.
*
* @param string $class
* @return PriorityQueue
* @param class-string<\SplPriorityQueue> $class
* @return $this
*/
public function setInternalQueueClass($class)
{
/** @psalm-suppress RedundantCastGivenDocblockType */
$this->queueClass = (string) $class;
return $this;
}

/**
* Does the queue contain the given datum?
*
* @param mixed $datum
* @param T $datum
* @return bool
*/
public function contains($datum)
Expand All @@ -320,7 +336,7 @@ public function contains($datum)
/**
* Does the queue have an item with the given priority?
*
* @param int $priority
* @param TPriority $priority
* @return bool
*/
public function hasPriority($priority)
Expand All @@ -337,19 +353,25 @@ public function hasPriority($priority)
* Get the inner priority queue instance
*
* @throws Exception\DomainException
* @return SplPriorityQueue
* @return \SplPriorityQueue<TPriority, T>
* @psalm-assert !null $this->queue
*/
protected function getQueue()
{
if (null === $this->queue) {
$this->queue = new $this->queueClass();
/** @psalm-suppress UnsafeInstantiation */
$queue = new $this->queueClass();
/** @psalm-var \SplPriorityQueue<TPriority, T> $queue */
$this->queue = $queue;
/** @psalm-suppress DocblockTypeContradiction, MixedArgument */
if (! $this->queue instanceof \SplPriorityQueue) {
throw new Exception\DomainException(sprintf(
'PriorityQueue expects an internal queue of type SplPriorityQueue; received "%s"',
get_class($this->queue)
));
}
}

return $this->queue;
}

Expand Down

0 comments on commit 2b93932

Please sign in to comment.