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