1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
//===--- Random.swift -----------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftShims
/// A type that provides uniformly distributed random data.
///
/// When you call methods that use random data, such as creating new random
/// values or shuffling a collection, you can pass a `RandomNumberGenerator`
/// type to be used as the source for randomness. When you don't pass a
/// generator, the default `SystemRandomNumberGenerator` type is used.
///
/// When providing new APIs that use randomness, provide a version that accepts
/// a generator conforming to the `RandomNumberGenerator` protocol as well as a
/// version that uses the default system generator. For example, this `Weekday`
/// enumeration provides static methods that return a random day of the week:
///
/// enum Weekday: CaseIterable {
/// case sunday, monday, tuesday, wednesday, thursday, friday, saturday
///
/// static func random<G: RandomNumberGenerator>(using generator: inout G) -> Weekday {
/// return Weekday.allCases.randomElement(using: &generator)!
/// }
///
/// static func random() -> Weekday {
/// var g = SystemRandomNumberGenerator()
/// return Weekday.random(using: &g)
/// }
/// }
///
/// Conforming to the RandomNumberGenerator Protocol
/// ================================================
///
/// A custom `RandomNumberGenerator` type can have different characteristics
/// than the default `SystemRandomNumberGenerator` type. For example, a
/// seedable generator can be used to generate a repeatable sequence of random
/// values for testing purposes.
///
/// To make a custom type conform to the `RandomNumberGenerator` protocol,
/// implement the required `next()` method. Each call to `next()` must produce
/// a uniform and independent random value.
///
/// Types that conform to `RandomNumberGenerator` should specifically document
/// the thread safety and quality of the generator.
public protocol RandomNumberGenerator {
/// Returns a value from a uniform, independent distribution of binary data.
///
/// Use this method when you need random binary data to generate another
/// value. If you need an integer value within a specific range, use the
/// static `random(in:using:)` method on that integer type instead of this
/// method.
///
/// - Returns: An unsigned 64-bit random value.
mutating func next() -> UInt64
}
extension RandomNumberGenerator {
// An unavailable default implementation of next() prevents types that do
// not implement the RandomNumberGenerator interface from conforming to the
// protocol; without this, the default next() method returning a generic
// unsigned integer will be used, recursing infinitely and probably blowing
// the stack.
@available(*, unavailable)
@_alwaysEmitIntoClient
public mutating func next() -> UInt64 { fatalError() }
/// Returns a value from a uniform, independent distribution of binary data.
///
/// Use this method when you need random binary data to generate another
/// value. If you need an integer value within a specific range, use the
/// static `random(in:using:)` method on that integer type instead of this
/// method.
///
/// - Returns: A random value of `T`. Bits are randomly distributed so that
/// every value of `T` is equally likely to be returned.
@inlinable
public mutating func next<T: FixedWidthInteger & UnsignedInteger>() -> T {
return T._random(using: &self)
}
/// Returns a random value that is less than the given upper bound.
///
/// Use this method when you need random binary data to generate another
/// value. If you need an integer value within a specific range, use the
/// static `random(in:using:)` method on that integer type instead of this
/// method.
///
/// - Parameter upperBound: The upper bound for the randomly generated value.
/// Must be non-zero.
/// - Returns: A random value of `T` in the range `0..<upperBound`. Every
/// value in the range `0..<upperBound` is equally likely to be returned.
@inlinable
public mutating func next<T: FixedWidthInteger & UnsignedInteger>(
upperBound: T
) -> T {
_precondition(upperBound != 0, "upperBound cannot be zero.")
// We use Lemire's "nearly divisionless" method for generating random
// integers in an interval. For a detailed explanation, see:
// https://arxiv.org/abs/1805.10941
var random: T = next()
var m = random.multipliedFullWidth(by: upperBound)
if m.low < upperBound {
let t = (0 &- upperBound) % upperBound
while m.low < t {
random = next()
m = random.multipliedFullWidth(by: upperBound)
}
}
return m.high
}
}
/// The system's default source of random data.
///
/// When you generate random values, shuffle a collection, or perform another
/// operation that depends on random data, this type is the generator used by
/// default. For example, the two method calls in this example are equivalent:
///
/// let x = Int.random(in: 1...100)
/// var g = SystemRandomNumberGenerator()
/// let y = Int.random(in: 1...100, using: &g)
///
/// `SystemRandomNumberGenerator` is automatically seeded, is safe to use in
/// multiple threads, and uses a cryptographically secure algorithm whenever
/// possible.
///
/// Platform Implementation of `SystemRandomNumberGenerator`
/// ========================================================
///
/// While the system generator is automatically seeded and thread-safe on every
/// platform, the cryptographic quality of the stream of random data produced by
/// the generator may vary. For more detail, see the documentation for the APIs
/// used by each platform.
///
/// - Apple platforms use `arc4random_buf(3)`.
/// - Linux platforms use `getrandom(2)` when available; otherwise, they read
/// from `/dev/urandom`.
/// - Windows uses `BCryptGenRandom`.
@frozen
public struct SystemRandomNumberGenerator: RandomNumberGenerator, Sendable {
/// Creates a new instance of the system's default random number generator.
@inlinable
public init() { }
/// Returns a value from a uniform, independent distribution of binary data.
///
/// - Returns: An unsigned 64-bit random value.
@inlinable
public mutating func next() -> UInt64 {
var random: UInt64 = 0
#if $TypedThrows
_withUnprotectedUnsafeMutablePointer(to: &random) {
swift_stdlib_random($0, MemoryLayout<UInt64>.size)
}
#else
__abi_se0413_withUnsafeMutablePointer(to: &random) {
swift_stdlib_random($0, MemoryLayout<UInt64>.size)
}
#endif
return random
}
}
|