From edce0d7656ac7cf6333e94da8f1a4e5048a46b85 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Sat, 29 Jun 2024 11:56:44 -0300 Subject: [PATCH] feat: Refactor ArrayQueue, Create CircularArrayQueue, Refactor ArrayDeque, and Add Extra Tests - Refactored ArrayQueue to inherit from the new CircularArrayQueue base class - Added clear method to ArrayQueue - Added getItems method to ArrayQueue - Updated tests to cover clear and getItems methods in ArrayQueue - Created CircularArrayQueue as a base class for circular array-based queue implementations - Implemented common functionality for enqueue, dequeue, and capacity management - Added clear and getItems methods - Refactored ArrayDeque to inherit from CircularArrayQueue - Removed redundant methods now provided by CircularArrayQueue - Added tests for clear and getItems methods - Added comprehensive tests for all new and refactored methods - Ensured 100% coverage for clear and getItems methods - Added tests for mixed operations, various data types, and circular behavior --- composer.lock | 22 +++---- src/Queue/ArrayDeque.php | 68 +--------------------- src/Queue/ArrayQueue.php | 67 +-------------------- src/Queue/CircularArrayQueue.php | 99 ++++++++++++++++++++++++++++++++ tests/Queue/ArrayDequeTest.php | 65 +++++++++++++++++++++ tests/Queue/ArrayQueueTest.php | 22 +++++++ 6 files changed, 203 insertions(+), 140 deletions(-) create mode 100644 src/Queue/CircularArrayQueue.php diff --git a/composer.lock b/composer.lock index 2abff7f..f2748bb 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "kariricode/contract", - "version": "v2.0.1", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/KaririCode-Framework/kariricode-contract.git", - "reference": "83ff17ce02c2d0e4aa90af352029f96b9a004828" + "reference": "f8a776c083882e260e68945d8cd8f193ec2fce6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-contract/zipball/83ff17ce02c2d0e4aa90af352029f96b9a004828", - "reference": "83ff17ce02c2d0e4aa90af352029f96b9a004828", + "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-contract/zipball/f8a776c083882e260e68945d8cd8f193ec2fce6f", + "reference": "f8a776c083882e260e68945d8cd8f193ec2fce6f", "shasum": "" }, "require": { @@ -66,7 +66,7 @@ "issues": "https://github.com/KaririCode-Framework/kariricode-contract/issues", "source": "https://github.com/KaririCode-Framework/kariricode-contract" }, - "time": "2024-06-28T18:53:05+00:00" + "time": "2024-06-29T14:45:04+00:00" } ], "packages-dev": [ @@ -1835,16 +1835,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.14", + "version": "10.1.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" + "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", + "reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae", "shasum": "" }, "require": { @@ -1901,7 +1901,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15" }, "funding": [ { @@ -1909,7 +1909,7 @@ "type": "github" } ], - "time": "2024-03-12T15:33:41+00:00" + "time": "2024-06-29T08:25:15+00:00" }, { "name": "phpunit/php-file-iterator", diff --git a/src/Queue/ArrayDeque.php b/src/Queue/ArrayDeque.php index f64a000..2261edd 100644 --- a/src/Queue/ArrayDeque.php +++ b/src/Queue/ArrayDeque.php @@ -4,6 +4,7 @@ namespace KaririCode\DataStructure\Queue; +use KaririCode\Contract\DataStructure\Deque; use KaririCode\Contract\DataStructure\Queue; /** @@ -16,45 +17,9 @@ * * @implements Queue */ -class ArrayDeque implements Queue -{ - private array $elements; - private int $front = 0; - private int $size = 0; - private int $capacity; - - public function __construct(int $initialCapacity = 16) - { - $this->capacity = $initialCapacity; - $this->elements = array_fill(0, $this->capacity, null); - } - - public function enqueue(mixed $element): void - { - $this->ensureCapacity(); - $index = ($this->front + $this->size) % $this->capacity; - $this->elements[$index] = $element; - ++$this->size; - } - - public function dequeue(): mixed - { - if ($this->isEmpty()) { - return null; - } - $element = $this->elements[$this->front]; - $this->elements[$this->front] = null; - $this->front = ($this->front + 1) % $this->capacity; - --$this->size; - - return $element; - } - - public function peek(): mixed - { - return $this->isEmpty() ? null : $this->elements[$this->front]; - } +class ArrayDeque extends CircularArrayQueue implements Deque +{ public function addFirst(mixed $element): void { $this->ensureCapacity(); @@ -85,31 +50,4 @@ public function peekLast(): mixed return $this->elements[$index]; } - - public function isEmpty(): bool - { - return 0 === $this->size; - } - - public function size(): int - { - return $this->size; - } - - /** - * Ensures that the deque has enough capacity to add a new element. - */ - private function ensureCapacity(): void - { - if ($this->size === $this->capacity) { - $newCapacity = $this->capacity * 2; - $newElements = array_fill(0, $newCapacity, null); - for ($i = 0; $i < $this->size; ++$i) { - $newElements[$i] = $this->elements[($this->front + $i) % $this->capacity]; - } - $this->elements = $newElements; - $this->front = 0; - $this->capacity = $newCapacity; - } - } } diff --git a/src/Queue/ArrayQueue.php b/src/Queue/ArrayQueue.php index e5ece5e..9986368 100644 --- a/src/Queue/ArrayQueue.php +++ b/src/Queue/ArrayQueue.php @@ -19,69 +19,8 @@ * * @see https://kariricode.org/ */ -class ArrayQueue implements Queue -{ - private array $elements; - private int $front = 0; - private int $size = 0; - private int $capacity; - - public function __construct(int $initialCapacity = 16) - { - $this->capacity = $initialCapacity; - $this->elements = array_fill(0, $this->capacity, null); - } - - public function enqueue(mixed $element): void - { - $this->ensureCapacity(); - $index = ($this->front + $this->size) % $this->capacity; - $this->elements[$index] = $element; - ++$this->size; - } - - public function dequeue(): mixed - { - if ($this->isEmpty()) { - return null; - } - $element = $this->elements[$this->front]; - $this->elements[$this->front] = null; - $this->front = ($this->front + 1) % $this->capacity; - --$this->size; - - return $element; - } - public function peek(): mixed - { - return $this->isEmpty() ? null : $this->elements[$this->front]; - } - - public function isEmpty(): bool - { - return 0 === $this->size; - } - - public function size(): int - { - return $this->size; - } - - /** - * Ensures that the queue has enough capacity to add a new element. - */ - private function ensureCapacity(): void - { - if ($this->size === $this->capacity) { - $newCapacity = $this->capacity * 2; - $newElements = array_fill(0, $newCapacity, null); - for ($i = 0; $i < $this->size; ++$i) { - $newElements[$i] = $this->elements[($this->front + $i) % $this->capacity]; - } - $this->elements = $newElements; - $this->front = 0; - $this->capacity = $newCapacity; - } - } +class ArrayQueue extends CircularArrayQueue implements Queue +{ + // No additional methods required, uses methods from CircularArrayQueue } diff --git a/src/Queue/CircularArrayQueue.php b/src/Queue/CircularArrayQueue.php new file mode 100644 index 0000000..229cf72 --- /dev/null +++ b/src/Queue/CircularArrayQueue.php @@ -0,0 +1,99 @@ + + * @license MIT + * + * @see https://kariricode.org/ + */ +abstract class CircularArrayQueue implements Queue +{ + protected array $elements; + protected int $front = 0; + protected int $size = 0; + protected int $capacity; + + public function __construct(int $initialCapacity = 16) + { + $this->capacity = $initialCapacity; + $this->elements = array_fill(0, $this->capacity, null); + } + + public function isEmpty(): bool + { + return $this->size === 0; + } + + public function size(): int + { + return $this->size; + } + + public function clear(): void + { + $this->elements = array_fill(0, $this->capacity, null); + $this->front = 0; + $this->size = 0; + } + + protected function ensureCapacity(): void + { + if ($this->size === $this->capacity) { + $newCapacity = $this->capacity * 2; + $newElements = array_fill(0, $newCapacity, null); + for ($i = 0; $i < $this->size; ++$i) { + $newElements[$i] = $this->elements[($this->front + $i) % $this->capacity]; + } + $this->elements = $newElements; + $this->front = 0; + $this->capacity = $newCapacity; + } + } + + public function peek(): mixed + { + return $this->isEmpty() ? null : $this->elements[$this->front]; + } + + public function dequeue(): mixed + { + if ($this->isEmpty()) { + return null; + } + $element = $this->elements[$this->front]; + $this->elements[$this->front] = null; + $this->front = ($this->front + 1) % $this->capacity; + --$this->size; + + return $element; + } + + public function enqueue(mixed $element): void + { + $this->ensureCapacity(); + $index = ($this->front + $this->size) % $this->capacity; + $this->elements[$index] = $element; + ++$this->size; + } + + public function getItems(): array + { + $items = []; + for ($i = 0; $i < $this->size; ++$i) { + $items[] = $this->elements[($this->front + $i) % $this->capacity]; + } + return $items; + } +} diff --git a/tests/Queue/ArrayDequeTest.php b/tests/Queue/ArrayDequeTest.php index 53c26cb..ce85f39 100644 --- a/tests/Queue/ArrayDequeTest.php +++ b/tests/Queue/ArrayDequeTest.php @@ -172,4 +172,69 @@ public function testDequeBehaviorAfterMixedOperations(): void $this->assertSame(1, $deque->dequeue()); $this->assertSame(3, $deque->peekLast()); } + + // Test capacity expansion during addFirst operations + public function testEnsureCapacityExpandsDuringAddFirstOperations(): void + { + $deque = new ArrayDeque(2); + $deque->addFirst(1); + $deque->addFirst(2); + $deque->addFirst(3); // Should trigger capacity increase + $this->assertSame(3, $deque->size()); + $this->assertSame(3, $deque->peek()); + $this->assertSame(1, $deque->peekLast()); + } + + // Test capacity expansion during removeLast operations + public function testEnsureCapacityExpandsDuringRemoveLastOperations(): void + { + $deque = new ArrayDeque(2); + $deque->enqueue(1); + $deque->enqueue(2); + $deque->enqueue(3); // Should trigger capacity increase + $deque->removeLast(); + $deque->removeLast(); + $this->assertSame(1, $deque->size()); + $this->assertSame(1, $deque->peek()); + } + + // Test mixed operations of addFirst, addLast, removeFirst, and removeLast + public function testMixedOperations(): void + { + $deque = new ArrayDeque(); + $deque->addFirst(1); + $deque->enqueue(2); + $deque->addFirst(0); + $this->assertSame(0, $deque->dequeue()); + $this->assertSame(1, $deque->dequeue()); + $this->assertSame(2, $deque->removeLast()); + $deque->enqueue(3); + $deque->addFirst(4); + $this->assertSame(4, $deque->peek()); + $this->assertSame(3, $deque->peekLast()); + } + + // Test clearing the deque + public function testClearEmptiesTheDeque(): void + { + $deque = new ArrayDeque(); + $deque->enqueue(1); + $deque->enqueue(2); + $deque->clear(); + $this->assertTrue($deque->isEmpty()); + $this->assertNull($deque->peek()); + $this->assertNull($deque->peekLast()); + $this->assertNull($deque->dequeue()); + $this->assertNull($deque->removeLast()); + } + + // Test getting all items + public function testGetItemsReturnsAllElementsInCorrectOrder(): void + { + $deque = new ArrayDeque(); + $deque->enqueue(1); + $deque->enqueue(2); + $deque->enqueue(3); + $this->assertSame([1, 2, 3], $deque->getItems()); + } } diff --git a/tests/Queue/ArrayQueueTest.php b/tests/Queue/ArrayQueueTest.php index 536080b..073a5f4 100644 --- a/tests/Queue/ArrayQueueTest.php +++ b/tests/Queue/ArrayQueueTest.php @@ -115,4 +115,26 @@ public function testQueueBehaviorAfterMixedOperations(): void $this->assertSame(3, $queue->dequeue()); $this->assertSame(4, $queue->peek()); } + + // Test clearing the queue + public function testClearEmptiesTheQueue(): void + { + $queue = new ArrayQueue(); + $queue->enqueue(1); + $queue->enqueue(2); + $queue->clear(); + $this->assertTrue($queue->isEmpty()); + $this->assertNull($queue->peek()); + $this->assertNull($queue->dequeue()); + } + + // Test getting all items + public function testGetItemsReturnsAllElementsInCorrectOrder(): void + { + $queue = new ArrayQueue(); + $queue->enqueue(1); + $queue->enqueue(2); + $queue->enqueue(3); + $this->assertSame([1, 2, 3], $queue->getItems()); + } }