Passed
Push — 1.x ( e8e3d1...d6258d )
by Ulises Jeremias
02:22
created

Sequenceable::insert()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 5
nop 2
dl 0
loc 16
rs 8.8571
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
    protected $sfa = null;
35
36
    /**
37
     * Create an fixed array
38
     *
39
     * @param Traversable $array data
40
     */
41
    protected function __construct(Traversable $array)
42
    {
43
        $this->sfa = $array;
44
    }
45
46
    /**
47
     * @inheritDoc
48
     */
49
    public static function fromArray(array $array)
50
    {
51
        return new static(SplFixedArray::fromArray($array));
52
    }
53
54
    /**
55
     * @inheritDoc
56
     */
57
    public static function fromItems(Traversable $array)
58
    {
59
        // We can only do it this way if we can count it
60
        if ($array instanceof Countable) {
61
            $sfa = new SplFixedArray(count($array));
62
63
            foreach ($array as $i => $elem) {
64
                $sfa[$i] = $elem;
65
            }
66
67
            return new static($sfa);
68
        }
69
70
        // If we can't count it, it's simplest to iterate into an array first
71
        return static::fromArray(iterator_to_array($array));
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function contains(...$values): bool
78
    {
79
        foreach ($values as $value) {
80
            if (!$this->find($value)) {
81
                return false;
82
            }
83
        }
84
85
        return true;
86
    }
87
88
    /**
89
     * @inheritDoc
90
     */
91
    public function copy()
92
    {
93
        return static::fromArray($this->toArray());
94
    }
95
96
    /**
97
    * @inheritDoc
98
    */
99
    public function first()
100
    {
101
        if ($this->isEmpty()) {
102
            throw new UnderflowException();
103
        }
104
105
        return $this[0];
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    public function get(int $index)
112
    {
113
        if (! $this->validIndex($index)) {
114
            throw new OutOfRangeException();
115
        }
116
117
        return $this[$index];
118
    }
119
120
    /**
121
     * @inheritDoc
122
     */
123
    public function insert(int $index, ...$values)
124
    {
125
        if (!$this->validIndex($index) && $index !== $this->count()) {
126
            throw new OutOfRangeException();
127
        }
128
129
        $slice = $this->slice($index, $this->count());
0 ignored issues
show
Bug introduced by
It seems like slice() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

129
        /** @scrutinizer ignore-call */ 
130
        $slice = $this->slice($index, $this->count());
Loading history...
130
        var_dump($slice);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($slice) looks like debug code. Are you sure you do not want to remove it?
Loading history...
131
        $this->setSize($this->count() + count($values));
132
133
        foreach ($values as &$item) {
134
            $this[$index++] = $item;
135
        }
136
137
        foreach ($slice->toArray() as &$item) {
0 ignored issues
show
Bug introduced by
The expression $slice->toArray() cannot be used as a reference.

Let?s assume that you have the following foreach statement:

foreach ($array as &$itemValue) { }

$itemValue is assigned by reference. This is possible because the expression (in the example $array) can be used as a reference target.

However, if we were to replace $array with something different like the result of a function call as in

foreach (getArray() as &$itemValue) { }

then assigning by reference is not possible anymore as there is no target that could be modified.

Available Fixes

1. Do not assign by reference
foreach (getArray() as $itemValue) { }
2. Assign to a local variable first
$array = getArray();
foreach ($array as &$itemValue) {}
3. Return a reference
function &getArray() { $array = array(); return $array; }

foreach (getArray() as &$itemValue) { }
Loading history...
138
            $this[$index++] = $item;
139
        }
140
    }
141
142
    /**
143
     * @inheritDoc
144
     */
145
    public function last()
146
    {
147
        if ($this->isEmpty()) {
148
            throw new UnderflowException();
149
        }
150
151
        return $this[$this->count() - 1];
152
    }
153
154
    /**
155
     * @inheritDoc
156
     */
157
    public function pop()
158
    {
159
        if ($this->isEmpty()) {
160
            throw new UnderflowException();
161
        }
162
163
        $value = $this->last();
164
        unset($this[$this->count() - 1]);
165
166
        $this->checkCapacity();
167
168
        return $value;
169
    }
170
171
    /**
172
     * Pushes all values of either an array or traversable object.
173
     */
174
    private function pushAll($values)
175
    {
176
        $size = $this->getSize();
177
178
        foreach ($values as $value) {
179
            $this->setSize(++$size);
180
            $this[$size - 1] = $value;
181
        }
182
183
        $this->checkCapacity();
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189
    public function push(...$values)
190
    {
191
        $this->pushAll($values);
192
    }
193
194
    public function toArray(): array
195
    {
196
        return $this->sfa->toArray();
197
    }
198
199
    protected function validIndex(int $index)
200
    {
201
        return $index >= 0 && $index < $this->getSize();
202
    }
203
204
    /**
205
     * Countable
206
     */
207
    public function count(): int
208
    {
209
        return count($this->sfa);
210
    }
211
212
    /**
213
     * Iterator
214
     */
215
    public function current()
216
    {
217
        return $this->sfa->current();
218
    }
219
220
    public function key(): int
221
    {
222
        return $this->sfa->key();
223
    }
224
225
    public function next()
226
    {
227
        return $this->sfa->next();
228
    }
229
230
    public function rewind()
231
    {
232
        return $this->sfa->rewind();
233
    }
234
235
    public function valid()
236
    {
237
        return $this->sfa->valid();
238
    }
239
240
    /**
241
     * ArrayAccess
242
     */
243
    public function offsetExists($offset): bool
244
    {
245
        return is_integer($offset)
246
            && $this->validIndex($offset)
247
            && $this->sfa->offsetExists($offset);
248
    }
249
250
    public function offsetGet($offset)
251
    {
252
        return $this->sfa->offsetGet($offset);
253
    }
254
255
    public function offsetSet($offset, $value)
256
    {
257
        if ($offset === null) {
258
            $this->push($value);
259
        } elseif (is_integer($offset) && $this->validIndex($offset)) {
260
            $this->sfa->offsetSet($offset, $value);
261
        }
262
    }
263
264
    public function offsetUnset($offset)
265
    {
266
        return is_integer($offset)
267
            && $this->validIndex($offset)
268
            && $this->sfa->offsetUnset($offset);
269
    }
270
271
    public function clear()
272
    {
273
        return $this->sfa->clear();
274
    }
275
276
    protected function getMainTraversable(): Traversable
277
    {
278
        return $this->sfa;
279
    }
280
281
    protected function setTraversable(Traversable $traversable)
282
    {
283
        $this->sfa = $traversable;
284
    }
285
286
    /**
287
     * Gets the size of the array.
288
     *
289
     * @return int
290
     */
291
    protected function getSize(): int
292
    {
293
        return $this->sfa->getSize();
294
    }
295
296
    /**
297
     * Change the size of an array to the new size of size.
298
     * If size is less than the current array size, any values after the
299
     * new size will be discarded. If size is greater than the current
300
     * array size, the array will be padded with NULL values.
301
     *
302
     * @param int $size The new array size. This should be a value between 0
303
     * and PHP_INT_MAX.
304
     * @return bool Returns TRUE on success or FALSE on failure.
305
     */
306
    protected function setSize(int $size): bool
307
    {
308
        return $this->sfa->setSize($size);
309
    }
310
311
    abstract protected function checkCapacity();
312
313
    abstract public function isEmpty(): bool;
314
315
    abstract public function find(callable $callback);
316
}
317