Skip to content

Commit

Permalink
bug #30 Keep FIFO order in PriorityQueue (pamil)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.7-dev branch.

Discussion
----------

Sorts them first by priority descending, then by the order in which they were added ascending.

Commits
-------

c1f2558 Keep FIFO order in PriorityQueue
  • Loading branch information
pamil authored May 25, 2020
2 parents edde22a + c1f2558 commit afd1238
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 17 deletions.
12 changes: 7 additions & 5 deletions spec/Suite/PriorityQueueSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ function it_is_initializable(): void

function it_keeps_fifo_order_for_elements_with_same_priority(): void
{
$this->insert(['element' => 1]);
$this->insert(['element' => 2]);
$this->insert(['element' => 1]);
$this->insert(['element' => 3]);

$this->getIterator()->shouldIterateAs([['element' => 1], ['element' => 2]]);
$this->getIterator()->shouldIterateAs([['element' => 2], ['element' => 1], ['element' => 3]]);
}

function it_sorts_elements_by_their_priority(): void
{
$this->insert(['element' => 3], -1);
$this->insert(['element' => 1], -1);
$this->insert(['element' => 2], 0);
$this->insert(['element' => 1], 1);
$this->insert(['element' => 3], 1);
$this->insert(['element' => 4], 0);

$this->getIterator()->shouldIterateAs([['element' => 1], ['element' => 2], ['element' => 3]]);
$this->getIterator()->shouldIterateAs([['element' => 3], ['element' => 2], ['element' => 4], ['element' => 1]]);
}
}
20 changes: 8 additions & 12 deletions src/Suite/PriorityQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ final class PriorityQueue implements \IteratorAggregate
*/
private $records = [];

/**
* @psalm-var array<int, array>
*
* @var array[]
*/
private $sortedRecords = [];

/** @var bool */
private $sorted = false;

Expand All @@ -44,16 +37,19 @@ public function insert(array $data, int $priority = 0): void
public function getIterator(): \Traversable
{
if ($this->sorted === false) {
// Reversing the records to maintain FIFO order for item with the same priority
$this->sortedRecords = array_reverse($this->records);

/** @psalm-suppress InvalidPassByReference Doing PHP magic, it works this way */
array_multisort(array_column($this->sortedRecords, 'priority'), \SORT_DESC, $this->sortedRecords);
array_multisort(
array_column($this->records, 'priority'),
\SORT_DESC,
array_keys($this->records),
\SORT_ASC,
$this->records
);

$this->sorted = true;
}

foreach ($this->sortedRecords as $record) {
foreach ($this->records as $record) {
yield $record['data'];
}
}
Expand Down

0 comments on commit afd1238

Please sign in to comment.