Files
c3c/lib/std/math/math.random.c3
2023-08-26 13:22:02 +02:00

138 lines
2.3 KiB
C

module std::math;
struct Random
{
RandomInterface* fns;
}
def RandomSeedFn = fn void(Random*, char[] seed);
def RandomNextBytesFn = fn void(Random*, char[] buffer);
struct RandomInterface
{
RandomSeedFn seed_fn;
RandomNextBytesFn next_bytes_fn;
}
/**
* @param [&inout] random
* @param [inout] buffer
**/
fn void Random.next_bytes(&random, char[] buffer)
{
if (!buffer.len) return;
random.fns.next_bytes_fn(random, buffer);
}
/**
* @param [&inout] self
**/
fn char Random.next_byte(&self)
{
char result @noinit;
self.next_bytes(((char*)&result)[:1]);
return result;
}
/**
* @param [&inout] self
**/
fn uint Random.next_short(&self)
{
ushort result @noinit;
self.next_bytes(((char*)&result)[:2]);
return result;
}
/**
* @param [&inout] self
**/
fn uint Random.next_int(&self)
{
uint result @noinit;
self.next_bytes(((char*)&result)[:4]);
return result;
}
/**
* @param [&inout] self
**/
fn ulong Random.next_long(&self)
{
ulong result @noinit;
self.next_bytes(((char*)&result)[:8]);
return result;
}
/**
* @param [&inout] self
**/
fn uint128 Random.next_uint128(&self)
{
uint128 result @noinit;
self.next_bytes(((char*)&result)[:16]);
return result;
}
/**
* @param [&inout] self
* @require types::is_numerical($typeof(seed))
**/
macro void Random.seed_random(&self, seed)
{
self.fns.seed_fn(self, @as_char_view(seed)) @inline;
}
/**
* @param [&inout] random
* @param [in] seed
**/
fn void Random.set_seed(&random, char[] seed)
{
random.fns.seed_fn(random, seed);
}
fn int Random.next(&random, int max)
{
return (int)(random.next_double() * max);
}
/**
* @param [&inout] self
**/
fn bool Random.next_bool(&self)
{
return self.next_byte() & 1 == 0;
}
fn float Random.next_float(&self)
{
uint val = self.next_int() & (1 << 24 - 1);
return val / (float)(1 << 24);
}
fn double Random.next_double(&self)
{
ulong val = self.next_long() & (1UL << 53 - 1);
return val * 0x1.0p-53;
}
macro @random_value_to_bytes(#function, char[] bytes)
{
var $byte_size = $sizeof(#function());
usz len = bytes.len;
// Same size or smaller? Then just copy.
while (len > 0)
{
var value = #function();
if (len <= $byte_size)
{
bytes[..] = ((char*)&value)[:len];
return;
}
bytes[:$byte_size] = ((char*)&value)[:$byte_size];
len -= $byte_size;
bytes = bytes[$byte_size..];
}
unreachable();
}