b2pweb /
bdf-collections
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace Bdf\Collection\Stream; |
||||
| 4 | |||||
| 5 | use Bdf\Collection\Util\Optional; |
||||
| 6 | use Bdf\Collection\Util\OptionalInterface; |
||||
| 7 | use Iterator; |
||||
| 8 | use function asort; |
||||
| 9 | use function current; |
||||
| 10 | use function key; |
||||
| 11 | use function next; |
||||
| 12 | use function reset; |
||||
| 13 | use function sort; |
||||
| 14 | use function uasort; |
||||
| 15 | use function usort; |
||||
| 16 | |||||
| 17 | /** |
||||
| 18 | * Implementation of StreamInterface::sort() return value |
||||
| 19 | * |
||||
| 20 | * @template T |
||||
| 21 | * |
||||
| 22 | * @implements StreamInterface<T, array-key> |
||||
| 23 | * @implements Iterator<array-key, T> |
||||
| 24 | * |
||||
| 25 | * @internal |
||||
| 26 | */ |
||||
| 27 | final class SortStream implements Iterator, StreamInterface |
||||
| 28 | { |
||||
| 29 | use StreamTrait; |
||||
| 30 | |||||
| 31 | /** |
||||
| 32 | * @var StreamInterface<T, mixed> |
||||
| 33 | */ |
||||
| 34 | private $stream; |
||||
| 35 | |||||
| 36 | /** |
||||
| 37 | * @var callable(T,T):int|null |
||||
| 38 | */ |
||||
| 39 | private $comparator; |
||||
| 40 | |||||
| 41 | /** |
||||
| 42 | * @var bool |
||||
| 43 | */ |
||||
| 44 | private $preserveKeys; |
||||
| 45 | |||||
| 46 | /** |
||||
| 47 | * @var T[]|null |
||||
| 48 | */ |
||||
| 49 | private $data = null; |
||||
| 50 | |||||
| 51 | |||||
| 52 | /** |
||||
| 53 | * SortStream constructor. |
||||
| 54 | * |
||||
| 55 | * @param StreamInterface<T, mixed> $stream |
||||
| 56 | * @param callable(T,T):int|null $comparator |
||||
| 57 | * @param bool $preserveKeys |
||||
| 58 | */ |
||||
| 59 | 39 | public function __construct(StreamInterface $stream, ?callable $comparator = null, bool $preserveKeys = true) |
|||
| 60 | { |
||||
| 61 | 39 | $this->stream = $stream; |
|||
| 62 | 39 | $this->comparator = $comparator; |
|||
| 63 | 39 | $this->preserveKeys = $preserveKeys; |
|||
| 64 | 39 | } |
|||
| 65 | |||||
| 66 | /** |
||||
| 67 | * {@inheritdoc} |
||||
| 68 | * |
||||
| 69 | * @psalm-suppress InvalidReturnType |
||||
| 70 | */ |
||||
| 71 | 22 | public function toArray(bool $preserveKeys = true): array |
|||
| 72 | { |
||||
| 73 | 22 | if ($this->data === null) { |
|||
| 74 | 22 | $this->buildData(); |
|||
| 75 | } |
||||
| 76 | |||||
| 77 | // Built data keep keys, but toArray() request without keys |
||||
| 78 | // So call array_values to remove keys |
||||
| 79 | /** @psalm-suppress RedundantConditionGivenDocblockType */ |
||||
| 80 | 22 | if (!$preserveKeys && $this->preserveKeys) { |
|||
| 81 | 2 | return array_values($this->data); |
|||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 82 | } |
||||
| 83 | |||||
| 84 | 21 | return $this->data; |
|||
|
0 ignored issues
–
show
|
|||||
| 85 | } |
||||
| 86 | |||||
| 87 | /** |
||||
| 88 | * {@inheritdoc} |
||||
| 89 | */ |
||||
| 90 | 1 | public function forEach(callable $consumer): void |
|||
| 91 | { |
||||
| 92 | 1 | foreach ($this->toArray() as $k => $v) { |
|||
| 93 | 1 | $consumer($v, $k); |
|||
| 94 | } |
||||
| 95 | 1 | } |
|||
| 96 | |||||
| 97 | /** |
||||
| 98 | * {@inheritdoc} |
||||
| 99 | */ |
||||
| 100 | 2 | public function first(): OptionalInterface |
|||
| 101 | { |
||||
| 102 | 2 | $empty = true; |
|||
| 103 | 2 | $min = null; |
|||
| 104 | |||||
| 105 | 2 | foreach ($this->stream as $value) { |
|||
| 106 | 2 | if ($empty) { |
|||
| 107 | 2 | $min = $value; |
|||
| 108 | 2 | $empty = false; |
|||
| 109 | } else { |
||||
| 110 | 2 | if ($this->comparator === null) { |
|||
| 111 | 1 | if ($value < $min) { |
|||
| 112 | 1 | $min = $value; |
|||
| 113 | } |
||||
| 114 | 1 | } elseif (($this->comparator)($value, $min) < 0) { |
|||
| 115 | 1 | $min = $value; |
|||
| 116 | } |
||||
| 117 | } |
||||
| 118 | } |
||||
| 119 | |||||
| 120 | 2 | return Optional::nullable($min); |
|||
| 121 | } |
||||
| 122 | |||||
| 123 | /** |
||||
| 124 | * {@inheritdoc} |
||||
| 125 | */ |
||||
| 126 | #[\ReturnTypeWillChange] |
||||
| 127 | 15 | public function current() |
|||
| 128 | { |
||||
| 129 | 15 | if ($this->data === null) { |
|||
| 130 | $this->buildData(); |
||||
| 131 | } |
||||
| 132 | |||||
| 133 | 15 | return current($this->data); |
|||
|
0 ignored issues
–
show
It seems like
$this->data can also be of type null; however, parameter $array of current() does only seem to accept array|object, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 134 | } |
||||
| 135 | |||||
| 136 | /** |
||||
| 137 | * {@inheritdoc} |
||||
| 138 | */ |
||||
| 139 | 15 | public function next(): void |
|||
| 140 | { |
||||
| 141 | 15 | if ($this->data === null) { |
|||
| 142 | $this->buildData(); |
||||
| 143 | } |
||||
| 144 | |||||
| 145 | 15 | next($this->data); |
|||
|
0 ignored issues
–
show
It seems like
$this->data can also be of type null; however, parameter $array of next() does only seem to accept array|object, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 146 | 15 | } |
|||
| 147 | |||||
| 148 | /** |
||||
| 149 | * {@inheritdoc} |
||||
| 150 | */ |
||||
| 151 | #[\ReturnTypeWillChange] |
||||
| 152 | 13 | public function key() |
|||
| 153 | { |
||||
| 154 | 13 | if ($this->data === null) { |
|||
| 155 | $this->buildData(); |
||||
| 156 | } |
||||
| 157 | |||||
| 158 | 13 | return key($this->data); |
|||
|
0 ignored issues
–
show
It seems like
$this->data can also be of type null; however, parameter $array of key() does only seem to accept array|object, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 159 | } |
||||
| 160 | |||||
| 161 | /** |
||||
| 162 | * {@inheritdoc} |
||||
| 163 | */ |
||||
| 164 | 15 | public function valid(): bool |
|||
| 165 | { |
||||
| 166 | 15 | if ($this->data === null) { |
|||
| 167 | 1 | $this->buildData(); |
|||
| 168 | } |
||||
| 169 | |||||
| 170 | 15 | return key($this->data) !== null; |
|||
|
0 ignored issues
–
show
It seems like
$this->data can also be of type null; however, parameter $array of key() does only seem to accept array|object, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 171 | } |
||||
| 172 | |||||
| 173 | /** |
||||
| 174 | * {@inheritdoc} |
||||
| 175 | */ |
||||
| 176 | 14 | public function rewind(): void |
|||
| 177 | { |
||||
| 178 | 14 | if ($this->data === null) { |
|||
| 179 | 14 | $this->buildData(); |
|||
| 180 | } |
||||
| 181 | |||||
| 182 | 14 | reset($this->data); |
|||
|
0 ignored issues
–
show
It seems like
$this->data can also be of type null; however, parameter $array of reset() does only seem to accept array|object, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 183 | 14 | } |
|||
| 184 | |||||
| 185 | /** |
||||
| 186 | * Build the inner sorted data array |
||||
| 187 | * |
||||
| 188 | * @psalm-assert !null $this->data |
||||
| 189 | */ |
||||
| 190 | 37 | private function buildData(): void |
|||
| 191 | { |
||||
| 192 | 37 | $data = $this->stream->toArray($this->preserveKeys); |
|||
| 193 | |||||
| 194 | 37 | if ($this->comparator) { |
|||
| 195 | 7 | if ($this->preserveKeys) { |
|||
| 196 | 2 | uasort($data, $this->comparator); |
|||
| 197 | } else { |
||||
| 198 | 7 | usort($data, $this->comparator); |
|||
| 199 | } |
||||
| 200 | 31 | } elseif($this->preserveKeys) { |
|||
| 201 | 18 | asort($data); |
|||
| 202 | } else { |
||||
| 203 | 15 | sort($data); |
|||
| 204 | } |
||||
| 205 | |||||
| 206 | 37 | $this->data = $data; |
|||
| 207 | 37 | } |
|||
| 208 | } |
||||
| 209 |