You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
1.4 KiB
72 lines
1.4 KiB
package stringx |
|
|
|
import ( |
|
"fmt" |
|
"math/rand" |
|
"sync" |
|
"time" |
|
) |
|
|
|
const ( |
|
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" |
|
letterIdxBits = 6 |
|
idLen = 8 |
|
defaultRandLen = 8 |
|
letterIdxMask = 1<<letterIdxBits - 1 |
|
letterIdxMax = 63 / letterIdxBits |
|
) |
|
|
|
var src = newLockedSource(time.Now().UnixNano()) |
|
|
|
type lockedSource struct { |
|
source rand.Source |
|
lock sync.Mutex |
|
} |
|
|
|
func newLockedSource(seed int64) *lockedSource { |
|
return &lockedSource{ |
|
source: rand.NewSource(seed), |
|
} |
|
} |
|
func (l *lockedSource) Int63() int64 { |
|
l.lock.Lock() |
|
defer l.lock.Unlock() |
|
return l.source.Int63() |
|
} |
|
func (l *lockedSource) Seed(seed int64) { |
|
l.lock.Lock() |
|
defer l.lock.Unlock() |
|
l.source.Seed(seed) |
|
} |
|
func Rand() string { |
|
return Randn(defaultRandLen) |
|
} |
|
func RandId() string { |
|
b := make([]byte, idLen) |
|
_, err := rand.Read(b) |
|
if err != nil { |
|
return Randn(idLen) |
|
} |
|
return fmt.Sprintf("%x%x%x%x", b[0:2], b[2:4], b[4:6], b[6:8]) |
|
} |
|
func Randn(n int) string { |
|
b := make([]byte, n) |
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters! |
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; { |
|
if remain == 0 { |
|
cache, remain = src.Int63(), letterIdxMax |
|
} |
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) { |
|
b[i] = letterBytes[idx] |
|
i-- |
|
} |
|
cache >>= letterIdxBits |
|
remain-- |
|
} |
|
|
|
return string(b) |
|
} |
|
|
|
func Seed(seed int64) { |
|
src.Seed(seed) |
|
}
|
|
|