use arc4random to seed non-csprng, fleshes out random subsystem

This commit is contained in:
2024-08-22 03:37:29 +10:00
parent 394e340f09
commit cb2ffe78a4
6 changed files with 83 additions and 15 deletions

View File

@ -17,8 +17,12 @@ public class Arc4Random: RandomProvider {
arc4random()
}
public func next(in bound: Range<Int>) -> Int {
assert(bound.upperBound <= Self.max)
return bound.lowerBound + Int(arc4random_uniform(UInt32(bound.upperBound)))
public func next(in bound: Int) -> Int {
assert(bound <= Self.max)
return Int(arc4random_uniform(UInt32(bound)))
}
public func next(in range: Range<Int>) -> Int {
return range.lowerBound + next(in: range.upperBound - range.lowerBound)
}
}

View File

@ -0,0 +1,33 @@
public struct DarwinRandom: RandomProvider {
public typealias Output = Int
public static var min: Int { 0x00000000 }
public static var max: Int { 0x7FFFFFFF }
private var state: Int
init() {
self.state = 0
}
public init(seed: Int) {
self.state = seed
}
mutating public func seed(with seed: Int) {
self.state = seed
}
mutating public func next() -> Int {
if self.state == 0 {
self.state = 123459876
}
let hi = self.state / 127773
let lo = self.state - hi * 127773
self.state = 16807 * lo - 2836 * hi
if self.state < 0 {
self.state += Self.max
}
return self.state % (Self.max + 1)
}
}

View File

@ -0,0 +1,20 @@
public extension RandomProvider where Output: BinaryInteger {
mutating func next(in range: Range<Int>) -> Int {
range.lowerBound + self.next(in: range.upperBound - range.lowerBound)
}
mutating func next(in range: ClosedRange<Int>) -> Int {
range.lowerBound + self.next(in: range.upperBound - range.lowerBound + 1)
}
mutating func next(in bound: Int) -> Int {
assert(Self.min == 0)
assert(Self.max >= bound)
let threshold = Int(Self.max % Output(bound))
var result: Int
repeat {
result = Int(truncatingIfNeeded: self.next())
} while result < threshold
return result % bound
}
}