Passed
Push — 1.x ( bf4b58...7b5b09 )
by Ulises Jeremias
02:25
created

Sequenceable::offsetExists()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php namespace Mbh\Collection\Traits;
2
3
use Mbh\Collection\Interfaces\Collection as CollectionInterface;
4
use Mbh\Collection\Interfaces\Sequenceable as SequenceableInterface;
5
use Mbh\Collection\FixedArray;
6
use Mbh\Collection\CallbackHeap;
7
use Mbh\Iterator\SliceIterator;
8
use Mbh\Iterator\ConcatIterator;
9
use SplFixedArray;
10
use SplHeap;
11
use SplStack;
12
use LimitIterator;
13
use Iterator;
14
use ArrayAccess;
15
use Countable;
16
use CallbackFilterIterator;
17
use JsonSerializable;
18
use RuntimeException;
19
use Traversable;
20
use ReflectionClass;
21
use UnderflowException;
22
use OutOfRangeException;
23
24
/**
25
 * MBHFramework
26
 *
27
 * @link      https://github.com/MBHFramework/mbh-framework
28
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
29
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
30
 */
31
32
trait Sequenceable
33
{
34
    use Collection;
35
    use Sort {
36
        Sort::heapSort as heapSortWithCallback;
37
        Sort::heapSorted as heapSortedWithCallback;
38
    }
39
40
41
    protected $sfa = null;
42
43
    /**
44
     * Create an fixed array
45
     *
46
     * @param Traversable $array data
47
     */
48
    protected function __construct(Traversable $array)
49
    {
50
        $this->sfa = $array;
51
    }
52
53
    public function toArray(): array
54
    {
55
        return $this->sfa->toArray();
56
    }
57
58
    protected function validIndex(int $index)
59
    {
60
        return $index >= 0 && $index < count($this);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

60
        return $index >= 0 && $index < count(/** @scrutinizer ignore-type */ $this);
Loading history...
61
    }
62
63
    /**
64
     * Countable
65
     */
66
    public function count(): int
67
    {
68
        return count($this->sfa);
69
    }
70
71
    /**
72
     * Iterator
73
     */
74
    public function current()
75
    {
76
        return $this->sfa->current();
77
    }
78
79
    public function key(): int
80
    {
81
        return $this->sfa->key();
82
    }
83
84
    public function next()
85
    {
86
        return $this->sfa->next();
87
    }
88
89
    public function rewind()
90
    {
91
        return $this->sfa->rewind();
92
    }
93
94
    public function valid()
95
    {
96
        return $this->sfa->valid();
97
    }
98
99
    /**
100
     * ArrayAccess
101
     */
102
    public function offsetExists($offset): bool
103
    {
104
        return is_integer($offset)
105
            && $this->validIndex($offset)
106
            && $this->sfa->offsetExists($offset);
107
    }
108
109
    public function offsetGet($offset)
110
    {
111
        return $this->sfa->offsetGet($offset);
112
    }
113
114
    public function offsetSet($offset, $value)
115
    {
116
        return is_integer($offset)
117
            && $this->validIndex($offset)
118
            && $this->sfa->offsetSet($offset, $value);
119
    }
120
121
    public function offsetUnset($offset)
122
    {
123
        return is_integer($offset)
124
            && $this->validIndex($offset)
125
            && $this->sfa->offsetUnset($offset);
126
    }
127
128
    public function clear()
129
    {
130
        return $this->sfa->clear();
131
    }
132
133
    protected function getMainTraversable(): Traversable
134
    {
135
        return $this->sfa;
136
    }
137
138
    protected function setTraversable(Traversable $traversable)
139
    {
140
        $this->sfa = $traversable;
141
    }
142
143
    /**
144
     * @inheritDoc
145
     */
146
    public static function fromItems(Traversable $array)
147
    {
148
        // We can only do it this way if we can count it
149
        if ($array instanceof Countable) {
150
            $sfa = new SplFixedArray(count($array));
151
152
            foreach ($array as $i => $elem) {
153
                $sfa[$i] = $elem;
154
            }
155
156
            return new static($sfa);
157
        }
158
159
        // If we can't count it, it's simplest to iterate into an array first
160
        return static::fromArray(iterator_to_array($array));
161
    }
162
163
    /**
164
     * @inheritDoc
165
     */
166
    public static function fromArray(array $array)
167
    {
168
        return new static(SplFixedArray::fromArray($array));
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174
    public function copy()
175
    {
176
        return static::fromArray($this->toArray());
177
    }
178
179
    /**
180
     * @inheritDoc
181
     */
182
    public function contains(...$values): bool
183
    {
184
        foreach ($values as $value) {
185
            if (!$this->find($value)) {
186
                return false;
187
            }
188
        }
189
190
        return true;
191
    }
192
193
    /**
194
    * @inheritDoc
195
    */
196
    public function first()
197
    {
198
        if ($this->isEmpty()) {
199
            throw new UnderflowException();
200
        }
201
202
        return $this[0];
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    public function get(int $index)
209
    {
210
        if (! $this->validIndex($index)) {
211
            throw new OutOfRangeException();
212
        }
213
214
        return $this[$index];
215
    }
216
217
    /**
218
     * @inheritDoc
219
     */
220
    public function insert(int $index, ...$values)
0 ignored issues
show
Unused Code introduced by
The parameter $values is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

220
    public function insert(int $index, /** @scrutinizer ignore-unused */ ...$values)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
221
    {
222
        if (! $this->validIndex($index) && $index !== count($this)) {
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

222
        if (! $this->validIndex($index) && $index !== count(/** @scrutinizer ignore-type */ $this)) {
Loading history...
223
            throw new OutOfRangeException();
224
        }
225
    }
226
227
    /**
228
     * @inheritDoc
229
     */
230
    public function last()
231
    {
232
        if ($this->isEmpty()) {
233
            throw new UnderflowException();
234
        }
235
236
        return $this[count($this) - 1];
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

236
        return $this[count(/** @scrutinizer ignore-type */ $this) - 1];
Loading history...
237
    }
238
239
    /**
240
     * Pushes all values of either an array or traversable object.
241
     */
242
    private function pushAll($values)
243
    {
244
        foreach ($values as $value) {
245
            $this[] = $value;
246
        }
247
    }
248
249
    /**
250
     * @inheritDoc
251
     */
252
    public function push(...$values)
253
    {
254
        $this->pushAll($values);
255
    }
256
257
    /**
258
     * @inheritDoc
259
     */
260 View Code Duplication
    public function map(callable $callback)
0 ignored issues
show
Duplication introduced by
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.

Loading history...
261
    {
262
        $count = count($this);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

262
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
263
        $sfa = new SplFixedArray($count);
264
265
        for ($i = 0; $i < $count; $i++) {
266
            $sfa[$i] = $callback($this[$i], $i, $this);
267
        }
268
269
        return new static($sfa);
270
    }
271
272
    /**
273
     * @inheritDoc
274
     */
275
    public function walk(callable $callback)
276
    {
277
        foreach ($this as $i => $elem) {
278
            $callback($elem, $i, $this);
279
        }
280
281
        return $this;
282
    }
283
284
    /**
285
     * @inheritDoc
286
     */
287 View Code Duplication
    public function filter(callable $callback)
0 ignored issues
show
Duplication introduced by
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.

Loading history...
288
    {
289
        $count = count($this);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

289
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
290
        $sfa = new SplFixedArray($count);
291
        $newCount = 0;
292
293
        foreach ($this as $elem) {
294
            if ($callback($elem)) {
295
                $sfa[$newCount++] = $elem;
296
            }
297
        }
298
299
        $sfa->setSize($newCount);
300
        return new static($sfa);
301
    }
302
303
    /**
304
     * @inheritDoc
305
     */
306
    public function reduce(callable $callback, $accumulator = null)
307
    {
308
        foreach ($this as $i => $elem) {
309
            $accumulator = $callback($accumulator, $elem, $i, $this);
310
        }
311
312
        return $accumulator;
313
    }
314
315
    /**
316
     * @inheritDoc
317
     */
318
    public function join(string $token = ',', string $secondToken = null): string
319
    {
320
        $str = "";
321
        if ($secondToken) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $secondToken of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
322
            foreach ($this as $i => $elem) {
323
                $str .= $token . (string) $elem . $secondToken;
324
            }
325
        } else {
326
            $this->rewind();
327
            while ($this->valid()) {
328
                $str .= (string) $this->current();
329
                $this->next();
330
                if ($this->valid()) {
331
                    $str .= $token;
332
                }
333
            }
334
        }
335
336
        return $str;
337
    }
338
339
    /**
340
     * @inheritDoc
341
     */
342
    public function slice(int $begin = 0, int $end = null)
343
    {
344
        $it = new SliceIterator($this, $begin, $end);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Iterator expected by parameter $iterator of Mbh\Iterator\SliceIterator::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

344
        $it = new SliceIterator(/** @scrutinizer ignore-type */ $this, $begin, $end);
Loading history...
345
        return new static($it);
346
    }
347
348
    /**
349
     * @inheritDoc
350
     */
351
    public function concat()
352
    {
353
        $args = func_get_args();
354
        array_unshift($args, $this);
355
356
        // Concat this iterator, and variadic args
357
        $class = new ReflectionClass('Mbh\Iterator\ConcatIterator');
358
        $concatIt = $class->newInstanceArgs($args);
359
360
        // Create as new immutable's iterator
361
        return new static($concatIt);
362
    }
363
364
    /**
365
     * @inheritDoc
366
     */
367
    public function find(callable $callback)
368
    {
369
        foreach ($this as $i => $elem) {
370
            if ($callback($elem, $i, $this)) {
371
                return $elem;
372
            }
373
        }
374
    }
375
376
    /**
377
     * @inheritDoc
378
     */
379
    public function sort(callable $callback = null)
380
    {
381
        if ($callback) {
382
            return $this->mergeSort($callback);
383
        }
384
385
        return $this->arraySort();
386
    }
387
388
    /**
389
     * @inheritDoc
390
     */
391
    public function sorted(callable $callback = null)
392
    {
393
        $copy = FixedArray::fromItems($this);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Traversable expected by parameter $array of Mbh\Collection\FixedArray::fromItems(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

393
        $copy = FixedArray::fromItems(/** @scrutinizer ignore-type */ $this);
Loading history...
394
395
        if ($callback) {
396
            $copy->mergeSort($callback);
397
        }
398
399
        $copy->arraySort();
400
401
        return static::fromItems($copy);
402
    }
403
404
    /**
405
     * @inheritDoc
406
     */
407
    public function heapSorted(SplHeap $heap)
408
    {
409
        return $this->copy()->heapSort($heap);
410
    }
411
412
    /**
413
     * @inheritDoc
414
     */
415
    public function heapSort(SplHeap $heap)
416
    {
417
        foreach ($this as $item) {
418
            $heap->insert($item);
419
        }
420
421
        $this->setTraversable(static::fromItems($heap));
0 ignored issues
show
Bug introduced by
static::fromItems($heap) of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Traversable expected by parameter $traversable of Mbh\Collection\Traits\Se...eable::setTraversable(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

421
        $this->setTraversable(/** @scrutinizer ignore-type */ static::fromItems($heap));
Loading history...
422
423
        return $this;
424
    }
425
}
426