package core.random
-#local seed : i64 = 8675309
+//
+// The state of a random number generator.
+Random :: struct {
+ seed: i64;
+}
-#local RANDOM_MULTIPLIER :: 25214903917
-#local RANDOM_INCREMENT :: cast(i64) 11
-// #local RANDOM_MODULUS :: 1 << 32
+#inject Random {
+ //
+ // Creates a new random number generator.
+ // An initial seed can be passed in, otherwise the
+ // current UNIX time is used.
+ make :: (seed: i64 = core.os.time()) -> Random {
+ return .{ seed };
+ }
-set_seed :: #match {
- (s: u32) do seed = ~~s; ,
- (s: u64) do seed = s; ,
-}
+ //
+ // Sets the seed of the random number generator
+ set_seed :: #match {
+ (self: ^Random, s: u32) { self.seed = ~~s; },
+ (self: ^Random, s: u64) { self.seed = s; },
+ }
-int :: (s := ^seed) -> u32 {
- *s = *s * RANDOM_MULTIPLIER + RANDOM_INCREMENT;
- return cast(u32) ((*s >> 16) & ~~0xffffffff);
-}
+ //
+ // Generates a random 32-bit integer.
+ int :: (self: ^Random) -> u32 {
+ s := self.seed * RANDOM_MULTIPLIER + RANDOM_INCREMENT;
+ defer self.seed = s;
+ return cast(u32) ((s >> 16) & ~~0xffffffff);
+ }
-between :: (lo: i32, hi: i32) -> i32 do return int () % (hi + 1 - lo) + lo;
+ //
+ // Generates a random 32-bit integer between `lo` and `hi`.
+ between :: (self: ^Random, lo: i32, hi: i32) -> i32 {
+ return self->int() % (hi + 1 - lo) + lo;
+ }
-float :: (lo := 0.0f, hi := 1.0f) -> f32 {
- return (cast(f32) (int() % (1 << 20)) / cast(f32) (1 << 20)) * (hi - lo) + lo;
-}
+ //
+ // Generates a random floating point number between `lo` and `hi`.
+ float :: (self: ^Random, lo := 0.0f, hi := 1.0f) -> f32 {
+ return (cast(f32) (self->int() % (1 << 20)) / cast(f32) (1 << 20)) * (hi - lo) + lo;
+ }
-choice :: (a: [] $T) -> T {
- return a[between(0, a.count - 1)];
-}
+ //
+ // Returns a random element from a slice.
+ choice :: (self: ^Random, a: [] $T) -> T {
+ return a[self->between(0, a.count - 1)];
+ }
-string :: (bytes_long: u32, alpha_numeric := false, allocator := context.allocator) -> str {
- memory :: package core.memory
+ //
+ // Returns a random string of length `bytes_long`. If `alpha_numeric` is
+ // true, then the string will only consist of alpha-numeric characters.
+ string :: (self: ^Random, bytes_long: u32, alpha_numeric := false, allocator := context.allocator) -> str {
+ memory :: package core.memory
- s := memory.make_slice(u8, bytes_long, allocator=allocator);
- for^ s {
- if alpha_numeric {
- #persist alpha_numeral := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- *it = choice(alpha_numeral);
- } else {
- *it = ~~between(32, 127);
+ s := memory.make_slice(u8, bytes_long, allocator=allocator);
+ for^ s {
+ if alpha_numeric {
+ #persist alpha_numeral := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ *it = self->choice(alpha_numeral);
+ } else {
+ *it = ~~(self->between(32, 127));
+ }
}
+ return s;
}
- return s;
}
+
+//
+// Below are procedures that use a global random number
+// generator for quick random number generation.
+//
+
+
+//
+// The global random state.
+global_random := Random.{ 8675309 };
+
+set_seed :: #match {
+ (s: u32) { global_random->set_seed(~~s); },
+ (s: u64) { global_random->set_seed(s); },
+}
+
+int :: () =>
+ global_random->int();
+
+between :: (lo: i32, hi: i32) =>
+ global_random->between(lo, hi);
+
+float :: (lo := 0.0f, hi := 1.0f) =>
+ global_random->float(lo, hi);
+
+choice :: (a: [] $T) =>
+ global_random->choice(a);
+
+string :: (bytes_long: u32, alpha_numeric := false, allocator := context.allocator) =>
+ global_random->string(bytes_long, alpha_numeric, allocator);
+
+
+
+//
+// Internal implementation details
+//
+
+#package {
+ RANDOM_MULTIPLIER :: 25214903917
+ RANDOM_INCREMENT :: cast(i64) 11
+}
+