Completed
Pull Request — master (#339)
by thomas
105:25 queued 102:16
created

Stack::swap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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