Passed
Push — 1.x ( dd62ad...cae2e0 )
by Ulises Jeremias
02:30
created

Sequenceable::validIndex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
rs 10
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
        if (!$array instanceof Countable) {
60
            return static::fromArray(iterator_to_array($array));
61
        }
62
63
        $sfa = new SplFixedArray(count($array));
64
65
        foreach ($array as $i => $elem) {
66
            $sfa[$i] = $elem;
67
        }
68
69
        return new static($sfa);
70
    }
71
72
    /**
73
     * @inheritDoc
74
     */
75
    public function contains(...$values): bool
76
    {
77
        foreach ($values as $value) {
78
            if ($this->search($value) !== null) {
79
                return false;
80
            }
81
        }
82
83
        return true;
84
    }
85
86
    /**
87
     * @inheritDoc
88
     */
89
    public function copy()
90
    {
91
        return static::fromArray($this->toArray());
92
    }
93
94
    /**
95
     * @inheritDoc
96
     */
97
    public function first()
98
    {
99
        if ($this->isEmpty()) {
100
            throw new UnderflowException();
101
        }
102
103
        return $this[0];
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109
    public function get(int $index)
110
    {
111
        if (!$this->validIndex($index)) {
112
            throw new OutOfRangeException();
113
        }
114
115
        return $this[$index];
116
    }
117
118
    /**
119
     * @inheritDoc
120
     */
121
    public function insert(int $index, ...$values)
122
    {
123
        if (!$this->validIndex($index) && $index !== $this->count()) {
124
            throw new OutOfRangeException();
125
        }
126
127
        $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

127
        /** @scrutinizer ignore-call */ 
128
        $slice = $this->slice($index, $this->count());
Loading history...
128
        $this->setSize($index);
129
130
        $this->pushAll($values, $slice);
131
    }
132
133
    /**
134
     * @inheritDoc
135
     */
136
    public function last()
137
    {
138
        if ($this->isEmpty()) {
139
            throw new UnderflowException();
140
        }
141
142
        return $this[$this->count() - 1];
143
    }
144
145
    /**
146
     * @inheritDoc
147
     */
148 View Code Duplication
    public function pop()
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...
149
    {
150
        if ($this->isEmpty()) {
151
            throw new UnderflowException();
152
        }
153
154
        $value = $this->last();
155
        unset($this[$this->count() - 1]);
156
157
        $this->checkCapacity();
158
159
        return $value;
160
    }
161
162
    /**
163
     * Pushes all values of either an array or traversable object.
164
     */
165
    private function pushAll(...$args)
166
    {
167
        $size = $this->getSize();
168
169
        foreach ($args as &$values) {
170
            $this->setSize($size + count($values));
171
172
            foreach ($values as $value) {
173
                $this[$size++] = $value;
174
            }
175
        }
176
177
        $this->checkCapacity();
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    public function push(...$values)
184
    {
185
        $this->pushAll($values);
186
    }
187
188
    /**
189
     * @inheritDoc
190
     */
191
    public function remove(int $index)
192
    {
193
        if (!$this->validIndex($index)) {
194
            throw new OutOfRangeException();
195
        }
196
197
        $value = $this[$index];
198
        $this->sfa->offsetUnset($index);
199
200
        $this->checkCapacity();
201
        return $value;
202
    }
203
204
    /**
205
     * @inheritDoc
206
     */
207
    public function set(int $index, $value)
208
    {
209
        if (!$this->validIndex($index)) {
210
            throw new OutOfRangeException();
211
        }
212
213
        $this->sfa->offsetSet($index, $value);
214
    }
215
216
    /**
217
     * @inheritDoc
218
     */
219 View Code Duplication
    public function shift()
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...
220
    {
221
        if ($this->isEmpty()) {
222
            throw new UnderflowException();
223
        }
224
225
        $value = $this->first();
226
        unset($this[0]);
227
228
        $this->checkCapacity();
229
230
        return $value;
231
    }
232
233
    public function toArray(): array
234
    {
235
        return $this->sfa->toArray();
236
    }
237
238
    /**
239
     * @inheritDoc
240
     */
241
    public function unshift(...$values)
242
    {
243
        $this->insert(0, ...$values);
244
245
        return $this->count();
246
    }
247
248
    protected function validIndex(int $index)
249
    {
250
        return $index >= 0 && $index < $this->getSize();
251
    }
252
253
    /**
254
     * Countable
255
     */
256
    public function count(): int
257
    {
258
        return count($this->sfa);
259
    }
260
261
    /**
262
     * Iterator
263
     */
264
    public function current()
265
    {
266
        return $this->sfa->current();
267
    }
268
269
    public function key(): int
270
    {
271
        return $this->sfa->key();
272
    }
273
274
    public function next()
275
    {
276
        return $this->sfa->next();
277
    }
278
279
    public function rewind()
280
    {
281
        return $this->sfa->rewind();
282
    }
283
284
    public function valid()
285
    {
286
        return $this->sfa->valid();
287
    }
288
289
    /**
290
     * ArrayAccess
291
     */
292
    public function offsetExists($offset): bool
293
    {
294
        return is_integer($offset)
295
            && $this->validIndex($offset)
296
            && $this->sfa->offsetExists($offset);
297
    }
298
299
    public function offsetGet($offset)
300
    {
301
        return $this->sfa->offsetGet($offset);
302
    }
303
304
    public function offsetSet($offset, $value)
305
    {
306
        if ($offset === null) {
307
            $this->push($value);
308
        } elseif (is_integer($offset)) {
309
            $this->set($offset, $value);
310
        }
311
    }
312
313
    public function offsetUnset($offset)
314
    {
315
        return is_integer($offset)
316
            && $this->remove($offset);
317
    }
318
319
    public function clear()
320
    {
321
        return $this->sfa->clear();
322
    }
323
324
    protected function getMainTraversable(): Traversable
325
    {
326
        return $this->sfa;
327
    }
328
329
    protected function setTraversable(Traversable $traversable)
330
    {
331
        $this->sfa = $traversable;
332
    }
333
334
    /**
335
     * Gets the size of the array.
336
     *
337
     * @return int
338
     */
339
    protected function getSize(): int
340
    {
341
        return $this->sfa->getSize();
342
    }
343
344
    /**
345
     * Change the size of an array to the new size of size.
346
     * If size is less than the current array size, any values after the
347
     * new size will be discarded. If size is greater than the current
348
     * array size, the array will be padded with NULL values.
349
     *
350
     * @param int $size The new array size. This should be a value between 0
351
     * and PHP_INT_MAX.
352
     * @return bool Returns TRUE on success or FALSE on failure.
353
     */
354
    protected function setSize(int $size): bool
355
    {
356
        return $this->sfa->setSize($size);
357
    }
358
359
    abstract protected function checkCapacity();
360
361
    abstract public function isEmpty(): bool;
362
363
    abstract public function search($value);
364
}
365