Skip to content

Commit 2610519

Browse files
authored
Add Decode (#4)
1 parent f20a5df commit 2610519

3 files changed

Lines changed: 60 additions & 15 deletions

File tree

example_test.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@ import (
77
)
88

99
func Example() {
10-
s := miniid.Encode(1234)
11-
fmt.Printf("num: %d -> %s\n", 1234, s)
10+
const num = uint64(1234)
11+
const long = uint64(405160095143)
12+
const str1 = "Ju"
13+
const str2 = "078FWT6F"
1214

13-
f := miniid.EncodeFixed(1234, 8)
14-
fmt.Printf("fix: %d -> %s\n", 1234, f)
15+
s := miniid.Encode(num)
16+
d1 := miniid.Decode(str1)
17+
fmt.Printf("num: %d -> %s -> %d\n", num, s, d1)
18+
19+
f := miniid.EncodeFixed(long, 8)
20+
d2 := miniid.Decode(str2)
21+
fmt.Printf("fix: %d -> %s -> %d\n", long, f, d2)
1522

1623
gen := miniid.New(1200)
1724

@@ -21,7 +28,7 @@ func Example() {
2128
fmt.Println()
2229

2330
// Output:
24-
// num: 1234 -> Ju
25-
// fix: 1234 -> 000000Ju
31+
// num: 1234 -> Ju -> 1234
32+
// fix: 405160095143 -> 078FWT6F -> 405160095143
2633
// JN JO JP JQ JR JS JT JU JV JW
2734
}

miniid.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@ package miniid
22

33
import "sync/atomic"
44

5+
const (
6+
Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
7+
base = uint64(len(Alphabet))
8+
)
9+
10+
var index = func() [256]int {
11+
var index [256]int
12+
for i := range index {
13+
index[i] = -1
14+
}
15+
for i, c := range Alphabet {
16+
index[c] = i
17+
}
18+
return index
19+
}()
20+
521
// Encode number in base62.
622
func Encode(n uint64) string {
723
return encodeBase62(n)
@@ -12,6 +28,20 @@ func EncodeFixed(n uint64, length int) string {
1228
return encodeFixedBase62(n, length)
1329
}
1430

31+
// Decode converts a base62-encoded string back into a uint64 number.
32+
// It panics if the input contains characters not in the base62 alphabet.
33+
func Decode(s string) uint64 {
34+
var n uint64
35+
for i := 0; i < len(s); i++ {
36+
val := index[s[i]]
37+
if val < 0 {
38+
panic("invalid base62 character")
39+
}
40+
n = n*base + uint64(val)
41+
}
42+
return n
43+
}
44+
1545
// Generator can encode integers into base62 strings.
1646
type Generator struct {
1747
currID atomic.Int64
@@ -31,11 +61,8 @@ func (g *Generator) Next() string {
3161
}
3262

3363
func encodeBase62(num uint64) string {
34-
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
35-
const base = uint64(len(alphabet))
36-
3764
if num == 0 {
38-
return string(alphabet[0])
65+
return string(Alphabet[0])
3966
}
4067

4168
const maxLen = 16
@@ -44,19 +71,16 @@ func encodeBase62(num uint64) string {
4471

4572
for ; num > 0; i-- {
4673
rem := num % base
47-
result[i] = alphabet[rem]
74+
result[i] = Alphabet[rem]
4875
num /= base
4976
}
5077
return string(result[i+1:])
5178
}
5279

5380
func encodeFixedBase62(num uint64, length int) string {
54-
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
55-
const base = uint64(len(alphabet))
56-
5781
buf := make([]byte, length)
5882
for i := length - 1; i >= 0; i-- {
59-
buf[i] = alphabet[num%base]
83+
buf[i] = Alphabet[num%base]
6084
num /= base
6185
}
6286
return string(buf)

miniid_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ func TestEncodeFixed(t *testing.T) {
6262
}
6363
}
6464

65+
func TestEncodeDecode(t *testing.T) {
66+
tests := []uint64{
67+
0, 1, 10, 61, 62, 12345, 999999, 405160095143, 1<<63 - 1,
68+
}
69+
70+
for _, n := range tests {
71+
enc := Encode(n)
72+
dec := Decode(enc)
73+
if dec != n {
74+
t.Fatalf("Encode/Decode failed for %d: got %d (encoded: %s)", n, dec, enc)
75+
}
76+
}
77+
}
78+
6579
func TestGenerator(t *testing.T) {
6680
testCases := []struct {
6781
num uint64

0 commit comments

Comments
 (0)