mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Add _stdlib_random for more platforms (#1)
* Remove refs to Countable ranges * Add `_stdlib_random` for more platforms * Use `getrandom` (if available) for Android, Cygwin * Reorder the `_stdlib_random` functions * Also include <features.h> on Linux * Add `#error TODO` in `_stdlib_random` for Windows * Colon after Fatal Error Performance improvement for Random gybify ranges Fix typo in 'basic random numbers' Add _stdlib_random as a testable method Switch to generic constraints Hopefully link against bcrypt Fix some implementation details 1. Uniform distribution is now uniform 2. Apply Jens' method for uniform floats Fix a lineable attribute
This commit is contained in:
@@ -2532,6 +2532,99 @@ ${assignmentOperatorComment(x.operator, False)}
|
||||
|
||||
% for Range in ['Range', 'ClosedRange']:
|
||||
|
||||
extension ${Range}
|
||||
where Bound: FixedWidthInteger,
|
||||
Bound.Magnitude: UnsignedInteger {
|
||||
|
||||
/// Returns a random element from this collection.
|
||||
///
|
||||
/// - Parameter generator: The random number generator to use when getting
|
||||
/// a random element.
|
||||
/// - Returns: A random element from this collection.
|
||||
///
|
||||
/// A good example of this is getting a random greeting from an array:
|
||||
///
|
||||
/// let greetings = ["hi", "hey", "hello", "hola"]
|
||||
/// let randomGreeting = greetings.random()
|
||||
///
|
||||
/// If the collection is empty, the value of this function is `nil`.
|
||||
///
|
||||
/// let numbers = [10, 20, 30, 40, 50]
|
||||
/// if let randomNumber = numbers.random() {
|
||||
/// print(randomNumber)
|
||||
/// }
|
||||
/// // Could print "20", perhaps
|
||||
@inlinable
|
||||
public func random<T: RandomNumberGenerator>(
|
||||
using generator: T
|
||||
) -> Element? {
|
||||
% if 'Closed' not in Range:
|
||||
guard lowerBound != upperBound else {
|
||||
return nil
|
||||
}
|
||||
% end
|
||||
let isLowerNegative = Bound.isSigned && lowerBound < 0
|
||||
let sameSign = !Bound.isSigned || isLowerNegative == (upperBound < 0)
|
||||
% if 'Closed' not in Range:
|
||||
let delta: Bound.Magnitude
|
||||
% else:
|
||||
var delta: Bound.Magnitude
|
||||
% end
|
||||
if isLowerNegative {
|
||||
delta = sameSign
|
||||
? lowerBound.magnitude - upperBound.magnitude
|
||||
: lowerBound.magnitude + upperBound.magnitude
|
||||
} else {
|
||||
delta = upperBound.magnitude - lowerBound.magnitude
|
||||
}
|
||||
% if 'Closed' in Range:
|
||||
if delta == Bound.Magnitude.max {
|
||||
return Bound(truncatingIfNeeded: generator.next() as Bound.Magnitude)
|
||||
}
|
||||
delta += 1
|
||||
% end
|
||||
let randomMagnitude = generator.next(upperBound: delta)
|
||||
if sameSign {
|
||||
return lowerBound + Bound(randomMagnitude)
|
||||
} else {
|
||||
% if 'Closed' not in Range:
|
||||
return randomMagnitude < upperBound.magnitude
|
||||
? Bound(randomMagnitude)
|
||||
: -1 - Bound(randomMagnitude - upperBound.magnitude)
|
||||
% else:
|
||||
return Bound.isSigned && randomMagnitude <= upperBound.magnitude
|
||||
? Bound(randomMagnitude)
|
||||
: 0 - Bound(randomMagnitude - upperBound.magnitude)
|
||||
% end
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a random element from this collection.
|
||||
///
|
||||
/// - Parameter generator: The random number generator to use when getting
|
||||
/// a random element.
|
||||
/// - Returns: A random element from this collection.
|
||||
///
|
||||
/// A good example of this is getting a random greeting from an array:
|
||||
///
|
||||
/// let greetings = ["hi", "hey", "hello", "hola"]
|
||||
/// let randomGreeting = greetings.random()
|
||||
///
|
||||
/// If the collection is empty, the value of this function is `nil`.
|
||||
///
|
||||
/// let numbers = [10, 20, 30, 40, 50]
|
||||
/// if let randomNumber = numbers.random() {
|
||||
/// print(randomNumber)
|
||||
/// }
|
||||
/// // Could print "20", perhaps
|
||||
///
|
||||
/// This uses the standard library's default random number generator.
|
||||
@inlinable
|
||||
public func random() -> Element? {
|
||||
return self.random(using: Random.default)
|
||||
}
|
||||
}
|
||||
|
||||
extension FixedWidthInteger
|
||||
where Self.Stride : SignedInteger,
|
||||
Self.Magnitude : UnsignedInteger {
|
||||
@@ -2543,10 +2636,10 @@ where Self.Stride : SignedInteger,
|
||||
/// - Parameter generator: The random number generator to use when getting
|
||||
/// the random integer.
|
||||
/// - Returns: A random representation of this integer.
|
||||
@_inlineable
|
||||
public static func random(
|
||||
@inlinable
|
||||
public static func random<T: RandomNumberGenerator>(
|
||||
in range: ${Range}<Self>,
|
||||
using generator: RandomNumberGenerator = Random.default
|
||||
using generator: T
|
||||
) -> Self {
|
||||
% if 'Closed' not in Range:
|
||||
_precondition(
|
||||
@@ -2556,6 +2649,20 @@ where Self.Stride : SignedInteger,
|
||||
% end
|
||||
return range.random(using: generator)!
|
||||
}
|
||||
|
||||
/// Returns a random representation of this integer within the range.
|
||||
///
|
||||
/// - Parameter range: A ${Range} to determine the bounds to get a random value
|
||||
/// from.
|
||||
/// - Parameter generator: The random number generator to use when getting
|
||||
/// the random integer.
|
||||
/// - Returns: A random representation of this integer.
|
||||
///
|
||||
/// This uses the standard library's default random number generator.
|
||||
@inlinable
|
||||
public static func random(in range: ${Range}<Self>) -> Self {
|
||||
return Self.random(in: range, using: Random.default)
|
||||
}
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
Reference in New Issue
Block a user