github.com/wuhuizuo/gomplate@v3.5.0+incompatible/random/random.go (about)

     1  // Package random contains functions for generating random values
     2  package random
     3  
     4  import (
     5  	"math"
     6  	"math/rand"
     7  	"regexp"
     8  	"time"
     9  	"unicode"
    10  
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // Rnd -
    15  var Rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
    16  
    17  // Default set, matches "[a-zA-Z0-9_.-]"
    18  const defaultSet = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
    19  
    20  // StringRE - Generate a random string that matches a given regular
    21  // expression. Defaults to "[a-zA-Z0-9_.-]"
    22  func StringRE(count int, match string) (r string, err error) {
    23  	var chars = []rune(defaultSet)
    24  	if match != "" {
    25  		chars, err = matchChars(match)
    26  		if err != nil {
    27  			return "", err
    28  		}
    29  	}
    30  
    31  	return rndString(count, chars)
    32  }
    33  
    34  // StringBounds returns a random string of characters with a codepoint
    35  // between the lower and upper bounds. Only valid characters are returned
    36  // and if a range is given where no valid characters can be found, an error
    37  // will be returned.
    38  func StringBounds(count int, lower, upper rune) (r string, err error) {
    39  	chars := filterRange(lower, upper)
    40  	if len(chars) == 0 {
    41  		return "", errors.Errorf("No printable codepoints found between U%#q and U%#q.", lower, upper)
    42  	}
    43  	return rndString(count, chars)
    44  }
    45  
    46  // produce a string containing a random selection of given characters
    47  func rndString(count int, chars []rune) (string, error) {
    48  	s := make([]rune, count)
    49  	for i := range s {
    50  		s[i] = chars[Rnd.Intn(len(chars))]
    51  	}
    52  	return string(s), nil
    53  }
    54  
    55  func filterRange(lower, upper rune) []rune {
    56  	out := []rune{}
    57  	for r := lower; r <= upper; r++ {
    58  		if unicode.IsGraphic(r) {
    59  			out = append(out, r)
    60  		}
    61  	}
    62  	return out
    63  }
    64  
    65  func matchChars(match string) ([]rune, error) {
    66  	r, err := regexp.Compile(match)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	candidates := filterRange(0, unicode.MaxRune)
    71  	out := []rune{}
    72  	for _, c := range candidates {
    73  		if r.MatchString(string(c)) {
    74  			out = append(out, c)
    75  		}
    76  	}
    77  	return out, nil
    78  }
    79  
    80  // Item -
    81  func Item(items []interface{}) (interface{}, error) {
    82  	if len(items) == 0 {
    83  		return nil, errors.Errorf("expected a non-empty array or slice")
    84  	}
    85  	if len(items) == 1 {
    86  		return items[0], nil
    87  	}
    88  	n := Rnd.Intn(len(items))
    89  	return items[n], nil
    90  }
    91  
    92  // Number -
    93  func Number(min, max int64) (int64, error) {
    94  	if min > max {
    95  		return 0, errors.Errorf("min must not be greater than max (was %d, %d)", min, max)
    96  	}
    97  	if min == math.MinInt64 {
    98  		min++
    99  	}
   100  	if max-min >= (math.MaxInt64 >> 1) {
   101  		return 0, errors.Errorf("spread between min and max too high - must not be greater than 63-bit maximum (%d - %d = %d)", max, min, max-min)
   102  	}
   103  	return Rnd.Int63n(max-min+1) + min, nil
   104  }
   105  
   106  // Float - For now this is really just a wrapper around `rand.Float64`
   107  func Float(min, max float64) (float64, error) {
   108  	return min + Rnd.Float64()*(max-min), nil
   109  }