Stack   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Test Coverage

Coverage 84.62%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 67
c 2
b 0
f 1
dl 0
loc 239
ccs 77
cts 91
cp 0.8462
rs 9.76
wmc 33

20 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetExists() 0 4 1
A swap() 0 6 1
A add() 0 17 4
A rewind() 0 3 1
A isEmpty() 0 3 1
A offsetGet() 0 8 2
A next() 0 3 1
A valid() 0 3 1
A push() 0 3 1
A end() 0 8 2
A pop() 0 9 2
A offsetUnset() 0 9 2
A current() 0 3 1
A bottom() 0 8 2
A resize() 0 11 3
A offsetSet() 0 15 4
A key() 0 3 1
A all() 0 3 1
A count() 0 3 1
A __construct() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Script\Interpreter;
6
7
use BitWasp\Buffertools\BufferInterface;
8
9
class Stack implements \Countable, \ArrayAccess, \Iterator
10
{
11
    /**
12
     * @var int
13
     */
14
    private $position = 0;
15
16
    /**
17
     * @var BufferInterface[]
18
     */
19
    private $values = [];
20
21
    /**
22
     * Stack constructor.
23
     * @param BufferInterface[] $values
24
     */
25
    public function __construct(array $values = [])
26
    {
27 4813
        $this->values = array_map(function (BufferInterface $value) {
28 96
            return $value;
29 4813
        }, $values);
30 4813
    }
31
32
    /**
33
     * @return BufferInterface[]
34
     */
35 93
    public function all()
36
    {
37 93
        return $this->values;
38
    }
39
40
    /**
41
     * @return BufferInterface
42
     */
43 2858
    public function current()
44
    {
45 2858
        return $this->values[$this->position];
46
    }
47
48 2858
    public function next()
49
    {
50 2858
        ++$this->position;
51 2858
    }
52
53
    /**
54
     * @return int
55
     */
56
    public function key()
57
    {
58
        return $this->position;
59
    }
60
61
    /**
62
     * @return bool
63
     */
64 4789
    public function valid()
65
    {
66 4789
        return isset($this->values[$this->position]);
67
    }
68
69 4789
    public function rewind()
70
    {
71 4789
        $this->position = 0;
72 4789
    }
73
74
    /**
75
     * @return int
76
     */
77 4691
    public function count()
78
    {
79 4691
        return count($this->values);
80
    }
81
82
    /**
83
     * @return bool
84
     */
85 3866
    public function isEmpty()
86
    {
87 3866
        return count($this->values) === 0;
88
    }
89
90
    /**
91
     * @return BufferInterface
92
     */
93 289
    public function bottom()
94
    {
95 289
        $count = count($this);
96 289
        if ($count < 1) {
97
            throw new \RuntimeException('No values in stack');
98
        }
99
100 289
        return $this->values[$count - 1];
101
    }
102
103
    /**
104
     * @see \ArrayAccess::offsetGet()
105
     * @param int $offset
106
     * @return \BitWasp\Buffertools\BufferInterface
107
     */
108 4080
    public function offsetGet($offset)
109
    {
110 4080
        $index = count($this) + $offset;
111 4080
        if (!isset($this->values[$index])) {
112 4
            throw new \RuntimeException('No value at this position');
113
        }
114
115 4080
        return $this->values[$index];
116
    }
117
118
    /**
119
     * @see \ArrayAccess::offsetSet()
120
     * @param int $offset
121
     * @param BufferInterface $value
122
     * @throws \InvalidArgumentException
123
     */
124 69
    public function offsetSet($offset, $value)
125
    {
126 69
        if (!$value instanceof BufferInterface) {
0 ignored issues
show
introduced by
$value is always a sub-type of BitWasp\Buffertools\BufferInterface.
Loading history...
127
            throw new \InvalidArgumentException;
128
        }
129
130 69
        $count = count($this);
131 69
        $index = $count + $offset;
132 69
        if (isset($this->values[$index])) {
133 69
            $this->values[$index] = $value;
134 69
            return;
135
        }
136
137
        if ($index !== $count) {
138
            throw new \RuntimeException('Index must be end position');
139
        }
140
    }
141
142
    /**
143
     * @see \ArrayAccess::offsetExists()
144
     * @param int $offset
145
     * @return bool
146
     */
147 1
    public function offsetExists($offset)
148
    {
149 1
        $index = count($this) + $offset;
150 1
        return isset($this->values[$index]);
151
    }
152
153
    /**
154
     * @see \ArrayAccess::offsetUnset()
155
     * @param int $offset
156
     */
157 86
    public function offsetUnset($offset)
158
    {
159 86
        $count = count($this);
160 86
        $index = $count + $offset;
161 86
        if (!isset($this->values[$index])) {
162 1
            throw new \RuntimeException('Nothing at this position');
163
        }
164
165 85
        array_splice($this->values, $index, 1);
166 85
    }
167
168
    /**
169
     * @param int $first
170
     * @param int $second
171
     */
172 69
    public function swap($first, $second)
173
    {
174 69
        $val1 = $this->offsetGet($first);
175 69
        $val2 = $this->offsetGet($second);
176 69
        $this->offsetSet($second, $val1);
177 69
        $this->offsetSet($first, $val2);
178 69
    }
179
180
    /**
181
     * @param int $offset
182
     * @param BufferInterface $value
183
     */
184 14
    public function add($offset, $value)
185
    {
186 14
        $size = count($this);
187 14
        $index = $size + $offset;
188 14
        if ($index > $size) {
189
            throw new \RuntimeException('Invalid add position');
190
        }
191
192
        // Unwind current values, push provided value, reapply popped values
193 14
        $values = [];
194 14
        for ($i = $size; $i > $index; $i--) {
195 14
            $values[] = $this->pop();
196
        }
197
198 14
        $this->push($value);
199 14
        for ($i = count($values); $i > 0; $i--) {
200 14
            $this->push(array_pop($values));
201
        }
202 14
    }
203
204 3350
    public function pop()
205
    {
206 3350
        $count = count($this);
207 3350
        if ($count === 0) {
208 1
            throw new \RuntimeException('Cannot pop from empty stack');
209
        }
210
211 3349
        $value = array_pop($this->values);
212 3349
        return $value;
213
    }
214
215 4467
    public function push($buffer)
216
    {
217 4467
        $this->values[] = $buffer;
218 4467
    }
219
220
    /**
221
     * @return int
222
     */
223
    public function end()
224
    {
225
        $count = count($this);
226
        if ($count === 0) {
227
            return 0;
228
        }
229
230
        return $count - 1;
231
    }
232
233
    /**
234
     * @param int $length
235
     * @return $this
236
     */
237 72
    public function resize($length)
238
    {
239 72
        if ($length > count($this)) {
240
            throw new \RuntimeException('Invalid start or length');
241
        }
242
243 72
        while (count($this) > $length) {
244 72
            $this->pop();
245
        }
246
247 72
        return $this;
248
    }
249
}
250