|
6 | 6 |
|
7 | 7 | #include <algorithm> |
8 | 8 | #include <array> |
| 9 | +#include <bit> |
9 | 10 | #include <chrono> |
10 | 11 | #include <cstddef> |
11 | 12 | #include <cstdint> |
|
25 | 26 | #include "runtime-common/stdlib/math/random-functions.h" |
26 | 27 | #include "runtime-light/coroutine/task.h" |
27 | 28 | #include "runtime-light/k2-platform/k2-api.h" |
| 29 | +#include "runtime-light/stdlib/diagnostics/logs.h" |
28 | 30 | #include "runtime-light/stdlib/math/random-state.h" |
29 | 31 | #include "runtime-light/stdlib/system/system-functions.h" |
30 | 32 |
|
@@ -157,6 +159,48 @@ inline Optional<string> f$random_bytes(int64_t length) noexcept { |
157 | 159 | return str; |
158 | 160 | } |
159 | 161 |
|
| 162 | +inline Optional<int64_t> f$random_int(int64_t min, int64_t max) noexcept { |
| 163 | + if (min > max) [[unlikely]] { |
| 164 | + kphp::log::warning("argument #1 ($min) must be less than or equal to argument #2 ($max)"); |
| 165 | + return false; |
| 166 | + } |
| 167 | + |
| 168 | + if (min == max) { |
| 169 | + return min; |
| 170 | + } |
| 171 | + |
| 172 | + auto umax{static_cast<uint64_t>(max) - static_cast<uint64_t>(min)}; |
| 173 | + |
| 174 | + uint64_t trial{}; |
| 175 | + if (random_impl_::secure_rand_buf(std::addressof(trial), sizeof(trial)) == -1) [[unlikely]] { |
| 176 | + kphp::log::warning("source of randomness cannot be found"); |
| 177 | + return false; |
| 178 | + } |
| 179 | + |
| 180 | + // special case where no modulus is required |
| 181 | + if (umax == std::numeric_limits<uint64_t>::max()) { |
| 182 | + return static_cast<int64_t>(trial); |
| 183 | + } |
| 184 | + |
| 185 | + ++umax; // increment the max so the range is inclusive of max |
| 186 | + |
| 187 | + // powers of two are not biased |
| 188 | + if (!std::has_single_bit(umax)) { |
| 189 | + // ceiling under which UINT64_MAX % max == 0 |
| 190 | + const auto limit{std::numeric_limits<uint64_t>::max() - (std::numeric_limits<uint64_t>::max() % umax) - 1}; |
| 191 | + |
| 192 | + // discard numbers over the limit to avoid modulo bias |
| 193 | + while (trial > limit) { |
| 194 | + if (random_impl_::secure_rand_buf(std::addressof(trial), sizeof(trial)) == -1) [[unlikely]] { |
| 195 | + kphp::log::warning("source of randomness cannot be found"); |
| 196 | + return false; |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + return min + static_cast<int64_t>(trial % umax); |
| 202 | +} |
| 203 | + |
160 | 204 | inline kphp::coro::task<string> f$uniqid(string prefix = string{}, bool more_entropy = false) noexcept { |
161 | 205 | if (!more_entropy) { |
162 | 206 | co_await f$usleep(1); |
|
0 commit comments