Completed
Pull Request — master (#388)
by thomas
316:52 queued 244:52
created

Stack::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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