@@ -28,6 +28,7 @@ func LoadModule() (starlark.StringDict, error) {
28
28
Name : "random" ,
29
29
Members : starlark.StringDict {
30
30
"randbytes" : starlark .NewBuiltin ("random.randbytes" , randbytes ),
31
+ "randstr" : starlark .NewBuiltin ("random.randstr" , randstr ),
31
32
"randint" : starlark .NewBuiltin ("random.randint" , randint ),
32
33
"choice" : starlark .NewBuiltin ("random.choice" , choice ),
33
34
"shuffle" : starlark .NewBuiltin ("random.shuffle" , shuffle ),
@@ -40,6 +41,13 @@ func LoadModule() (starlark.StringDict, error) {
40
41
return module , nil
41
42
}
42
43
44
+ // for convenience
45
+ var (
46
+ emptyStr string
47
+ none = starlark .None
48
+ defaultLenN = big .NewInt (10 )
49
+ )
50
+
43
51
// randbytes(n) returns a random byte string of length n.
44
52
func randbytes (thread * starlark.Thread , bn * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
45
53
// precondition checks
@@ -50,7 +58,7 @@ func randbytes(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tupl
50
58
// set default value if n is not provided correctly
51
59
nInt := n .BigInt ()
52
60
if nInt .Sign () <= 0 {
53
- nInt = big . NewInt ( 10 )
61
+ nInt = defaultLenN
54
62
}
55
63
// get random bytes
56
64
buf := make ([]byte , nInt .Int64 ())
@@ -60,6 +68,29 @@ func randbytes(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tupl
60
68
return starlark .Bytes (buf ), nil
61
69
}
62
70
71
+ // randstr(chars, n) returns a random string of given length from given characters.
72
+ func randstr (thread * starlark.Thread , bn * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
73
+ // precondition checks
74
+ var (
75
+ ab starlark.String
76
+ n starlark.Int
77
+ )
78
+ if err := starlark .UnpackArgs (bn .Name (), args , kwargs , "chars" , & ab , "n?" , & n ); err != nil {
79
+ return nil , err
80
+ }
81
+ // set default value if n is not provided correctly
82
+ nInt := n .BigInt ()
83
+ if nInt .Sign () <= 0 {
84
+ nInt = defaultLenN
85
+ }
86
+ // get random strings
87
+ s , err := getRandStr (ab .GoString (), nInt .Int64 ())
88
+ if err != nil {
89
+ return nil , err
90
+ }
91
+ return starlark .String (s ), nil
92
+ }
93
+
63
94
// randint(a, b) returns a random integer N such that a <= N <= b. Alias for randrange(a, b+1).
64
95
func randint (thread * starlark.Thread , bn * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
65
96
// precondition checks
@@ -92,16 +123,16 @@ func choice(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tuple,
92
123
// precondition checks
93
124
var seq starlark.Indexable
94
125
if err := starlark .UnpackArgs (bn .Name (), args , kwargs , "seq" , & seq ); err != nil {
95
- return starlark . None , err
126
+ return nil , err
96
127
}
97
128
l := seq .Len ()
98
129
if l == 0 {
99
- return starlark . None , errors .New (`cannot choose from an empty sequence` )
130
+ return nil , errors .New (`cannot choose from an empty sequence` )
100
131
}
101
132
// get random index
102
133
i , err := getRandomInt (l )
103
134
if err != nil {
104
- return starlark . None , err
135
+ return nil , err
105
136
}
106
137
// return element at index
107
138
return seq .Index (i ), nil
@@ -112,12 +143,12 @@ func shuffle(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tuple,
112
143
// precondition checks
113
144
var seq starlark.HasSetIndex
114
145
if err := starlark .UnpackArgs (bn .Name (), args , kwargs , "seq" , & seq ); err != nil {
115
- return starlark . None , err
146
+ return nil , err
116
147
}
117
148
// nothing to do if seq is empty or has only one element
118
149
l := seq .Len ()
119
150
if l <= 1 {
120
- return starlark . None , nil
151
+ return none , nil
121
152
}
122
153
// The shuffle algorithm is the Fisher-Yates Shuffle and its complexity is O(n).
123
154
var (
@@ -137,27 +168,27 @@ func shuffle(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tuple,
137
168
)
138
169
for i := uint64 (l - 1 ); i > 0 ; {
139
170
if _ , err := rand .Read (randBytes ); err != nil {
140
- return starlark . None , err
171
+ return nil , err
141
172
}
142
173
randBig .SetBytes (randBytes )
143
174
for num := randBig .Uint64 (); num > i && i > 0 ; i -- {
144
175
max := i + 1
145
176
j := int (num % max )
146
177
num /= max
147
178
if e := swap (int (i ), j ); e != nil {
148
- return starlark . None , e
179
+ return nil , e
149
180
}
150
181
}
151
182
}
152
183
// done
153
- return starlark . None , nil
184
+ return none , nil
154
185
}
155
186
156
187
// random() returns a random floating point number in the range 0.0 <= X < 1.0.
157
188
func random (thread * starlark.Thread , _ * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
158
189
f , err := getRandomFloat (1 << 53 )
159
190
if err != nil {
160
- return starlark . None , err
191
+ return nil , err
161
192
}
162
193
return starlark .Float (f ), nil
163
194
}
@@ -167,12 +198,12 @@ func uniform(thread *starlark.Thread, bn *starlark.Builtin, args starlark.Tuple,
167
198
// precondition checks
168
199
var a , b itn.FloatOrInt
169
200
if err := starlark .UnpackArgs (bn .Name (), args , kwargs , "a" , & a , "b" , & b ); err != nil {
170
- return starlark . None , err
201
+ return nil , err
171
202
}
172
203
// get random float
173
204
f , err := getRandomFloat (1 << 53 )
174
205
if err != nil {
175
- return starlark . None , err
206
+ return nil , err
176
207
}
177
208
// a + (b-a) * random()
178
209
diff := float64 (b - a )
@@ -192,6 +223,7 @@ func getRandomInt(max int) (int, error) {
192
223
return int (n .Int64 ()), nil
193
224
}
194
225
226
+ // getRandomFloat returns a random floating point number in the range [0.0, 1.0).
195
227
func getRandomFloat (prec int64 ) (n float64 , err error ) {
196
228
if prec <= 0 {
197
229
return 0 , errors .New (`prec must be > 0` )
@@ -203,3 +235,31 @@ func getRandomFloat(prec int64) (n float64, err error) {
203
235
}
204
236
return float64 (nBig .Int64 ()) / float64 (prec ), nil
205
237
}
238
+
239
+ // getRandStr returns a random string of given length from given characters.
240
+ func getRandStr (chars string , length int64 ) (string , error ) {
241
+ // basic checks
242
+ if length <= 0 {
243
+ return emptyStr , errors .New (`length must be > 0` )
244
+ }
245
+ if chars == emptyStr {
246
+ return emptyStr , errors .New (`chars must not be empty` )
247
+ }
248
+
249
+ // split chars into runes
250
+ runes := []rune (chars )
251
+ rc := len (runes )
252
+
253
+ // get random runes
254
+ buf := make ([]rune , length )
255
+ for i := range buf {
256
+ idx , err := getRandomInt (rc )
257
+ if err != nil {
258
+ return emptyStr , err
259
+ }
260
+ buf [i ] = runes [idx ]
261
+ }
262
+
263
+ // convert to string
264
+ return string (buf ), nil
265
+ }
0 commit comments