@@ -79,6 +79,13 @@ M.le = function(a, b, rel_tol, abs_tol)
7979 return M .lt (a , b , rel_tol , abs_tol ) or M .eq (a , b , rel_tol , abs_tol )
8080end
8181
82+ --- @param a integer
83+ --- @param b integer
84+ --- @return integer
85+ M .mod = function (a , b )
86+ return math.floor (math.fmod (a , b ))
87+ end
88+
8289--- @param value number
8390--- @param left number ? lower bound , by default INT32_MIN
8491--- @param right number ? upper bound , by default INT32_MAX
@@ -132,4 +139,34 @@ M.max = function(f, a, ...)
132139 return maximal_item , maximal_index
133140end
134141
142+ -- Drop-in 32-bit random replacement of `math.random`.
143+ --- @param m integer ?
144+ --- @param n integer ?
145+ --- @return number
146+ M .random = function (m , n )
147+ local uv = vim .uv or vim .loop
148+ local rand_result , rand_err = uv .random (4 )
149+ assert (rand_result ~= nil , rand_err )
150+
151+ local bytes = {
152+ string.byte (rand_result --[[ @as string]] , 1 , - 1 ),
153+ }
154+ local total = 0
155+ for _ , b in ipairs (bytes ) do
156+ total = M .mod (total * 256 + b , M .INT32_MAX )
157+ end
158+ if m == nil and n == nil then
159+ return total / M .INT32_MAX
160+ elseif m ~= nil and n == nil then
161+ assert (type (m ) == " number" )
162+ assert (m >= 1 )
163+ return M .mod (total , m ) + 1
164+ else
165+ assert (type (m ) == " number" )
166+ assert (type (n ) == " number" )
167+ assert (n >= m )
168+ return M .mod (total , n - m + 1 ) + m
169+ end
170+ end
171+
135172return M
0 commit comments