-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsansan.go
119 lines (98 loc) · 2.06 KB
/
sansan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package sansan
import (
"fmt"
"io"
"os"
"sync"
"sync/atomic"
)
const heapsize = 30000
type heap []int32
type Machine struct {
mem heap
wg *sync.WaitGroup
stdin io.Reader
stdout io.Writer
}
func NewMachine() Machine {
return Machine{
mem: make(heap, heapsize),
wg: &sync.WaitGroup{},
stdin: os.Stdin,
stdout: os.Stdout,
}
}
func (m Machine) Run(p program) {
defer m.wg.Wait()
m.run(p, new(state))
}
type state struct {
pnt int16
atomic bool
}
func (m Machine) run(p program, s *state) {
for i := 0; i < len(p); i++ {
switch ins := p[i]; ins.Action {
case Move:
s.pnt += ins.Val
s.pnt = (s.pnt%heapsize + heapsize) % heapsize
case Modify:
if s.atomic {
atomic.AddInt32(&m.mem[s.pnt], int32(ins.Val))
} else {
m.mem[s.pnt] += int32(ins.Val)
}
case LStart:
end := i + int(ins.Val)
if (s.atomic && atomic.LoadInt32(&m.mem[s.pnt]) != 0) || (!s.atomic && m.mem[s.pnt] != 0) {
m.run(p[i+1:end+1], s) // enter loop
}
i = end // goto end
case LEnd:
if (s.atomic && atomic.LoadInt32(&m.mem[s.pnt]) == 0) || (!s.atomic && m.mem[s.pnt] == 0) {
return
}
i = -1
case TStart:
end := i + int(ins.Val)
m.wg.Add(1)
go m.runThread(p[i+1:end+1], *s)
i = end // continue parrent thread
case TEnd:
return // kill thread
case Toggle:
// toggle atomic operations on current thread
s.atomic = s.atomic != true
case Print:
var v int32
if s.atomic {
v = atomic.LoadInt32(&m.mem[s.pnt])
} else {
v = m.mem[s.pnt]
}
fmt.Fprintf(m.stdout, "%c", v)
case Read:
var n int32
if _, err := fmt.Fscanf(m.stdin, "%d\n", &n); err != nil {
panic(err)
}
if s.atomic {
atomic.SwapInt32(&m.mem[s.pnt], n)
} else {
m.mem[s.pnt] = n
}
}
}
}
// runThread runs the given program with a local copy of the
// heap pointer and decrements waitgroup when finished.
func (m Machine) runThread(p program, s state) {
defer m.wg.Done()
m.run(p, &s)
}
func (m *Machine) SetInput(r io.Reader) {
m.stdin = r
}
func (m *Machine) SetOutput(w io.Writer) {
m.stdout = w
}