randbp

package
v0.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2020 License: BSD-3-Clause Imports: 5 Imported by: 3

Documentation

Overview

Package randbp provides some random generator related features:

1. A thread-safe, properly seeded global *math/rand.Rand implementation.

2. Helper functions for common use cases.

Index

Examples

Constants

View Source
const Base64Runes = `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+/=`

Base64Runes are all the runes allowed in standard and url safe base64 encodings.

This is a common, safe to use set of runes to be used with GenerateRandomString.

Variables

View Source
var R = New(GetSeed())

R is a global thread-safe rng.

It embeds *math/rand.Rand, but properly seeded and safe for concurrent use.

It should be used instead of the global functions inside math/rand package.

For example, instead of this:

import "math/rand"
i := rand.Uint64()

Use this:

import "github.com/reddit/baseplate.go/randbp"
i := randbp.R.Uint64()

NOTE: Its Read function has worse performance comparing to rand's global rander or rand.Rand created with non-thread-safe source for small buffers. See the doc of Rand.Read for more details. All other functions (Uint64, Float64, etc.) have comparable performance to math/rand's implementations.

Functions

func GenerateRandomString

func GenerateRandomString(args RandomStringArgs) string

GenerateRandomString generates a random string with length [MinLength, MaxLength), and all characters limited to Runes.

It could be used to help implement testing/quick.Generator interface.

Example

This example demonstrates how to use GenerateRandomString in your tests with testing/quick package.

package main

import (
	"math/rand"
	"reflect"
	"testing"
	"testing/quick"

	"github.com/reddit/baseplate.go/randbp"
)

const (
	MinLength = 1
	MaxLength = 20
)

type RandomString string

func (RandomString) Generate(r *rand.Rand, _ int) reflect.Value {
	return reflect.ValueOf(RandomString(randbp.GenerateRandomString(
		randbp.RandomStringArgs{
			R:         r,
			MinLength: MinLength,
			MaxLength: MaxLength,
		},
	)))
}

var _ quick.Generator = RandomString("")

// In real code the function name should be TestRandomString,
// but using that name here will break the example.
func RandomStringTest(t *testing.T) {
	f := func(input RandomString) bool {
		s := string(input)
		if len(s) < MinLength {
			t.Errorf(
				"Expected random string to have a minimal length of %d, got %q",
				MinLength,
				s,
			)
		}
		if len(s) >= MaxLength {
			t.Errorf(
				"Expected random string to have a maximum length of %d, got %q",
				MaxLength,
				s,
			)
		}
		return !t.Failed()
	}
	if err := quick.Check(f, nil); err != nil {
		t.Error(err)
	}
}

// This example demonstrates how to use GenerateRandomString in your tests with
// testing/quick package.
func main() {
	// Nothing really here.
	// The real example is on the other functions/types above.
}

func GetSeed

func GetSeed() int64

GetSeed returns a seed for pseudo-random generator.

It tries to use crypto/rand to read an int64, and fallback to use current time if that fails for whatever reason.

func ShouldSampleWithRate

func ShouldSampleWithRate(rate float64) bool

ShouldSampleWithRate generates a random float64 in [0, 1) and check it against rate.

rate should be in the range of [0, 1]. When rate <= 0 this function always returns false; When rate >= 1 this function always returns true.

Types

type LockedSource64

type LockedSource64 struct {
	// contains filtered or unexported fields
}

LockedSource64 is a thread-safe implementation of rand.Source64.

NOTE: When using *LockedSource64 to create rand.Rand, its Read function will have a much worse performance comparing to rand's global rander or rand.Rand created with non-thread-safe source.

func NewLockedSource64

func NewLockedSource64(src rand.Source) *LockedSource64

NewLockedSource64 creates a *LockedSource64 from the given src.

func (*LockedSource64) Int63

func (ls *LockedSource64) Int63() (n int64)

Int63 implements rand.Source64.

It calls underlying source's Int63 with lock.

func (*LockedSource64) Seed

func (ls *LockedSource64) Seed(seed int64)

Seed implements rand.Source64.

It calls underlying source's Seed with lock.

func (*LockedSource64) Uint64

func (ls *LockedSource64) Uint64() (n uint64)

Uint64 implements rand.Source64.

If the underlying source implements rand.Source64, it calls its Uint64 with lock. Otherwise, it calls its Int64 twice with lock.

type Rand

type Rand struct {
	*rand.Rand
}

Rand embeds *math/rand.Rand.

All functions besides Read are directly calling the embedded rand.Rand. When initialized with New(), all functions are safe for concurrent use, and have comparable performance to the top level math/rand functions.

See the doc of Read function for more details on that one.

func New

func New(seed int64) Rand

New initializes a thread-safe, properly seeded Rand.

func (Rand) Read

func (r Rand) Read(p []byte) (int, error)

Read overrides math/rand's Read implementation with thread-safety.

It's safe for concurrent use and always returns len(p) with nil error.

Compare to math/rand.Read (the top level one) performance-wise, it has a constant ~1us overhead, which is significant when len(p) is small, but less significant when len(p) grows larger, and starts to outperform math/rand.Read when len(p) is very large because it only need to lock once. See the following sample benchmark result:

$ go test -bench Rand/Read -benchmem
goos: darwin
goarch: amd64
pkg: github.com/reddit/baseplate.go/randbp
BenchmarkRand/Read/size-16/math/rand-8         	 8213564	       138 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-16/crypto/rand-8       	 9739500	       123 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-16/randbp-8            	  979442	      1329 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-64/math/rand-8         	 5289319	       227 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-64/crypto/rand-8       	 6050103	       197 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-64/randbp-8            	  911760	      1301 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-256/math/rand-8        	 4223463	       274 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-256/crypto/rand-8      	 2263252	       534 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-256/randbp-8           	  940459	      1333 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-512/math/rand-8        	 2455426	       481 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-512/crypto/rand-8      	 1000000	      1008 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-512/randbp-8           	  885555	      1445 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-1024/math/rand-8       	 1275535	       925 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-1024/crypto/rand-8     	  636202	      1980 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-1024/randbp-8          	  800511	      1630 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-4096/math/rand-8       	  310982	      3765 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-4096/crypto/rand-8     	  159490	      7538 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-4096/randbp-8          	  511124	      2319 ns/op	       0 B/op	       0 allocs/op
BenchmarkRand/Read/size-1048576/math/rand-8    	    1341	    860809 ns/op	    6255 B/op	       0 allocs/op
BenchmarkRand/Read/size-1048576/crypto/rand-8  	     838	   1349225 ns/op	   10016 B/op	       0 allocs/op
BenchmarkRand/Read/size-1048576/randbp-8       	    5330	    238657 ns/op	    1582 B/op	       0 allocs/op
PASS
ok  	github.com/reddit/baseplate.go/randbp	29.982s

Regardless performance, it's never suitable for security purpose, and you should always use crypto/rand for that instead.

type RandomStringArgs added in v0.7.0

type RandomStringArgs struct {
	// Required. If MaxLength <= MinLength it will cause panic.
	MaxLength int

	// Optional. Default is 0, which means it could generate empty strings.
	// If MinLength < 0 or MinLength >= MaxLength it will cause panic.
	MinLength int

	// Optional. If nil randbp.R will be used instead.
	R *rand.Rand

	// Optional. If empty []rune(randbp.Base64Runes) will be used instead.
	Runes []rune
}

RandomStringArgs defines the args used by GenerateRandomString.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL