mediocre-go-lib/mrand/mrand.go

106 lines
2.7 KiB
Go
Raw Permalink Normal View History

// Package mrand implements extensions and conveniences for using the default
// math/rand package.
package mrand
import (
"encoding/hex"
"math/rand"
"reflect"
"time"
)
// Rand extends the default rand.Rand type with extra functionality.
type Rand struct {
*rand.Rand
}
// NewSyncRand initializes and returns a new Rand instance using the given
// Source. The returned Rand will be safe for concurrent use.
//
// This will panic if the given Source doesn't implement rand.Source64.
func NewSyncRand(src rand.Source) Rand {
return Rand{
Rand: rand.New(&lockedSource{src: src.(rand.Source64)}),
}
}
// Bytes returns n random bytes.
func (r Rand) Bytes(n int) []byte {
b := make([]byte, n)
if _, err := r.Read(b); err != nil {
panic(err)
}
return b
}
// Hex returns a random hex string which is n characters long.
func (r Rand) Hex(n int) string {
origN := n
if n%2 == 1 {
n++
}
b := r.Bytes(hex.DecodedLen(n))
return hex.EncodeToString(b)[:origN]
}
// Element returns a random element from the given slice.
//
// If a weighting function is given then that function is used to weight each
// element of the slice relative to the others, based on whatever metric and
// scale is desired. The weight function must be able to be called more than
// once on each element.
func (r Rand) Element(slice interface{}, weight func(i int) uint64) interface{} {
v := reflect.ValueOf(slice)
l := v.Len()
if weight == nil {
return v.Index(r.Intn(l)).Interface()
}
var totalWeight uint64
for i := 0; i < l; i++ {
totalWeight += weight(i)
}
target := r.Int63n(int64(totalWeight))
for i := 0; i < l; i++ {
w := int64(weight(i))
target -= w
if target < 0 {
return v.Index(i).Interface()
}
}
panic("should never get here, perhaps the weighting function is inconsistent?")
}
////////////////////////////////////////////////////////////////////////////////
// DefaultRand is an instance off Rand whose methods are directly exported by
// this package for convenience.
var DefaultRand = NewSyncRand(rand.NewSource(time.Now().UnixNano()))
// Methods off DefaultRand exported to the top level of this package.
var (
ExpFloat64 = DefaultRand.ExpFloat64
Float32 = DefaultRand.Float32
Float64 = DefaultRand.Float64
Int = DefaultRand.Int
Int31 = DefaultRand.Int31
Int31n = DefaultRand.Int31n
Int63 = DefaultRand.Int63
Int63n = DefaultRand.Int63n
Intn = DefaultRand.Intn
NormFloat64 = DefaultRand.NormFloat64
Perm = DefaultRand.Perm
Read = DefaultRand.Read
Seed = DefaultRand.Seed
Shuffle = DefaultRand.Shuffle
Uint32 = DefaultRand.Uint32
Uint64 = DefaultRand.Uint64
// extended methods
Bytes = DefaultRand.Bytes
Hex = DefaultRand.Hex
Element = DefaultRand.Element
)