-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DO NOT MERGE] [stdlib] Random unification #12772
Changes from 38 commits
b30c095
b1340ea
580a670
0c7ce54
7ca2f1c
310e4e1
22ea738
40c1433
a81fe12
cb6292c
b20b238
1b6a3d3
0cee853
7326b68
e4719f8
410e2f7
7a61fef
3878792
63405b4
987af08
844c120
7aabe8c
24c29e8
c31bc1a
b0ca3d4
573408d
2c5ae76
e763457
2e18d36
4f4f65e
a53bec5
8fd12eb
d006c21
6f4f1c5
b94a5ff
47e25db
f31c344
2f4294b
6927e9a
7ae4c03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
//===--- RandomShuffle.swift ----------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 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 TestsUtils | ||
|
||
// | ||
// Benchmark that shuffles arrays of integers. Measures the performance of | ||
// shuffling large arrays. | ||
// | ||
|
||
public let RandomShuffle = [ | ||
BenchmarkInfo(name: "RandomShuffleDef", runFunction: run_RandomShuffleDef, | ||
tags: [.api], setUpFunction: setup_RandomShuffle), | ||
BenchmarkInfo(name: "RandomShuffleLCG", runFunction: run_RandomShuffleLCG, | ||
tags: [.api], setUpFunction: setup_RandomShuffle), | ||
] | ||
|
||
/// A linear congruential PRNG. | ||
struct LCRNG: RandomNumberGenerator { | ||
private var state: UInt64 | ||
|
||
init(seed: Int) { | ||
state = UInt64(truncatingIfNeeded: seed) | ||
for _ in 0..<10 { _ = next() } | ||
} | ||
|
||
mutating func next() -> UInt64 { | ||
state = 2862933555777941757 &* state &+ 3037000493 | ||
return state | ||
} | ||
} | ||
|
||
var numbers = Array(0...3_000_000) | ||
|
||
@inline(never) | ||
func setup_RandomShuffle() { | ||
_ = numbers.count | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomShuffleDef(_ N: Int) { | ||
for _ in 0 ..< N { | ||
numbers.shuffle() | ||
blackHole(numbers.first!) | ||
} | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomShuffleLCG(_ N: Int) { | ||
var generator = LCRNG(seed: 0) | ||
for _ in 0 ..< N { | ||
numbers.shuffle(using: &generator) | ||
blackHole(numbers.first!) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
//===--- RandomValues.swift -----------------------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 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 TestsUtils | ||
|
||
// | ||
// Benchmark generating lots of random values. Measures the performance of | ||
// the default random generator and the algorithms for generating integers | ||
// and floating-point values. | ||
// | ||
|
||
public let RandomValues = [ | ||
BenchmarkInfo(name: "RandomIntegersDef", runFunction: run_RandomIntegersDef, tags: [.api]), | ||
BenchmarkInfo(name: "RandomIntegersLCG", runFunction: run_RandomIntegersLCG, tags: [.api]), | ||
BenchmarkInfo(name: "RandomDoubleDef", runFunction: run_RandomDoubleDef, tags: [.api]), | ||
BenchmarkInfo(name: "RandomDoubleLCG", runFunction: run_RandomDoubleLCG, tags: [.api]), | ||
] | ||
|
||
/// A linear congruential PRNG. | ||
struct LCRNG: RandomNumberGenerator { | ||
private var state: UInt64 | ||
|
||
init(seed: Int) { | ||
state = UInt64(truncatingIfNeeded: seed) | ||
for _ in 0..<10 { _ = next() } | ||
} | ||
|
||
mutating func next() -> UInt64 { | ||
state = 2862933555777941757 &* state &+ 3037000493 | ||
return state | ||
} | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomIntegersDef(_ N: Int) { | ||
for _ in 0 ..< N { | ||
var x = 0 | ||
for _ in 0 ..< 100_000 { | ||
x &+= Int.random(in: 0...10_000) | ||
} | ||
blackHole(x) | ||
} | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomIntegersLCG(_ N: Int) { | ||
for _ in 0 ..< N { | ||
var x = 0 | ||
var generator = LCRNG(seed: 0) | ||
for _ in 0 ..< 100_000 { | ||
x &+= Int.random(in: 0...10_000, using: &generator) | ||
} | ||
CheckResults(x == 498214315) | ||
} | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomDoubleDef(_ N: Int) { | ||
for _ in 0 ..< N { | ||
var x = 0.0 | ||
for _ in 0 ..< 100_000 { | ||
x += Double.random(in: -1000...1000) | ||
} | ||
blackHole(x) | ||
} | ||
} | ||
|
||
@inline(never) | ||
public func run_RandomDoubleLCG(_ N: Int) { | ||
for _ in 0 ..< N { | ||
var x = 0.0 | ||
var generator = LCRNG(seed: 0) | ||
for _ in 0 ..< 100_000 { | ||
x += Double.random(in: -1000...1000, using: &generator) | ||
} | ||
blackHole(x) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,30 @@ public struct Bool { | |
public init(_ value: Bool) { | ||
self = value | ||
} | ||
|
||
/// Returns a random Boolean | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this be "Boolean value." to match the rest of the file? |
||
/// | ||
/// - Parameter generator: The random number generator to use when getting a | ||
/// random Boolean. | ||
/// - Returns: A random Boolean. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto x2: "Boolean value." |
||
@inlinable | ||
public static func random<T: RandomNumberGenerator>( | ||
using generator: inout T | ||
) -> Bool { | ||
return (generator.next() >> 17) & 1 == 0 | ||
} | ||
|
||
/// Returns a random Boolean | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto x2: "Boolean value." |
||
/// | ||
/// - Parameter generator: The random number generator to use when getting a | ||
/// random Boolean. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function doesn't have a |
||
/// - 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 { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,6 +96,7 @@ set(SWIFTLIB_ESSENTIAL | |
Policy.swift | ||
PrefixWhile.swift | ||
Print.swift | ||
Random.swift | ||
RandomAccessCollection.swift | ||
Range.swift | ||
RangeReplaceableCollection.swift | ||
|
@@ -192,6 +193,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") | |
list(APPEND swift_core_link_flags "-all_load") | ||
list(APPEND swift_core_framework_depends Foundation) | ||
list(APPEND swift_core_framework_depends CoreFoundation) | ||
list(APPEND swift_core_framework_depends Security) | ||
list(APPEND swift_core_private_link_libraries icucore) | ||
else() | ||
# With the GNU linker the equivalent of -all_load is to tell the linker | ||
|
@@ -226,6 +228,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() | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @benrimmington Does this look correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Azoy, I think the https://msdn.microsoft.com/en-us/library/windows/desktop/ms681914(v=vs.85).aspx Are you able to test on Windows? If not, shall we ask @compnerd for help? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is wrong. You don't link against the dll but the import library. You should be able to just add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @compnerd, please see Azoy/swift@b2ef08f in Azoy#2. It uses It also uses |
||
option(SWIFT_CHECK_ESSENTIAL_STDLIB | ||
"Check core standard library layering by linking its essential subset" | ||
FALSE) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -790,6 +790,25 @@ public protocol Collection: Sequence where SubSequence: Collection { | |
/// `endIndex`. | ||
func formIndex(after i: inout Index) | ||
|
||
/// Returns a random element of the collection, using the given generator as | ||
/// a source for randomness. | ||
/// | ||
/// You use this method to select a random element from a collection when you | ||
/// are using a custom random number generator. For example, call | ||
/// `randomElement(using:)` to select a random element from an array of names. | ||
/// | ||
/// let names = ["Zoey", "Chloe", "Amani", "Amaia"] | ||
/// let randomName = names.randomElement(using: &myGenerator)! | ||
/// // randomName == "Amani" (maybe) | ||
/// | ||
/// - Parameter generator: The random number generator to use when choosing | ||
/// a random element. | ||
/// - Returns: A random element from the collection. If the collection is | ||
/// empty, the method returns `nil`. | ||
func randomElement<T: RandomNumberGenerator>( | ||
using generator: inout T | ||
) -> Element? | ||
|
||
@available(*, deprecated, message: "all index distances are now of type Int") | ||
typealias IndexDistance = Int | ||
} | ||
|
@@ -1003,6 +1022,54 @@ extension Collection { | |
return count | ||
} | ||
|
||
/// Returns a random element of the collection, using the given generator as | ||
/// a source for randomness. | ||
/// | ||
/// You use this method to select a random element from a collection when you | ||
/// are using a custom random number generator. For example, call | ||
/// `randomElement(using:)` to select a random element from an array of names. | ||
/// | ||
/// let names = ["Zoey", "Chloe", "Amani", "Amaia"] | ||
/// let randomName = names.randomElement(using: &myGenerator)! | ||
/// // randomName == "Amani" (maybe) | ||
/// | ||
/// - Parameter generator: The random number generator to use when choosing | ||
/// a random element. | ||
/// - Returns: A random element from the collection. If the collection is | ||
/// empty, the method returns `nil`. | ||
@inlinable | ||
public func randomElement<T: RandomNumberGenerator>( | ||
using generator: inout T | ||
) -> Element? { | ||
guard !isEmpty else { return nil } | ||
let random = generator.next(upperBound: UInt(count)) | ||
let index = self.index( | ||
startIndex, | ||
offsetBy: numericCast(random) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of using let randomDistance = Int.random(in: 0 ..< count, using: &generator)
let randomIndex = index(startIndex, offsetBy: randomDistance)
return self[randomIndex] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. However, this would be indirectly calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @benrimmington The changes you proposed worked, I'm not sure if you want to proceed with it however. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indirectly calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My initial reaction is yes it will be slower, but it should be minuscule however. |
||
) | ||
return self[index] | ||
} | ||
|
||
/// Returns a random element of the collection. | ||
/// | ||
/// For example, call `randomElement()` to select a random element from an | ||
/// array of names. | ||
/// | ||
/// let names = ["Zoey", "Chloe", "Amani", "Amaia"] | ||
/// let randomName = names.randomElement()! | ||
/// // randomName == "Amani" (perhaps) | ||
/// | ||
/// This method uses the default random generator, `Random.default`. The call | ||
/// to `names.randomElement()` above is equivalent to calling | ||
/// `names.randomElement(using: &Random.default)`. | ||
/// | ||
/// - Returns: A random element from the collection. If the collection is | ||
/// empty, the method returns `nil`. | ||
@inlinable | ||
public func randomElement() -> Element? { | ||
return randomElement(using: &Random.default) | ||
} | ||
|
||
/// Do not use this method directly; call advanced(by: n) instead. | ||
@inlinable | ||
@usableFromInline | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this function be
SWIFT_RUNTIME_STDLIB_INTERNAL
instead?Should
@_inlineable
be removed from theRandom.next()
method?https://github.com/apple/swift/blob/master/stdlib/public/SwiftShims/Visibility.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!