Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Migrator/overlay4.json
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@
"NodeKind": "Function",
"NodeAnnotation": "Rename",
"ChildIndex": "0",
"LeftUsr": "s:STsE7flatMapySayqd__Gqd__Sg7ElementQzKXEKlF",
"LeftUsr": "s:STsE7flatMapySayqd__Gqd__Sg7ElementQzqd_0_YKXEqd_0_YKs5ErrorRd_0_r0_lF",
"LeftComment": "flatMap",
"RightUsr": "",
"RightComment": "compactMap",
Expand Down
292 changes: 292 additions & 0 deletions stdlib/public/Concurrency/AsyncSequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -485,3 +485,295 @@ extension AsyncSequence where Element: Comparable {
return try await self.max(by: <)
}
}

// These overloads exist to fix the incorrect overload resolution
// when a type conforms to both Sequence and AsyncSequence.
// They are now needed as Sequence methods are generalized for
// typed throws but AsyncSequence methods cannot be generalized yet.
//
// Without these overloads, the below now fails to compile:
// func f() async {
// let ds = DualSequence()
// _ = ds.contains { _ in false }
// |- error: expression is 'async' but is not marked with 'await'
// `- note: call is 'async'
// }
@available(SwiftStdlib 5.1, *)
extension AsyncSequence where Self: Sequence {
/// Returns a Boolean value indicating whether the sequence contains an
/// element that satisfies the given predicate.
///
/// You can use the predicate to check for an element of a type that
/// doesn't conform to the `Equatable` protocol, such as the
/// `HTTPResponse` enumeration in this example.
///
/// enum HTTPResponse {
/// case ok
/// case error(Int)
/// }
///
/// let lastThreeResponses: [HTTPResponse] = [.ok, .ok, .error(404)]
/// let hadError = lastThreeResponses.contains { element in
/// if case .error = element {
/// return true
/// } else {
/// return false
/// }
/// }
/// // 'hadError' == true
///
/// Alternatively, a predicate can be satisfied by a range of `Equatable`
/// elements or a general condition. This example shows how you can check an
/// array for an expense greater than $100.
///
/// let expenses = [21.37, 55.21, 9.32, 10.18, 388.77, 11.41]
/// let hasBigPurchase = expenses.contains { $0 > 100 }
/// // 'hasBigPurchase' == true
///
/// - Parameter predicate: A closure that takes an element of the sequence
/// as its argument and returns a Boolean value that indicates whether
/// the passed element represents a match.
/// - Returns: `true` if the sequence contains an element that satisfies
/// `predicate`; otherwise, `false`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
public func contains(
where predicate: (Element) throws -> Bool
) rethrows -> Bool {
for e in self {
if try predicate(e) {
return true
}
}
return false
}

/// Returns a Boolean value indicating whether every element of a sequence
/// satisfies a given predicate.
///
/// The following code uses this method to test whether all the names in an
/// array have at least five characters:
///
/// let names = ["Sofia", "Camilla", "Martina", "Mateo", "Nicolás"]
/// let allHaveAtLeastFive = names.allSatisfy({ $0.count >= 5 })
/// // allHaveAtLeastFive == true
///
/// If the sequence is empty, this method returns `true`.
///
/// - Parameter predicate: A closure that takes an element of the sequence
/// as its argument and returns a Boolean value that indicates whether
/// the passed element satisfies a condition.
/// - Returns: `true` if the sequence contains only elements that satisfy
/// `predicate`; otherwise, `false`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
public func allSatisfy(
_ predicate: (Element) throws -> Bool
) rethrows -> Bool {
return try !contains { try !predicate($0) }
}

/// Returns the minimum element in the sequence, using the given predicate
/// as the comparison between elements.
///
/// The predicate must be a *strict weak ordering* over the elements. That
/// is, for any elements `a`, `b`, and `c`, the following conditions must
/// hold:
///
/// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
/// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
/// both `true`, then `areInIncreasingOrder(a, c)` is also
/// `true`. (Transitive comparability)
/// - Two elements are *incomparable* if neither is ordered before the other
/// according to the predicate. If `a` and `b` are incomparable, and `b`
/// and `c` are incomparable, then `a` and `c` are also incomparable.
/// (Transitive incomparability)
///
/// This example shows how to use the `min(by:)` method on a
/// dictionary to find the key-value pair with the lowest value.
///
/// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
/// let leastHue = hues.min { a, b in a.value < b.value }
/// print(leastHue)
/// // Prints "Optional((key: "Coral", value: 16))"
///
/// - Parameter areInIncreasingOrder: A predicate that returns `true`
/// if its first argument should be ordered before its second
/// argument; otherwise, `false`.
/// - Returns: The sequence's minimum element, according to
/// `areInIncreasingOrder`. If the sequence has no elements, returns
/// `nil`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
@warn_unqualified_access
public func min(
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> Element? {
var it = makeIterator()
guard var result = it.next() else { return nil }
while let e = it.next() {
if try areInIncreasingOrder(e, result) { result = e }
}
return result
}

/// Returns the maximum element in the sequence, using the given predicate
/// as the comparison between elements.
///
/// The predicate must be a *strict weak ordering* over the elements. That
/// is, for any elements `a`, `b`, and `c`, the following conditions must
/// hold:
///
/// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
/// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
/// both `true`, then `areInIncreasingOrder(a, c)` is also
/// `true`. (Transitive comparability)
/// - Two elements are *incomparable* if neither is ordered before the other
/// according to the predicate. If `a` and `b` are incomparable, and `b`
/// and `c` are incomparable, then `a` and `c` are also incomparable.
/// (Transitive incomparability)
///
/// This example shows how to use the `max(by:)` method on a
/// dictionary to find the key-value pair with the highest value.
///
/// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
/// let greatestHue = hues.max { a, b in a.value < b.value }
/// print(greatestHue)
/// // Prints "Optional((key: "Heliotrope", value: 296))"
///
/// - Parameter areInIncreasingOrder: A predicate that returns `true` if its
/// first argument should be ordered before its second argument;
/// otherwise, `false`.
/// - Returns: The sequence's maximum element if the sequence is not empty;
/// otherwise, `nil`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
@warn_unqualified_access
public func max(
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows -> Element? {
var it = makeIterator()
guard var result = it.next() else { return nil }
while let e = it.next() {
if try areInIncreasingOrder(result, e) { result = e }
}
return result
}

/// Returns the result of combining the elements of the sequence using the
/// given closure.
///
/// Use the `reduce(_:_:)` method to produce a single value from the elements
/// of an entire sequence. For example, you can use this method on an array
/// of numbers to find their sum or product.
///
/// The `nextPartialResult` closure is called sequentially with an
/// accumulating value initialized to `initialResult` and each element of
/// the sequence. This example shows how to find the sum of an array of
/// numbers.
///
/// let numbers = [1, 2, 3, 4]
/// let numberSum = numbers.reduce(0, { x, y in
/// x + y
/// })
/// // numberSum == 10
///
/// When `numbers.reduce(_:_:)` is called, the following steps occur:
///
/// 1. The `nextPartialResult` closure is called with `initialResult`---`0`
/// in this case---and the first element of `numbers`, returning the sum:
/// `1`.
/// 2. The closure is called again repeatedly with the previous call's return
/// value and each element of the sequence.
/// 3. When the sequence is exhausted, the last value returned from the
/// closure is returned to the caller.
///
/// If the sequence has no elements, `nextPartialResult` is never executed
/// and `initialResult` is the result of the call to `reduce(_:_:)`.
///
/// - Parameters:
/// - initialResult: The value to use as the initial accumulating value.
/// `initialResult` is passed to `nextPartialResult` the first time the
/// closure is executed.
/// - nextPartialResult: A closure that combines an accumulating value and
/// an element of the sequence into a new accumulating value, to be used
/// in the next call of the `nextPartialResult` closure or returned to
/// the caller.
/// - Returns: The final accumulated value. If the sequence has no elements,
/// the result is `initialResult`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
public func reduce<Result>(
_ initialResult: Result,
_ nextPartialResult:
(_ partialResult: Result, Element) throws -> Result
) rethrows -> Result {
var accumulator = initialResult
for element in self {
accumulator = try nextPartialResult(accumulator, element)
}
return accumulator
}

/// Returns the result of combining the elements of the sequence using the
/// given closure.
///
/// Use the `reduce(into:_:)` method to produce a single value from the
/// elements of an entire sequence. For example, you can use this method on an
/// array of integers to filter adjacent equal entries or count frequencies.
///
/// This method is preferred over `reduce(_:_:)` for efficiency when the
/// result is a copy-on-write type, for example an Array or a Dictionary.
///
/// The `updateAccumulatingResult` closure is called sequentially with a
/// mutable accumulating value initialized to `initialResult` and each element
/// of the sequence. This example shows how to build a dictionary of letter
/// frequencies of a string.
///
/// let letters = "abracadabra"
/// let letterCount = letters.reduce(into: [:]) { counts, letter in
/// counts[letter, default: 0] += 1
/// }
/// // letterCount == ["a": 5, "b": 2, "r": 2, "c": 1, "d": 1]
///
/// When `letters.reduce(into:_:)` is called, the following steps occur:
///
/// 1. The `updateAccumulatingResult` closure is called with the initial
/// accumulating value---`[:]` in this case---and the first character of
/// `letters`, modifying the accumulating value by setting `1` for the key
/// `"a"`.
/// 2. The closure is called again repeatedly with the updated accumulating
/// value and each element of the sequence.
/// 3. When the sequence is exhausted, the accumulating value is returned to
/// the caller.
///
/// If the sequence has no elements, `updateAccumulatingResult` is never
/// executed and `initialResult` is the result of the call to
/// `reduce(into:_:)`.
///
/// - Parameters:
/// - initialResult: The value to use as the initial accumulating value.
/// - updateAccumulatingResult: A closure that updates the accumulating
/// value with an element of the sequence.
/// - Returns: The final accumulated value. If the sequence has no elements,
/// the result is `initialResult`.
///
/// - Complexity: O(*n*), where *n* is the length of the sequence.
@_alwaysEmitIntoClient
public func reduce<Result>(
into initialResult: __owned Result,
_ updateAccumulatingResult:
(_ partialResult: inout Result, Element) throws -> ()
) rethrows -> Result {
var accumulator = initialResult
for element in self {
try updateAccumulatingResult(&accumulator, element)
}
return accumulator
}
}
22 changes: 19 additions & 3 deletions stdlib/public/core/MigrationSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2026 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
Expand Down Expand Up @@ -536,11 +536,27 @@ extension UnsafeMutableRawBufferPointer {
extension Sequence {
@available(swift, deprecated: 4.1/*, obsoleted: 5.1 */, renamed: "compactMap(_:)",
message: "Please use compactMap(_:) for the case where closure returns an optional value")
public func flatMap<ElementOfResult>(
@_alwaysEmitIntoClient
public func flatMap<ElementOfResult, E: Error>(
_ transform: (Element) throws(E) -> ElementOfResult?
) throws(E) -> [ElementOfResult] {
return try _compactMap(transform)
}

#if !hasFeature(Embedded)
@_spi(SwiftStdlibLegacyABI) @available(swift, obsoleted: 1)
@abi(
func flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) throws -> [ElementOfResult]
)
@usableFromInline
internal func __rethrows_flatMap_deprecated<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult] {
) throws -> [ElementOfResult] {
return try _compactMap(transform)
}
#endif // !hasFeature(Embedded)
}

extension Collection {
Expand Down
Loading