github.com/haraldrudell/parl@v0.4.176/prand/fastrand.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 // Package prand provides a fast and thread-safe random number generation. 7 // - prand.Uint32: 2 ns ±0.5 8 // - math/rand.Uint32: 14 ns ±0.5 9 // - /crypto/rand.Read: 330 ns ±0.5 10 // - same methods as math/rand package 11 // - based on runtime.fastrand 12 package prand 13 14 import ( 15 "encoding/binary" 16 "unsafe" 17 ) 18 19 const ( 20 bitsPerByte = 8 21 sizeOfUint32 = int(unsafe.Sizeof(uint32(1))) 22 ) 23 24 // Uint32 returns a 32-bit unsigned random number using runtime.fastrand. Thread-safe 25 func Uint32() (random uint32) { 26 return fastrand() 27 } 28 29 // Uint32n returns a 32-bit unsigned random number using runtime.fastrand. Thread-safe 30 func Uint32n(n uint32) (random uint32) { 31 return fastrandn(n) 32 } 33 34 // Uint64 returns a 64-bit unsigned random number using runtime.fastrand. Thread-safe 35 func Uint64() (random uint64) { 36 return uint64(fastrand())<<32 | uint64(fastrand()) 37 } 38 39 // Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). 40 // It panics if n <= 0. 41 func Int31n(n int32) (i32 int32) { 42 if n <= 0 { 43 panic("invalid argument to Int31n") 44 } 45 i32 = int32(fastrandn(uint32(n))) 46 return 47 } 48 49 // Read reads n random bytes into p. Thread-Safe. 50 // - n always len(p), err always nil 51 func Read(p []byte) (n int, err error) { 52 n = len(p) 53 54 // randomize using 32-bit integers 55 index := 0 56 lengthMod4 := n &^ (sizeOfUint32 - 1) 57 for index < lengthMod4 { 58 binary.LittleEndian.PutUint32(p[index:], Uint32()) 59 index += sizeOfUint32 60 } 61 if index == n { 62 return 63 } 64 65 // odd bytes at end 66 v := Uint32() 67 for index < n { 68 p[index] = byte(v) 69 index++ 70 v >>= bitsPerByte 71 } 72 73 return 74 } 75 76 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64. 77 func Int63() (random int64) { return int64(Uint64() >> 1) } 78 79 // Int31 returns a non-negative pseudo-random 31-bit integer as an int32. 80 func Int31() int32 { return int32(Uint32() >> 1) }