Add StrictQueue and StrictStack data structures
This commit is contained in:
parent
9cb46b4935
commit
0b3e23ebdc
|
@ -0,0 +1,298 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful PHP Basics
|
||||||
|
* Copyright (C) 2023 Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace OCC\Basics\DataStructures;
|
||||||
|
|
||||||
|
use Countable;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Iterator;
|
||||||
|
use OCC\Basics\Traits\Getter;
|
||||||
|
use Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for a type-sensitive list of items.
|
||||||
|
*
|
||||||
|
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
* @package opencultureconsulting/basics
|
||||||
|
* @implements \Countable
|
||||||
|
* @implements \Iterator
|
||||||
|
* @implements \Serializable
|
||||||
|
*/
|
||||||
|
abstract class AbstractStrictList implements Countable, Iterator, Serializable
|
||||||
|
{
|
||||||
|
use Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The items.
|
||||||
|
*/
|
||||||
|
protected array $items = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count of iterations.
|
||||||
|
*/
|
||||||
|
protected int $iterations = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the allowed types for items.
|
||||||
|
* If empty, all types are allowed.
|
||||||
|
* Possible values are:
|
||||||
|
* - "array"
|
||||||
|
* - "bool"
|
||||||
|
* - "callable"
|
||||||
|
* - "countable"
|
||||||
|
* - "float" or "double"
|
||||||
|
* - "int" or "integer" or "long"
|
||||||
|
* - "iterable"
|
||||||
|
* - "null"
|
||||||
|
* - "numeric"
|
||||||
|
* - "object" or FQCN
|
||||||
|
* - "resource"
|
||||||
|
* - "scalar"
|
||||||
|
* - "string"
|
||||||
|
* Fully qualified class names (FQCN) can be specified instead of the
|
||||||
|
* generic type "object".
|
||||||
|
*/
|
||||||
|
protected array $allowedTypes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append items.
|
||||||
|
*
|
||||||
|
* @param mixed ...$items One or more items to add
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function append(mixed ...$items): void
|
||||||
|
{
|
||||||
|
if (!empty($this->allowedTypes)) {
|
||||||
|
foreach ($items as $count => $item) {
|
||||||
|
if (!$this->isAllowedType($item)) {
|
||||||
|
throw new InvalidArgumentException('Item ' . $count + 1 . ' must be an allowed type, ' . get_debug_type($item) . ' given.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->items = array_merge($this->items, $items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of items.
|
||||||
|
* @see Countable::count
|
||||||
|
*
|
||||||
|
* @return int The number of items
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return count($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all items.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function clear(): void
|
||||||
|
{
|
||||||
|
$this->items = [];
|
||||||
|
$this->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get and remove the current item.
|
||||||
|
* @see Iterator::current
|
||||||
|
*
|
||||||
|
* @return mixed The current item or NULL if empty
|
||||||
|
*/
|
||||||
|
abstract public function current(): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an item is an allowed type.
|
||||||
|
*
|
||||||
|
* @param mixed $item The item to check
|
||||||
|
*
|
||||||
|
* @return bool Whether the item is an allowed type
|
||||||
|
*/
|
||||||
|
protected function isAllowedType(mixed $item): bool
|
||||||
|
{
|
||||||
|
if (empty($this->allowedTypes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach ($this->allowedTypes as $type) {
|
||||||
|
$function = 'is_' . $type;
|
||||||
|
$fqcn = '\\' . ltrim($type, '\\');
|
||||||
|
if (function_exists($function) && $function($item)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_object($item) && is_a($item, $fqcn)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of the current iteration.
|
||||||
|
* @see Iterator::key
|
||||||
|
*
|
||||||
|
* @return int The number of the current iteration
|
||||||
|
*/
|
||||||
|
public function key(): int
|
||||||
|
{
|
||||||
|
return $this->iterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic getter method for $this->allowedTypes.
|
||||||
|
* @see OCC\Basics\Traits\Getter
|
||||||
|
*
|
||||||
|
* @return array The list of allowed item types
|
||||||
|
*/
|
||||||
|
protected function magicGetAllowedTypes(): array
|
||||||
|
{
|
||||||
|
return $this->allowedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the next iteration.
|
||||||
|
* @see Iterator::next
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function next(): void
|
||||||
|
{
|
||||||
|
++$this->iterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current item without removing it.
|
||||||
|
*
|
||||||
|
* @return mixed The current item or NULL if empty
|
||||||
|
*/
|
||||||
|
abstract public function peek(): mixed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the iterator position.
|
||||||
|
* @see Iterator::rewind
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function rewind(): void
|
||||||
|
{
|
||||||
|
$this->iterations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get string representation of $this.
|
||||||
|
* @see Serializable::serialize
|
||||||
|
*
|
||||||
|
* @return ?string String representation
|
||||||
|
*/
|
||||||
|
public function serialize(): ?string
|
||||||
|
{
|
||||||
|
return serialize($this->__serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore $this from string representation.
|
||||||
|
* @see Serializable::unserialize
|
||||||
|
*
|
||||||
|
* @param string $data String representation
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unserialize($data): void
|
||||||
|
{
|
||||||
|
$this->__unserialize(unserialize($data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are any items.
|
||||||
|
* @see Iterator::valid
|
||||||
|
*
|
||||||
|
* @return bool Whether there are items
|
||||||
|
*/
|
||||||
|
public function valid(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset iteration counter after cloning.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __clone(): void
|
||||||
|
{
|
||||||
|
$this->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a (type-sensitive) traversable set of items.
|
||||||
|
*
|
||||||
|
* @param array $items Initial set of items
|
||||||
|
* @param string[] $allowedTypes Allowed types of items (optional)
|
||||||
|
*/
|
||||||
|
public function __construct(array $items = [], array $allowedTypes = [])
|
||||||
|
{
|
||||||
|
if (!empty($allowedTypes)) {
|
||||||
|
if (array_sum(array_map('is_string', $allowedTypes)) !== count($allowedTypes)) {
|
||||||
|
throw new InvalidArgumentException('Allowed types must be array of strings or empty array.');
|
||||||
|
}
|
||||||
|
$this->allowedTypes = $allowedTypes;
|
||||||
|
}
|
||||||
|
$this->append(...$items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get debug information for $this.
|
||||||
|
*
|
||||||
|
* @return array Array of debug information
|
||||||
|
*/
|
||||||
|
public function __debugInfo(): array
|
||||||
|
{
|
||||||
|
return $this->__serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get array representation of $this.
|
||||||
|
*
|
||||||
|
* @return array Array representation
|
||||||
|
*/
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'allowedTypes' => $this->allowedTypes,
|
||||||
|
'items' => $this->items
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore $this from array representation.
|
||||||
|
*
|
||||||
|
* @param array $data Array representation
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __unserialize(array $data): void
|
||||||
|
{
|
||||||
|
$this->allowedTypes = $data['allowedTypes'] ?? [];
|
||||||
|
$this->items = $data['items'] ?? [];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,303 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Useful PHP Basics
|
|
||||||
* Copyright (C) 2023 Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace OCC\Basics\DataStructures;
|
|
||||||
|
|
||||||
use ArrayAccess;
|
|
||||||
use Countable;
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use OCC\Basics\Traits\Getter;
|
|
||||||
use OutOfBoundsException;
|
|
||||||
use OutOfRangeException;
|
|
||||||
use SeekableIterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles an ordered queue of items - optionally type-sensitive.
|
|
||||||
*
|
|
||||||
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
|
||||||
* @package opencultureconsulting/basics
|
|
||||||
* @implements ArrayAccess
|
|
||||||
* @implements Countable
|
|
||||||
* @implements SeekableIterator
|
|
||||||
*/
|
|
||||||
class Queue implements ArrayAccess, Countable, SeekableIterator
|
|
||||||
{
|
|
||||||
use Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the queue's elements.
|
|
||||||
*/
|
|
||||||
protected array $queue = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the queue's current index.
|
|
||||||
*/
|
|
||||||
protected int $index = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the allowed types for the queue's elements.
|
|
||||||
* If empty, all types are allowed.
|
|
||||||
* Possible values are:
|
|
||||||
* - "array"
|
|
||||||
* - "bool"
|
|
||||||
* - "callable"
|
|
||||||
* - "countable"
|
|
||||||
* - "float" or "double"
|
|
||||||
* - "int" or "integer" or "long"
|
|
||||||
* - "iterable"
|
|
||||||
* - "null"
|
|
||||||
* - "numeric"
|
|
||||||
* - "object" or FQCN
|
|
||||||
* - "resource"
|
|
||||||
* - "scalar"
|
|
||||||
* - "string"
|
|
||||||
* Fully qualified class names (FQCN) can be specified instead of the
|
|
||||||
* generic type "object".
|
|
||||||
*/
|
|
||||||
protected array $allowedTypes = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a variable is an allowed type.
|
|
||||||
*
|
|
||||||
* @param mixed $var The variable to check
|
|
||||||
*
|
|
||||||
* @return bool Whether the variable is an allowed type
|
|
||||||
*/
|
|
||||||
protected function isAllowedType(mixed $var): bool
|
|
||||||
{
|
|
||||||
if (empty($this->allowedTypes)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
foreach ($this->allowedTypes as $type) {
|
|
||||||
$function = 'is_' . $type;
|
|
||||||
$fqcn = '\\' . ltrim($type, '\\');
|
|
||||||
if (function_exists($function) && $function($var)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (is_object($var) && is_a($var, $fqcn)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given index is in the range of valid indexes.
|
|
||||||
*
|
|
||||||
* @param mixed $offset The index to check
|
|
||||||
* @param bool $allowAppend Should the next free index be valid as well?
|
|
||||||
*
|
|
||||||
* @return bool Whether the given index is in valid range
|
|
||||||
*/
|
|
||||||
protected function isIndexInRange(mixed $offset, bool $allowAppend = false): bool
|
|
||||||
{
|
|
||||||
$options = [
|
|
||||||
'options' => [
|
|
||||||
'min_range' => 0,
|
|
||||||
'max_range' => count($this->queue) - ($allowAppend ? 0 : 1)
|
|
||||||
]
|
|
||||||
];
|
|
||||||
return filter_var($offset, FILTER_VALIDATE_INT, $options) !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a given index exists on the queue.
|
|
||||||
* @see ArrayAccess::offsetExists
|
|
||||||
*
|
|
||||||
* @param int $offset The queue's index to check
|
|
||||||
*
|
|
||||||
* @return bool Whether the given index is valid
|
|
||||||
*/
|
|
||||||
public function offsetExists(mixed $offset): bool
|
|
||||||
{
|
|
||||||
return isset($this->queue[$offset]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the element with given index from the queue.
|
|
||||||
* @see ArrayAccess::offsetGet
|
|
||||||
*
|
|
||||||
* @param int $offset The queue's index to get
|
|
||||||
*
|
|
||||||
* @return ?mixed The queue's element at given index or NULL
|
|
||||||
*/
|
|
||||||
public function offsetGet(mixed $offset): mixed
|
|
||||||
{
|
|
||||||
return $this->queue[$offset] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the element at given index in the queue.
|
|
||||||
* @see ArrayAccess::offsetSet
|
|
||||||
*
|
|
||||||
* @param ?int $offset The queue's index to set or NULL to append
|
|
||||||
* Must be between 0 and the length of the queue.
|
|
||||||
* @param mixed $value The element to set at the given index
|
|
||||||
* Must be of an allowed type if applicable.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws OutOfRangeException
|
|
||||||
*/
|
|
||||||
public function offsetSet(mixed $offset, mixed $value): void
|
|
||||||
{
|
|
||||||
if (is_null($offset)) {
|
|
||||||
$offset = count($this->queue);
|
|
||||||
} elseif (!$this->isIndexInRange($offset, true)) {
|
|
||||||
throw new OutOfRangeException('Index must be an integer between 0 and the length of the queue (' . count($this->queue) . ') or NULL to append: ' . get_debug_type($offset) . (is_int($offset) ? ' ' . (string) $offset : '') . ' given.');
|
|
||||||
}
|
|
||||||
if (!$this->isAllowedType($value)) {
|
|
||||||
throw new InvalidArgumentException('Value must be one of ' . implode(', ', $this->allowedTypes) . ': ' . get_debug_type($value) . ' given.');
|
|
||||||
}
|
|
||||||
$this->queue[(int) $offset] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the element with given index from the queue.
|
|
||||||
* @see ArrayAccess::offsetUnset
|
|
||||||
*
|
|
||||||
* @param int $offset The queue's index to unset
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function offsetUnset(mixed $offset): void
|
|
||||||
{
|
|
||||||
if ($this->isIndexInRange($offset)) {
|
|
||||||
array_splice($this->queue, (int) $offset, 1);
|
|
||||||
if ((int) $offset <= $this->index) {
|
|
||||||
--$this->index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of elements in the queue.
|
|
||||||
* @see Countable::count
|
|
||||||
*
|
|
||||||
* @return int The number of items in the queue
|
|
||||||
*/
|
|
||||||
public function count(): int
|
|
||||||
{
|
|
||||||
return count($this->queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current element from the queue.
|
|
||||||
* @see Iterator::current
|
|
||||||
*
|
|
||||||
* @return mixed|null The queue's current element or NULL
|
|
||||||
*/
|
|
||||||
public function current(): mixed
|
|
||||||
{
|
|
||||||
return $this->queue[$this->index] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current index from the queue.
|
|
||||||
* @see Iterator::key
|
|
||||||
*
|
|
||||||
* @return int The queue's current index
|
|
||||||
*/
|
|
||||||
public function key(): int
|
|
||||||
{
|
|
||||||
return $this->index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the index to next element of the queue.
|
|
||||||
* @see Iterator::next
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function next(): void
|
|
||||||
{
|
|
||||||
++$this->index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the index to the first element of the queue.
|
|
||||||
* @see Iterator::rewind
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function rewind(): void
|
|
||||||
{
|
|
||||||
$this->index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the queue's current index is valid.
|
|
||||||
* @see Iterator::valid
|
|
||||||
*
|
|
||||||
* @return bool Whether the queue's current index is valid
|
|
||||||
*/
|
|
||||||
public function valid(): bool
|
|
||||||
{
|
|
||||||
return isset($this->queue[$this->index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the queue's current index.
|
|
||||||
* @see SeekableIterator::seek
|
|
||||||
*
|
|
||||||
* @param int $offset The queue's new index
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @throws OutOfBoundsException
|
|
||||||
*/
|
|
||||||
public function seek(int $offset): void
|
|
||||||
{
|
|
||||||
if (!$this->isIndexInRange($offset)) {
|
|
||||||
throw new OutOfBoundsException('Index must be an integer between 0 and the length of the queue (' . count($this->queue) . '): ' . (string) $offset . ' given.');
|
|
||||||
}
|
|
||||||
$this->index = $offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Magic getter method for $this->allowedTypes.
|
|
||||||
* @see OCC\Traits\Getter
|
|
||||||
*
|
|
||||||
* @return array The list of the queue's allowed element types
|
|
||||||
*/
|
|
||||||
protected function magicGetAllowedTypes(): array
|
|
||||||
{
|
|
||||||
return $this->allowedTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a (type-sensitive) queue of elements.
|
|
||||||
* @see OCC\Helper\Queue::allowedTypes
|
|
||||||
*
|
|
||||||
* @param string[] $allowedTypes Allowed types of queue's elements
|
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public function __construct(array $allowedTypes = [])
|
|
||||||
{
|
|
||||||
if (array_sum(array_map('is_string', $allowedTypes)) !== count($allowedTypes)) {
|
|
||||||
throw new InvalidArgumentException('Parameter 1 must be array of strings or empty array.');
|
|
||||||
}
|
|
||||||
$this->allowedTypes = $allowedTypes;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful PHP Basics
|
||||||
|
* Copyright (C) 2023 Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace OCC\Basics\DataStructures;
|
||||||
|
|
||||||
|
use Countable;
|
||||||
|
use Iterator;
|
||||||
|
use Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (type-sensitive) destructive First In, First Out Queue.
|
||||||
|
*
|
||||||
|
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
* @package opencultureconsulting/basics
|
||||||
|
* @implements \Countable
|
||||||
|
* @implements \Iterator
|
||||||
|
* @implements \Serializable
|
||||||
|
*/
|
||||||
|
class StrictQueue extends AbstractStrictList
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get and remove the first item.
|
||||||
|
* @see Iterator::current
|
||||||
|
*
|
||||||
|
* @return mixed The first item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return array_shift($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dequeue the first item.
|
||||||
|
* Alias of Queue::current
|
||||||
|
*
|
||||||
|
* @return mixed The first item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function dequeue(): mixed
|
||||||
|
{
|
||||||
|
return $this->current();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue items.
|
||||||
|
* Alias of Queue::append
|
||||||
|
*
|
||||||
|
* @param mixed ...$items One or more items to add
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function enqueue(mixed ...$items): void
|
||||||
|
{
|
||||||
|
$this->append(...$items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first item without removing it.
|
||||||
|
*
|
||||||
|
* @return mixed The first item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function peek(): mixed
|
||||||
|
{
|
||||||
|
return $this->items[array_key_first($this->items)] ?? null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful PHP Basics
|
||||||
|
* Copyright (C) 2023 Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace OCC\Basics\DataStructures;
|
||||||
|
|
||||||
|
use Countable;
|
||||||
|
use Iterator;
|
||||||
|
use Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (type-sensitive) destructive Last In, First Out Stack.
|
||||||
|
*
|
||||||
|
* @author Sebastian Meyer <sebastian.meyer@opencultureconsulting.com>
|
||||||
|
* @package opencultureconsulting/basics
|
||||||
|
* @implements \Countable
|
||||||
|
* @implements \Iterator
|
||||||
|
* @implements \Serializable
|
||||||
|
*/
|
||||||
|
class StrictStack extends AbstractStrictList
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get and remove the last item.
|
||||||
|
* @see Iterator::current
|
||||||
|
*
|
||||||
|
* @return mixed The last item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return array_pop($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last item without removing it.
|
||||||
|
*
|
||||||
|
* @return mixed The first item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function peek(): mixed
|
||||||
|
{
|
||||||
|
return $this->items[array_key_last($this->items)] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack items.
|
||||||
|
* Alias of Stack::append
|
||||||
|
*
|
||||||
|
* @param mixed ...$items One or more items to add
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function stack(mixed ...$items): void
|
||||||
|
{
|
||||||
|
$this->append(...$items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unstack the last item.
|
||||||
|
* Alias of Stack::current
|
||||||
|
*
|
||||||
|
* @return mixed The last item or NULL if empty
|
||||||
|
*/
|
||||||
|
public function unstack(): mixed
|
||||||
|
{
|
||||||
|
return $this->current();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue