diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index ac4e903b562c0..cf29da88138c9 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -64,6 +64,7 @@ set(SWIFT_BENCH_MODULES single-source/ClassArrayGetter single-source/CodableTest single-source/Combos + single-source/CountAlgo single-source/DataBenchmarks single-source/DeadArray single-source/DevirtualizeProtocolComposition diff --git a/benchmark/single-source/CountAlgo.swift b/benchmark/single-source/CountAlgo.swift new file mode 100644 index 0000000000000..7361c2b5befb3 --- /dev/null +++ b/benchmark/single-source/CountAlgo.swift @@ -0,0 +1,127 @@ +//===--- CountAlgo.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 + +public let benchmarks = [ + BenchmarkInfo( + name: "CountAlgoArray", + runFunction: run_CountAlgoArray, + tags: [.validation, .api]), + BenchmarkInfo( + name: "CountAlgoString", + runFunction: run_CountAlgoString, + tags: [.validation, .api], + legacyFactor: 5), +] + +@inline(never) +public func run_CountAlgoArray(_ N: Int) { + for _ in 1...10*N { + CheckResults(numbers.count(where: { $0 & 4095 == 0 }) == 25) + } +} + +@inline(never) +public func run_CountAlgoString(_ N: Int) { + let vowels = Set("aeiou") + for _ in 1...N { + CheckResults(text.count(where: vowels.contains) == 2014) + } +} + +let numbers = Array(0..<100_000) + +let text = """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempus + dictum tellus placerat ultrices. Proin mauris risus, eleifend a elit ut, + semper consectetur nibh. Nulla ultricies est a vehicula rhoncus. Morbi + sollicitudin efficitur est a hendrerit. Interdum et malesuada fames ac ante + ipsum primis in faucibus. Lorem ipsum dolor sit amet, consectetur + adipiscing elit. Nulla facilisi. Sed euismod sagittis laoreet. Ut elementum + tempus ultrices. Donec convallis mauris at faucibus maximus. + Nullam in nunc sit amet ante tristique elementum quis ut eros. Fusce + dignissim, ante at efficitur dapibus, ex massa convallis nibh, et venenatis + leo leo sit amet nisl. Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Quisque sed mi eu mi rutrum accumsan vel non massa. Nunc condimentum, + arcu eget interdum hendrerit, ipsum mi pretium felis, ut mollis erat metus + non est. Donec eu sapien id urna lobortis eleifend et eu ipsum. Mauris + purus dolor, consequat ac nulla a, vehicula sollicitudin nulla. + Phasellus a congue diam. Curabitur sed orci at sem laoreet facilisis eget + quis est. Pellentesque habitant morbi tristique senectus et netus et + malesuada fames ac turpis egestas. Maecenas justo tellus, efficitur id + velit at, mollis pellentesque mi. Vivamus maximus nibh et ipsum porttitor + facilisis. Curabitur cursus lobortis erat. Sed vitae eros et dolor feugiat + consequat. In ac massa in odio gravida dignissim. Praesent aliquam gravida + ullamcorper. + Etiam feugiat sit amet odio sed tincidunt. Duis dolor odio, posuere at + pretium sed, dignissim eu diam. Aenean eu convallis orci, vitae finibus + erat. Aliquam nec mollis tellus. Morbi luctus sed quam et vestibulum. + Praesent id diam tempus, consectetur tortor vel, auctor orci. Aliquam + congue ex eu sagittis sodales. Suspendisse non convallis nulla. Praesent + elementum semper augue, et fringilla risus ullamcorper id. Fusce eu lorem + sit amet augue fermentum tincidunt. In aliquam libero sit amet dui rhoncus, + ac scelerisque sem porttitor. Cras venenatis, nisi quis ullamcorper + dapibus, odio dolor rutrum magna, vel pellentesque sem lectus in tellus. + Proin faucibus leo iaculis nulla egestas molestie. + Phasellus vitae tortor vitae erat elementum feugiat vel vel enim. Phasellus + fringilla lacus sed venenatis dapibus. Phasellus sagittis vel neque ut + varius. Proin aliquam, lectus sit amet auctor finibus, lorem libero + pellentesque turpis, ac condimentum augue felis sit amet sem. Pellentesque + pharetra nisl nec est congue, in posuere felis maximus. In ut nulla + sodales, pharetra neque et, venenatis dui. Mauris imperdiet, arcu vel + hendrerit vehicula, elit massa consectetur purus, eu blandit nunc orci sit + amet turpis. Vestibulum ultricies id lorem id maximus. Pellentesque + feugiat, lacus et aliquet consequat, mi leo vehicula justo, dapibus dictum + mi quam convallis magna. Quisque id pulvinar dui, consequat gravida nisl. + Nam nec justo venenatis, tincidunt enim a, iaculis odio. Maecenas eget + lorem posuere, euismod nisl vel, pulvinar ex. Maecenas vitae risus ipsum. + Proin congue sem ante, sit amet sagittis odio mattis sit amet. Nullam et + nisi nulla. + Donec vel hendrerit metus. Praesent quis finibus erat. Aliquam erat + volutpat. Fusce sit amet ultricies tellus, vitae dictum dolor. Morbi auctor + dolor vel ligula pretium aliquam. Aenean lobortis vel magna vel ultricies. + Aenean porta urna vitae ornare porta. Quisque pretium dui diam, quis + iaculis odio venenatis non. Maecenas at lacus et ligula tincidunt feugiat + eu vel ipsum. Proin fermentum elit et quam tempus, eget pulvinar nisl + pharetra. + Mauris sodales tempus erat in lobortis. Duis vitae lacinia sapien. + Pellentesque vitae massa eget orci sodales aliquet. Orci varius natoque + penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce + nisi arcu, egestas vel consectetur eu, auctor et metus. In ultricies ligula + felis, vitae pellentesque dolor tempor ac. Praesent mi magna, ultrices ut + ultrices vel, sollicitudin a leo. + Nam porta, nisi in scelerisque consequat, leo lacus accumsan massa, + venenatis faucibus tellus quam eget tellus. Curabitur pulvinar, tellus ac + facilisis consectetur, lacus lacus venenatis est, eu pretium orci augue + gravida nunc. Aenean odio tellus, facilisis et finibus id, varius vitae + diam. Aenean at suscipit sem. Suspendisse porta neque at nibh semper, sit + amet suscipit libero egestas. Donec commodo vitae justo vitae laoreet. + Suspendisse dignissim erat id ante maximus porta. Curabitur hendrerit + maximus odio, et maximus felis malesuada eu. Integer dapibus finibus diam, + quis convallis metus bibendum non. + In vel vulputate nisi, non lacinia nunc. Nullam vitae ligula finibus, + varius arcu in, pellentesque ipsum. Morbi vel velit tincidunt quam cursus + lacinia non in neque. Suspendisse id feugiat nibh. Vestibulum egestas eu + leo viverra fringilla. Curabitur ultrices sollicitudin libero, non sagittis + felis consectetur id. Aenean non metus eget leo ornare porta sed in metus. + Nullam quis fermentum sapien, sit amet sodales mi. Maecenas nec purus urna. + Phasellus condimentum enim nec magna convallis, eu lacinia libero + scelerisque. Suspendisse justo libero, maximus in auctor id, euismod quis + risus. Nam eget augue diam. Ut id risus pulvinar elit consectetur varius. + Aliquam tincidunt tortor pretium feugiat tempor. Nunc nec feugiat ex. + Ut pulvinar augue eget pharetra vehicula. Phasellus malesuada tempor sem, + ut tincidunt velit convallis in. Vivamus luctus libero vitae massa tempus, + id elementum urna iaculis. Sed eleifend quis purus quis convallis. In + rhoncus interdum mollis. Pellentesque dictum euismod felis, eget lacinia + elit blandit vel. Praesent elit velit, pharetra a sodales in, cursus vitae + tortor. In vitae scelerisque tellus. + """ diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index dbc38c3f7654a..3bacfaeea6ded 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -52,6 +52,7 @@ import Chars import ClassArrayGetter import CodableTest import Combos +import CountAlgo import CreateObjects import CxxSetToCollection import CxxStringConversion @@ -245,6 +246,7 @@ register(CharacterRecognizer.benchmarks) register(Chars.benchmarks) register(CodableTest.benchmarks) register(Combos.benchmarks) +register(CountAlgo.benchmarks) register(ClassArrayGetter.benchmarks) register(CreateObjects.benchmarks) register(CxxSetToCollection.benchmarks) diff --git a/stdlib/public/core/SequenceAlgorithms.swift b/stdlib/public/core/SequenceAlgorithms.swift index 05aa8dbcd10a4..01b63fa3c0b02 100644 --- a/stdlib/public/core/SequenceAlgorithms.swift +++ b/stdlib/public/core/SequenceAlgorithms.swift @@ -572,6 +572,48 @@ extension Sequence where Element: Equatable { } } +//===----------------------------------------------------------------------===// +// count(where:) +//===----------------------------------------------------------------------===// + +extension Sequence { + /// Returns the number of elements in the sequence that satisfy the given + /// predicate. + /// + /// You can use this method to count the number of elements that pass a test. + /// The following example finds the number of names that are fewer than + /// five characters long: + /// + /// let names = ["Jacqueline", "Ian", "Amy", "Juan", "Soroush", "Tiffany"] + /// let shortNameCount = names.count(where: { $0.count < 5 }) + /// // shortNameCount == 3 + /// + /// To find the number of times a specific element appears in the sequence, + /// use the equal to operator (`==`) in the closure to test for a match. + /// + /// let birds = ["duck", "duck", "duck", "duck", "goose"] + /// let duckCount = birds.count(where: { $0 == "duck" }) + /// // duckCount == 4 + /// + /// The sequence must be finite. + /// + /// - Parameter predicate: A closure that takes each element of the sequence + /// as its argument and returns a Boolean value indicating whether + /// the element should be included in the count. + /// - Returns: The number of elements in the sequence that satisfy the given + /// predicate. + @_alwaysEmitIntoClient + public func count( + where predicate: (Element) throws(E) -> Bool + ) throws(E) -> Int { + var count = 0 + for e in self { + count += try predicate(e) ? 1 : 0 + } + return count + } +} + //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===// diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 63f43e779c62e..e08854ee59244 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -172,7 +172,9 @@ func rdar21080030() { var s = "Hello" // https://github.com/apple/swift/issues/50141 // This should be 'cannot_call_non_function_value'. - if s.count() == 0 {} // expected-error{{cannot call value of non-function type 'Int'}} {{13-15=}} + if s.count() == 0 {} + // expected-error@-1 {{generic parameter 'E' could not be inferred}} + // expected-error@-2 {{missing argument for parameter 'where' in call}} } // QoI: problem with return type inference mis-diagnosed as invalid arguments @@ -1534,7 +1536,8 @@ func issue63746() { func rdar86611718(list: [Int]) { String(list.count()) - // expected-error@-1 {{cannot call value of non-function type 'Int'}} + // expected-error@-1 {{missing argument for parameter 'where' in call}} + // expected-error@-2 {{generic parameter 'E' could not be inferred}} } // rdar://108977234 - failed to produce diagnostic when argument to AnyHashable parameter doesn't conform to Hashable protocol @@ -1553,18 +1556,18 @@ func testNilCoalescingOperatorRemoveFix() { let _ = "" /* This is a comment */ ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{13-43=}} let _ = "" // This is a comment - ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1555:13-1556:10=}} + ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1559:10=}} let _ = "" // This is a comment /* * The blank line below is part of the test case, do not delete it */ - ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1563:10=}} + ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1561:13-1566:10=}} - if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{9-1566:9=}} + if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{9-1569:9=}} "").isEmpty {} if ("" // This is a comment - ?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1568:9-1569:12=}} + ?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1571:9-1572:12=}} } diff --git a/validation-test/stdlib/SequenceType.swift.gyb b/validation-test/stdlib/SequenceType.swift.gyb index 4643274767296..f3da6a2b88112 100644 --- a/validation-test/stdlib/SequenceType.swift.gyb +++ b/validation-test/stdlib/SequenceType.swift.gyb @@ -628,6 +628,40 @@ SequenceTypeTests.test("allSatisfy/Predicate") { } } +//===----------------------------------------------------------------------===// +// count(where:) +//===----------------------------------------------------------------------===// + +SequenceTypeTests.test("count/Predicate") { + for test in predicateCountTests { + let s = MinimalSequence>( + elements: test.sequence.map { OpaqueValue($0) }) + expectEqual( + test.expected, + s.count(where: { test.includeElement($0.value) }), + stackTrace: SourceLocStack().with(test.loc)) + } +} + +SequenceTypeTests.test("count/Predicate/throws") { + struct E: Error, Equatable {} + + // FIXME: remove `throws(E)` annotations once error type is inferred + do throws(E) { + let c = try ([] as [Int]).count(where: { (_) throws(E) in throw E() }) + expectEqual(c, 0) + } catch { + expectUnreachable() + } + + do throws(E) { + let c = try [1, 2, 3].count(where: { (_) throws(E) in throw E() }) + expectUnreachable() + } catch { + expectEqual(error, E()) + } +} + //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===//