-
Notifications
You must be signed in to change notification settings - Fork 1
/
roman.go
100 lines (88 loc) · 1.71 KB
/
roman.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
package romanumeral
import (
"errors"
"fmt"
"unicode/utf8"
"unsafe"
)
var (
errAccessBeyond = errors.New("romanumeral: Roman access beyond the numeral")
errNilPointer = errors.New("romanumeral: Roman decode on nil pointer")
)
var (
romanLetterValue = map[rune]Roman{
'M': 1000,
'D': 500,
'C': 100,
'L': 50,
'X': 10,
'V': 5,
'I': 1,
}
romanValues = []Roman{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}
romanLetters = []string{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}
)
type Roman uint16
func (r Roman) IsValid() bool {
return r > 0 && r < 4000
}
func (r *Roman) Decode(s []byte) (n int, err error) {
if r == nil {
return 0, errNilPointer
}
var pre Roman
var curr Roman
var ret Roman
for n != len(s) {
ch, size := utf8.DecodeRune(s[n:])
curr = romanLetterValue[ch]
if pre >= curr {
ret += pre
} else {
ret -= pre
}
if curr == 0 {
break
}
pre = curr
n += size
}
if !ret.IsValid() {
return 0, errAccessBeyond
}
*r = ret
return n, nil
}
func (r *Roman) DecodeString(s string) (n int, err error) {
return r.Decode(*(*[]byte)(unsafe.Pointer(&s)))
}
func (r Roman) Encode() ([]byte, error) {
if !r.IsValid() {
return nil, errAccessBeyond
}
buf := make([]byte, 0, 16)
for i := 0; i != len(romanValues); {
v := romanValues[i]
if r >= v {
r -= v
buf = append(buf, romanLetters[i]...)
} else {
i++
}
}
return buf, nil
}
func (r Roman) EncodeToString() (string, error) {
b, err := r.Encode()
if err != nil {
return "", err
}
return *(*string)(unsafe.Pointer(&b)), nil
}
func (r Roman) String() string {
ret, err := r.EncodeToString()
if err != nil {
return fmt.Sprintf("Roman(%d)", uint16(r))
}
return ret
}