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 }