github.com/xaionaro-go/rand@v0.0.0-20191005105903-aba1befc54a5/internal/autogen/get_templates.go (about) 1 package main 2 3 import ( 4 "strings" 5 "text/template" 6 ) 7 8 var ( 9 templateRead = ` 10 {{- if .IsXORRead }} 11 // XORRead{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }} XORs argument "b" with a pseudo-random value. 12 // The result is the same (but faster) as: 13 // 14 // x := make([]byte, len(b)) 15 // mathrand.Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}(x) 16 // for i := range b { 17 // b[i] ^= x[i] 18 // } 19 {{- else }} 20 // Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }} is an analog of math/rand.Read. This random 21 // numbers could easily be predicted (it's not an analog of crypto/rand.Read). 22 {{- if .EnableReseed }} 23 // 24 // "Reseed" forces to use a new seed (generated using XORShift method) on setting value to 25 // a pointer `+"`& 0xff < {{ .ResultSize }}`"+`. Sometimes it allows to improve randomness of random numbers with a 26 // small performance impact. 27 // This method makes sense only if len(b) is large enough (>= 256 bytes). 28 // Otherwise it could affect strongly performance or it will not improve the randomness. 29 {{- end }} 30 // 31 // Applied PRNG method: 32 // {{ .AdditionalInfo }} 33 {{- end }} 34 func (prng *PRNG) {{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}(b []byte) (l int, err error) { 35 l = len(b) 36 s := (uintptr)((unsafe.Pointer)(&b[0])) 37 p := s 38 e := s + uintptr(l) 39 { 40 `+ // uint32 PRNG: 41 // 42 // len(b) == 12: ....p...f...e last p -> f 43 // ^ ^ ^ ^ 44 // 45 // len(b) == 11: ....p..f...e last p -> f-3 46 // ^ ^ ^ 47 // 48 // len(b) == 10: ....p.f...e last p -> f-2 49 // ^ ^ ^ 50 // 51 // len(b) == 9: ....pf...e last p -> f-1 52 // ^ ^ ^ 53 ` {{ .InitCode }} 54 for f := e - {{ .ResultSize }}; p <= f; p += {{ .ResultSize }} { 55 {{ .GetValueCode }} 56 *(*uint{{ umul .ResultSize 8 }})((unsafe.Pointer)(p)) {{ if .IsXORRead }}^{{ end }}= {{ .ResultVariable }} 57 {{- if .EnableReseed }} 58 if p & 0xff < {{ .ResultSize }} { 59 continue 60 } 61 {{- if eq .MethodName "Uint32PCG" }} 62 pcgStateTemp = xorShift64(pcgStateTemp ^ primeNumber64bit0) << 1 + 1 63 {{- else }} 64 {{- if eq .ResultSize 8 }} 65 state64Temp0 = xorShift64(state64Temp0 ^ primeNumber64bit0) 66 {{- else }} 67 state{{ umul .ResultSize 8 }}Temp0 = (uint{{ umul .ResultSize 8 }})(xorShift32(state{{ umul .ResultSize 8 }}Temp0 ^ primeNumber{{ umul .ResultSize 8 }}bit0)) 68 {{- end }} 69 {{- end }} 70 {{- end }} 71 } 72 {{ .FinishCode }} 73 } 74 75 if e - p == 0 { 76 return 77 } 78 rest := prng.{{ .MethodName }}() 79 80 {{- if eq .ResultSize 8 }} 81 if e - p >= 4 { 82 *(*uint32)((unsafe.Pointer)(p)) {{ if .IsXORRead }}^{{ end }}= uint32(rest) 83 rest >>= 32 84 p += 4 85 } 86 {{- end }} 87 if e - p >= 2 { 88 *(*uint16)((unsafe.Pointer)(p)) {{ if .IsXORRead }}^{{ end }}= uint16(rest) 89 rest >>= 16 90 p += 2 91 } 92 if e - p >= 1 { 93 *(*uint8)((unsafe.Pointer)(p)) {{ if .IsXORRead }}^{{ end }}= uint8(rest) 94 } 95 return 96 } 97 ` 98 templateTestRead = ` 99 func Test{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}(t *testing.T) { 100 //testRead(t, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}) 101 prng := mathrand.NewWithSeed(initialSeed) 102 prepareSample( 103 "{{ if .IsXORRead }}XOR{{ end }}{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}", 104 prng.Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 105 {{ .EnableReseed }}, 106 ) 107 {{- if .EnableReseed }} 108 a := make([]byte, 65536) 109 b := make([]byte, 65536) 110 mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}(a) 111 mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}(b) 112 assert.NotEqual(t, a, b) 113 {{- end }} 114 } 115 func Benchmark{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}1(b *testing.B) { 116 benchmarkRead(b, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 1) 117 } 118 func Benchmark{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}16(b *testing.B) { 119 benchmarkRead(b, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 16) 120 } 121 func Benchmark{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}1024(b *testing.B) { 122 benchmarkRead(b, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 1024) 123 } 124 func Benchmark{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}65536(b *testing.B) { 125 benchmarkRead(b, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 65536) 126 } 127 func Benchmark{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}65536Concurrent(b *testing.B) { 128 benchmarkConcurrentRead(b, mathrand.GlobalPRNG.{{ if .IsXORRead }}XOR{{ end }}Read{{ .MethodName }}{{- if .EnableReseed }}WithReseed{{- end }}, 65536) 129 } 130 ` 131 templateTestMethod = ` 132 func Test{{ .MethodName }}(t *testing.T) { 133 {{- if eq .ResultSize 8 }} 134 //testUint64(t, mathrand.GlobalPRNG.{{ .MethodName }}) 135 {{- else }} 136 //testUint32(t, mathrand.GlobalPRNG.{{ .MethodName }}) 137 {{- end }} 138 } 139 func Benchmark{{ .MethodName }}(b *testing.B) { 140 prng := mathrand.New() 141 b.SetBytes({{ .ResultSize }}) 142 b.ResetTimer() 143 for i := 0; i < b.N; i++ { 144 prng.{{ .MethodName }}() 145 } 146 } 147 ` 148 ) 149 150 type Templates struct { 151 TestMethod *template.Template 152 Read *template.Template 153 TestRead *template.Template 154 } 155 156 func GetTemplates() (result *Templates, err error) { 157 result = &Templates{} 158 159 funcs := map[string]interface{}{ 160 "stringsJoin": func(slice []string, sep string) string { 161 return strings.Join(slice, sep) 162 }, 163 "umul": func(a, b uint) uint { 164 return a * b 165 }, 166 } 167 168 result.TestMethod, err = template.New(`TestMethod`). 169 Funcs(funcs).Parse(templateTestMethod) 170 if err != nil { 171 return 172 } 173 174 result.Read, err = template.New(`Read`). 175 Funcs(funcs).Parse(templateRead) 176 if err != nil { 177 return 178 } 179 180 result.TestRead, err = template.New(`TestRead`). 181 Funcs(funcs).Parse(templateTestRead) 182 if err != nil { 183 return 184 } 185 186 return 187 }