1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @license https://github.com/f500/equatable/blob/master/LICENSE MIT |
5
|
|
|
*/ |
6
|
|
|
|
7
|
|
|
declare(strict_types=1); |
8
|
|
|
|
9
|
|
|
namespace F500\Equatable; |
10
|
|
|
|
11
|
|
|
use F500\Equatable\Exceptions\OutOfRangeException; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* @copyright Copyright (c) 2015 Future500 B.V. |
15
|
|
|
* @author Jasper N. Brouwer <[email protected]> |
16
|
|
|
*/ |
17
|
|
|
final class Vector extends Collection |
18
|
|
|
{ |
19
|
273 |
|
public function __construct(array $values = []) |
20
|
|
|
{ |
21
|
273 |
|
foreach ($values as $value) { |
22
|
240 |
|
$this->guardAgainstInvalidValue($value); |
23
|
237 |
|
$this->items[] = $value; |
24
|
|
|
} |
25
|
270 |
|
} |
26
|
|
|
|
27
|
3 |
View Code Duplication |
public function __clone() |
|
|
|
|
28
|
|
|
{ |
29
|
3 |
|
$items = []; |
30
|
|
|
|
31
|
3 |
|
foreach ($this->items as $item) { |
32
|
3 |
|
if (is_object($item)) { |
33
|
3 |
|
$items[] = clone $item; |
34
|
|
|
} else { |
35
|
3 |
|
$items[] = $item; |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
|
39
|
3 |
|
$this->items = $items; |
40
|
3 |
|
} |
41
|
|
|
|
42
|
81 |
|
public function get(int $index) |
|
|
|
|
43
|
|
|
{ |
44
|
81 |
|
if (!$this->containsIndex($index)) { |
45
|
3 |
|
throw OutOfRangeException::doesNotContainIndex($index); |
46
|
|
|
} |
47
|
|
|
|
48
|
78 |
|
return $this->items[$index]; |
49
|
|
|
} |
50
|
|
|
|
51
|
66 |
View Code Duplication |
public function search($value): int |
|
|
|
|
52
|
|
|
{ |
53
|
66 |
|
foreach ($this->items as $index => $item) { |
54
|
63 |
|
if ($this->theseAreEqual($item, $value)) { |
55
|
63 |
|
return $index; |
56
|
|
|
} |
57
|
|
|
} |
58
|
|
|
|
59
|
33 |
|
throw OutOfRangeException::doesNotContainValue($value); |
60
|
|
|
} |
61
|
|
|
|
62
|
63 |
|
public function equals($other): bool |
63
|
|
|
{ |
64
|
63 |
|
if (!$other instanceof static) { |
65
|
3 |
|
return false; |
66
|
|
|
} |
67
|
|
|
|
68
|
60 |
|
if ($this->count() !== $other->count()) { |
69
|
6 |
|
return false; |
70
|
|
|
} |
71
|
|
|
|
72
|
54 |
|
foreach ($this->items as $item) { |
73
|
45 |
|
if ($this->countItem($item) !== $other->countItem($item)) { |
74
|
45 |
|
return false; |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
|
78
|
42 |
|
return true; |
79
|
|
|
} |
80
|
|
|
|
81
|
9 |
|
public function add($value): self |
82
|
|
|
{ |
83
|
9 |
|
$items = $this->items; |
84
|
|
|
|
85
|
9 |
|
$items[] = $value; |
86
|
|
|
|
87
|
9 |
|
return new self($items); |
88
|
|
|
} |
89
|
|
|
|
90
|
12 |
View Code Duplication |
public function replace($searchValue, $replacementValue): self |
|
|
|
|
91
|
|
|
{ |
92
|
12 |
|
$items = $this->items; |
93
|
12 |
|
$index = $this->search($searchValue); |
94
|
|
|
|
95
|
9 |
|
$items[$index] = $replacementValue; |
96
|
|
|
|
97
|
9 |
|
return new self($items); |
98
|
|
|
} |
99
|
|
|
|
100
|
12 |
View Code Duplication |
public function replaceAll($searchValue, $replacementValue): self |
|
|
|
|
101
|
|
|
{ |
102
|
12 |
|
$items = $this->items; |
103
|
12 |
|
$indexes = $this->searchAll($searchValue); |
104
|
|
|
|
105
|
12 |
|
if ($indexes->isEmpty()) { |
106
|
3 |
|
return $this; |
107
|
|
|
} |
108
|
|
|
|
109
|
9 |
|
foreach ($indexes as $index) { |
110
|
9 |
|
$items[$index] = $replacementValue; |
111
|
|
|
} |
112
|
|
|
|
113
|
9 |
|
return new self($items); |
114
|
|
|
} |
115
|
|
|
|
116
|
12 |
View Code Duplication |
public function remove($value): self |
|
|
|
|
117
|
|
|
{ |
118
|
12 |
|
$items = $this->items; |
119
|
12 |
|
$index = $this->search($value); |
120
|
|
|
|
121
|
9 |
|
unset($items[$index]); |
122
|
|
|
|
123
|
9 |
|
return new self($items); |
124
|
|
|
} |
125
|
|
|
|
126
|
12 |
View Code Duplication |
public function removeAll($value): self |
|
|
|
|
127
|
|
|
{ |
128
|
12 |
|
$items = $this->items; |
129
|
12 |
|
$indexes = $this->searchAll($value); |
130
|
|
|
|
131
|
12 |
|
if ($indexes->isEmpty()) { |
132
|
3 |
|
return $this; |
133
|
|
|
} |
134
|
|
|
|
135
|
9 |
|
foreach ($indexes as $index) { |
136
|
9 |
|
unset($items[$index]); |
137
|
|
|
} |
138
|
|
|
|
139
|
9 |
|
return new self($items); |
140
|
|
|
} |
141
|
|
|
|
142
|
6 |
|
public function merge(self $other): self |
143
|
|
|
{ |
144
|
6 |
|
$items = array_merge($this->items, $other->items); |
145
|
|
|
|
146
|
6 |
|
return new self($items); |
147
|
|
|
} |
148
|
|
|
|
149
|
6 |
View Code Duplication |
public function intersect(self $other): self |
|
|
|
|
150
|
|
|
{ |
151
|
6 |
|
$items = []; |
152
|
|
|
|
153
|
6 |
|
foreach ($this->items as $item) { |
154
|
6 |
|
if ($other->contains($item)) { |
155
|
6 |
|
$items[] = $item; |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
6 |
|
return new self($items); |
160
|
|
|
} |
161
|
|
|
|
162
|
6 |
View Code Duplication |
public function diff(self $other): self |
|
|
|
|
163
|
|
|
{ |
164
|
6 |
|
$items = []; |
165
|
|
|
|
166
|
6 |
|
foreach ($this->items as $item) { |
167
|
6 |
|
if (!$other->contains($item)) { |
168
|
6 |
|
$items[] = $item; |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
6 |
|
return new self($items); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* The filter callable is given an item, and should return |
177
|
|
|
* a boolean indicating whether the item remains or not. |
178
|
|
|
* |
179
|
|
|
* function ($item): bool { |
180
|
|
|
* return true; |
181
|
|
|
* } |
182
|
|
|
*/ |
183
|
6 |
|
public function filter(callable $filter): self |
184
|
|
|
{ |
185
|
6 |
|
$items = array_filter($this->items, $filter); |
186
|
|
|
|
187
|
6 |
|
return new self($items); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* The mapper callable is given an item, and should return |
192
|
|
|
* a new value to use in it's place. |
193
|
|
|
* |
194
|
|
|
* function ($item) { |
195
|
|
|
* return $item; |
196
|
|
|
* } |
197
|
|
|
*/ |
198
|
6 |
|
public function map(callable $mapper): self |
199
|
|
|
{ |
200
|
6 |
|
$items = array_map($mapper, $this->items); |
201
|
|
|
|
202
|
6 |
|
return new self($items); |
203
|
|
|
} |
204
|
|
|
|
205
|
81 |
|
private function containsIndex(int $index): bool |
206
|
|
|
{ |
207
|
81 |
|
return isset($this->items[$index]); |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
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.