-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathcrockford.go
More file actions
114 lines (98 loc) · 2.45 KB
/
Copy pathcrockford.go
File metadata and controls
114 lines (98 loc) · 2.45 KB
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
// Package uuidkey provides Crockford Base32 encoding that's compatible with the original crock32 number-based approach
package uuidkey
import (
"encoding/base32"
"fmt"
)
// crockford is the standard library base32 encoding with Crockford's alphabet (for entropy generation)
var crockford = base32.NewEncoding("0123456789ABCDEFGHJKMNPQRSTVWXYZ").WithPadding(base32.NoPadding)
// crock32Encode encodes a uint32 as a Crockford Base32 string (number-based encoding)
func crock32Encode(n uint32) string {
const digits = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
if n == 0 {
return "0"
}
// Use a fixed-size array to avoid allocations
var buf [8]byte // Maximum size needed for uint32 in base32
idx := len(buf)
for n > 0 {
idx--
buf[idx] = digits[n%32]
n /= 32
}
return string(buf[idx:])
}
// Pre-computed lookup table for fast character to digit conversion
// 255 indicates invalid character
var decodeTable = func() [256]byte {
table := [256]byte{}
// Initialize all values to 255 (invalid)
for i := range table {
table[i] = 255
}
// Numbers 0-9
for i := byte('0'); i <= '9'; i++ {
table[i] = i - '0'
}
// Uppercase letters
table['A'] = 10
table['B'] = 11
table['C'] = 12
table['D'] = 13
table['E'] = 14
table['F'] = 15
table['G'] = 16
table['H'] = 17
// Skip I
table['J'] = 18
table['K'] = 19
// Skip L
table['M'] = 20
table['N'] = 21
// Skip O
table['P'] = 22
table['Q'] = 23
table['R'] = 24
table['S'] = 25
table['T'] = 26
// Skip U
table['V'] = 27
table['W'] = 28
table['X'] = 29
table['Y'] = 30
table['Z'] = 31
// Lowercase letters (same values as uppercase)
for c := byte('a'); c <= 'z'; c++ {
if table[c-'a'+'A'] != 255 {
table[c] = table[c-'a'+'A']
}
}
// Special mappings per Crockford spec
table['O'] = 0
table['o'] = 0
table['I'] = 1
table['i'] = 1
table['L'] = 1
table['l'] = 1
return table
}()
// crock32Decode decodes a Crockford Base32 string to a uint32 (number-based decoding)
func crock32Decode(s string) (uint32, error) {
if len(s) == 0 {
return 0, fmt.Errorf("crock32.Decode: empty string")
}
var result uint32
for i := range len(s) {
// Use lookup table for fast conversion
digit := decodeTable[s[i]]
if digit == 255 {
return 0, fmt.Errorf("crock32.Decode: invalid character %c", s[i])
}
// Check for overflow before multiplication
if result > (^uint32(0))/32 {
return 0, fmt.Errorf("crock32.Decode: integer overflow")
}
result = result*32 + uint32(digit)
}
return result, nil
}