github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/tools/random.go (about)

     1  package tools
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/binary"
     6  	mathRand "math/rand"
     7  	"sync"
     8  	_ "unsafe"
     9  )
    10  
    11  /*
    12     Creation Time: 2019 - Oct - 03
    13     Created by:  (ehsan)
    14     Maintainers:
    15        1.  Ehsan N. Moosa (E2)
    16     Auditor: Ehsan N. Moosa (E2)
    17     Copyright Ronak Software Group 2020
    18  */
    19  
    20  const (
    21  	digits              = "0123456789"
    22  	digitsLength        = uint32(len(digits))
    23  	alphaNumerics       = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    24  	alphaNumericsLength = uint32(len(alphaNumerics))
    25  )
    26  
    27  // FastRand is a fast thread local random function.
    28  //go:linkname FastRand runtime.fastrand
    29  func FastRand() uint32
    30  
    31  type randomGenerator struct {
    32  	sync.Pool
    33  }
    34  
    35  func (rg *randomGenerator) GetRand() *mathRand.Rand {
    36  	return rg.Get().(*mathRand.Rand)
    37  }
    38  
    39  func (rg *randomGenerator) PutRand(r *mathRand.Rand) {
    40  	rg.Put(r)
    41  }
    42  
    43  var rndGen randomGenerator
    44  
    45  func init() {
    46  	rndGen.New = func() interface{} {
    47  		x := mathRand.New(mathRand.NewSource(CPUTicks()))
    48  
    49  		return x
    50  	}
    51  }
    52  
    53  // RandomID generates a pseudo-random string with length 'n' which characters are alphanumerics.
    54  func RandomID(n int) string {
    55  	rnd := rndGen.GetRand()
    56  	b := make([]byte, n)
    57  	for i := range b {
    58  		b[i] = alphaNumerics[FastRand()%alphaNumericsLength]
    59  	}
    60  	rndGen.PutRand(rnd)
    61  
    62  	return ByteToStr(b)
    63  }
    64  
    65  func RandomIDs(n ...int) []string {
    66  	var str = make([]string, 0, len(n))
    67  	for _, x := range n {
    68  		str = append(str, RandomID(x))
    69  	}
    70  
    71  	return str
    72  }
    73  
    74  // RandomDigit generates a pseudo-random string with length 'n' which characters are only digits (0-9)
    75  func RandomDigit(n int) string {
    76  	rnd := rndGen.GetRand()
    77  	b := make([]byte, n)
    78  	for i := 0; i < len(b); i++ {
    79  		b[i] = digits[FastRand()%digitsLength]
    80  	}
    81  	rndGen.PutRand(rnd)
    82  
    83  	return ByteToStr(b)
    84  }
    85  
    86  // RandomInt64 produces a pseudo-random 63bit number, if n == 0 there will be no limit otherwise
    87  // the output will be smaller than n
    88  func RandomInt64(n int64) (x int64) {
    89  	rnd := rndGen.GetRand()
    90  	if n == 0 {
    91  		x = rnd.Int63()
    92  	} else {
    93  		x = rnd.Int63n(n)
    94  	}
    95  	rndGen.PutRand(rnd)
    96  
    97  	return
    98  }
    99  
   100  // RandomInt32 produces a pseudo-random 31bit number, if n == 0 there will be no limit otherwise
   101  // the output will be smaller than n
   102  func RandomInt32(n int32) (x int32) {
   103  	rnd := rndGen.GetRand()
   104  	if n == 0 {
   105  		x = rnd.Int31()
   106  	} else {
   107  		x = rnd.Int31n(n)
   108  	}
   109  	rndGen.PutRand(rnd)
   110  
   111  	return
   112  }
   113  
   114  // SecureRandomInt63 produces a secure pseudo-random 63bit number
   115  func SecureRandomInt63(n int64) (x int64) {
   116  	var b [8]byte
   117  	_, _ = rand.Read(b[:])
   118  	xx := binary.BigEndian.Uint64(b[:])
   119  	if n > 0 {
   120  		x = int64(xx) % n
   121  	} else {
   122  		x = int64(xx >> 1)
   123  	}
   124  
   125  	return
   126  }
   127  
   128  func RandomInt(n int) (x int) {
   129  	rnd := rndGen.GetRand()
   130  	if n == 0 {
   131  		x = rnd.Int()
   132  	} else {
   133  		x = rnd.Intn(n)
   134  	}
   135  	rndGen.PutRand(rnd)
   136  
   137  	return
   138  }
   139  
   140  // RandomUint64 produces a pseudo-random unsigned number
   141  func RandomUint64(n uint64) (x uint64) {
   142  	rnd := rndGen.GetRand()
   143  	if n == 0 {
   144  		x = rnd.Uint64()
   145  	} else {
   146  		x = rnd.Uint64() % n
   147  	}
   148  	rndGen.PutRand(rnd)
   149  
   150  	return
   151  }
   152  
   153  // SecureRandomUint64 produces a secure pseudo-random 64bit number
   154  func SecureRandomUint64() (x uint64) {
   155  	var b [8]byte
   156  	_, _ = rand.Read(b[:])
   157  	x = binary.BigEndian.Uint64(b[:])
   158  
   159  	return
   160  }