Added Base58 encoder/decoder

This commit is contained in:
Bruce Marriner 2017-02-21 09:58:29 -06:00
parent 34b33bf22a
commit 734cbe306e
2 changed files with 97 additions and 0 deletions

View File

@ -19,6 +19,25 @@ const (
nodeShift uint8 = stepBits nodeShift uint8 = stepBits
) )
const encodeBase58Map = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
var decodeBase58Map [256]byte
// Create a map for decoding Base58. This speeds up the process tremendously.
func init() {
for i := 0; i < len(encodeBase58Map); i++ {
decodeBase58Map[i] = 0xFF
}
for i := 0; i < len(encodeBase58Map); i++ {
decodeBase58Map[encodeBase58Map[i]] = byte(i)
}
}
// ErrInvalidBase58 is returned by ParseBase58 when given an invalid []byte
var ErrInvalidBase58 = errors.New("invalid base58")
// Epoch is set to the twitter snowflake epoch of 2006-03-21:20:50:14 GMT // Epoch is set to the twitter snowflake epoch of 2006-03-21:20:50:14 GMT
// You may customize this to set a different epoch for your application. // You may customize this to set a different epoch for your application.
var Epoch int64 = 1288834974657 var Epoch int64 = 1288834974657
@ -101,6 +120,42 @@ func (f ID) Base36() string {
return strconv.FormatInt(int64(f), 36) return strconv.FormatInt(int64(f), 36)
} }
// Base58 returns a base58 string of the snowflake ID
func (f ID) Base58() string {
if f < 58 {
return string(encodeBase58Map[f])
}
b := make([]byte, 0, 11)
for f >= 58 {
b = append(b, encodeBase58Map[f%58])
f /= 58
}
b = append(b, encodeBase58Map[f])
for x, y := 0, len(b)-1; x < y; x, y = x+1, y-1 {
b[x], b[y] = b[y], b[x]
}
return string(b)
}
// ParseBase58 parses a base58 []byte into a snowflake ID
func ParseBase58(b []byte) (ID, error) {
var id int64
for i := range b {
if decodeBase58Map[b[i]] == 0xFF {
return -1, ErrInvalidBase58
}
id = id*58 + int64(decodeBase58Map[b[i]])
}
return ID(id), nil
}
// Base64 returns a base64 string of the snowflake ID // Base64 returns a base64 string of the snowflake ID
func (f ID) Base64() string { func (f ID) Base64() string {
return base64.StdEncoding.EncodeToString(f.Bytes()) return base64.StdEncoding.EncodeToString(f.Bytes())

View File

@ -42,6 +42,48 @@ func TestUnmarshalJSON(t *testing.T) {
} }
} }
func TestBase58(t *testing.T) {
node, _ := NewNode(1)
for i := 0; i < 10; i++ {
sf := node.Generate()
b58 := sf.Base58()
psf, err := ParseBase58([]byte(b58))
if err != nil {
t.Fatal(err)
}
if sf != psf {
t.Fatal("Parsed does not match String.")
}
}
}
func BenchmarkParseBase58(b *testing.B) {
node, _ := NewNode(1)
sf := node.Generate()
b58 := sf.Base58()
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
ParseBase58([]byte(b58))
}
}
func BenchmarkBase58(b *testing.B) {
node, _ := NewNode(1)
sf := node.Generate()
b.ReportAllocs()
b.ResetTimer()
for n := 0; n < b.N; n++ {
sf.Base58()
}
}
func BenchmarkGenerate(b *testing.B) { func BenchmarkGenerate(b *testing.B) {
node, _ := NewNode(1) node, _ := NewNode(1)