These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types = 1); |
||
3 | |||
4 | namespace Innmind\Immutable; |
||
5 | |||
6 | use Innmind\Immutable\{ |
||
7 | Exception\InvalidArgumentException, |
||
8 | Exception\LogicException, |
||
9 | Exception\ElementNotFoundException, |
||
10 | Exception\GroupEmptyMapException |
||
11 | }; |
||
12 | |||
13 | class Map implements MapInterface |
||
14 | { |
||
15 | use Type; |
||
16 | |||
17 | private $keyType; |
||
18 | private $valueType; |
||
19 | private $keySpec; |
||
20 | private $valueSpec; |
||
21 | private $keys; |
||
22 | private $values; |
||
23 | private $pairs; |
||
24 | |||
25 | 31 | public function __construct(string $keyType, string $valueType) |
|
26 | { |
||
27 | 31 | $this->keyType = $keyType; |
|
28 | 31 | $this->valueType = $valueType; |
|
29 | 31 | $this->keySpec = $this->getSpecFor($keyType); |
|
30 | 31 | $this->valueSpec = $this->getSpecFor($valueType); |
|
31 | 31 | $this->keys = new Sequence; |
|
32 | 31 | $this->values = new Sequence; |
|
33 | 31 | $this->pairs = new Sequence; |
|
34 | 31 | } |
|
35 | |||
36 | /** |
||
37 | * {@inheritdoc} |
||
38 | */ |
||
39 | 10 | public function keyType(): string |
|
40 | { |
||
41 | 10 | return $this->keyType; |
|
42 | } |
||
43 | |||
44 | /** |
||
45 | * {@inheritdoc} |
||
46 | */ |
||
47 | 10 | public function valueType(): string |
|
48 | { |
||
49 | 10 | return $this->valueType; |
|
50 | } |
||
51 | |||
52 | /** |
||
53 | * {@inheritdoc} |
||
54 | */ |
||
55 | 10 | public function size(): int |
|
56 | { |
||
57 | 10 | return $this->keys->size(); |
|
58 | } |
||
59 | |||
60 | /** |
||
61 | * {@inheritdoc} |
||
62 | */ |
||
63 | public function count(): int |
||
64 | { |
||
65 | return $this->keys->count(); |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * {@inheritdoc} |
||
70 | */ |
||
71 | 1 | public function current() |
|
72 | { |
||
73 | 1 | return $this->values->current(); |
|
74 | } |
||
75 | |||
76 | /** |
||
77 | * {@inheritdoc} |
||
78 | */ |
||
79 | 1 | public function key() |
|
80 | { |
||
81 | 1 | return $this->keys->current(); |
|
82 | } |
||
83 | |||
84 | /** |
||
85 | * {@inheritdoc} |
||
86 | */ |
||
87 | 1 | public function next() |
|
88 | { |
||
89 | 1 | $this->keys->next(); |
|
90 | 1 | $this->values->next(); |
|
91 | 1 | $this->pairs->next(); |
|
92 | 1 | } |
|
93 | |||
94 | /** |
||
95 | * {@inheritdoc} |
||
96 | */ |
||
97 | 1 | public function rewind() |
|
98 | { |
||
99 | 1 | $this->keys->rewind(); |
|
100 | 1 | $this->values->rewind(); |
|
101 | 1 | $this->pairs->rewind(); |
|
102 | 1 | } |
|
103 | |||
104 | /** |
||
105 | * {@inheritdoc} |
||
106 | */ |
||
107 | 1 | public function valid() |
|
108 | { |
||
109 | 1 | return $this->keys->valid(); |
|
110 | } |
||
111 | |||
112 | /** |
||
113 | * {@inheritdoc} |
||
114 | */ |
||
115 | 1 | public function offsetExists($offset): bool |
|
116 | { |
||
117 | 1 | return $this->keys->contains($offset); |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * {@inheritdoc} |
||
122 | */ |
||
123 | 2 | public function offsetGet($offset) |
|
124 | { |
||
125 | 2 | return $this->get($offset); |
|
126 | } |
||
127 | |||
128 | /** |
||
129 | * {@inheritdoc} |
||
130 | */ |
||
131 | 1 | public function offsetSet($offset, $value) |
|
132 | { |
||
133 | 1 | throw new LogicException('You can\'t modify a map'); |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * {@inheritdoc} |
||
138 | */ |
||
139 | 1 | public function offsetUnset($offset) |
|
140 | { |
||
141 | 1 | throw new LogicException('You can\'t modify a map'); |
|
142 | } |
||
143 | |||
144 | /** |
||
145 | * {@inheritdoc} |
||
146 | */ |
||
147 | 26 | public function put($key, $value): MapInterface |
|
148 | { |
||
149 | 26 | $this->keySpec->validate($key); |
|
150 | 25 | $this->valueSpec->validate($value); |
|
151 | |||
152 | 23 | $map = clone $this; |
|
153 | |||
154 | 23 | if ($this->keys->contains($key)) { |
|
155 | 4 | $index = $this->keys->indexOf($key); |
|
156 | 4 | $map->values = (new Sequence) |
|
157 | 4 | ->append($this->values->take($index)) |
|
158 | 4 | ->add($value) |
|
159 | 4 | ->append($this->values->drop($index + 1)); |
|
160 | 4 | $map->pairs = (new Sequence) |
|
161 | 4 | ->append($this->pairs->take($index)) |
|
162 | 4 | ->add(new Pair($key, $value)) |
|
163 | 4 | ->append($this->pairs->drop($index + 1)); |
|
164 | } else { |
||
165 | 23 | $map->keys = $this->keys->add($key); |
|
166 | 23 | $map->values = $this->values->add($value); |
|
167 | 23 | $map->pairs = $this->pairs->add(new Pair($key, $value)); |
|
168 | } |
||
169 | |||
170 | 23 | return $map; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * {@inheritdoc} |
||
175 | */ |
||
176 | 10 | public function get($key) |
|
177 | { |
||
178 | 10 | if (!$this->keys->contains($key)) { |
|
179 | 2 | throw new ElementNotFoundException; |
|
180 | } |
||
181 | |||
182 | 8 | return $this->values->get( |
|
183 | 8 | $this->keys->indexOf($key) |
|
184 | ); |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * {@inheritdoc} |
||
189 | */ |
||
190 | 9 | public function contains($key): bool |
|
191 | { |
||
192 | 9 | return $this->keys->contains($key); |
|
193 | } |
||
194 | |||
195 | /** |
||
196 | * {@inheritdoc} |
||
197 | */ |
||
198 | 1 | View Code Duplication | public function drop(int $size): MapInterface |
0 ignored issues
–
show
|
|||
199 | { |
||
200 | 1 | $map = clone $this; |
|
201 | 1 | $map->keys = $this->keys->drop($size); |
|
202 | 1 | $map->values = $this->values->drop($size); |
|
203 | 1 | $map->pairs = $this->pairs->drop($size); |
|
204 | |||
205 | 1 | return $map; |
|
206 | } |
||
207 | |||
208 | /** |
||
209 | * {@inheritdoc} |
||
210 | */ |
||
211 | 1 | View Code Duplication | public function dropEnd(int $size): MapInterface |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
212 | { |
||
213 | 1 | $map = clone $this; |
|
214 | 1 | $map->keys = $this->keys->dropEnd($size); |
|
215 | 1 | $map->values = $this->values->dropEnd($size); |
|
216 | 1 | $map->pairs = $this->pairs->dropEnd($size); |
|
217 | |||
218 | 1 | return $map; |
|
219 | } |
||
220 | |||
221 | /** |
||
222 | * {@inheritdoc} |
||
223 | */ |
||
224 | 3 | public function clear(): MapInterface |
|
225 | { |
||
226 | 3 | $map = clone $this; |
|
227 | 3 | $map->keys = new Sequence; |
|
228 | 3 | $map->values = new Sequence; |
|
229 | 3 | $map->pairs = new Sequence; |
|
230 | |||
231 | 3 | return $map; |
|
232 | } |
||
233 | |||
234 | /** |
||
235 | * {@inheritdoc} |
||
236 | */ |
||
237 | 1 | public function equals(MapInterface $map): bool |
|
238 | { |
||
239 | 1 | if ($map->keys()->equals($this->keys())) { |
|
240 | 1 | return true; |
|
241 | } |
||
242 | |||
243 | 1 | return $map->values()->equals($this->values()); |
|
244 | } |
||
245 | |||
246 | /** |
||
247 | * {@inheritdoc} |
||
248 | */ |
||
249 | 1 | public function filter(\Closure $predicate): MapInterface |
|
250 | { |
||
251 | 1 | $map = $this->clear(); |
|
252 | |||
253 | 1 | foreach ($this->keys as $index => $key) { |
|
254 | 1 | $value = $this->values->get($index); |
|
255 | |||
256 | 1 | if ($predicate($key, $value) === true) { |
|
257 | 1 | $map->keys = $map->keys->add($key); |
|
258 | 1 | $map->values = $map->values->add($value); |
|
259 | 1 | $map->pairs = $map->pairs->add($this->pairs->get($index)); |
|
260 | } |
||
261 | } |
||
262 | |||
263 | 1 | return $map; |
|
264 | } |
||
265 | |||
266 | /** |
||
267 | * {@inheritdoc} |
||
268 | */ |
||
269 | 1 | public function foreach(\Closure $function): MapInterface |
|
270 | { |
||
271 | 1 | foreach ($this->keys as $index => $key) { |
|
272 | 1 | $function($key, $this->values->get($index)); |
|
273 | } |
||
274 | |||
275 | 1 | return $this; |
|
276 | } |
||
277 | |||
278 | /** |
||
279 | * {@inheritdoc} |
||
280 | */ |
||
281 | 2 | public function groupBy(\Closure $discriminator): MapInterface |
|
282 | { |
||
283 | 2 | if ($this->size() === 0) { |
|
284 | 1 | throw new GroupEmptyMapException; |
|
285 | } |
||
286 | |||
287 | 1 | $map = null; |
|
288 | |||
289 | 1 | foreach ($this->keys as $index => $key) { |
|
290 | 1 | $newKey = $discriminator($key, $this->values->get($index)); |
|
291 | |||
292 | 1 | View Code Duplication | if ($map === null) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
293 | 1 | $type = gettype($newKey); |
|
294 | 1 | $map = new self( |
|
295 | 1 | $type === 'object' ? get_class($newKey) : $type, |
|
296 | 1 | SequenceInterface::class |
|
297 | ); |
||
298 | } |
||
299 | |||
300 | 1 | $pair = $this->pairs->get($index); |
|
301 | |||
302 | 1 | if ($map->contains($newKey)) { |
|
303 | 1 | $map = $map->put( |
|
304 | $newKey, |
||
305 | 1 | $map->get($newKey)->add($pair) |
|
306 | ); |
||
307 | } else { |
||
308 | 1 | $map = $map->put($newKey, new Sequence($pair)); |
|
309 | } |
||
310 | } |
||
311 | |||
312 | 1 | return $map; |
|
313 | } |
||
314 | |||
315 | /** |
||
316 | * {@inheritdoc} |
||
317 | */ |
||
318 | 1 | public function first(): Pair |
|
319 | { |
||
320 | 1 | return $this->pairs->first(); |
|
321 | } |
||
322 | |||
323 | /** |
||
324 | * {@inheritdoc} |
||
325 | */ |
||
326 | 1 | public function last(): Pair |
|
327 | { |
||
328 | 1 | return $this->pairs->last(); |
|
329 | } |
||
330 | |||
331 | /** |
||
332 | * {@inheritdoc} |
||
333 | */ |
||
334 | 5 | public function keys(): SequenceInterface |
|
335 | { |
||
336 | 5 | return $this->keys; |
|
337 | } |
||
338 | |||
339 | /** |
||
340 | * {@inheritdoc} |
||
341 | */ |
||
342 | 3 | public function values(): SequenceInterface |
|
343 | { |
||
344 | 3 | return $this->values; |
|
345 | } |
||
346 | |||
347 | /** |
||
348 | * {@inheritdoc} |
||
349 | */ |
||
350 | 1 | public function map(\Closure $function): MapInterface |
|
351 | { |
||
352 | 1 | $map = $this->clear(); |
|
353 | |||
354 | 1 | foreach ($this->keys as $index => $key) { |
|
355 | 1 | $return = $function( |
|
356 | $key, |
||
357 | 1 | $this->values->get($index) |
|
358 | ); |
||
359 | |||
360 | 1 | if ($return instanceof Pair) { |
|
361 | 1 | $key = $return->key(); |
|
362 | 1 | $value = $return->value(); |
|
363 | } else { |
||
364 | 1 | $value = $return; |
|
365 | } |
||
366 | |||
367 | 1 | $map = $map->put($key, $value); |
|
368 | } |
||
369 | |||
370 | 1 | return $map; |
|
371 | } |
||
372 | |||
373 | /** |
||
374 | * {@inheritdoc} |
||
375 | */ |
||
376 | 1 | View Code Duplication | public function take(int $size): MapInterface |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
377 | { |
||
378 | 1 | $map = clone $this; |
|
379 | 1 | $map->keys = $this->keys->take($size); |
|
380 | 1 | $map->values = $this->values->take($size); |
|
381 | 1 | $map->pairs = $this->pairs->take($size); |
|
382 | |||
383 | 1 | return $map; |
|
384 | } |
||
385 | |||
386 | /** |
||
387 | * {@inheritdoc} |
||
388 | */ |
||
389 | 1 | View Code Duplication | public function takeEnd(int $size): MapInterface |
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
390 | { |
||
391 | 1 | $map = clone $this; |
|
392 | 1 | $map->keys = $this->keys->takeEnd($size); |
|
393 | 1 | $map->values = $this->values->takeEnd($size); |
|
394 | 1 | $map->pairs = $this->pairs->takeEnd($size); |
|
395 | |||
396 | 1 | return $map; |
|
397 | } |
||
398 | |||
399 | /** |
||
400 | * {@inheritdoc} |
||
401 | */ |
||
402 | 1 | public function join(string $separator): StringPrimitive |
|
403 | { |
||
404 | 1 | return $this->values->join($separator); |
|
405 | } |
||
406 | } |
||
407 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.