Files
bluelib/core/random.c

104 lines
2.1 KiB
C
Raw Normal View History

2024-10-24 21:33:05 +01:00
#include "random.h"
#include <blue/core/random.h>
#define GET_ALGORITHM_ID(flags) ((flags) & 0xFF)
2024-11-14 16:56:12 +00:00
BLUE_API struct b_random_algorithm z__b_gen_mt19937;
2024-10-24 21:33:05 +01:00
static struct b_random_algorithm *generators[] = {
[B_RANDOM_MT19937] = &z__b_gen_mt19937,
};
static size_t nr_generators = sizeof generators / sizeof generators[0];
static struct b_random_ctx g_global_ctx = {0};
static void init_global_ctx(void)
{
b_random_init(&g_global_ctx, B_RANDOM_MT19937);
}
struct b_random_ctx *b_random_global_ctx(void)
{
if (!g_global_ctx.__f) {
init_global_ctx();
}
return &g_global_ctx;
}
b_status b_random_init(struct b_random_ctx *ctx, b_random_flags flags)
{
unsigned int algorithm_id = GET_ALGORITHM_ID(flags);
if (algorithm_id >= nr_generators || !generators[algorithm_id]) {
return B_ERR_INVALID_ARGUMENT;
}
struct b_random_algorithm *algorithm = generators[algorithm_id];
ctx->__f = flags;
ctx->__a = algorithm;
unsigned long long seed;
if (flags & B_RANDOM_SECURE) {
seed = z__b_platform_random_seed_secure();
} else {
seed = z__b_platform_random_seed();
}
algorithm->gen_init(ctx, seed);
return B_SUCCESS;
}
unsigned long long b_random_next_int64(struct b_random_ctx *ctx)
{
if (!ctx->__a || !ctx->__a->gen_getrand) {
return 0;
}
return ctx->__a->gen_getrand(ctx);
}
double b_random_next_double(struct b_random_ctx *ctx)
{
unsigned long long v = b_random_next_int64(ctx);
if (!v) {
return 0.0;
}
return (double)(v >> 11) * (1.0 / 9007199254740991.0);
}
void b_random_next_bytes(struct b_random_ctx *ctx, unsigned char *out, size_t nbytes)
{
size_t n_qwords = 0;
n_qwords = nbytes >> 3;
if ((n_qwords << 3) < nbytes) {
n_qwords++;
}
size_t bytes_written = 0;
for (size_t i = 0; i < n_qwords; i++) {
uint64_t *dest = (uint64_t *)&out[bytes_written];
*dest = b_random_next_int64(ctx);
bytes_written += 8;
}
if (bytes_written == nbytes) {
return;
}
uint64_t padding = b_random_next_int64(ctx);
unsigned char *padding_bytes = (unsigned char *)&padding;
for (size_t i = 0; i < 8; i++) {
out[bytes_written++] = padding_bytes[i];
if (bytes_written == nbytes) {
break;
}
}
}