Completed
Push — master ( 6db18d...e8104d )
by Nate
02:21
created

ArrayList::has()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/*
3
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
namespace Tebru\Collection;
8
9
use ArrayIterator;
10
use OutOfBoundsException;
11
12
/**
13
 * Class ArrayList
14
 *
15
 * Implements [@see ListInterface] and maintains an array of elements
16
 *
17
 * @author Nate Brunette <[email protected]>
18
 */
19
class ArrayList extends AbstractList
20
{
21
    /**
22
     * An array of elements
23
     *
24
     * @var array
25
     */
26
    protected $elements = [];
27
28
    /**
29
     * Constructor
30
     *
31
     * @param array $elements
32
     */
33 67
    public function __construct(array $elements = [])
34
    {
35 67
        $this->elements = array_values($elements);
36 67
    }
37
38
    /**
39
     * Ensure the element exists in the collection
40
     *
41
     * Returns true if the collection can contain duplicates,
42
     * and false if it cannot.
43
     *
44
     * @param mixed $element
45
     * @return bool
46
     */
47 42
    public function add($element): bool
48
    {
49 42
        $this->elements[] = $element;
50
51 42
        return true;
52
    }
53
54
    /**
55
     * Removes object if it exists
56
     *
57
     * Returns true if the element was removed
58
     *
59
     * @param mixed $element
60
     * @return bool
61
     */
62 6
    public function remove($element): bool
63
    {
64 6
        $index = $this->indexOf($element);
65
66 6
        if (-1 === $index) {
67 2
            return false;
68
        }
69
70 5
        array_splice($this->elements, $index, 1);
71
72 5
        return true;
73
    }
74
75
    /**
76
     * Removes all elements from a collection
77
     *
78
     * @return void
79
     */
80 1
    public function clear()
81
    {
82 1
        $this->elements = [];
83 1
    }
84
85
    /**
86
     * Returns the size of the collection
87
     *
88
     * @return int
89
     */
90 41
    public function count(): int
91
    {
92 41
        return count($this->elements);
93
    }
94
95
    /**
96
     * Returns true if the collection contains element
97
     *
98
     * @param mixed $element
99
     * @return bool
100
     */
101 13
    public function contains($element): bool
102
    {
103 13
        return in_array($element, $this->elements, true);
104
    }
105
106
    /**
107
     * Returns an array of all elements in the collection
108
     *
109
     * @return array
110
     */
111 20
    public function toArray(): array
112
    {
113 20
        return $this->elements;
114
    }
115
116
    /**
117
     * Filter the collection using closure
118
     *
119
     * The closure will get passed each element.  Returning true from the
120
     * closure will include that element in the new collection.
121
     *
122
     * @param callable $filter
123
     * @return CollectionInterface
124
     */
125 1
    public function filter(callable $filter): CollectionInterface
126
    {
127 1
        return new ArrayList(array_filter($this->elements, $filter));
128
    }
129
130
    /**
131
     * Retrieve an external iterator
132
     *
133
     * @return ArrayIterator
134
     */
135 59
    public function getIterator(): ArrayIterator
136
    {
137 59
        return new ArrayIterator($this->elements);
138
    }
139
140
    /**
141
     * Insert element at the specified index
142
     *
143
     * @param int $index
144
     * @param mixed $element
145
     * @return void
146
     * @throws \OutOfBoundsException if the index doesn't exist
147
     */
148 6
    public function insert(int $index, $element)
149
    {
150 6
        $this->assertIndex($index);
151
152 5
        array_splice($this->elements, $index, 0, [$element]);
153 5
    }
154
155
    /**
156
     * Inserts all elements of a collection at index
157
     *
158
     * @param int $index
159
     * @param CollectionInterface $collection
160
     * @return bool
161
     * @throws \OutOfBoundsException if the index doesn't exist
162
     */
163 4
    public function insertAll(int $index, CollectionInterface $collection): bool
164
    {
165 4
        $this->assertIndex($index);
166
167 3
        $size = $this->count();
168 3
        array_splice($this->elements, $index, 0, $collection->toArray());
169
170 3
        return $size !== $this->count();
171
    }
172
173
    /**
174
     * Returns the element at the index
175
     *
176
     * @param int $index
177
     * @return mixed
178
     * @throws \OutOfBoundsException if the index doesn't exist
179
     */
180 13
    public function get(int $index)
181
    {
182 13
        if (!$this->has($index)) {
183 2
            throw new OutOfBoundsException(sprintf('Tried to access element at index "%s"', $index));
184
        }
185
186 11
        return $this->elements[$index];
187
    }
188
189
    /**
190
     * Returns true if an element exists at the index
191
     *
192
     * @param int $index
193
     * @return bool
194
     */
195 19
    public function has(int $index): bool
196
    {
197 19
        return array_key_exists($index, $this->elements);
198
    }
199
200
    /**
201
     * Returns the index of the first instance of the element, -1 if the element
202
     * doesn't exist
203
     *
204
     * @param mixed $element
205
     * @return int
206
     */
207 8
    public function indexOf($element): int
208
    {
209 8
        $index = array_search($element, $this->elements, true);
210
211 8
        return false === $index ? -1 : $index;
212
    }
213
214
    /**
215
     * Returns the index of the last instance of the element, -1 if the element
216
     * doesn't exist
217
     *
218
     * @param mixed $element
219
     * @return int
220
     */
221 2
    public function lastIndexOf($element): int
222
    {
223 2
        $elements = array_reverse($this->elements);
224
225 2
        $index = array_search($element, $elements, true);
226
227
        // return -1 if not found or (size - index found - 1) to return the index of the element after reverse
228 2
        return false === $index ? -1 : $this->count() - $index - 1;
229
    }
230
231
    /**
232
     * Removes the element at the specified index
233
     *
234
     * This returns the element that was previously at this index
235
     *
236
     * @param int $index
237
     * @return mixed
238
     * @throws \OutOfBoundsException if the index doesn't exist
239
     */
240 2
    public function removeAt(int $index)
241
    {
242 2
        $oldElement = $this->get($index);
243 1
        array_splice($this->elements, $index, 1);
244
245 1
        return $oldElement;
246
    }
247
248
    /**
249
     * Replace the element at the specified index
250
     *
251
     * Returns the element that was previously at this index
252
     *
253
     * @param int $index
254
     * @param mixed $element
255
     * @return mixed
256
     * @throws \OutOfBoundsException if the index doesn't exist
257
     */
258 3
    public function set(int $index, $element)
259
    {
260 3
        $this->assertIndex($index);
261
262 2
        $oldElement = null;
263 2
        if ($this->has($index)) {
264 1
            $oldElement = $this->get($index);
265
        }
266
267 2
        $this->elements[$index] = $element;
268
269 2
        return $oldElement;
270
    }
271
272
    /**
273
     * Returns a new ListInterface ranging from $fromIndex inclusive to
274
     * $toIndex exclusive
275
     *
276
     * @param int $fromIndex
277
     * @param int $toIndex
278
     * @return ListInterface
279
     * @throws \OutOfBoundsException If to or from index does not exist
280
     */
281 4
    public function subList(int $fromIndex, int $toIndex): ListInterface
282
    {
283 4
        if (!$this->has($fromIndex) || !$this->has($toIndex - 1)) {
284 2
            throw new OutOfBoundsException('Unable to create sub list as $toIndex or $fromIndex do not exist in list');
285
        }
286
287 2
        $newList = array_slice($this->elements, $fromIndex, $toIndex - $fromIndex);
288
289 2
        return new ArrayList($newList);
290
    }
291
292
    /**
293
     * Assert the index is able to be inserted
294
     *
295
     * @param int $index
296
     * @return void
297
     * @throws \OutOfBoundsException If the index is less than 0 or greater than current size
298
     */
299 13
    private function assertIndex(int $index)
300
    {
301 13
        if ($index < 0 || $index > $this->count()) {
302 3
            throw new OutOfBoundsException(sprintf('Element unable to be inserted at index "%s"', $index));
303
        }
304 10
    }
305
}
306