| /* |
| Copyright 2015 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| // Package rand provides utilities related to randomization. |
| package rand |
| |
| import ( |
| "math/rand" |
| "sync" |
| "time" |
| ) |
| |
| var rng = struct { |
| sync.Mutex |
| rand *rand.Rand |
| }{ |
| rand: rand.New(rand.NewSource(time.Now().UnixNano())), |
| } |
| |
| // Int returns a non-negative pseudo-random int. |
| func Int() int { |
| rng.Lock() |
| defer rng.Unlock() |
| return rng.rand.Int() |
| } |
| |
| // Intn generates an integer in range [0,max). |
| // By design this should panic if input is invalid, <= 0. |
| func Intn(max int) int { |
| rng.Lock() |
| defer rng.Unlock() |
| return rng.rand.Intn(max) |
| } |
| |
| // IntnRange generates an integer in range [min,max). |
| // By design this should panic if input is invalid, <= 0. |
| func IntnRange(min, max int) int { |
| rng.Lock() |
| defer rng.Unlock() |
| return rng.rand.Intn(max-min) + min |
| } |
| |
| // IntnRange generates an int64 integer in range [min,max). |
| // By design this should panic if input is invalid, <= 0. |
| func Int63nRange(min, max int64) int64 { |
| rng.Lock() |
| defer rng.Unlock() |
| return rng.rand.Int63n(max-min) + min |
| } |
| |
| // Seed seeds the rng with the provided seed. |
| func Seed(seed int64) { |
| rng.Lock() |
| defer rng.Unlock() |
| |
| rng.rand = rand.New(rand.NewSource(seed)) |
| } |
| |
| // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n) |
| // from the default Source. |
| func Perm(n int) []int { |
| rng.Lock() |
| defer rng.Unlock() |
| return rng.rand.Perm(n) |
| } |
| |
| const ( |
| // We omit vowels from the set of available characters to reduce the chances |
| // of "bad words" being formed. |
| alphanums = "bcdfghjklmnpqrstvwxz2456789" |
| // No. of bits required to index into alphanums string. |
| alphanumsIdxBits = 5 |
| // Mask used to extract last alphanumsIdxBits of an int. |
| alphanumsIdxMask = 1<<alphanumsIdxBits - 1 |
| // No. of random letters we can extract from a single int63. |
| maxAlphanumsPerInt = 63 / alphanumsIdxBits |
| ) |
| |
| // String generates a random alphanumeric string, without vowels, which is n |
| // characters long. This will panic if n is less than zero. |
| // How the random string is created: |
| // - we generate random int63's |
| // - from each int63, we are extracting multiple random letters by bit-shifting and masking |
| // - if some index is out of range of alphanums we neglect it (unlikely to happen multiple times in a row) |
| func String(n int) string { |
| b := make([]byte, n) |
| rng.Lock() |
| defer rng.Unlock() |
| |
| randomInt63 := rng.rand.Int63() |
| remaining := maxAlphanumsPerInt |
| for i := 0; i < n; { |
| if remaining == 0 { |
| randomInt63, remaining = rng.rand.Int63(), maxAlphanumsPerInt |
| } |
| if idx := int(randomInt63 & alphanumsIdxMask); idx < len(alphanums) { |
| b[i] = alphanums[idx] |
| i++ |
| } |
| randomInt63 >>= alphanumsIdxBits |
| remaining-- |
| } |
| return string(b) |
| } |
| |
| // SafeEncodeString encodes s using the same characters as rand.String. This reduces the chances of bad words and |
| // ensures that strings generated from hash functions appear consistent throughout the API. |
| func SafeEncodeString(s string) string { |
| r := make([]byte, len(s)) |
| for i, b := range []rune(s) { |
| r[i] = alphanums[(int(b) % len(alphanums))] |
| } |
| return string(r) |
| } |