From 9a18f2708621896bef3c594af4f1149a2ca40f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Bystr=C3=B6m=20Ericsson?= Date: Sun, 25 Aug 2024 07:50:07 +0200 Subject: [PATCH] Randomness in Stdlib methods (#73). --- Sources/RandomIntKit/FuzzerInt.swift | 39 ++++++++++++++++++- Sources/RandomIntKit/RandomInt.swift | 16 ++++++-- Tests/RandomIntKitTests/FuzzerInt.swift | 52 +++++++++++++++++-------- Tests/RandomIntKitTests/RandomInt.swift | 28 +++++++++++++ 4 files changed, 114 insertions(+), 21 deletions(-) create mode 100644 Tests/RandomIntKitTests/RandomInt.swift diff --git a/Sources/RandomIntKit/FuzzerInt.swift b/Sources/RandomIntKit/FuzzerInt.swift index 79bca1c2..568f8cfc 100644 --- a/Sources/RandomIntKit/FuzzerInt.swift +++ b/Sources/RandomIntKit/FuzzerInt.swift @@ -23,7 +23,7 @@ import CoreKit /// /// - Important: It may use a different algorithm in the future. /// -@frozen public struct FuzzerInt: Randomness, Sendable { +@frozen public struct FuzzerInt: Equatable, Interoperable, Randomness, Sendable { //=------------------------------------------------------------------------= // MARK: State @@ -39,6 +39,14 @@ import CoreKit self.state = (seed) } + @inlinable public init(_ source: consuming Stdlib) { + self = source.base + } + + @inlinable public consuming func stdlib() -> Stdlib { + Stdlib(self) + } + //=------------------------------------------------------------------------= // MARK: Utilities //=------------------------------------------------------------------------= @@ -50,4 +58,33 @@ import CoreKit next = (next ^ (next &>> 27)) &* 0x94d049bb133111eb return (next ^ (next &>> 31)) } + + //*========================================================================* + // MARK: * Stdlib + //*========================================================================* + + @frozen public struct Stdlib: Swift.RandomNumberGenerator { + + //=--------------------------------------------------------------------= + // MARK: State + //=--------------------------------------------------------------------= + + @usableFromInline var base: FuzzerInt + + //=--------------------------------------------------------------------= + // MARK: Initializers + //=--------------------------------------------------------------------= + + @inlinable init(_ base: consuming FuzzerInt) { + self.base = base + } + + //=--------------------------------------------------------------------= + // MARK: Utilities + //=--------------------------------------------------------------------= + + @inlinable public mutating func next() -> Swift.UInt64 { + Swift.UInt64(self.base.next(as: U64.self)) + } + } } diff --git a/Sources/RandomIntKit/RandomInt.swift b/Sources/RandomIntKit/RandomInt.swift index a59eff60..c2598f89 100644 --- a/Sources/RandomIntKit/RandomInt.swift +++ b/Sources/RandomIntKit/RandomInt.swift @@ -19,20 +19,30 @@ import CoreKit /// /// It uses Swift's `SystemRandomNumberGenerator`. /// -@frozen public struct RandomInt: Randomness, Sendable { +@frozen public struct RandomInt: Interoperable, Randomness, Sendable { + public typealias Stdlib = Swift.SystemRandomNumberGenerator + //=------------------------------------------------------------------------= // MARK: State //=------------------------------------------------------------------------= - @usableFromInline var base: SystemRandomNumberGenerator + @usableFromInline var base: Stdlib //=------------------------------------------------------------------------= // MARK: Initializers //=------------------------------------------------------------------------= @inlinable public init() { - self.base = SystemRandomNumberGenerator() + self.base = Stdlib() + } + + @inlinable public init(_ source: consuming Stdlib) { + self.base = source + } + + @inlinable public consuming func stdlib() -> Stdlib { + self.base } //=------------------------------------------------------------------------= diff --git a/Tests/RandomIntKitTests/FuzzerInt.swift b/Tests/RandomIntKitTests/FuzzerInt.swift index 31a3fbf7..691b56e6 100644 --- a/Tests/RandomIntKitTests/FuzzerInt.swift +++ b/Tests/RandomIntKitTests/FuzzerInt.swift @@ -21,32 +21,50 @@ final class FuzzerIntTests: XCTestCase { // MARK: Tests //=------------------------------------------------------------------------= + func testMetadata() { + Test().yay(FuzzerInt.self as Any is any Randomness.Type) + Test().yay(FuzzerInt.Stdlib.self as Any is any Swift.RandomNumberGenerator.Type) + } + func testSeeds() { - var randomness: FuzzerInt + var randomness = FuzzerInt(seed: 0) + + func expect(_ expectation: U64, line: UInt = #line) { + var copy = randomness + var stdlibX = randomness.stdlib + var stdlibY = randomness.stdlib() + + Test(line: line).same(randomness, copy) + Test(line: line).same(randomness .next(), (expectation), "normal") + Test(line: line).same(copy.stdlib.next(), UInt64(expectation), "stdlib modify") + Test(line: line).same(((stdlibX)).next(), UInt64(expectation), "stdlib mutating read") + Test(line: line).same(((stdlibY)).next(), UInt64(expectation), "stdlib consuming get") + Test(line: line).same(randomness, copy) + } randomness = .init(seed: 0) - Test().same(randomness.next(), 16294208416658607535) - Test().same(randomness.next(), 07960286522194355700) - Test().same(randomness.next(), 00487617019471545679) - Test().same(randomness.next(), 17909611376780542444) + expect(16294208416658607535) + expect(07960286522194355700) + expect(00487617019471545679) + expect(17909611376780542444) randomness = .init(seed: 1) - Test().same(randomness.next(), 10451216379200822465) - Test().same(randomness.next(), 13757245211066428519) - Test().same(randomness.next(), 17911839290282890590) - Test().same(randomness.next(), 08196980753821780235) + expect(10451216379200822465) + expect(13757245211066428519) + expect(17911839290282890590) + expect(08196980753821780235) randomness = .init(seed: ~1) - Test().same(randomness.next(), 17519071339639777313) - Test().same(randomness.next(), 13427082724269423081) - Test().same(randomness.next(), 15047954047655532813) - Test().same(randomness.next(), 02229658653670313015) + expect(17519071339639777313) + expect(13427082724269423081) + expect(15047954047655532813) + expect(02229658653670313015) randomness = .init(seed: ~0) - Test().same(randomness.next(), 16490336266968443936) - Test().same(randomness.next(), 16834447057089888969) - Test().same(randomness.next(), 04048727598324417001) - Test().same(randomness.next(), 07862637804313477842) + expect(16490336266968443936) + expect(16834447057089888969) + expect(04048727598324417001) + expect(07862637804313477842) randomness = .init(seed: 0) var unique = Set() diff --git a/Tests/RandomIntKitTests/RandomInt.swift b/Tests/RandomIntKitTests/RandomInt.swift new file mode 100644 index 00000000..f1415a38 --- /dev/null +++ b/Tests/RandomIntKitTests/RandomInt.swift @@ -0,0 +1,28 @@ +//=----------------------------------------------------------------------------= +// This source file is part of the Ultimathnum open source project. +// +// Copyright (c) 2023 Oscar Byström Ericsson +// Licensed under Apache License, Version 2.0 +// +// See http://www.apache.org/licenses/LICENSE-2.0 for license information. +//=----------------------------------------------------------------------------= + +import CoreKit +import RandomIntKit +import TestKit + +//*============================================================================* +// MARK: * Random Int +//*============================================================================* + +final class RandomIntTests: XCTestCase { + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testMetadata() { + Test().yay(RandomInt.self as Any is any Randomness.Type) + Test().yay(RandomInt.Stdlib.self as Any is any Swift.RandomNumberGenerator.Type) + } +}