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 | 30 | public function __construct(string $keyType, string $valueType) |
|
26 | { |
||
27 | 30 | $this->keyType = $keyType; |
|
28 | 30 | $this->valueType = $valueType; |
|
29 | 30 | $this->keySpec = $this->getSpecFor($keyType); |
|
30 | 30 | $this->valueSpec = $this->getSpecFor($valueType); |
|
31 | 30 | $this->keys = new Sequence; |
|
32 | 30 | $this->values = new Sequence; |
|
33 | 30 | $this->pairs = new Sequence; |
|
34 | 30 | } |
|
35 | |||
36 | /** |
||
37 | * {@inheritdoc} |
||
38 | */ |
||
39 | 3 | public function keyType(): string |
|
40 | { |
||
41 | 3 | return $this->keyType; |
|
42 | } |
||
43 | |||
44 | /** |
||
45 | * {@inheritdoc} |
||
46 | */ |
||
47 | 3 | public function valueType(): string |
|
48 | { |
||
49 | 3 | 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 | 25 | public function put($key, $value): MapInterface |
|
148 | { |
||
149 | 25 | $this->keySpec->validate($key); |
|
150 | 24 | $this->valueSpec->validate($value); |
|
151 | |||
152 | 22 | $map = clone $this; |
|
153 | |||
154 | 22 | if ($this->keys->contains($key)) { |
|
155 | 3 | $index = $this->keys->indexOf($key); |
|
156 | 3 | $map->values = (new Sequence) |
|
157 | 3 | ->append($this->values->take($index)) |
|
158 | 3 | ->add($value) |
|
159 | 3 | ->append($this->values->drop($index + 1)); |
|
160 | 3 | $map->pairs = (new Sequence) |
|
161 | 3 | ->append($this->pairs->take($index)) |
|
162 | 3 | ->add(new Pair($key, $value)) |
|
163 | 3 | ->append($this->pairs->drop($index + 1)); |
|
164 | } else { |
||
165 | 22 | $map->keys = $this->keys->add($key); |
|
166 | 22 | $map->values = $this->values->add($value); |
|
167 | 22 | $map->pairs = $this->pairs->add(new Pair($key, $value)); |
|
168 | } |
||
169 | |||
170 | 22 | return $map; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * {@inheritdoc} |
||
175 | */ |
||
176 | 9 | public function get($key) |
|
177 | { |
||
178 | 9 | if (!$this->keys->contains($key)) { |
|
179 | 2 | throw new ElementNotFoundException; |
|
180 | } |
||
181 | |||
182 | 7 | return $this->values->get( |
|
183 | 7 | $this->keys->indexOf($key) |
|
184 | ); |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * {@inheritdoc} |
||
189 | */ |
||
190 | 8 | public function contains($key): bool |
|
191 | { |
||
192 | 8 | return $this->keys->contains($key); |
|
193 | } |
||
194 | |||
195 | /** |
||
196 | * {@inheritdoc} |
||
197 | */ |
||
198 | 1 | View Code Duplication | public function drop(int $size): MapInterface |
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 |
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) { |
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 | View Code Duplication | if ($map->contains($newKey)) { |
0 ignored issues
–
show
|
|||
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 | 4 | public function keys(): SequenceInterface |
|
335 | { |
||
336 | 4 | 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 |
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 |
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.