Skip to content

Commit

Permalink
chore(data-structure): rework exceptions
Browse files Browse the repository at this point in the history
Signed-off-by: azjezz <azjezz@protonmail.com>
  • Loading branch information
azjezz committed Dec 23, 2021
1 parent dff3b04 commit 187fb49
Show file tree
Hide file tree
Showing 15 changed files with 128 additions and 108 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@
* **BC** - `Psl\Collection\IndexAccessInterface::at()` now throw `Psl\Collection\Exception\OutOfBoundsException` instead of `Psl\Exception\InvariantViolationException` if `$k` is out-of-bounds.
* **BC** - `Psl\Collection\AccessibleCollectionInterface::slice` signature has changed from `slice(int $start, int $length): static` to `slice(int $start, ?int $length = null): static`
* **BC** - All psl functions previously accepting `callable`, now accept only `Closure`.
* **BC** - `Psl\DataStructure\QueueInterface::dequeue`, and `Psl\DataStructure\StackInterface::pop` now throw `Psl\DataStructure\Exception\UnderflowException` instead of `Psl\Exception\InvariantViolationException` when the data structure is empty.
10 changes: 5 additions & 5 deletions docs/component/data-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
#### `Interfaces`

- [PriorityQueueInterface](./../../src/Psl/DataStructure/PriorityQueueInterface.php#L12)
- [QueueInterface](./../../src/Psl/DataStructure/QueueInterface.php#L17)
- [StackInterface](./../../src/Psl/DataStructure/StackInterface.php#L17)
- [QueueInterface](./../../src/Psl/DataStructure/QueueInterface.php#L16)
- [StackInterface](./../../src/Psl/DataStructure/StackInterface.php#L16)

#### `Classes`

- [PriorityQueue](./../../src/Psl/DataStructure/PriorityQueue.php#L20)
- [Queue](./../../src/Psl/DataStructure/Queue.php#L21)
- [Stack](./../../src/Psl/DataStructure/Stack.php#L19)
- [PriorityQueue](./../../src/Psl/DataStructure/PriorityQueue.php#L18)
- [Queue](./../../src/Psl/DataStructure/Queue.php#L17)
- [Stack](./../../src/Psl/DataStructure/Stack.php#L17)


11 changes: 11 additions & 0 deletions src/Psl/DataStructure/Exception/ExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Psl\DataStructure\Exception;

use Psl\Exception;

interface ExceptionInterface extends Exception\ExceptionInterface
{
}
11 changes: 11 additions & 0 deletions src/Psl/DataStructure/Exception/UnderflowException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Psl\DataStructure\Exception;

use Psl\Exception;

final class UnderflowException extends Exception\UnderflowException implements ExceptionInterface
{
}
69 changes: 27 additions & 42 deletions src/Psl/DataStructure/PriorityQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

namespace Psl\DataStructure;

use Psl;
use Psl\Dict;
use Psl\Iter;
use Psl\Math;
use Psl\Vec;

use function array_keys;
use function array_shift;
use function count;

/**
Expand All @@ -20,7 +18,7 @@
final class PriorityQueue implements PriorityQueueInterface
{
/**
* @var array<int, list<T>>
* @var array<int, non-empty-list<T>>
*/
private array $queue = [];

Expand Down Expand Up @@ -49,7 +47,7 @@ public function peek(): mixed
return null;
}

$keys = Vec\keys($this->queue);
$keys = array_keys($this->queue);

// Retrieve the highest priority.
$priority = Math\max($keys) ?? 0;
Expand All @@ -58,7 +56,7 @@ public function peek(): mixed
$nodes = $this->queue[$priority] ?? [];

// Retrieve the first node of the list.
return Iter\first($nodes);
return $nodes[0] ?? null;
}

/**
Expand All @@ -69,63 +67,50 @@ public function peek(): mixed
*/
public function pull(): mixed
{
if (0 === $this->count()) {
try {
return $this->dequeue();
} catch (Exception\UnderflowException) {
return null;
}

/** @psalm-suppress MissingThrowsDocblock - the queue is not empty */
return $this->dequeue();
}

/**
* Dequeues a node from the queue.
*
* @throws Psl\Exception\InvariantViolationException If the Queue is invalid.
* @throws Exception\UnderflowException If the queue is empty.
*
* @return T
*/
public function dequeue(): mixed
{
Psl\invariant(0 !== $this->count(), 'Cannot dequeue a node from an empty Queue.');
if (0 === $this->count()) {
throw new Exception\UnderflowException('Cannot dequeue a node from an empty queue.');
}

/**
* Peeking into a non-empty queue always results in a value.
* retrieve the highest priority.
*
* @var T $node
* @var int
*/
$node = $this->peek();

$this->drop();

return $node;
}

private function drop(): void
{
$priority = Math\max(array_keys($this->queue));
/**
* Retrieve the highest priority.
*
* @var int $priority
* retrieve the list of nodes with the priority `$priority`.
*/
$priority = Math\max(Vec\keys($this->queue));

$nodes = $this->queue[$priority];
/**
* Retrieve the list of nodes with the priority `$priority`.
* shit the first node out.
*/
$nodes = $this->queue[$priority];

// If the list contained only this node,
// remove the list of nodes with priority `$priority`.
if (1 === Iter\count($nodes)) {
$node = array_shift($nodes);
/**
* If the list contained only this node, remove the list of nodes with priority `$priority`.
*/
if ([] === $nodes) {
unset($this->queue[$priority]);
} else {
/**
* otherwise, drop the first node.
*
* @psalm-suppress MissingThrowsDocblock
*/
$this->queue[$priority] = Vec\values(Dict\drop($nodes, 1));
$this->queue[$priority] = $nodes;
}

return $node;
}

/**
Expand All @@ -136,7 +121,7 @@ private function drop(): void
public function count(): int
{
$count = 0;
foreach ($this->queue as $_priority => $list) {
foreach ($this->queue as $list) {
$count += count($list);
}

Expand Down
27 changes: 9 additions & 18 deletions src/Psl/DataStructure/Queue.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@

namespace Psl\DataStructure;

use Psl;
use Psl\Dict;
use Psl\Iter;
use Psl\Vec;

use function array_shift;
use function count;

/**
Expand Down Expand Up @@ -43,7 +39,7 @@ public function enqueue(mixed $node): void
*/
public function peek(): mixed
{
return Iter\first($this->queue);
return $this->queue[0] ?? null;
}

/**
Expand All @@ -54,29 +50,24 @@ public function peek(): mixed
*/
public function pull(): mixed
{
if (0 === $this->count()) {
return null;
}

/** @psalm-suppress MissingThrowsDocblock - we are sure that the queue is not empty. */
return $this->dequeue();
return array_shift($this->queue);
}

/**
* Dequeues a node from the queue.
*
* @throws Psl\Exception\InvariantViolationException If the Queue is invalid.
* @throws Exception\UnderflowException If the queue is empty.
*
* @return T
*/
public function dequeue(): mixed
{
Psl\invariant(0 !== $this->count(), 'Cannot dequeue a node from an empty Queue.');

$node = $this->queue[0];
$this->queue = Vec\values(Dict\drop($this->queue, 1));
if ([] === $this->queue) {
throw new Exception\UnderflowException('Cannot dequeue a node from an empty queue.');
}

return $node;
/** @var T */
return array_shift($this->queue);
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Psl/DataStructure/QueueInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Psl\DataStructure;

use Countable;
use Psl;

/**
* An interface representing a queue data structure ( FIFO ).
Expand Down Expand Up @@ -42,7 +41,7 @@ public function pull(): mixed;
/**
* Retrieves and removes the node at the head of this queue.
*
* @throws Psl\Exception\InvariantViolationException If the Queue is invalid.
* @throws Exception\UnderflowException If the queue is empty.
*
* @return T
*/
Expand Down
35 changes: 15 additions & 20 deletions src/Psl/DataStructure/Stack.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

namespace Psl\DataStructure;

use Psl;
use Psl\Dict;
use Psl\Iter;
use Psl\Vec;
use function array_pop;
use function count;

/**
* An basic implementation of a stack data structure ( LIFO ).
Expand Down Expand Up @@ -41,7 +39,9 @@ public function push(mixed $item): void
*/
public function peek(): mixed
{
return Iter\last($this->items);
$items = $this->items;

return array_pop($items);
}

/**
Expand All @@ -52,38 +52,33 @@ public function peek(): mixed
*/
public function pull(): mixed
{
if (0 === $this->count()) {
return null;
}

/** @psalm-suppress MissingThrowsDocblock - the stack is not empty. */
return $this->pop();
return array_pop($this->items);
}

/**
* Retrieve and removes the most recently added item that was not yet removed.
*
* @throws Psl\Exception\InvariantViolationException If the stack is empty.
* @throws Exception\UnderflowException If the stack is empty.
*
* @return T
*/
public function pop(): mixed
{
Psl\invariant(0 !== ($i = $this->count()), 'Cannot pop an item from an empty Stack.');

/** @var int<0, max> $position */
$position = $i - 1;
$tail = $this->items[$position];
$this->items = Vec\values(Dict\take($this->items, $position));
if ([] === $this->items) {
throw new Exception\UnderflowException('Cannot pop an item from an empty stack.');
}

return $tail;
/** @var T */
return array_pop($this->items);
}

/**
* Count the items in the stack.
*
* @return int<0, max>
*/
public function count(): int
{
return Iter\count($this->items);
return count($this->items);
}
}
5 changes: 3 additions & 2 deletions src/Psl/DataStructure/StackInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Psl\DataStructure;

use Countable;
use Psl;

/**
* An interface representing a stack data structure ( LIFO ).
Expand Down Expand Up @@ -42,14 +41,16 @@ public function pull(): mixed;
/**
* Retrieve and removes the most recently added item that was not yet removed.
*
* @throws Psl\Exception\InvariantViolationException If the stack is empty.
* @throws Exception\UnderflowException If the stack is empty.
*
* @return T
*/
public function pop(): mixed;

/**
* Count the items in the stack.
*
* @return int<0, max>
*/
public function count(): int;
}
11 changes: 11 additions & 0 deletions src/Psl/Exception/UnderflowException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Psl\Exception;

use UnderflowException as UnderflowRootException;

class UnderflowException extends UnderflowRootException implements ExceptionInterface
{
}
Loading

0 comments on commit 187fb49

Please sign in to comment.