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  }