Innmind /
Immutable
| 1 | <?php |
||
| 2 | declare(strict_types = 1); |
||
| 3 | |||
| 4 | namespace Innmind\Immutable\Map; |
||
| 5 | |||
| 6 | use Innmind\Immutable\{ |
||
| 7 | Map, |
||
| 8 | Str, |
||
| 9 | Sequence, |
||
| 10 | Set, |
||
| 11 | Pair, |
||
| 12 | Maybe, |
||
| 13 | SideEffect, |
||
| 14 | }; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * @template T |
||
| 18 | * @template S |
||
| 19 | * @psalm-immutable |
||
| 20 | */ |
||
| 21 | final class Primitive implements Implementation |
||
| 22 | { |
||
| 23 | /** @var array<T, S> */ |
||
| 24 | private array $values; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @param array<T, S> $values |
||
| 28 | */ |
||
| 29 | public function __construct(array $values = []) |
||
| 30 | { |
||
| 31 | $this->values = $values; |
||
| 32 | } |
||
| 33 | 76 | ||
| 34 | /** |
||
| 35 | 76 | * @param T $key |
|
|
0 ignored issues
–
show
|
|||
| 36 | * @param S $value |
||
|
0 ignored issues
–
show
The type
Innmind\Immutable\Map\S was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 37 | 76 | * |
|
| 38 | 1 | * @return Implementation<T, S> |
|
| 39 | */ |
||
| 40 | public function __invoke($key, $value): Implementation |
||
| 41 | 75 | { |
|
| 42 | 75 | /** @psalm-suppress DocblockTypeContradiction */ |
|
| 43 | 75 | if (\is_string($key) && \is_numeric($key)) { |
|
|
0 ignored issues
–
show
|
|||
| 44 | 75 | // numeric-string keys are casted to ints by php, so when iterating |
|
| 45 | 75 | // over the array afterward the type is not conserved so we switch |
|
| 46 | 75 | // the implementation to DoubleIndex so keep the type |
|
| 47 | return (new DoubleIndex)->merge($this)($key, $value); |
||
| 48 | 23 | } |
|
| 49 | |||
| 50 | 23 | $values = $this->values; |
|
| 51 | $values[$key] = $value; |
||
| 52 | |||
| 53 | 20 | return new self($values); |
|
| 54 | } |
||
| 55 | 20 | ||
| 56 | /** |
||
| 57 | * @template A |
||
| 58 | 31 | * @template B |
|
| 59 | * |
||
| 60 | * @param A $key |
||
|
0 ignored issues
–
show
The type
Innmind\Immutable\Map\A was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 61 | 31 | * @param B $value |
|
|
0 ignored issues
–
show
The type
Innmind\Immutable\Map\B was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 62 | * |
||
| 63 | * @return Maybe<Implementation<A, B>> |
||
| 64 | */ |
||
| 65 | public static function of($key, $value): Maybe |
||
| 66 | { |
||
| 67 | 15 | /** @psalm-suppress DocblockTypeContradiction */ |
|
| 68 | if (\is_string($key) && \is_numeric($key)) { |
||
|
0 ignored issues
–
show
|
|||
| 69 | 15 | /** @var Maybe<Implementation<A, B>> */ |
|
| 70 | return Maybe::nothing(); |
||
| 71 | } |
||
| 72 | |||
| 73 | if (\is_string($key) || \is_int($key)) { |
||
|
0 ignored issues
–
show
|
|||
| 74 | /** @var self<A, B> */ |
||
| 75 | $self = new self; |
||
| 76 | |||
| 77 | return Maybe::just(($self)($key, $value)); |
||
| 78 | 62 | } |
|
| 79 | |||
| 80 | 62 | /** @var Maybe<Implementation<A, B>> */ |
|
| 81 | 61 | return Maybe::nothing(); |
|
| 82 | } |
||
| 83 | 60 | ||
| 84 | 60 | public function size(): int |
|
| 85 | 60 | { |
|
| 86 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
| 87 | 60 | return \count($this->values); |
|
| 88 | } |
||
| 89 | |||
| 90 | public function count(): int |
||
| 91 | { |
||
| 92 | return $this->size(); |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * @param T $key |
||
| 97 | 34 | * |
|
| 98 | * @return Maybe<S> |
||
| 99 | 34 | */ |
|
| 100 | 2 | public function get($key): Maybe |
|
| 101 | { |
||
| 102 | if (!$this->contains($key)) { |
||
| 103 | 32 | return Maybe::nothing(); |
|
| 104 | } |
||
| 105 | |||
| 106 | return Maybe::just($this->values[$key]); |
||
| 107 | } |
||
| 108 | |||
| 109 | 39 | /** |
|
| 110 | * @param T $key |
||
| 111 | */ |
||
| 112 | 39 | public function contains($key): bool |
|
| 113 | { |
||
| 114 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
| 115 | return \array_key_exists($key, $this->values); |
||
| 116 | } |
||
| 117 | |||
| 118 | 10 | /** |
|
| 119 | * @return self<T, S> |
||
| 120 | 10 | */ |
|
| 121 | 10 | public function clear(): self |
|
| 122 | 10 | { |
|
| 123 | return new self; |
||
| 124 | 10 | } |
|
| 125 | |||
| 126 | /** |
||
| 127 | * @param Implementation<T, S> $map |
||
| 128 | */ |
||
| 129 | public function equals(Implementation $map): bool |
||
| 130 | 7 | { |
|
| 131 | if (!$map->keys()->equals($this->keys())) { |
||
| 132 | 7 | return false; |
|
| 133 | 2 | } |
|
| 134 | |||
| 135 | foreach ($this->values as $k => $v) { |
||
| 136 | 7 | $equals = $map |
|
| 137 | 6 | ->get($k) |
|
| 138 | 2 | ->filter(static fn($value) => $value === $v) |
|
| 139 | ->match( |
||
| 140 | static fn() => true, |
||
| 141 | 6 | static fn() => false, |
|
| 142 | 3 | ); |
|
| 143 | |||
| 144 | if (!$equals) { |
||
| 145 | return false; |
||
| 146 | 6 | } |
|
| 147 | } |
||
| 148 | |||
| 149 | return true; |
||
| 150 | } |
||
| 151 | |||
| 152 | /** |
||
| 153 | * @param callable(T, S): bool $predicate |
||
| 154 | 2 | * |
|
| 155 | * @return self<T, S> |
||
| 156 | 2 | */ |
|
| 157 | public function filter(callable $predicate): self |
||
| 158 | 2 | { |
|
| 159 | 2 | /** @var array<T, S> */ |
|
| 160 | 2 | $values = []; |
|
| 161 | |||
| 162 | foreach ($this->values as $k => $v) { |
||
| 163 | if ($predicate($k, $v) === true) { |
||
| 164 | 2 | $values[$k] = $v; |
|
| 165 | } |
||
| 166 | } |
||
| 167 | |||
| 168 | return new self($values); |
||
| 169 | } |
||
| 170 | 3 | ||
| 171 | /** |
||
| 172 | 3 | * @param callable(T, S): void $function |
|
| 173 | 3 | */ |
|
| 174 | public function foreach(callable $function): SideEffect |
||
| 175 | 3 | { |
|
| 176 | foreach ($this->values as $k => $v) { |
||
| 177 | $function($k, $v); |
||
| 178 | } |
||
| 179 | |||
| 180 | return new SideEffect; |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * @template D |
||
| 185 | 4 | * |
|
| 186 | * @param callable(T, S): D $discriminator |
||
| 187 | 4 | * |
|
| 188 | 2 | * @return Map<D, Map<T, S>> |
|
| 189 | */ |
||
| 190 | public function groupBy(callable $discriminator): Map |
||
| 191 | 2 | { |
|
| 192 | /** @var Map<D, Map<T, S>> */ |
||
| 193 | 2 | $groups = Map::of(); |
|
| 194 | |||
| 195 | 2 | foreach ($this->values as $key => $value) { |
|
| 196 | $discriminant = $discriminator($key, $value); |
||
| 197 | 2 | ||
| 198 | 2 | $group = $groups->get($discriminant)->match( |
|
| 199 | static fn($group) => $group, |
||
| 200 | 2 | fn() => $this->clearMap(), |
|
| 201 | ); |
||
| 202 | 2 | $groups = ($groups)($discriminant, ($group)($key, $value)); |
|
| 203 | 2 | } |
|
| 204 | 2 | ||
| 205 | /** @var Map<D, Map<T, S>> */ |
||
| 206 | return $groups; |
||
| 207 | } |
||
| 208 | 2 | ||
| 209 | /** |
||
| 210 | 2 | * @return Set<T> |
|
| 211 | */ |
||
| 212 | 2 | public function keys(): Set |
|
| 213 | { |
||
| 214 | 2 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
|
| 215 | $keys = \array_keys($this->values); |
||
| 216 | |||
| 217 | 2 | return Set::of(...$keys); |
|
| 218 | } |
||
| 219 | 2 | ||
| 220 | /** |
||
| 221 | * @return Sequence<S> |
||
| 222 | */ |
||
| 223 | public function values(): Sequence |
||
| 224 | 2 | { |
|
| 225 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
| 226 | $values = \array_values($this->values); |
||
| 227 | |||
| 228 | return Sequence::of(...$values); |
||
| 229 | } |
||
| 230 | 14 | ||
| 231 | /** |
||
| 232 | * @template B |
||
| 233 | 14 | * |
|
| 234 | * @param callable(T, S): B $function |
||
| 235 | 14 | * |
|
| 236 | 14 | * @return self<T, B> |
|
| 237 | 14 | */ |
|
| 238 | public function map(callable $function): self |
||
| 239 | 14 | { |
|
| 240 | 14 | /** @var array<T, B> */ |
|
| 241 | 14 | $values = []; |
|
| 242 | |||
| 243 | foreach ($this->values as $k => $v) { |
||
| 244 | $values[$k] = $function($k, $v); |
||
| 245 | } |
||
| 246 | |||
| 247 | return new self($values); |
||
| 248 | } |
||
| 249 | 12 | ||
| 250 | /** |
||
| 251 | * @param T $key |
||
| 252 | 12 | * |
|
| 253 | * @return self<T, S> |
||
| 254 | 12 | */ |
|
| 255 | public function remove($key): self |
||
| 256 | { |
||
| 257 | if (!$this->contains($key)) { |
||
| 258 | return $this; |
||
| 259 | } |
||
| 260 | |||
| 261 | $values = $this->values; |
||
| 262 | 6 | /** @psalm-suppress MixedArrayTypeCoercion */ |
|
| 263 | unset($values[$key]); |
||
| 264 | 6 | ||
| 265 | return new self($values); |
||
| 266 | 6 | } |
|
| 267 | 6 | ||
| 268 | /** |
||
| 269 | 6 | * @param Implementation<T, S> $map |
|
| 270 | 4 | * |
|
| 271 | * @return Implementation<T, S> |
||
| 272 | */ |
||
| 273 | 2 | public function merge(Implementation $map): Implementation |
|
| 274 | { |
||
| 275 | 2 | return $map->reduce( |
|
| 276 | $this, |
||
| 277 | 4 | static fn(Implementation $carry, $key, $value): Implementation => ($carry)($key, $value), |
|
| 278 | 4 | ); |
|
| 279 | } |
||
| 280 | |||
| 281 | 4 | /** |
|
| 282 | * @param callable(T, S): bool $predicate |
||
| 283 | 2 | * |
|
| 284 | * @return Map<bool, Map<T, S>> |
||
| 285 | */ |
||
| 286 | 2 | public function partition(callable $predicate): Map |
|
| 287 | { |
||
| 288 | $truthy = $this->clearMap(); |
||
| 289 | $falsy = $this->clearMap(); |
||
| 290 | |||
| 291 | foreach ($this->values as $k => $v) { |
||
| 292 | $return = $predicate($k, $v); |
||
| 293 | |||
| 294 | 2 | if ($return === true) { |
|
| 295 | $truthy = ($truthy)($k, $v); |
||
| 296 | 2 | } else { |
|
| 297 | 2 | $falsy = ($falsy)($k, $v); |
|
| 298 | } |
||
| 299 | } |
||
| 300 | 2 | ||
| 301 | 2 | return Map::of([true, $truthy], [false, $falsy]); |
|
| 302 | } |
||
| 303 | 2 | ||
| 304 | /** |
||
| 305 | 2 | * @template R |
|
| 306 | * @param R $carry |
||
|
0 ignored issues
–
show
The type
Innmind\Immutable\Map\R was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 307 | * @param callable(R, T, S): R $reducer |
||
| 308 | * |
||
| 309 | * @return R |
||
| 310 | */ |
||
| 311 | public function reduce($carry, callable $reducer) |
||
| 312 | { |
||
| 313 | 1 | foreach ($this->values as $k => $v) { |
|
| 314 | $carry = $reducer($carry, $k, $v); |
||
| 315 | } |
||
| 316 | 1 | ||
| 317 | 1 | return $carry; |
|
| 318 | } |
||
| 319 | 1 | ||
| 320 | 1 | public function empty(): bool |
|
| 321 | { |
||
| 322 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
| 323 | 1 | \reset($this->values); |
|
| 324 | |||
| 325 | /** @psalm-suppress MixedArgumentTypeCoercion */ |
||
| 326 | return \is_null(\key($this->values)); |
||
| 327 | } |
||
| 328 | |||
| 329 | public function find(callable $predicate): Maybe |
||
| 330 | { |
||
| 331 | 2 | foreach ($this->values as $k => $v) { |
|
| 332 | if ($predicate($k, $v)) { |
||
| 333 | 2 | return Maybe::just(new Pair($k, $v)); |
|
| 334 | 2 | } |
|
| 335 | } |
||
| 336 | 2 | ||
| 337 | 2 | /** @var Maybe<Pair<T, S>> */ |
|
| 338 | return Maybe::nothing(); |
||
| 339 | 2 | } |
|
| 340 | 2 | ||
| 341 | /** |
||
| 342 | 2 | * @return Map<T, S> |
|
| 343 | */ |
||
| 344 | private function clearMap(): Map |
||
| 345 | { |
||
| 346 | return Map::of(); |
||
| 347 | } |
||
| 348 | } |
||
| 349 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths