Passed
Push — 1.x ( d24c09...111e55 )
by Ulises Jeremias
02:33
created

Sequenceable::copy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
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
    use Sequenceable\Countable;
35
    use Sequenceable\ArrayAccess;
36
    use Sequenceable\Iterator;
37
    use Sequenceable\Builder;
38
39
    protected $sfa = null;
40
41
    /**
42
     * Create an fixed array
43
     *
44
     * @param Traversable $array data
45
     */
46
    protected function __construct(Traversable $array)
47
    {
48
        $this->sfa = $array;
49
        $this->checkCapacity();
50
    }
51
52
    /**
53
     * @inheritDoc
54
     */
55
    public function contains(...$values): bool
56
    {
57
        foreach ($values as $value) {
58
            if ($this->search($value) !== null) {
59
                return false;
60
            }
61
        }
62
63
        return true;
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function copy()
70
    {
71
        return static::fromArray($this->toArray());
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function first()
78
    {
79
        if ($this->isEmpty()) {
80
            throw new UnderflowException();
81
        }
82
83
        return $this[0];
84
    }
85
86
    /**
87
     * @inheritDoc
88
     */
89
    public function get(int $index)
90
    {
91
        if (!$this->validIndex($index)) {
92
            throw new OutOfRangeException();
93
        }
94
95
        return $this[$index];
96
    }
97
98
    /**
99
     * @inheritDoc
100
     */
101
    public function insert(int $index, ...$values)
102
    {
103
        if (!$this->validIndex($index) && $index !== $this->count()) {
104
            throw new OutOfRangeException();
105
        }
106
107
        $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

107
        /** @scrutinizer ignore-call */ 
108
        $slice = $this->slice($index, $this->count());
Loading history...
108
        $this->setSize($index);
109
110
        $this->pushAll($values, $slice);
111
    }
112
113
    /**
114
     * @inheritDoc
115
     */
116
    public function last()
117
    {
118
        if ($this->isEmpty()) {
119
            throw new UnderflowException();
120
        }
121
122
        return $this[$this->count() - 1];
123
    }
124
125
    /**
126
     * Converts negative or large rotations into the minimum positive number
127
     * of rotations required to rotate the sequence by a given $r.
128
     */
129
    private function normalizeRotations(int $r)
130
    {
131
        $n = $this->count();
132
133
        if ($n < 2) {
134
            return 0;
135
        }
136
137
        if ($r < 0) {
138
            return $n - (abs($r) % $n);
139
        }
140
141
        return $r % $n;
142
    }
143
144
    /**
145
     * @inheritDoc
146
     */
147
    public function pop()
148
    {
149
        if ($this->isEmpty()) {
150
            throw new UnderflowException();
151
        }
152
153
        $value = $this->last();
154
        $count = $this->count();
155
        unset($this[--$count]);
156
        $this->setSize($count);
157
158
        $this->checkCapacity();
159
160
        return $value;
161
    }
162
163
    /**
164
     * Pushes all values of either an array or traversable object.
165
     */
166
    private function pushAll(...$args)
167
    {
168
        $size = $this->getSize();
169
170
        foreach ($args as &$values) {
171
            $this->setSize($size + count($values));
172
173
            foreach ($values as $value) {
174
                $this[$size++] = $value;
175
            }
176
        }
177
178
        $this->checkCapacity();
179
    }
180
181
    /**
182
     * @inheritDoc
183
     */
184
    public function push(...$values)
185
    {
186
        $this->pushAll($values);
187
    }
188
189
    /**
190
     * @inheritDoc
191
     */
192
    public function remove(int $index)
193
    {
194
        if (!$this->validIndex($index)) {
195
            throw new OutOfRangeException();
196
        }
197
198
        $value = $this[$index];
199
        $this->sfa->offsetUnset($index);
200
201
        $this->checkCapacity();
202
        return $value;
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    public function set(int $index, $value)
209
    {
210
        if (!$this->validIndex($index)) {
211
            throw new OutOfRangeException();
212
        }
213
214
        $this->sfa->offsetSet($index, $value);
215
    }
216
217
    /**
218
     * @inheritDoc
219
     */
220
    public function shift()
221
    {
222
        if ($this->isEmpty()) {
223
            throw new UnderflowException();
224
        }
225
226
        $value = $this->first();
227
        unset($this[0]);
228
229
        $this->checkCapacity();
230
231
        return $value;
232
    }
233
234
    public function toArray(): array
235
    {
236
        return $this->sfa->toArray();
237
    }
238
239
    /**
240
     * @inheritDoc
241
     */
242
    public function unshift(...$values)
243
    {
244
        $this->insert(0, ...$values);
245
246
        return $this->count();
247
    }
248
249
    public function unserialize($values)
250
    {
251
        $values = unserialize($values);
252
        $this->setTraversable(SplFixedArray::fromArray($values));
253
    }
254
255
    protected function validIndex(int $index)
256
    {
257
        return $index >= 0 && $index < $this->getSize();
258
    }
259
260
    public function clear()
261
    {
262
        $this->sfa->setSize(0);
263
        $this->checkCapacity();
264
    }
265
266
    protected function getMainTraversable(): Traversable
267
    {
268
        return $this->sfa;
269
    }
270
271
    protected function setTraversable(Traversable $traversable)
272
    {
273
        $this->sfa = $traversable;
274
    }
275
276
    /**
277
     * Gets the size of the array.
278
     *
279
     * @return int
280
     */
281
    protected function getSize(): int
282
    {
283
        return $this->sfa->getSize();
284
    }
285
286
    /**
287
     * Change the size of an array to the new size of size.
288
     * If size is less than the current array size, any values after the
289
     * new size will be discarded. If size is greater than the current
290
     * array size, the array will be padded with NULL values.
291
     *
292
     * @param int $size The new array size. This should be a value between 0
293
     * and PHP_INT_MAX.
294
     * @return bool Returns TRUE on success or FALSE on failure.
295
     */
296
    protected function setSize(int $size): bool
297
    {
298
        return $this->sfa->setSize($size);
299
    }
300
301
    public function __clone()
302
    {
303
        return $this->copy();
304
    }
305
306
    abstract protected function checkCapacity();
307
308
    abstract public function isEmpty(): bool;
309
310
    abstract public function search($value);
311
}
312