Skip to content

Commit a5df0ef

Browse files
benrimmingtonAzoy
authored andcommitted
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
1 parent d23d219 commit a5df0ef

File tree

11 files changed

+334
-175
lines changed

11 files changed

+334
-175
lines changed

stdlib/public/core/Bool.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,24 @@ public struct Bool {
9292
/// - Parameter generator: The random number generator to use when getting a
9393
/// random Boolean.
9494
/// - Returns: A random Boolean.
95-
@_inlineable
96-
public static func random(
97-
using generator: RandomNumberGenerator = Random.default
95+
@inlinable
96+
public static func random<T: RandomNumberGenerator>(
97+
using generator: T
9898
) -> Bool {
9999
return generator.next() % 2 == 0
100100
}
101+
102+
/// Returns a random Boolean
103+
///
104+
/// - Parameter generator: The random number generator to use when getting a
105+
/// random Boolean.
106+
/// - Returns: A random Boolean.
107+
///
108+
/// This uses the standard library's default random number generator.
109+
@inlinable
110+
public static func random() -> Bool {
111+
return Bool.random(using: Random.default)
112+
}
101113
}
102114

103115
extension Bool : _ExpressibleByBuiltinBooleanLiteral, ExpressibleByBooleanLiteral {

stdlib/public/core/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
229229
${EXECINFO_LIBRARY})
230230
endif()
231231

232+
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
233+
list(APPEND swift_core_link_flags "$ENV{SystemRoot}/system32/bcrypt.dll")
234+
endif()
235+
232236
option(SWIFT_CHECK_ESSENTIAL_STDLIB
233237
"Check core standard library layering by linking its essential subset"
234238
FALSE)

stdlib/public/core/ClosedRange.swift

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -480,57 +480,6 @@ extension ClosedRange where Bound: Strideable, Bound.Stride : SignedInteger {
480480
}
481481
}
482482

