Completed
Pull Request — master (#446)
by thomas
105:00 queued 101:56
created

Stack::current()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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