///|
/// PRNG-only checkpoint, not a cryptographic seed or a uniqueness-state snapshot.
pub fn Generator::snapshot(self : Generator) -> UInt {
self.state
}
///|
pub fn Generator::restore(
self : Generator,
state : UInt,
) -> Unit raise FakeError {
if state == 0U {
raise Invalid("xorshift state must be nonzero")
}
self.state = state
}
///|
pub fn[T] Generator::choose(
self : Generator,
items : Array[T],
) -> T raise FakeError {
if items.is_empty() || items.length() > 100000 {
raise Invalid("choice length 1..100000 required")
}
items[self.integer(0, items.length() - 1)]
}
///|
/// Sample distinct input positions without changing the source array.
pub fn[T] Generator::sample(
self : Generator,
items : Array[T],
count : Int,
) -> Array[T] raise FakeError {
if items.length() > 100000 || count < 0 || count > items.length() {
raise Invalid("sample size")
}
let copy = items.copy()
for i in 0.. Int raise FakeError {
if weights.is_empty() || weights.length() > 100000 {
raise Invalid("weight count")
}
let mut total = 0
for weight in weights {
if weight < 0 || weight > 1000000000 - total {
raise Invalid("weight total 1..1000000000 required")
}
total += weight
}
if total == 0 {
raise Invalid("at least one positive weight required")
}
total
}
///|
pub fn Generator::weighted_index(
self : Generator,
weights : Array[Int],
) -> Int raise FakeError {
let mut value = self.integer(0, weight_total(weights) - 1)
for i, weight in weights {
if value < weight {
return i
}
value -= weight
}
abort("unreachable weighted choice")
}
///|
pub fn Generator::boolean(
self : Generator,
percent? : Int = 50,
) -> Bool raise FakeError {
if percent < 0 || percent > 100 {
raise Invalid("percentage 0..100 required")
}
self.integer(1, 100) <= percent
}
///|
pub fn Generator::decimal(
self : Generator,
min_scaled : Int,
max_scaled : Int,
places : Int,
) -> String raise FakeError {
if places < 0 || places > 6 {
raise Invalid("decimal places 0..6 required")
}
let number = self.integer(min_scaled, max_scaled)
let magnitude = if number < 0 { -number } else { number }
let mut scale = 1
for _ in 0.. String raise FakeError {
if template.length() > 4096 {
raise Invalid("template length")
}
let cs = template.to_array()
let alphabet = "abcdefghijklmnopqrstuvwxyz".to_array()
let mut result = ""
let mut escaped = false
for c in cs {
if escaped {
result += c.to_string()
escaped = false
} else if c == '\\' {
escaped = true
} else if c == '#' {
result += self.integer(0, 9).to_string()
} else if c == '?' {
result += alphabet[self.integer(0, 25)].to_string()
} else {
result += c.to_string()
}
}
if escaped {
raise Invalid("trailing template escape")
}
result
}