github.com/gogf/gf@v1.16.9/util/grand/grand.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 // Package grand provides high performance random bytes/number/string generation functionality. 8 package grand 9 10 import ( 11 "encoding/binary" 12 "time" 13 "unsafe" 14 ) 15 16 var ( 17 letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52 18 symbols = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // 32 19 digits = "0123456789" // 10 20 characters = letters + digits + symbols // 94 21 ) 22 23 // Intn returns a int number which is between 0 and max: [0, max). 24 // 25 // Note that: 26 // 1. The `max` can only be greater than 0, or else it returns `max` directly; 27 // 2. The result is greater than or equal to 0, but less than `max`; 28 // 3. The result number is 32bit and less than math.MaxUint32. 29 func Intn(max int) int { 30 if max <= 0 { 31 return max 32 } 33 n := int(binary.LittleEndian.Uint32(<-bufferChan)) % max 34 if (max > 0 && n < 0) || (max < 0 && n > 0) { 35 return -n 36 } 37 return n 38 } 39 40 // B retrieves and returns random bytes of given length `n`. 41 func B(n int) []byte { 42 if n <= 0 { 43 return nil 44 } 45 i := 0 46 b := make([]byte, n) 47 for { 48 copy(b[i:], <-bufferChan) 49 i += 4 50 if i >= n { 51 break 52 } 53 } 54 return b 55 } 56 57 // N returns a random int between min and max: [min, max]. 58 // The `min` and `max` also support negative numbers. 59 func N(min, max int) int { 60 if min >= max { 61 return min 62 } 63 if min >= 0 { 64 // Because Intn dose not support negative number, 65 // so we should first shift the value to left, 66 // then call Intn to produce the random number, 67 // and finally shift the result back to right. 68 return Intn(max-(min-0)+1) + (min - 0) 69 } 70 if min < 0 { 71 // Because Intn dose not support negative number, 72 // so we should first shift the value to right, 73 // then call Intn to produce the random number, 74 // and finally shift the result back to left. 75 return Intn(max+(0-min)+1) - (0 - min) 76 } 77 return 0 78 } 79 80 // S returns a random string which contains digits and letters, and its length is `n`. 81 // The optional parameter `symbols` specifies whether the result could contain symbols, 82 // which is false in default. 83 func S(n int, symbols ...bool) string { 84 if n <= 0 { 85 return "" 86 } 87 var ( 88 b = make([]byte, n) 89 numberBytes = B(n) 90 ) 91 for i := range b { 92 if len(symbols) > 0 && symbols[0] { 93 b[i] = characters[numberBytes[i]%94] 94 } else { 95 b[i] = characters[numberBytes[i]%62] 96 } 97 } 98 return *(*string)(unsafe.Pointer(&b)) 99 } 100 101 // D returns a random time.Duration between min and max: [min, max]. 102 func D(min, max time.Duration) time.Duration { 103 multiple := int64(1) 104 if min != 0 { 105 for min%10 == 0 { 106 multiple *= 10 107 min /= 10 108 max /= 10 109 } 110 } 111 n := int64(N(int(min), int(max))) 112 return time.Duration(n * multiple) 113 } 114 115 // Str randomly picks and returns `n` count of chars from given string `s`. 116 // It also supports unicode string like Chinese/Russian/Japanese, etc. 117 func Str(s string, n int) string { 118 if n <= 0 { 119 return "" 120 } 121 var ( 122 b = make([]rune, n) 123 runes = []rune(s) 124 ) 125 if len(runes) <= 255 { 126 numberBytes := B(n) 127 for i := range b { 128 b[i] = runes[int(numberBytes[i])%len(runes)] 129 } 130 } else { 131 for i := range b { 132 b[i] = runes[Intn(len(runes))] 133 } 134 } 135 return string(b) 136 } 137 138 // Digits returns a random string which contains only digits, and its length is `n`. 139 func Digits(n int) string { 140 if n <= 0 { 141 return "" 142 } 143 var ( 144 b = make([]byte, n) 145 numberBytes = B(n) 146 ) 147 for i := range b { 148 b[i] = digits[numberBytes[i]%10] 149 } 150 return *(*string)(unsafe.Pointer(&b)) 151 } 152 153 // Letters returns a random string which contains only letters, and its length is `n`. 154 func Letters(n int) string { 155 if n <= 0 { 156 return "" 157 } 158 var ( 159 b = make([]byte, n) 160 numberBytes = B(n) 161 ) 162 for i := range b { 163 b[i] = letters[numberBytes[i]%52] 164 } 165 return *(*string)(unsafe.Pointer(&b)) 166 } 167 168 // Symbols returns a random string which contains only symbols, and its length is `n`. 169 func Symbols(n int) string { 170 if n <= 0 { 171 return "" 172 } 173 var ( 174 b = make([]byte, n) 175 numberBytes = B(n) 176 ) 177 for i := range b { 178 b[i] = symbols[numberBytes[i]%32] 179 } 180 return *(*string)(unsafe.Pointer(&b)) 181 } 182 183 // Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n). 184 // TODO performance improving for large slice producing. 185 func Perm(n int) []int { 186 m := make([]int, n) 187 for i := 0; i < n; i++ { 188 j := Intn(i + 1) 189 m[i] = m[j] 190 m[j] = i 191 } 192 return m 193 } 194 195 // Meet randomly calculate whether the given probability `num`/`total` is met. 196 func Meet(num, total int) bool { 197 return Intn(total) < num 198 } 199 200 // MeetProb randomly calculate whether the given probability is met. 201 func MeetProb(prob float32) bool { 202 return Intn(1e7) < int(prob*1e7) 203 }