483-
extension ClosedRange
484-
where Bound : FixedWidthInteger,
485-
Bound.Magnitude : UnsignedInteger {
486-
487-
/// Returns a random element from this collection.
488-
///
489-
/// - Parameter generator: The random number generator to use when getting
490-
/// a random element.
491-
/// - Returns: A random element from this collection.
492-
///
493-
/// A good example of this is getting a random greeting from an array:
494-
///
495-
/// let greetings = ["hi", "hey", "hello", "hola"]
496-
/// let randomGreeting = greetings.random()
497-
///
498-
/// If the collection is empty, the value of this function is `nil`.
499-
///
500-
/// let numbers = [10, 20, 30, 40, 50]
501-
/// if let randomNumber = numbers.random() {
502-
/// print(randomNumber)
503-
/// }
504-
/// // Could print "20", perhaps
505-
@_inlineable
506-
public func random(
507-
using generator: RandomNumberGenerator = Random.default
508-
) -> Element? {
509-
let isLowerNegative = Bound.isSigned && lowerBound < 0
510-
let sameSign = !Bound.isSigned || isLowerNegative == (upperBound < 0)
511-
var delta: Bound.Magnitude
512-
if isLowerNegative {
513-
delta = sameSign
514-
? lowerBound.magnitude - upperBound.magnitude
515-
: lowerBound.magnitude + upperBound.magnitude
516-
} else {
517-
delta = upperBound.magnitude - lowerBound.magnitude
518-
}
519-
if delta == Bound.Magnitude.max {
520-
return Bound(truncatingIfNeeded: generator.next() as Bound.Magnitude)
521-
}
522-
delta += 1
523-
let randomMagnitude = generator.next(upperBound: delta)
524-
if sameSign {
525-
return lowerBound + Bound(randomMagnitude)
526-
} else {
527-
return Bound.isSigned && randomMagnitude <= upperBound.magnitude
528-
? Bound(randomMagnitude)
529-
: 0 - Bound(randomMagnitude - upperBound.magnitude)
530-
}
531-
}
532-
}
533-
534483
extension ClosedRange {
535484
@inlinable
536485
public func overlaps(_ other: ClosedRange<Bound>) -> Bool {

stdlib/public/core/Collection.swift

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,12 +1034,12 @@ extension Collection {
10341034
/// print(randomNumber)
10351035
/// }
10361036
/// // Could print "20", perhaps
1037-
@_inlineable
1038-
public func random(
1039-
using generator: RandomNumberGenerator = Random.default
1037+
@inlinable
1038+
public func random<T: RandomNumberGenerator>(
1039+
using generator: T
10401040
) -> Element? {
10411041
guard !isEmpty else { return nil }
1042-
let random = generator.next(upperBound: UInt(self.count))
1042+
let random = generator.next(upperBound: UInt(count))
10431043
let index = self.index(
10441044
self.startIndex,
10451045
offsetBy: IndexDistance(random),
@@ -1048,6 +1048,31 @@ extension Collection {
10481048
return self[index]
10491049
}
10501050

1051+
/// Returns a random element from this collection.
1052+
///
1053+
/// - Parameter generator: The random number generator to use when getting
1054+
/// a random element.
1055+
/// - Returns: A random element from this collection.
1056+
///
1057+
/// A good example of this is getting a random greeting from an array:
1058+
///
1059+
/// let greetings = ["hi", "hey", "hello", "hola"]
1060+
/// let randomGreeting = greetings.random()
1061+
///
1062+
/// If the collection is empty, the value of this function is `nil`.
1063+
///
1064+
/// let numbers = [10, 20, 30, 40, 50]
1065+
/// if let randomNumber = numbers.random() {
1066+
/// print(randomNumber)
1067+
/// }
1068+
/// // Could print "20", perhaps
1069+
///
1070+
/// This uses the standard library's default random number generator.
1071+
@inlinable
1072+
public func random() -> Element? {
1073+
return random(using: Random.default)
1074+
}
1075+
10511076
/// Do not use this method directly; call advanced(by: n) instead.
10521077
@inlinable
10531078
@inline(__always)

stdlib/public/core/CollectionAlgorithms.swift

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ extension MutableCollection where Self : BidirectionalCollection {
368368
}
369369

370370
//===----------------------------------------------------------------------===//
371-
// shuffled()
371+
// shuffled()/shuffle()
372372
//===----------------------------------------------------------------------===//
373373

374374
extension Sequence {
@@ -377,24 +377,36 @@ extension Sequence {
377377
/// - Parameter generator: The random number generator to use when shuffling
378378
/// the sequence.
379379
/// - Returns: A shuffled array of this sequence's elements.
380-
@_inlineable
381-
public func shuffled(
382-
using generator: RandomNumberGenerator = Random.default
380+
@inlinable
381+
public func shuffled<T: RandomNumberGenerator>(
382+
using generator: T
383383
) -> [Element] {
384384
var result = ContiguousArray(self)
385385
result.shuffle(using: generator)
386386
return Array(result)
387387
}
388+
389+
/// Returns the elements of the sequence, shuffled.
390+
///
391+
/// - Parameter generator: The random number generator to use when shuffling
392+
/// the sequence.
393+
/// - Returns: A shuffled array of this sequence's elements.
394+
///
395+
/// This uses the standard library's default random number generator.
396+
@inlinable
397+
public func shuffled() -> [Element] {
398+
return shuffled(using: Random.default)
399+
}
388400
}
389401

390402
extension MutableCollection {
391403
/// Shuffles the collection in place.
392404
///
393405
/// - Parameter generator: The random number generator to use when shuffling
394406
/// the collection.
395-
@_inlineable
396-
public mutating func shuffle(
397-
using generator: RandomNumberGenerator = Random.default
407+
@inlinable
408+
public mutating func shuffle<T: RandomNumberGenerator>(
409+
using generator: T
398410
) {
399411
guard count > 1 else { return }
400412
var amount = count
@@ -409,6 +421,17 @@ extension MutableCollection {
409421
formIndex(after: &currentIndex)
410422
}
411423
}
424+
425+
/// Shuffles the collection in place.
426+
///
427+
/// - Parameter generator: The random number generator to use when shuffling
428+
/// the collection.
429+
///
430+
/// This uses the standard library's default random number generator.
431+
@inlinable
432+
public mutating func shuffle() {
433+
shuffle(using: Random.default)
434+
}
412435
}
413436

414437
//===----------------------------------------------------------------------===//

stdlib/public/core/FloatingPoint.swift.gyb

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,10 +2413,10 @@ where Self.RawSignificand : FixedWidthInteger,
24132413
/// - Parameter generator: The random number generator to use when getting
24142414
/// the random floating point.
24152415
/// - Returns: A random representation of this floating point.
2416-
@_inlineable
2417-
public static func random(
2416+
@inlinable
2417+
public static func random<T: RandomNumberGenerator>(
24182418
in range: ${Range}<Self>,
2419-
using generator: RandomNumberGenerator = Random.default
2419+
using generator: T
24202420
) -> Self {
24212421
% if 'Closed' not in Range:
24222422
_precondition(
@@ -2425,7 +2425,7 @@ where Self.RawSignificand : FixedWidthInteger,
24252425
)
24262426
% end
24272427
let delta = range.upperBound - range.lowerBound
2428-
let maxSignificand: Self.RawSignificand = 1 << Self.significandBitCount
2428+
let maxSignificand = Self.RawSignificand(1 << (Self.significandBitCount + 1))
24292429
% if 'Closed' not in Range:
24302430
let rand: Self.RawSignificand = generator.next(upperBound: maxSignificand)
24312431
% else:
@@ -2434,14 +2434,23 @@ where Self.RawSignificand : FixedWidthInteger,
24342434
return range.upperBound
24352435
}
24362436
% end
2437-
let unitRandom = Self.init(
2438-
sign: .plus,
2439-
exponentBitPattern: (1 as Self).exponentBitPattern,
2440-
significandBitPattern: rand
2441-
) - 1
2437+
let unitRandom = Self.init(rand) * Self.ulpOfOne / 2
24422438
return delta * unitRandom + range.lowerBound
24432439
}
24442440

2441+
/// Returns a random representation of this floating point within the range.
2442+
///
2443+
/// - Parameter range: A ${Range} to determine the bounds to get a random value
2444+
/// from.
2445+
/// - Parameter generator: The random number generator to use when getting
2446+
/// the random floating point.
2447+
/// - Returns: A random representation of this floating point.
2448+
///
2449+
/// This uses the standard library's default random number generator.
2450+
@inlinable
2451+
public static func random(in range: ${Range}<Self>) -> Self {
2452+
return Self.random(in: range, using: Random.default)
2453+
}
24452454
}
24462455

24472456
% end

0 commit comments

Comments
 (0)