github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/util/random.go (about)

     1  package util
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/hex"
     6  	"errors"
     7  	"math"
     8  )
     9  
    10  const (
    11  	letterBytes   = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    12  	letterIdxBits = 6                    // 6 bits to represent a letter index
    13  	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    14  	letterIdxMax  = 31 / letterIdxBits   // # of letter indices fitting in 31 bits
    15  )
    16  
    17  var (
    18  	// Rand goroutine-safe, use Rand.xxx instead of rand.xxx
    19  	Rand = NewRand()
    20  	Seed = FastRand()
    21  )
    22  
    23  // RandInt (>=)min - (<)max
    24  func RandInt(min, max int) int {
    25  	if max == min {
    26  		return min
    27  	}
    28  	if max < min {
    29  		min, max = max, min
    30  	}
    31  	return FastIntn(max-min) + min
    32  }
    33  
    34  // RandUint32 (>=)min - (<)max
    35  func RandUint32(min, max uint32) uint32 {
    36  	if max == min {
    37  		return min
    38  	}
    39  	if max < min {
    40  		min, max = max, min
    41  	}
    42  	return FastRandn(max-min) + min
    43  }
    44  
    45  // FastIntn this is similar to rand.Intn, but faster.
    46  // A non-negative pseudo-random number in the half-open interval [0,n).
    47  // Return 0 if n <= 0.
    48  func FastIntn(n int) int {
    49  	if n <= 0 {
    50  		return 0
    51  	}
    52  	if n <= math.MaxUint32 {
    53  		return int(FastRandn(uint32(n)))
    54  	}
    55  	return int(Rand.Int63n(int64(n)))
    56  }
    57  
    58  // RandString a random string, which may contain uppercase letters, lowercase letters and numbers.
    59  // Ref: stackoverflow.icza
    60  func RandString(n int) string {
    61  	return string(FastRandBytes(n))
    62  }
    63  
    64  // RandHex a random string containing only the following characters: 0123456789abcdef
    65  func RandHex(nHalf int) string {
    66  	return hex.EncodeToString(FastRandBytes(nHalf))
    67  }
    68  
    69  // RandBytes returns n random bytes
    70  func RandBytes(n int) ([]byte, error) {
    71  	if n < 1 {
    72  		return nil, errors.New("invalid argument: n must be greater than zero")
    73  	}
    74  
    75  	b := make([]byte, n)
    76  	if _, err := rand.Read(b); err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	return b, nil
    81  }
    82  
    83  // FastRandBytes random bytes, but faster.
    84  func FastRandBytes(n int) []byte {
    85  	if n < 1 {
    86  		return nil
    87  	}
    88  	b := make([]byte, n)
    89  	for i, cache, remain := n-1, FastRand(), letterIdxMax; i >= 0; {
    90  		if remain == 0 {
    91  			cache, remain = FastRand(), letterIdxMax
    92  		}
    93  		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
    94  			b[i], i = letterBytes[idx], i-1
    95  		}
    96  		cache >>= letterIdxBits
    97  		remain--
    98  	}
    99  	return b
   100  }