123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- // Package grand provides high performance random bytes/number/string generation functionality.
- package grand
- import (
- "encoding/binary"
- "time"
- "unsafe"
- )
- var (
- letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52
- symbols = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // 32
- digits = "0123456789" // 10
- characters = letters + digits + symbols // 94
- )
- // Intn returns a int number which is between 0 and max: [0, max).
- //
- // Note that:
- // 1. The `max` can only be greater than 0, or else it returns `max` directly;
- // 2. The result is greater than or equal to 0, but less than `max`;
- // 3. The result number is 32bit and less than math.MaxUint32.
- func Intn(max int) int {
- if max <= 0 {
- return max
- }
- n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max
- if (max > 0 && n < 0) || (max < 0 && n > 0) {
- return -n
- }
- return n
- }
- // B retrieves and returns random bytes of given length `n`.
- func B(n int) []byte {
- if n <= 0 {
- return nil
- }
- i := 0
- b := make([]byte, n)
- for {
- copy(b[i:], <-bufferChan)
- i += 4
- if i >= n {
- break
- }
- }
- return b
- }
- // N returns a random int between min and max: [min, max].
- // The `min` and `max` also support negative numbers.
- func N(min, max int) int {
- if min >= max {
- return min
- }
- if min >= 0 {
- // Because Intn dose not support negative number,
- // so we should first shift the value to left,
- // then call Intn to produce the random number,
- // and finally shift the result back to right.
- return Intn(max-(min-0)+1) + (min - 0)
- }
- if min < 0 {
- // Because Intn dose not support negative number,
- // so we should first shift the value to right,
- // then call Intn to produce the random number,
- // and finally shift the result back to left.
- return Intn(max+(0-min)+1) - (0 - min)
- }
- return 0
- }
- // S returns a random string which contains digits and letters, and its length is `n`.
- // The optional parameter `symbols` specifies whether the result could contain symbols,
- // which is false in default.
- func S(n int, symbols ...bool) string {
- if n <= 0 {
- return ""
- }
- var (
- b = make([]byte, n)
- numberBytes = B(n)
- )
- for i := range b {
- if len(symbols) > 0 && symbols[0] {
- b[i] = characters[numberBytes[i]%94]
- } else {
- b[i] = characters[numberBytes[i]%62]
- }
- }
- return *(*string)(unsafe.Pointer(&b))
- }
- // D returns a random time.Duration between min and max: [min, max].
- func D(min, max time.Duration) time.Duration {
- multiple := int64(1)
- if min != 0 {
- for min%10 == 0 {
- multiple *= 10
- min /= 10
- max /= 10
- }
- }
- n := int64(N(int(min), int(max)))
- return time.Duration(n * multiple)
- }
- // Str randomly picks and returns `n` count of chars from given string `s`.
- // It also supports unicode string like Chinese/Russian/Japanese, etc.
- func Str(s string, n int) string {
- if n <= 0 {
- return ""
- }
- var (
- b = make([]rune, n)
- runes = []rune(s)
- )
- if len(runes) <= 255 {
- numberBytes := B(n)
- for i := range b {
- b[i] = runes[int(numberBytes[i])%len(runes)]
- }
- } else {
- for i := range b {
- b[i] = runes[Intn(len(runes))]
- }
- }
- return string(b)
- }
- // Digits returns a random string which contains only digits, and its length is `n`.
- func Digits(n int) string {
- if n <= 0 {
- return ""
- }
- var (
- b = make([]byte, n)
- numberBytes = B(n)
- )
- for i := range b {
- b[i] = digits[numberBytes[i]%10]
- }
- return *(*string)(unsafe.Pointer(&b))
- }
- // Letters returns a random string which contains only letters, and its length is `n`.
- func Letters(n int) string {
- if n <= 0 {
- return ""
- }
- var (
- b = make([]byte, n)
- numberBytes = B(n)
- )
- for i := range b {
- b[i] = letters[numberBytes[i]%52]
- }
- return *(*string)(unsafe.Pointer(&b))
- }
- // Symbols returns a random string which contains only symbols, and its length is `n`.
- func Symbols(n int) string {
- if n <= 0 {
- return ""
- }
- var (
- b = make([]byte, n)
- numberBytes = B(n)
- )
- for i := range b {
- b[i] = symbols[numberBytes[i]%32]
- }
- return *(*string)(unsafe.Pointer(&b))
- }
- // Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).
- // TODO performance improving for large slice producing.
- func Perm(n int) []int {
- m := make([]int, n)
- for i := 0; i < n; i++ {
- j := Intn(i + 1)
- m[i] = m[j]
- m[j] = i
- }
- return m
- }
- // Meet randomly calculate whether the given probability `num`/`total` is met.
- func Meet(num, total int) bool {
- return Intn(total) < num
- }
- // MeetProb randomly calculate whether the given probability is met.
- func MeetProb(prob float32) bool {
- return Intn(1e7) < int(prob*1e7)
- }
|