Completed
Pull Request — master (#388)
by thomas
191:28 queued 121:43
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 1344
    /**
20
     * Stack constructor.
21 1344
     * @param BufferInterface[] $values
22
     */
23
    public function __construct(array $values = [])
24 1344
    {
25
        $this->values = array_map(function (BufferInterface $value) {
26 1344
            return $value;
27 1344
        }, $values);
28
    }
29
30
    /**
31
     * @return BufferInterface[]
32
     */
33
    public function all()
34 2349
    {
35
        return $this->values;
36 2349
    }
37
38
    public function current()
39 2349
    {
40
        return $this->values[$this->position];
41 2349
    }
42 2349
43
    public function next()
44 2357
    {
45
        ++$this->position;
46 2357
    }
47
48
    public function key()
49 1851
    {
50
        return $this->position;
51 1851
    }
52
53
    public function valid()
54 88
    {
55
        return isset($this->values[$this->position]);
56 88
    }
57 88
58
    public function rewind()
59
    {
60
        $this->position = 0;
61 88
    }
62
63
    public function count()
64
    {
65
        return count($this->values);
66
    }
67
68
    public function isEmpty()
69 1831
    {
70
        return count($this->values) === 0;
71 1831
    }
72 1831
73 2
    public function bottom()
74
    {
75
        $count = count($this);
76 1831
        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 40
     * @param int $offset
86
     * @return \BitWasp\Buffertools\BufferInterface
87 40
     */
88
    public function offsetGet($offset)
89
    {
90
        $index = count($this) + $offset;
91 40
        if (!isset($this->values[$index])) {
92 40
            throw new \RuntimeException('No value at this position');
93 40
        }
94 40
95 40
        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 54
            throw new \RuntimeException('Index must be end position');
119
        }
120 54
    }
121 54
122 54
    /**
123 6
     * @see \ArrayAccess::offsetExists()
124
     * @param int $offset
125
     * @return bool
126 48
     */
127 48
    public function offsetExists($offset)
128
    {
129
        $index = count($this) + $offset;
130
        return isset($this->values[$index]);
131
    }
132
133 40
    /**
134
     * @see \ArrayAccess::offsetUnset()
135 40
     * @param int $offset
136 40
     */
137 40
    public function offsetUnset($offset)
138 40
    {
139 40
        $count = count($this);
140
        $index = $count + $offset;
141
        if (!isset($this->values[$index])) {
142
            throw new \RuntimeException('Nothing at this position');
143
        }
144
145 18
        array_splice($this->values, $index, 1);
146
    }
147 18
148 18
    /**
149 18
     * @param int $first
150
     * @param int $second
151
     */
152
    public function swap($first, $second)
153
    {
154 18
        $val1 = $this->offsetGet($first);
155 18
        $val2 = $this->offsetGet($second);
156 18
        $this->offsetSet($second, $val1);
157 4
        $this->offsetSet($first, $val2);
158
    }
159 18
160 18
    /**
161 18
     * @param int $offset
162 4
     * @param BufferInterface $value
163 18
     */
164
    public function add($offset, $value)
165 1579
    {
166
        $size = count($this);
167 1579
        $index = $size + $offset;
168 1579
        if ($index > $size) {
169 6
            throw new \RuntimeException('Invalid add position');
170
        }
171
172 1573
        // Unwind current values, push provided value, reapply popped values
173 1573
        $values = [];
174
        for ($i = $size; $i > $index; $i--) {
175
            $values[] = $this->pop();
176 2237
        }
177
178 2237
        $this->push($value);
179 2237
        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 23
    }
199
200 23
    /**
201
     * @return int
202
     */
203
    public function end()
204 23
    {
205 23
        $count = count($this);
206 5
        if ($count === 0) {
207
            return 0;
208 23
        }
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