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
|
||||
/// random Boolean.
|
||||
/// - Returns: A random Boolean.
|
||||
@_inlineable
|
||||
public static func random(
|
||||
using generator: RandomNumberGenerator = Random.default
|
||||
@inlinable
|
||||
public static func random<T: RandomNumberGenerator>(
|
||||
using generator: T
|
||||
) -> Bool {
|
||||
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 {
|
||||
|
||||
@@ -229,6 +229,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
${EXECINFO_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
list(APPEND swift_core_link_flags "$ENV{SystemRoot}/system32/bcrypt.dll")
|
||||
endif()
|
||||
|
||||
option(SWIFT_CHECK_ESSENTIAL_STDLIB
|
||||
"Check core standard library layering by linking its essential subset"
|
||||
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 {
|
||||
@inlinable
|
||||
public func overlaps(_ other: ClosedRange<Bound>) -> Bool {
|
||||
|
||||
@@ -1034,12 +1034,12 @@ extension Collection {
|
||||
/// print(randomNumber)
|
||||
/// }
|
||||
/// // Could print "20", perhaps
|
||||
@_inlineable
|
||||
public func random(
|
||||
using generator: RandomNumberGenerator = Random.default
|
||||
@inlinable
|
||||
public func random<T: RandomNumberGenerator>(
|
||||
using generator: T
|
||||
) -> Element? {
|
||||
guard !isEmpty else { return nil }
|
||||
let random = generator.next(upperBound: UInt(self.count))
|
||||
let random = generator.next(upperBound: UInt(count))
|
||||
let index = self.index(
|
||||
self.startIndex,
|
||||
offsetBy: IndexDistance(random),
|
||||
@@ -1048,6 +1048,31 @@ extension Collection {
|
||||
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.
|
||||
@inlinable
|
||||
@inline(__always)
|
||||
|
||||
@@ -368,7 +368,7 @@ extension MutableCollection where Self : BidirectionalCollection {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// shuffled()
|
||||
// shuffled()/shuffle()
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
extension Sequence {
|
||||
@@ -377,14 +377,26 @@ extension Sequence {
|
||||
/// - Parameter generator: The random number generator to use when shuffling
|
||||
/// the sequence.
|
||||
/// - Returns: A shuffled array of this sequence's elements.
|
||||
@_inlineable
|
||||
public func shuffled(
|
||||
using generator: RandomNumberGenerator = Random.default
|
||||
@inlinable
|
||||
public func shuffled<T: RandomNumberGenerator>(
|
||||
using generator: T
|
||||
) -> [Element] {
|
||||
var result = ContiguousArray(self)
|
||||
result.shuffle(using: generator)
|
||||
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 {
|
||||
@@ -392,9 +404,9 @@ extension MutableCollection {
|
||||
///
|
||||
/// - Parameter generator: The random number generator to use when shuffling
|
||||
/// the collection.
|
||||
@_inlineable
|
||||
public mutating func shuffle(
|
||||
using generator: RandomNumberGenerator = Random.default
|
||||
@inlinable
|
||||
public mutating func shuffle<T: RandomNumberGenerator>(
|
||||
using generator: T
|
||||
) {
|
||||
guard count > 1 else { return }
|
||||
var amount = count
|
||||
@@ -409,6 +421,17 @@ extension MutableCollection {
|
||||
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
|
||||
/// the random floating point.
|
||||
/// - Returns: A random representation of this floating point.
|
||||
@_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(
|
||||
@@ -2425,7 +2425,7 @@ where Self.RawSignificand : FixedWidthInteger,
|
||||
)
|
||||
% end
|
||||
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:
|
||||
let rand: Self.RawSignificand = generator.next(upperBound: maxSignificand)
|
||||
% else:
|
||||
@@ -2434,14 +2434,23 @@ where Self.RawSignificand : FixedWidthInteger,
|
||||
return range.upperBound
|
||||
}
|
||||
% end
|
||||
let unitRandom = Self.init(
|
||||
sign: .plus,
|
||||
exponentBitPattern: (1 as Self).exponentBitPattern,
|
||||
significandBitPattern: rand
|
||||
) - 1
|
||||
let unitRandom = Self.init(rand) * Self.ulpOfOne / 2
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,10 +46,10 @@ extension RandomNumberGenerator {
|
||||
///
|
||||
/// This differs from next() as this function has the ability to transform the
|
||||
/// generated number to any unsigned integer.
|
||||
@_inlineable
|
||||
@inlinable
|
||||
public func next<T: FixedWidthInteger & UnsignedInteger>() -> T {
|
||||
if T.bitWidth == UInt64.bitWidth {
|
||||
return T(self.next())
|
||||
if T.bitWidth <= UInt64.bitWidth {
|
||||
return T(truncatingIfNeeded: self.next())
|
||||
}
|
||||
|
||||
let (quotient, remainder) = T.bitWidth.quotientAndRemainder(
|
||||
@@ -76,11 +76,12 @@ extension RandomNumberGenerator {
|
||||
/// - Parameter upperBound: The max number this can generate up to.
|
||||
/// - Returns: A number that was randomly generated from 0 to upperBound
|
||||
///
|
||||
/// This uses the uniform distribution to form a random number within the
|
||||
/// upperBound.
|
||||
@_inlineable
|
||||
/// By default, this uses the uniform distribution to form a random number
|
||||
/// that is less than the upperBound.
|
||||
@inlinable
|
||||
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
|
||||
|
||||
repeat {
|
||||
@@ -125,4 +126,23 @@ public struct Random : RandomNumberGenerator {
|
||||
_stdlib_random(&random, MemoryLayout<UInt64>.size)
|
||||
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 {
|
||||
/// Returns the range of indices described by this range expression within
|
||||
/// the given collection.
|
||||
|
||||
@@ -11,35 +11,67 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define _REENTRANT
|
||||
#include <math.h>
|
||||
#endif
|
||||
#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>
|
||||
# define _REENTRANT
|
||||
# include <math.h>
|
||||
# include <Security/Security.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(__CYGWIN__)
|
||||
# include <cygwin/version.h>
|
||||
# if (CYGWIN_VERSION_API_MAJOR > 0) || (CYGWIN_VERSION_API_MINOR >= 306)
|
||||
# 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 <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <random>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "swift/Basic/Lazy.h"
|
||||
#include "swift/Runtime/Config.h"
|
||||
#include "swift/Runtime/Debug.h"
|
||||
#include "../SwiftShims/LibcShims.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
@@ -311,44 +343,72 @@ swift::_stdlib_cxx11_mt19937_uniform(__swift_uint32_t upper_bound) {
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <Security/Security.h>
|
||||
|
||||
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||
if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
|
||||
arc4random_buf(buf, nbytes);
|
||||
}else {
|
||||
} else {
|
||||
OSStatus status = SecRandomCopyBytes(kSecRandomDefault, nbytes, buf);
|
||||
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>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||
// TODO: Test on Windows
|
||||
|
||||
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||
void swift::_stdlib_random(void *buf, __swift_size_t nbytes) {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
|
||||
auto _read = [&]() -> __swift_ssize_t {
|
||||
return syscall(SYS_getrandom, buf, bytes, 0);
|
||||
};
|
||||
#else
|
||||
auto _read = [&]() -> __swift_ssize_t {
|
||||
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;
|
||||
NTSTATUS status = BCryptGenRandom(nullptr,
|
||||
static_cast<PUCHAR>(buf),
|
||||
static_cast<ULONG>(nbytes),
|
||||
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
fatalError(0, "Fatal error: %#.8x in '%s'\n", status, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -15,7 +15,7 @@ RandomTests.test("basic random numbers") {
|
||||
let randomDouble1 = Double.random(in: 0 ..< 1)
|
||||
expectTrue(randomDouble1 < 1 && randomDouble1 >= 0)
|
||||
let randomDouble2 = Double.random(in: 0 ..< 1)
|
||||
expectTrue(randomDouble1 < 1 && randomDouble2 >= 0)
|
||||
expectTrue(randomDouble2 < 1 && randomDouble2 >= 0)
|
||||
expectTrue(randomDouble1 != randomDouble2)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user