mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-06 13:39:07 +02:00
78 lines
1.8 KiB
Go
78 lines
1.8 KiB
Go
package base62
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
const (
|
|
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
base = uint32(len(alphabet))
|
|
maxBase62Digits = 6 // max number of digits required to encode MaxUint32
|
|
|
|
)
|
|
|
|
var (
|
|
ErrEmptyString = fmt.Errorf("empty string")
|
|
ErrInvalidChar = fmt.Errorf("invalid character")
|
|
ErrOverflow = fmt.Errorf("integer overflow")
|
|
)
|
|
|
|
// Fixed-size arrays have better performance and lower memory overhead compared to maps for small static sets of data
|
|
var charToIndex [123]int8 // Assuming ASCII from '\0' - 'z'
|
|
|
|
func init() {
|
|
for i := range charToIndex {
|
|
charToIndex[i] = -1
|
|
}
|
|
for i, c := range alphabet {
|
|
charToIndex[c] = int8(i)
|
|
}
|
|
}
|
|
|
|
// Encode encodes a uint32 value to a base62 string.
|
|
// The returned string will be between 1-6 characters long.
|
|
func Encode(n uint32) string {
|
|
if n < base {
|
|
return string(alphabet[n])
|
|
}
|
|
// avoid dynamic memory usage for small, fixed size data
|
|
buf := [maxBase62Digits]byte{}
|
|
idx := len(buf)
|
|
|
|
for n > 0 {
|
|
idx--
|
|
buf[idx] = alphabet[n%base]
|
|
n /= base
|
|
}
|
|
|
|
return string(buf[idx:])
|
|
}
|
|
|
|
// Decode decodes a base62 string to a uint32 value.
|
|
// Returns an error if the input string is empty, contains invalid characters,
|
|
// or would result in integer overflow.
|
|
func Decode(encoded string) (uint32, error) {
|
|
if len(encoded) == 0 {
|
|
return 0, ErrEmptyString
|
|
}
|
|
var decoded uint32
|
|
for _, char := range encoded {
|
|
index := int8(-1)
|
|
if int(char) < len(charToIndex) {
|
|
index = charToIndex[char]
|
|
}
|
|
if index < 0 {
|
|
return 0, fmt.Errorf("%w: %c", ErrInvalidChar, char)
|
|
}
|
|
// Add overflow check when calculating the decoded value to prevent silent overflow of uint32
|
|
if decoded > (math.MaxUint32-uint32(index))/base {
|
|
return 0, fmt.Errorf("%w: %s", ErrOverflow, encoded)
|
|
}
|
|
|
|
decoded = decoded*base + uint32(index)
|
|
}
|
|
|
|
return decoded, nil
|
|
}
|