mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +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:
@@ -92,12 +92,24 @@ public struct Bool {
|
|||||||
/// - Parameter generator: The random number generator to use when getting a
|
/// - Parameter generator: The random number generator to use when getting a
|
||||||
/// random Boolean.
|
/// random Boolean.
|
||||||
/// - Returns: A random Boolean.
|
/// - Returns: A random Boolean.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public static func random(
|
public static func random<T: RandomNumberGenerator>(
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
return generator.next() % 2 == 0
|
return generator.next() % 2 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a random Boolean
|
||||||
|
///
|
||||||
|
/// - Parameter generator: The random number generator to use when getting a
|
||||||
|
/// random Boolean.
|
||||||
|
/// - Returns: A random Boolean.
|
||||||
|
///
|
||||||
|
/// This uses the standard library's default random number generator.
|
||||||
|
@inlinable
|
||||||
|
public static func random() -> Bool {
|
||||||
|
return Bool.random(using: Random.default)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Bool : _ExpressibleByBuiltinBooleanLiteral, ExpressibleByBooleanLiteral {
|
extension Bool : _ExpressibleByBuiltinBooleanLiteral, ExpressibleByBooleanLiteral {
|
||||||
|
|||||||
@@ -229,6 +229,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
|||||||
${EXECINFO_LIBRARY})
|
${EXECINFO_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
|
list(APPEND swift_core_link_flags "$ENV{SystemRoot}/system32/bcrypt.dll")
|
||||||
|
endif()
|
||||||
|
|
||||||
option(SWIFT_CHECK_ESSENTIAL_STDLIB
|
option(SWIFT_CHECK_ESSENTIAL_STDLIB
|
||||||
"Check core standard library layering by linking its essential subset"
|
"Check core standard library layering by linking its essential subset"
|
||||||
FALSE)
|
FALSE)
|
||||||
|
|||||||
@@ -480,57 +480,6 @@ extension ClosedRange where Bound: Strideable, Bound.Stride : SignedInteger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ClosedRange
|
|
||||||
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
|
|
||||||
@_inlineable
|
|
||||||
public func random(
|
|
||||||
using generator: RandomNumberGenerator = Random.default
|
|
||||||
) -> Element? {
|
|
||||||
let isLowerNegative = Bound.isSigned && lowerBound < 0
|
|
||||||
let sameSign = !Bound.isSigned || isLowerNegative == (upperBound < 0)
|
|
||||||
var delta: Bound.Magnitude
|
|
||||||
if isLowerNegative {
|
|
||||||
delta = sameSign
|
|
||||||
? lowerBound.magnitude - upperBound.magnitude
|
|
||||||
: lowerBound.magnitude + upperBound.magnitude
|
|
||||||
} else {
|
|
||||||
delta = upperBound.magnitude - lowerBound.magnitude
|
|
||||||
}
|
|
||||||
if delta == Bound.Magnitude.max {
|
|
||||||
return Bound(truncatingIfNeeded: generator.next() as Bound.Magnitude)
|
|
||||||
}
|
|
||||||
delta += 1
|
|
||||||
let randomMagnitude = generator.next(upperBound: delta)
|
|
||||||
if sameSign {
|
|
||||||
return lowerBound + Bound(randomMagnitude)
|
|
||||||
} else {
|
|
||||||
return Bound.isSigned && randomMagnitude <= upperBound.magnitude
|
|
||||||
? Bound(randomMagnitude)
|
|
||||||
: 0 - Bound(randomMagnitude - upperBound.magnitude)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ClosedRange {
|
extension ClosedRange {
|
||||||
@inlinable
|
@inlinable
|
||||||
public func overlaps(_ other: ClosedRange<Bound>) -> Bool {
|
public func overlaps(_ other: ClosedRange<Bound>) -> Bool {
|
||||||
|
|||||||
@@ -1034,12 +1034,12 @@ extension Collection {
|
|||||||
/// print(randomNumber)
|
/// print(randomNumber)
|
||||||
/// }
|
/// }
|
||||||
/// // Could print "20", perhaps
|
/// // Could print "20", perhaps
|
||||||
@_inlineable
|
@inlinable
|
||||||
public func random(
|
public func random<T: RandomNumberGenerator>(
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) -> Element? {
|
) -> Element? {
|
||||||
guard !isEmpty else { return nil }
|
guard !isEmpty else { return nil }
|
||||||
let random = generator.next(upperBound: UInt(self.count))
|
let random = generator.next(upperBound: UInt(count))
|
||||||
let index = self.index(
|
let index = self.index(
|
||||||
self.startIndex,
|
self.startIndex,
|
||||||
offsetBy: IndexDistance(random),
|
offsetBy: IndexDistance(random),
|
||||||
@@ -1048,6 +1048,31 @@ extension Collection {
|
|||||||
return self[index]
|
return self[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 random(using: Random.default)
|
||||||
|
}
|
||||||
|
|
||||||
/// Do not use this method directly; call advanced(by: n) instead.
|
/// Do not use this method directly; call advanced(by: n) instead.
|
||||||
@inlinable
|
@inlinable
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ extension MutableCollection where Self : BidirectionalCollection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// shuffled()
|
// shuffled()/shuffle()
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
extension Sequence {
|
extension Sequence {
|
||||||
@@ -377,14 +377,26 @@ extension Sequence {
|
|||||||
/// - Parameter generator: The random number generator to use when shuffling
|
/// - Parameter generator: The random number generator to use when shuffling
|
||||||
/// the sequence.
|
/// the sequence.
|
||||||
/// - Returns: A shuffled array of this sequence's elements.
|
/// - Returns: A shuffled array of this sequence's elements.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public func shuffled(
|
public func shuffled<T: RandomNumberGenerator>(
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) -> [Element] {
|
) -> [Element] {
|
||||||
var result = ContiguousArray(self)
|
var result = ContiguousArray(self)
|
||||||
result.shuffle(using: generator)
|
result.shuffle(using: generator)
|
||||||
return Array(result)
|
return Array(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the elements of the sequence, shuffled.
|
||||||
|
///
|
||||||
|
/// - Parameter generator: The random number generator to use when shuffling
|
||||||
|
/// the sequence.
|
||||||
|
/// - Returns: A shuffled array of this sequence's elements.
|
||||||
|
///
|
||||||
|
/// This uses the standard library's default random number generator.
|
||||||
|
@inlinable
|
||||||
|
public func shuffled() -> [Element] {
|
||||||
|
return shuffled(using: Random.default)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MutableCollection {
|
extension MutableCollection {
|
||||||
@@ -392,9 +404,9 @@ extension MutableCollection {
|
|||||||
///
|
///
|
||||||
/// - Parameter generator: The random number generator to use when shuffling
|
/// - Parameter generator: The random number generator to use when shuffling
|
||||||
/// the collection.
|
/// the collection.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public mutating func shuffle(
|
public mutating func shuffle<T: RandomNumberGenerator>(
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) {
|
) {
|
||||||
guard count > 1 else { return }
|
guard count > 1 else { return }
|
||||||
var amount = count
|
var amount = count
|
||||||
@@ -409,6 +421,17 @@ extension MutableCollection {
|
|||||||
formIndex(after: ¤tIndex)
|
formIndex(after: ¤tIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shuffles the collection in place.
|
||||||
|
///
|
||||||
|
/// - Parameter generator: The random number generator to use when shuffling
|
||||||
|
/// the collection.
|
||||||
|
///
|
||||||
|
/// This uses the standard library's default random number generator.
|
||||||
|
@inlinable
|
||||||
|
public mutating func shuffle() {
|
||||||
|
shuffle(using: Random.default)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -2413,10 +2413,10 @@ where Self.RawSignificand : FixedWidthInteger,
|
|||||||
/// - Parameter generator: The random number generator to use when getting
|
/// - Parameter generator: The random number generator to use when getting
|
||||||
/// the random floating point.
|
/// the random floating point.
|
||||||
/// - Returns: A random representation of this floating point.
|
/// - Returns: A random representation of this floating point.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public static func random(
|
public static func random<T: RandomNumberGenerator>(
|
||||||
in range: ${Range}<Self>,
|
in range: ${Range}<Self>,
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) -> Self {
|
) -> Self {
|
||||||
% if 'Closed' not in Range:
|
% if 'Closed' not in Range:
|
||||||
_precondition(
|
_precondition(
|
||||||
@@ -2425,7 +2425,7 @@ where Self.RawSignificand : FixedWidthInteger,
|
|||||||
)
|
)
|
||||||
% end
|
% end
|
||||||
let delta = range.upperBound - range.lowerBound
|
let delta = range.upperBound - range.lowerBound
|
||||||
let maxSignificand: Self.RawSignificand = 1 << Self.significandBitCount
|
let maxSignificand = Self.RawSignificand(1 << (Self.significandBitCount + 1))
|
||||||
% if 'Closed' not in Range:
|
% if 'Closed' not in Range:
|
||||||
let rand: Self.RawSignificand = generator.next(upperBound: maxSignificand)
|
let rand: Self.RawSignificand = generator.next(upperBound: maxSignificand)
|
||||||
% else:
|
% else:
|
||||||
@@ -2434,14 +2434,23 @@ where Self.RawSignificand : FixedWidthInteger,
|
|||||||
return range.upperBound
|
return range.upperBound
|
||||||
}
|
}
|
||||||
% end
|
% end
|
||||||
let unitRandom = Self.init(
|
let unitRandom = Self.init(rand) * Self.ulpOfOne / 2
|
||||||
sign: .plus,
|
|
||||||
exponentBitPattern: (1 as Self).exponentBitPattern,
|
|
||||||
significandBitPattern: rand
|
|
||||||
) - 1
|
|
||||||
return delta * unitRandom + range.lowerBound
|
return delta * unitRandom + range.lowerBound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a random representation of this floating point 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 floating point.
|
||||||
|
/// - Returns: A random representation of this floating point.
|
||||||
|
///
|
||||||
|
/// 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
|
% end
|
||||||
|
|||||||
@@ -2532,6 +2532,99 @@ ${assignmentOperatorComment(x.operator, False)}
|
|||||||
|
|
||||||
% for Range in ['Range', 'ClosedRange']:
|
% 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
|
extension FixedWidthInteger
|
||||||
where Self.Stride : SignedInteger,
|
where Self.Stride : SignedInteger,
|
||||||
Self.Magnitude : UnsignedInteger {
|
Self.Magnitude : UnsignedInteger {
|
||||||
@@ -2543,10 +2636,10 @@ where Self.Stride : SignedInteger,
|
|||||||
/// - Parameter generator: The random number generator to use when getting
|
/// - Parameter generator: The random number generator to use when getting
|
||||||
/// the random integer.
|
/// the random integer.
|
||||||
/// - Returns: A random representation of this integer.
|
/// - Returns: A random representation of this integer.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public static func random(
|
public static func random<T: RandomNumberGenerator>(
|
||||||
in range: ${Range}<Self>,
|
in range: ${Range}<Self>,
|
||||||
using generator: RandomNumberGenerator = Random.default
|
using generator: T
|
||||||
) -> Self {
|
) -> Self {
|
||||||
% if 'Closed' not in Range:
|
% if 'Closed' not in Range:
|
||||||
_precondition(
|
_precondition(
|
||||||
@@ -2556,6 +2649,20 @@ where Self.Stride : SignedInteger,
|
|||||||
% end
|
% end
|
||||||
return range.random(using: generator)!
|
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
|
% end
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ extension RandomNumberGenerator {
|
|||||||
///
|
///
|
||||||
/// This differs from next() as this function has the ability to transform the
|
/// This differs from next() as this function has the ability to transform the
|
||||||
/// generated number to any unsigned integer.
|
/// generated number to any unsigned integer.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public func next<T: FixedWidthInteger & UnsignedInteger>() -> T {
|
public func next<T: FixedWidthInteger & UnsignedInteger>() -> T {
|
||||||
if T.bitWidth == UInt64.bitWidth {
|
if T.bitWidth <= UInt64.bitWidth {
|
||||||
return T(self.next())
|
return T(truncatingIfNeeded: self.next())
|
||||||
}
|
}
|
||||||
|
|
||||||
let (quotient, remainder) = T.bitWidth.quotientAndRemainder(
|
let (quotient, remainder) = T.bitWidth.quotientAndRemainder(
|
||||||
@@ -76,11 +76,12 @@ extension RandomNumberGenerator {
|
|||||||
/// - Parameter upperBound: The max number this can generate up to.
|
/// - Parameter upperBound: The max number this can generate up to.
|
||||||
/// - Returns: A number that was randomly generated from 0 to upperBound
|
/// - Returns: A number that was randomly generated from 0 to upperBound
|
||||||
///
|
///
|
||||||
/// This uses the uniform distribution to form a random number within the
|
/// By default, this uses the uniform distribution to form a random number
|
||||||
/// upperBound.
|
/// that is less than the upperBound.
|
||||||
@_inlineable
|
@inlinable
|
||||||
public func next<T: FixedWidthInteger & UnsignedInteger>(upperBound: T) -> T {
|
public func next<T: FixedWidthInteger & UnsignedInteger>(upperBound: T) -> T {
|
||||||
let range = T.max % upperBound
|
let tmp = (T.max % upperBound) + 1
|
||||||
|
let range = tmp == upperBound ? 0 : tmp
|
||||||
var random: T = 0
|
var random: T = 0
|
||||||
|
|
||||||
repeat {
|
repeat {
|
||||||
@@ -125,4 +126,23 @@ public struct Random : RandomNumberGenerator {
|
|||||||
_stdlib_random(&random, MemoryLayout<UInt64>.size)
|
_stdlib_random(&random, MemoryLayout<UInt64>.size)
|
||||||
return random
|
return random
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produces the next randomly generated number
|
||||||
|
///
|
||||||
|
/// - Returns: A number that was randomly generated
|
||||||
|
///
|
||||||
|
/// This differs from next() as this function has the ability to transform the
|
||||||
|
/// generated number to any unsigned integer.
|
||||||
|
public func next<T: FixedWidthInteger & UnsignedInteger>() -> T {
|
||||||
|
var random: T = 0
|
||||||
|
_stdlib_random(&random, MemoryLayout<T>.size)
|
||||||
|
return random
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public // @testable
|
||||||
|
func _stdlib_random(_ bytes: UnsafeMutableRawBufferPointer) {
|
||||||
|
if !bytes.isEmpty {
|
||||||
|
_stdlib_random(bytes.baseAddress!, bytes.count)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -303,56 +303,6 @@ extension Range where Bound: Strideable, Bound.Stride : SignedInteger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
@_inlineable
|
|
||||||
public func random(
|
|
||||||
using generator: RandomNumberGenerator = Random.default
|
|
||||||
) -> Element? {
|
|
||||||
guard lowerBound != upperBound else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let isLowerNegative = Bound.isSigned && lowerBound < 0
|
|
||||||
let sameSign = !Bound.isSigned || isLowerNegative == (upperBound < 0)
|
|
||||||
let delta: Bound.Magnitude
|
|
||||||
if isLowerNegative {
|
|
||||||
delta = sameSign
|
|
||||||
? lowerBound.magnitude - upperBound.magnitude
|
|
||||||
: lowerBound.magnitude + upperBound.magnitude
|
|
||||||
} else {
|
|
||||||
delta = upperBound.magnitude - lowerBound.magnitude
|
|
||||||
}
|
|
||||||
let randomMagnitude = generator.next(upperBound: delta)
|
|
||||||
if sameSign {
|
|
||||||
return lowerBound + Bound(randomMagnitude)
|
|
||||||
} else {
|
|
||||||
return randomMagnitude < upperBound.magnitude
|
|
||||||
? Bound(randomMagnitude)
|
|
||||||
: -1 - Bound(randomMagnitude - upperBound.magnitude)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Range: RangeExpression {
|
extension Range: RangeExpression {
|
||||||
/// Returns the range of indices described by this range expression within
|
/// Returns the range of indices described by this range expression within
|
||||||
/// the given collection.
|
/// the given collection.
|
||||||
|
|||||||
@@ -11,35 +11,67 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#define _REENTRANT
|
# define _REENTRANT
|
||||||
#include <math.h>
|
# include <math.h>
|
||||||
#endif
|
# include <Security/Security.h>
|
||||||
#include <random>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cmath>
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <io.h>
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <Windows.h>
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#if defined(__CYGWIN__)
|
||||||
#include <stdio.h>
|
# include <cygwin/version.h>
|
||||||
#include <string.h>
|
# if (CYGWIN_VERSION_API_MAJOR > 0) || (CYGWIN_VERSION_API_MINOR >= 306)
|
||||||
#include <fcntl.h>
|
# include <sys/random.h>
|
||||||
|
# define SWIFT_STDLIB_USING_GETRANDOM
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__Fuchsia__)
|
||||||
|
# include <sys/random.h>
|
||||||
|
# define SWIFT_STDLIB_USING_GETENTROPY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <linux/version.h>
|
||||||
|
# if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0))
|
||||||
|
# include <features.h>
|
||||||
|
# if defined(__BIONIC__) || (defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,25))
|
||||||
|
# include <sys/random.h>
|
||||||
|
# define SWIFT_STDLIB_USING_GETRANDOM
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
# include <io.h>
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_NO_STATUS
|
||||||
|
# include <Windows.h>
|
||||||
|
# undef WIN32_NO_STATUS
|
||||||
|
# include <Ntstatus.h>
|
||||||
|
# include <Ntdef.h>
|
||||||
|
# include <Bcrypt.h>
|
||||||
|
#else
|
||||||
|
# include <pthread.h>
|
||||||
|
# include <semaphore.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <fcntl.h>
|
||||||
|
#include <random>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "llvm/Support/DataTypes.h"
|
||||||
#include "swift/Basic/Lazy.h"
|
#include "swift/Basic/Lazy.h"
|
||||||
#include "swift/Runtime/Config.h"
|
#include "swift/Runtime/Config.h"
|
||||||
#include "swift/Runtime/Debug.h"
|
#include "swift/Runtime/Debug.h"
|
||||||
#include "../SwiftShims/LibcShims.h"
|
#include "../SwiftShims/LibcShims.h"
|
||||||
#include "llvm/Support/DataTypes.h"
|
|
||||||
|
|
||||||
using namespace swift;
|
using namespace swift;
|
||||||
|
|
||||||
@@ -311,44 +343,72 @@ swift::_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <Security/Security.h>
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||||
if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
|
if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
|
||||||
arc4random_buf(buf, nbytes);
|
arc4random_buf(buf, nbytes);
|
||||||
}else {
|
} else {
|
||||||
OSStatus status = SecRandomCopyBytes(kSecRandomDefault, nbytes, buf);
|
OSStatus status = SecRandomCopyBytes(kSecRandomDefault, nbytes, buf);
|
||||||
if (status != errSecSuccess) {
|
if (status != errSecSuccess) {
|
||||||
fatalError(0, "Fatal error: SecRandomCopyBytes failed with error %d\n", status);
|
fatalError(0, "Fatal error: %d in '%s'\n", status, __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(__linux__)
|
|
||||||
#include <linux/version.h>
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
#include <sys/syscall.h>
|
// TODO: Test on Windows
|
||||||
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
|
NTSTATUS status = BCryptGenRandom(nullptr,
|
||||||
auto _read = [&]() -> __swift_ssize_t {
|
static_cast<PUCHAR>(buf),
|
||||||
return syscall(SYS_getrandom, buf, bytes, 0);
|
static_cast<ULONG>(nbytes),
|
||||||
};
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||||
#else
|
if (!NT_SUCCESS(status)) {
|
||||||
auto _read = [&]() -> __swift_ssize_t {
|
fatalError(0, "Fatal error: %#.8x in '%s'\n", status, __func__);
|
||||||
static const int fd = _stdlib_open("/dev/urandom", O_RDONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
fatalError(0, "Unable to open '/dev/urandom'\n");
|
|
||||||
}
|
|
||||||
return _stdlib_read(fd, buf, bytes);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
while (nbytes > 0) {
|
|
||||||
auto result = _read();
|
|
||||||
if (result < 1) {
|
|
||||||
if (errno == EINTR) { continue; }
|
|
||||||
fatalError(0, "Unable to read '/dev/urandom'\n");
|
|
||||||
}
|
|
||||||
buf = static_cast<uint8_t *>(buf) + result;
|
|
||||||
nbytes -= result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(SWIFT_STDLIB_USING_GETENTROPY)
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
|
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||||
|
while (nbytes > 0) {
|
||||||
|
constexpr __swift_size_t max_nbytes = 256;
|
||||||
|
__swift_size_t actual_nbytes = (nbytes < max_nbytes ?
|
||||||
|
nbytes : max_nbytes);
|
||||||
|
if (0 != getentropy(buf, actual_nbytes)) {
|
||||||
|
fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__);
|
||||||
|
}
|
||||||
|
buf = static_cast<uint8_t *>(buf) + actual_nbytes;
|
||||||
|
nbytes -= actual_nbytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
|
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||||
|
#if !defined(SWIFT_STDLIB_USING_GETRANDOM)
|
||||||
|
static const int fd = _stdlib_open("/dev/urandom", O_RDONLY, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
while (nbytes > 0) {
|
||||||
|
#if !defined(SWIFT_STDLIB_USING_GETRANDOM)
|
||||||
|
__swift_ssize_t actual_nbytes = _stdlib_read(fd, buf, nbytes);
|
||||||
|
#else
|
||||||
|
__swift_ssize_t actual_nbytes = getrandom(buf, nbytes, 0);
|
||||||
|
#endif
|
||||||
|
if (actual_nbytes < 1) {
|
||||||
|
if (errno == EINTR) { continue; }
|
||||||
|
fatalError(0, "Fatal error: %d in '%s'\n", errno, __func__);
|
||||||
|
}
|
||||||
|
buf = static_cast<uint8_t *>(buf) + actual_nbytes;
|
||||||
|
nbytes -= actual_nbytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RandomTests.test("basic random numbers") {
|
|||||||
let randomDouble1 = Double.random(in: 0 ..< 1)
|
let randomDouble1 = Double.random(in: 0 ..< 1)
|
||||||
expectTrue(randomDouble1 < 1 && randomDouble1 >= 0)
|
expectTrue(randomDouble1 < 1 && randomDouble1 >= 0)
|
||||||
let randomDouble2 = Double.random(in: 0 ..< 1)
|
let randomDouble2 = Double.random(in: 0 ..< 1)
|
||||||
expectTrue(randomDouble1 < 1 && randomDouble2 >= 0)
|
expectTrue(randomDouble2 < 1 && randomDouble2 >= 0)
|
||||||
expectTrue(randomDouble1 != randomDouble2)
|
expectTrue(randomDouble1 != randomDouble2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user