Commit 577f5ca
committed
Proposal: Add
This has lower memory usage and better performance than SplDoublyLinkedList for
push/pop operations.
The API is as follows:
```php
/**
* A double-ended queue represented internally as a circular buffer.
* This has much lower memory usage than SplDoublyLinkedList or its subclasses (SplStack, SplStack),
* and operations are significantly faster than SplDoublyLinkedList.
*
* This supports amortized constant time pushing and popping onto the front or back of the array.
*
* Naming is based on https://www.php.net/spldoublylinkedlist
* and on array_push/pop/unshift/shift.
*/
final class Deque implements IteratorAggregate, Countable, JsonSerializable, ArrayAccess
{
/** Construct the Deque from the values of the Traversable/array, ignoring keys */
public function __construct(iterable $iterator = []) {}
/**
* The final version of getIterator will iterate over a copy of the Deque's values taken at the time getIterator was called.
* The iteration keys will be the offsets of the copy(0, 1, ...), and the values will be the values from front to back.
*
* i.e. `foreach($deque as $k => $v)` and `foreach($deque->toArray() as $k => $v)` will iterate over the same elements.
*
* This will be done to avoid surprises in case pushFront/popFront/clear are called.
*
* To access the current version of the Deque without making a copy,
* use `for ($i = 0; $i < count($deque); $i++) { process($deque[$i]); }`.
*/
public function getIterator(): InternalIterator {}
/** Returns the number of elements in the Deque. */
public function count(): int {}
/** Returns true if there are 0 elements in the Deque. */
public function isEmpty(): bool {}
/** Removes all elements from the Deque. */
public function clear(): void {}
public function __serialize(): array {}
public function __unserialize(array $data): void {}
/** Construct the Deque from the values of the array, ignoring keys */
public static function __set_state(array $array): Deque {}
/** Appends value(s) to the end of the Deque. */
public function push(mixed $value): void {}
/** Prepends value(s) to the start of the Deque. */
public function unshift(mixed ...$values): void {}
/** Pops a value from the end of the Deque. */
public function pop(): mixed {}
/** Shifts a value from the front of the Deque. */
public function shift(): mixed {}
/** Peeks at the value at the start of the Deque, throws if empty */
public function bottom(): mixed {}
/** Peeks at the value at the end of the Deque, throws if empty */
public function top(): mixed {}
/** Returns a list of the elements from front to back. */
public function toArray(): array {}
/* Get and set are strictly typed, unlike offsetGet/offsetSet. */
public function get(int $offset): mixed {}
public function set(int $offset, mixed $value): void {}
// Must be mixed for compatibility with ArrayAccess
public function offsetGet(mixed $offset): mixed {}
public function offsetExists(mixed $offset): bool {}
public function offsetSet(mixed $offset, mixed $value): void {}
/** Throws unconditionally */
public function offsetUnset(mixed $offset): void {}
/** This is JSON serialized as a JSON array with elements from front to back */
public function jsonSerialize(): array {}
}
```
Earlier work on the implementation can be found at
https://github.com/TysonAndre/pecl-teds
(though `Teds\Deque` hasn't been updated with new names yet)
This was originally based on spl_fixedarray.c and previous work I did on an RFC.
Notable features of `Deque`
- Significantly lower memory usage and better performance than
`SplDoublyLinkedList`
- Amortized constant time operations for push/pop/unshift/shift.
- Reclaims memory when roughly a quarter of the capacity is used,
unlike array, which never releases allocated capacity
https://www.npopov.com/2014/12/22/PHPs-new-hashtable-implementation.html
> One problem with the current implementation is that arData never shrinks
> (unless explicitly told to). So if you create an array with a few million
> elements and remove them afterwards, the array will still take a lot of
> memory. We should probably half the arData size if utilization falls below a
> certain level.
For long-running applications when the maximum count of Deque
is larger than the average count, this may be a concern.
- Adds functionality that cannot be implemented nearly efficiently in
an array. For example, shifting a single element onto an array
(and making it first in iteration order) with `array_shift`
would take linear time, because all elements in the array
would need to be moved to make room for the first one
- Support `$deque[] = $element`, like ArrayObject.
- Having this functionality in php itself rather than a third party extension
would encourage wider adoption of this
Backwards incompatible changes:
- Userland classlikes named \Deque in the global namespace would
cause a compile error due to this class now being declared internally.final class Deque to PHP1 parent 80d2ade commit 577f5ca
File tree
33 files changed
+2455
-35
lines changed- ext/spl
- tests/Deque
33 files changed
+2455
-35
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
| 1 | + | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
708 | 709 | | |
709 | 710 | | |
710 | 711 | | |
| 712 | + | |
711 | 713 | | |
712 | 714 | | |
713 | 715 | | |
| |||
0 commit comments