forked from twinj/uuid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
format.go
164 lines (145 loc) · 4.32 KB
/
format.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package uuid
import (
"errors"
"strings"
)
// Format represents different styles a UUID can be printed in constants
// represent a pattern used by the package with which to print a UUID.
type Format string
const (
FormatHex Format = "%x%x%x%x%x"
FormatHexCurly Format = "{%x%x%x%x%x}"
FormatHexBracket Format = "(%x%x%x%x%x)"
// This is the canonical format.
FormatCanonical Format = "%x-%x-%x-%x-%x"
FormatCanonicalCurly Format = "{%x-%x-%x-%x-%x}"
FormatCanonicalBracket Format = "(%x-%x-%x-%x-%x)"
FormatUrn Format = "urn:uuid:" + FormatCanonical
)
var printFormat Format = FormatCanonical
var defaultFormats map[Format]bool = make(map[Format]bool)
func init() {
defaultFormats[FormatHex] = true
defaultFormats[FormatHexCurly] = true
defaultFormats[FormatHexBracket] = true
defaultFormats[FormatCanonical] = true
defaultFormats[FormatCanonicalCurly] = true
defaultFormats[FormatCanonicalBracket] = true
defaultFormats[FormatUrn] = true
}
// SwitchFormat switches the default printing format for ALL UUIDs.
//
// The default is the canonical uuid.Format.FormatCanonical which has been
// optimised for use with this package. It is twice as fast compared to other
// formats; supplied or given. However, the benchmark for non default formats
// is still very quick and quite usable. The package has moved away from using
// fmt.Sprintf which was up to 5 times slower in comparison to custom formats
// and 10 times slower in comparison to the canonical format.
//
// A valid format will have 5 groups of [%x|%X] or follow the pattern,
// *%[xX]*%[xX]*%[xX]*%[xX]*%[xX]*. If the supplied format does not meet this
// standard the function will panic. Note any extra uses of [%] outside of the
// [%x|%X] will also cause a panic.
// Constant uuid.Formats have been provided for the most likely formats.
func SwitchFormat(pFormat Format) {
checkFormat(pFormat)
printFormat = pFormat
}
// SwitchFormatToUpper is a convenience function to set the Format to uppercase
// versions of the given constants.
func SwitchFormatToUpper(pFormat Format) {
SwitchFormat(Format(strings.ToUpper(string(pFormat))))
}
// Formatter will return a string representation of the given UUID.
//
// Use this for one time formatting when setting the default using
// uuid.SwitchFormat would be overkill.
//
// A valid format will have 5 groups of [%x|%X] or follow the pattern,
// *%[xX]*%[xX]*%[xX]*%[xX]*%[xX]*. If the supplied format does not meet this
// standard the function will panic. Note any extra uses of [%] outside of the
// [%x|%X] will also cause a panic.
func Formatter(pId UUID, pFormat Format) string {
checkFormat(pFormat)
return formatUuid(pId.Bytes(), pFormat)
}
func checkFormat(pFormat Format) {
if defaultFormats[pFormat] {
return
}
s := strings.ToLower(string(pFormat))
if strings.Count(s, "%x") != 5 {
panic(errors.New("uuid.Format: invalid format"))
}
s = strings.Replace(s, "%x", "", -1)
if strings.Count(s, "%") > 0 {
panic(errors.New("uuid.Format: invalid format"))
}
}
const (
hexTable = "0123456789abcdef"
hexUpperTable = "0123456789ABCDEF"
canonicalLength = length*2 + 4
formatArgCount = 10
uuidStringBufferSize = length*2 - formatArgCount
)
var groups = [...]int{4, 2, 2, 2, 6}
func formatUuid(pSrc []byte, pFormat Format) string {
if pFormat == FormatCanonical {
return string(formatCanonical(pSrc))
}
return string(format(pSrc, string(pFormat)))
}
func format(pSrc []byte, pFormat string) []byte {
end := len(pFormat)
buf := make([]byte, end+uuidStringBufferSize)
var s, ls, b, e, p int
var u bool
for _, v := range groups {
ls = s
for ; s < end && pFormat[s] != '%'; s++ {
}
copy(buf[p:], pFormat[ls:s])
p += s - ls
s++
u = pFormat[s] == 'X'
s++
e = b + v
for i, t := range pSrc[b:e] {
j := p + i + i
table := hexTable
if u {
table = hexUpperTable
}
buf[j] = table[t>>4]
buf[j+1] = table[t&0x0f]
}
b = e
p += v + v
}
ls = s
for ; s < end && pFormat[s] != '%'; s++ {
}
copy(buf[p:], pFormat[ls:s])
p += s - ls
return buf
}
func formatCanonical(pSrc []byte) []byte {
buf := make([]byte, canonicalLength)
var b, p, e int
for h, v := range groups {
e = b + v
for i, t := range pSrc[b:e] {
j := p + i + i
buf[j] = hexTable[t>>4]
buf[j+1] = hexTable[t&0x0f]
}
b = e
p += v + v
if h < 4 {
buf[p] = '-'
p += 1
}
}
return buf
}