Passed
Push — 1.x ( ed32ac...ad97f5 )
by Ulises Jeremias
02:42
created

Sequenceable::set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
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
    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
    public function pop()
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
            foreach ($values as $value) {
171
                $this->setSize(++$size);
172
                $this[$size - 1] = $value;
173
            }
174
        }
175
176
        $this->checkCapacity();
177
    }
178
179
    /**
180
     * @inheritDoc
181
     */
182
    public function push(...$values)
183
    {
184
        $this->pushAll($values);
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190
    public function remove(int $index)
191
    {
192
        if (! $this->validIndex($index)) {
193
            throw new OutOfRangeException();
194
        }
195
        $value = array_splice($this->array, $index, 1, null)[0];
0 ignored issues
show
Bug Best Practice introduced by
The property array does not exist on Mbh\Collection\Traits\Sequenceable. Did you maybe forget to declare it?
Loading history...
196
        $this->checkCapacity();
197
        return $value;
198
    }
199
200
    /**
201
     * @inheritDoc
202
     */
203
    public function set(int $index, $value)
204
    {
205
        if (! $this->validIndex($index)) {
206
            throw new OutOfRangeException();
207
        }
208
209
        $this->sfa->offsetSet($index, $value);
210
    }
211
212
    public function toArray(): array
213
    {
214
        return $this->sfa->toArray();
215
    }
216
217
    protected function validIndex(int $index)
218
    {
219
        return $index >= 0 && $index < $this->getSize();
220
    }
221
222
    /**
223
     * Countable
224
     */
225
    public function count(): int
226
    {
227
        return count($this->sfa);
228
    }
229
230
    /**
231
     * Iterator
232
     */
233
    public function current()
234
    {
235
        return $this->sfa->current();
236
    }
237
238
    public function key(): int
239
    {
240
        return $this->sfa->key();
241
    }
242
243
    public function next()
244
    {
245
        return $this->sfa->next();
246
    }
247
248
    public function rewind()
249
    {
250
        return $this->sfa->rewind();
251
    }
252
253
    public function valid()
254
    {
255
        return $this->sfa->valid();
256
    }
257
258
    /**
259
     * ArrayAccess
260
     */
261
    public function offsetExists($offset): bool
262
    {
263
        return is_integer($offset)
264
            && $this->validIndex($offset)
265
            && $this->sfa->offsetExists($offset);
266
    }
267
268
    public function offsetGet($offset)
269
    {
270
        return $this->sfa->offsetGet($offset);
271
    }
272
273
    public function offsetSet($offset, $value)
274
    {
275
        if ($offset === null) {
276
            $this->push($value);
277
        } elseif (is_integer($offset)) {
278
            $this->set($offset, $value);
279
        }
280
    }
281
282
    public function offsetUnset($offset)
283
    {
284
        return is_integer($offset)
285
            && $this->validIndex($offset)
286
            && $this->sfa->offsetUnset($offset);
287
    }
288
289
    public function clear()
290
    {
291
        return $this->sfa->clear();
292
    }
293
294
    protected function getMainTraversable(): Traversable
295
    {
296
        return $this->sfa;
297
    }
298
299
    protected function setTraversable(Traversable $traversable)
300
    {
301
        $this->sfa = $traversable;
302
    }
303
304
    /**
305
     * Gets the size of the array.
306
     *
307
     * @return int
308
     */
309
    protected function getSize(): int
310
    {
311
        return $this->sfa->getSize();
312
    }
313
314
    /**
315
     * Change the size of an array to the new size of size.
316
     * If size is less than the current array size, any values after the
317
     * new size will be discarded. If size is greater than the current
318
     * array size, the array will be padded with NULL values.
319
     *
320
     * @param int $size The new array size. This should be a value between 0
321
     * and PHP_INT_MAX.
322
     * @return bool Returns TRUE on success or FALSE on failure.
323
     */
324
    protected function setSize(int $size): bool
325
    {
326
        return $this->sfa->setSize($size);
327
    }
328
329
    abstract protected function checkCapacity();
330
331
    abstract public function isEmpty(): bool;
332
333
    abstract public function search($value);
334
}
335