mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[stdlib] Implement reduce with inout (SE-0171)
Implement and document `reduce(into:_:)`, with a few notes: - The `initial` parameter was renamed `initialResult` to match the first parameter in `reduce(_:_:)`. - The unnamed `combining` parameter was renamed `updateAccumulatingResult` to try and resemble the naming of the closure parameter in `reduce(_:_:)`. - The closure throws and `reduce(into:_)` re-throws. - This documentation mentions that `reduce(into:_)` is preferred over `reduce(_:_:)` when the result is a copy-on-write type and an example where the result is a dictionary. Add benchmarks for reduce with accumulation into a scalar, an array, and a dictionary. Update expected error message in closures test (since there are now two `reduce` methods, the diagnostic is different).
This commit is contained in:
@@ -91,6 +91,7 @@ set(SWIFT_BENCH_MODULES
|
||||
single-source/RGBHistogram
|
||||
single-source/RangeAssignment
|
||||
single-source/RecursiveOwnedParameter
|
||||
single-source/ReduceInto
|
||||
single-source/ReversedCollections
|
||||
single-source/SetTests
|
||||
single-source/SevenBoom
|
||||
|
||||
84
benchmark/single-source/ReduceInto.swift
Normal file
84
benchmark/single-source/ReduceInto.swift
Normal file
@@ -0,0 +1,84 @@
|
||||
//===--- ReduceInto.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 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
|
||||
import Foundation
|
||||
|
||||
@inline(never)
|
||||
public func run_ReduceIntoInt(_ N: Int) {
|
||||
let numbers = [Int](0..<1000)
|
||||
|
||||
var c = 0
|
||||
for _ in 1...N*100 {
|
||||
c = c &+ numbers.reduce(into: 0) { (acc: inout Int, num: Int) in
|
||||
acc = acc &+ num
|
||||
}
|
||||
}
|
||||
CheckResults(c != 0)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ReduceIntoArray(_ N: Int) {
|
||||
let numbers = [Int](0..<100)
|
||||
|
||||
var c = 0
|
||||
for _ in 1...N*100 {
|
||||
let a = numbers.reduce(into: []) { (acc: inout [Int], num: Int) in
|
||||
acc.append(num)
|
||||
}
|
||||
c = c &+ a.count
|
||||
}
|
||||
CheckResults(c != 0)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ReduceIntoDictionary(_ N: Int) {
|
||||
let numbers = [Int](0..<100)
|
||||
|
||||
var c = 0
|
||||
for _ in 1...N*100 {
|
||||
let d = numbers.reduce(into: [:]) { (acc: inout [Int: Int], num: Int) in
|
||||
acc[num] = num
|
||||
}
|
||||
c = c &+ d.count
|
||||
}
|
||||
CheckResults(c != 0)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_MapUsingReduceInto(_ N: Int) {
|
||||
let numbers = [Int](0..<100)
|
||||
|
||||
var c = 0
|
||||
let f: (Int) -> Int = { $0 &+ 5 }
|
||||
for _ in 1...N*100 {
|
||||
let a = numbers.reduce(into: []) { (acc: inout [Int], x: Int) in
|
||||
acc.append(f(x))
|
||||
}
|
||||
c = c &+ a.count
|
||||
}
|
||||
CheckResults(c != 0)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_FrequenciesUsingReduceInto(_ N: Int) {
|
||||
let s = "thequickbrownfoxjumpsoverthelazydogusingasmanycharacteraspossible123456789"
|
||||
|
||||
var c = 0
|
||||
for _ in 1...N*100 {
|
||||
let a = s.reduce(into: [:]) { (acc: inout [Character: Int], c: Character) in
|
||||
acc[c, default: 0] += 1
|
||||
}
|
||||
c = c &+ a.count
|
||||
}
|
||||
CheckResults(c != 0)
|
||||
}
|
||||
@@ -96,6 +96,7 @@ import RC4
|
||||
import RGBHistogram
|
||||
import RangeAssignment
|
||||
import RecursiveOwnedParameter
|
||||
import ReduceInto
|
||||
import ReversedCollections
|
||||
import SetTests
|
||||
import SevenBoom
|
||||
@@ -274,6 +275,7 @@ addTo(&precommitTests, "EqualSubstringString", run_EqualSubstringString)
|
||||
addTo(&precommitTests, "EqualSubstringSubstring", run_EqualSubstringSubstring)
|
||||
addTo(&precommitTests, "EqualSubstringSubstringGenericEquatable", run_EqualSubstringSubstringGenericEquatable)
|
||||
addTo(&precommitTests, "ErrorHandling", run_ErrorHandling)
|
||||
addTo(&precommitTests, "FrequenciesUsingReduceInto", run_FrequenciesUsingReduceInto)
|
||||
addTo(&precommitTests, "Hanoi", run_Hanoi)
|
||||
addTo(&precommitTests, "HashTest", run_HashTest)
|
||||
addTo(&precommitTests, "Histogram", run_Histogram)
|
||||
@@ -297,6 +299,7 @@ addTo(&precommitTests, "MapReduceSequence", run_MapReduceSequence)
|
||||
addTo(&precommitTests, "MapReduceShort", run_MapReduceShort)
|
||||
addTo(&precommitTests, "MapReduceShortString", run_MapReduceShortString)
|
||||
addTo(&precommitTests, "MapReduceString", run_MapReduceString)
|
||||
addTo(&precommitTests, "MapUsingReduceInto", run_MapUsingReduceInto)
|
||||
addTo(&precommitTests, "Memset", run_Memset)
|
||||
addTo(&precommitTests, "MonteCarloE", run_MonteCarloE)
|
||||
addTo(&precommitTests, "MonteCarloPi", run_MonteCarloPi)
|
||||
@@ -387,6 +390,9 @@ addTo(&precommitTests, "RGBHistogram", run_RGBHistogram)
|
||||
addTo(&precommitTests, "RGBHistogramOfObjects", run_RGBHistogramOfObjects)
|
||||
addTo(&precommitTests, "RangeAssignment", run_RangeAssignment)
|
||||
addTo(&precommitTests, "RecursiveOwnedParameter", run_RecursiveOwnedParameter)
|
||||
addTo(&precommitTests, "ReduceIntoArray", run_ReduceIntoArray)
|
||||
addTo(&precommitTests, "ReduceIntoDictionary", run_ReduceIntoDictionary)
|
||||
addTo(&precommitTests, "ReduceIntoInt", run_ReduceIntoInt)
|
||||
addTo(&precommitTests, "ReversedArray", run_ReversedArray)
|
||||
addTo(&precommitTests, "ReversedBidirectional", run_ReversedBidirectional)
|
||||
addTo(&precommitTests, "ReversedDictionary", run_ReversedDictionary)
|
||||
|
||||
@@ -596,6 +596,61 @@ extension Sequence {
|
||||
}
|
||||
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`.
|
||||
@_inlineable
|
||||
public func reduce<Result>(
|
||||
into initialResult: Result,
|
||||
_ updateAccumulatingResult:
|
||||
(_ partialResult: inout Result, Element) throws -> ()
|
||||
) rethrows -> Result {
|
||||
var accumulator = initialResult
|
||||
for element in self {
|
||||
try updateAccumulatingResult(&accumulator, element)
|
||||
}
|
||||
return accumulator
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@@ -164,7 +164,7 @@ func testMap() {
|
||||
}
|
||||
|
||||
// <rdar://problem/22414757> "UnresolvedDot" "in wrong phase" assertion from verifier
|
||||
[].reduce { $0 + $1 } // expected-error {{missing argument for parameter #1 in call}}
|
||||
[].reduce { $0 + $1 } // expected-error {{cannot invoke 'reduce' with an argument list of type '((_, _) -> _)'}}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user