Skip to content

Commit 38e1370

Browse files
authored
Revert "Revert count(where:)" (#70816)
* Revert "Revert count(where:)" This reverts commit 779ea19. Now that SE-0220 has been re-accepted, this adds the `count(where:)` Sequence method to the standard library.
1 parent 8b22079 commit 38e1370

File tree

6 files changed

+215
-6
lines changed

6 files changed

+215
-6
lines changed

benchmark/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ set(SWIFT_BENCH_MODULES
6464
single-source/ClassArrayGetter
6565
single-source/CodableTest
6666
single-source/Combos
67+
single-source/CountAlgo
6768
single-source/DataBenchmarks
6869
single-source/DeadArray
6970
single-source/DevirtualizeProtocolComposition
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//===--- CountAlgo.swift --------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
import TestsUtils
13+
14+
public let benchmarks = [
15+
BenchmarkInfo(
16+
name: "CountAlgoArray",
17+
runFunction: run_CountAlgoArray,
18+
tags: [.validation, .api]),
19+
BenchmarkInfo(
20+
name: "CountAlgoString",
21+
runFunction: run_CountAlgoString,
22+
tags: [.validation, .api],
23+
legacyFactor: 5),
24+
]
25+
26+
@inline(never)
27+
public func run_CountAlgoArray(_ N: Int) {
28+
for _ in 1...10*N {
29+
CheckResults(numbers.count(where: { $0 & 4095 == 0 }) == 25)
30+
}
31+
}
32+
33+
@inline(never)
34+
public func run_CountAlgoString(_ N: Int) {
35+
let vowels = Set("aeiou")
36+
for _ in 1...N {
37+
CheckResults(text.count(where: vowels.contains) == 2014)
38+
}
39+
}
40+
41+
let numbers = Array(0..<100_000)
42+
43+
let text = """
44+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempus
45+
dictum tellus placerat ultrices. Proin mauris risus, eleifend a elit ut,
46+
semper consectetur nibh. Nulla ultricies est a vehicula rhoncus. Morbi
47+
sollicitudin efficitur est a hendrerit. Interdum et malesuada fames ac ante
48+
ipsum primis in faucibus. Lorem ipsum dolor sit amet, consectetur
49+
adipiscing elit. Nulla facilisi. Sed euismod sagittis laoreet. Ut elementum
50+
tempus ultrices. Donec convallis mauris at faucibus maximus.
51+
Nullam in nunc sit amet ante tristique elementum quis ut eros. Fusce
52+
dignissim, ante at efficitur dapibus, ex massa convallis nibh, et venenatis
53+
leo leo sit amet nisl. Lorem ipsum dolor sit amet, consectetur adipiscing
54+
elit. Quisque sed mi eu mi rutrum accumsan vel non massa. Nunc condimentum,
55+
arcu eget interdum hendrerit, ipsum mi pretium felis, ut mollis erat metus
56+
non est. Donec eu sapien id urna lobortis eleifend et eu ipsum. Mauris
57+
purus dolor, consequat ac nulla a, vehicula sollicitudin nulla.
58+
Phasellus a congue diam. Curabitur sed orci at sem laoreet facilisis eget
59+
quis est. Pellentesque habitant morbi tristique senectus et netus et
60+
malesuada fames ac turpis egestas. Maecenas justo tellus, efficitur id
61+
velit at, mollis pellentesque mi. Vivamus maximus nibh et ipsum porttitor
62+
facilisis. Curabitur cursus lobortis erat. Sed vitae eros et dolor feugiat
63+
consequat. In ac massa in odio gravida dignissim. Praesent aliquam gravida
64+
ullamcorper.
65+
Etiam feugiat sit amet odio sed tincidunt. Duis dolor odio, posuere at
66+
pretium sed, dignissim eu diam. Aenean eu convallis orci, vitae finibus
67+
erat. Aliquam nec mollis tellus. Morbi luctus sed quam et vestibulum.
68+
Praesent id diam tempus, consectetur tortor vel, auctor orci. Aliquam
69+
congue ex eu sagittis sodales. Suspendisse non convallis nulla. Praesent
70+
elementum semper augue, et fringilla risus ullamcorper id. Fusce eu lorem
71+
sit amet augue fermentum tincidunt. In aliquam libero sit amet dui rhoncus,
72+
ac scelerisque sem porttitor. Cras venenatis, nisi quis ullamcorper
73+
dapibus, odio dolor rutrum magna, vel pellentesque sem lectus in tellus.
74+
Proin faucibus leo iaculis nulla egestas molestie.
75+
Phasellus vitae tortor vitae erat elementum feugiat vel vel enim. Phasellus
76+
fringilla lacus sed venenatis dapibus. Phasellus sagittis vel neque ut
77+
varius. Proin aliquam, lectus sit amet auctor finibus, lorem libero
78+
pellentesque turpis, ac condimentum augue felis sit amet sem. Pellentesque
79+
pharetra nisl nec est congue, in posuere felis maximus. In ut nulla
80+
sodales, pharetra neque et, venenatis dui. Mauris imperdiet, arcu vel
81+
hendrerit vehicula, elit massa consectetur purus, eu blandit nunc orci sit
82+
amet turpis. Vestibulum ultricies id lorem id maximus. Pellentesque
83+
feugiat, lacus et aliquet consequat, mi leo vehicula justo, dapibus dictum
84+
mi quam convallis magna. Quisque id pulvinar dui, consequat gravida nisl.
85+
Nam nec justo venenatis, tincidunt enim a, iaculis odio. Maecenas eget
86+
lorem posuere, euismod nisl vel, pulvinar ex. Maecenas vitae risus ipsum.
87+
Proin congue sem ante, sit amet sagittis odio mattis sit amet. Nullam et
88+
nisi nulla.
89+
Donec vel hendrerit metus. Praesent quis finibus erat. Aliquam erat
90+
volutpat. Fusce sit amet ultricies tellus, vitae dictum dolor. Morbi auctor
91+
dolor vel ligula pretium aliquam. Aenean lobortis vel magna vel ultricies.
92+
Aenean porta urna vitae ornare porta. Quisque pretium dui diam, quis
93+
iaculis odio venenatis non. Maecenas at lacus et ligula tincidunt feugiat
94+
eu vel ipsum. Proin fermentum elit et quam tempus, eget pulvinar nisl
95+
pharetra.
96+
Mauris sodales tempus erat in lobortis. Duis vitae lacinia sapien.
97+
Pellentesque vitae massa eget orci sodales aliquet. Orci varius natoque
98+
penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce
99+
nisi arcu, egestas vel consectetur eu, auctor et metus. In ultricies ligula
100+
felis, vitae pellentesque dolor tempor ac. Praesent mi magna, ultrices ut
101+
ultrices vel, sollicitudin a leo.
102+
Nam porta, nisi in scelerisque consequat, leo lacus accumsan massa,
103+
venenatis faucibus tellus quam eget tellus. Curabitur pulvinar, tellus ac
104+
facilisis consectetur, lacus lacus venenatis est, eu pretium orci augue
105+
gravida nunc. Aenean odio tellus, facilisis et finibus id, varius vitae
106+
diam. Aenean at suscipit sem. Suspendisse porta neque at nibh semper, sit
107+
amet suscipit libero egestas. Donec commodo vitae justo vitae laoreet.
108+
Suspendisse dignissim erat id ante maximus porta. Curabitur hendrerit
109+
maximus odio, et maximus felis malesuada eu. Integer dapibus finibus diam,
110+
quis convallis metus bibendum non.
111+
In vel vulputate nisi, non lacinia nunc. Nullam vitae ligula finibus,
112+
varius arcu in, pellentesque ipsum. Morbi vel velit tincidunt quam cursus
113+
lacinia non in neque. Suspendisse id feugiat nibh. Vestibulum egestas eu
114+
leo viverra fringilla. Curabitur ultrices sollicitudin libero, non sagittis
115+
felis consectetur id. Aenean non metus eget leo ornare porta sed in metus.
116+
Nullam quis fermentum sapien, sit amet sodales mi. Maecenas nec purus urna.
117+
Phasellus condimentum enim nec magna convallis, eu lacinia libero
118+
scelerisque. Suspendisse justo libero, maximus in auctor id, euismod quis
119+
risus. Nam eget augue diam. Ut id risus pulvinar elit consectetur varius.
120+
Aliquam tincidunt tortor pretium feugiat tempor. Nunc nec feugiat ex.
121+
Ut pulvinar augue eget pharetra vehicula. Phasellus malesuada tempor sem,
122+
ut tincidunt velit convallis in. Vivamus luctus libero vitae massa tempus,
123+
id elementum urna iaculis. Sed eleifend quis purus quis convallis. In
124+
rhoncus interdum mollis. Pellentesque dictum euismod felis, eget lacinia
125+
elit blandit vel. Praesent elit velit, pharetra a sodales in, cursus vitae
126+
tortor. In vitae scelerisque tellus.
127+
"""

benchmark/utils/main.swift

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import Chars
5252
import ClassArrayGetter
5353
import CodableTest
5454
import Combos
55+
import CountAlgo
5556
import CreateObjects
5657
import CxxSetToCollection
5758
import CxxStringConversion
@@ -245,6 +246,7 @@ register(CharacterRecognizer.benchmarks)
245246
register(Chars.benchmarks)
246247
register(CodableTest.benchmarks)
247248
register(Combos.benchmarks)
249+
register(CountAlgo.benchmarks)
248250
register(ClassArrayGetter.benchmarks)
249251
register(CreateObjects.benchmarks)
250252
register(CxxSetToCollection.benchmarks)

stdlib/public/core/SequenceAlgorithms.swift

+42
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,48 @@ extension Sequence where Element: Equatable {
572572
}
573573
}
574574

575+
//===----------------------------------------------------------------------===//
576+
// count(where:)
577+
//===----------------------------------------------------------------------===//
578+
579+
extension Sequence {
580+
/// Returns the number of elements in the sequence that satisfy the given
581+
/// predicate.
582+
///
583+
/// You can use this method to count the number of elements that pass a test.
584+
/// The following example finds the number of names that are fewer than
585+
/// five characters long:
586+
///
587+
/// let names = ["Jacqueline", "Ian", "Amy", "Juan", "Soroush", "Tiffany"]
588+
/// let shortNameCount = names.count(where: { $0.count < 5 })
589+
/// // shortNameCount == 3
590+
///
591+
/// To find the number of times a specific element appears in the sequence,
592+
/// use the equal to operator (`==`) in the closure to test for a match.
593+
///
594+
/// let birds = ["duck", "duck", "duck", "duck", "goose"]
595+
/// let duckCount = birds.count(where: { $0 == "duck" })
596+
/// // duckCount == 4
597+
///
598+
/// The sequence must be finite.
599+
///
600+
/// - Parameter predicate: A closure that takes each element of the sequence
601+
/// as its argument and returns a Boolean value indicating whether
602+
/// the element should be included in the count.
603+
/// - Returns: The number of elements in the sequence that satisfy the given
604+
/// predicate.
605+
@_alwaysEmitIntoClient
606+
public func count<E>(
607+
where predicate: (Element) throws(E) -> Bool
608+
) throws(E) -> Int {
609+
var count = 0
610+
for e in self {
611+
count += try predicate(e) ? 1 : 0
612+
}
613+
return count
614+
}
615+
}
616+
575617
//===----------------------------------------------------------------------===//
576618
// reduce()
577619
//===----------------------------------------------------------------------===//

test/Constraints/diagnostics.swift

+9-6
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ func rdar21080030() {
172172
var s = "Hello"
173173
// https://github.com/apple/swift/issues/50141
174174
// This should be 'cannot_call_non_function_value'.
175-
if s.count() == 0 {} // expected-error{{cannot call value of non-function type 'Int'}} {{13-15=}}
175+
if s.count() == 0 {}
176+
// expected-error@-1 {{generic parameter 'E' could not be inferred}}
177+
// expected-error@-2 {{missing argument for parameter 'where' in call}}
176178
}
177179

178180
// <rdar://problem/21248136> QoI: problem with return type inference mis-diagnosed as invalid arguments
@@ -1534,7 +1536,8 @@ func issue63746() {
15341536

15351537
func rdar86611718(list: [Int]) {
15361538
String(list.count())
1537-
// expected-error@-1 {{cannot call value of non-function type 'Int'}}
1539+
// expected-error@-1 {{missing argument for parameter 'where' in call}}
1540+
// expected-error@-2 {{generic parameter 'E' could not be inferred}}
15381541
}
15391542

15401543
// rdar://108977234 - failed to produce diagnostic when argument to AnyHashable parameter doesn't conform to Hashable protocol
@@ -1553,18 +1556,18 @@ func testNilCoalescingOperatorRemoveFix() {
15531556
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=}}
15541557

15551558
let _ = "" // This is a comment
1556-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1555:13-1556:10=}}
1559+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1559:10=}}
15571560

15581561
let _ = "" // This is a comment
15591562
/*
15601563
* The blank line below is part of the test case, do not delete it
15611564
*/
15621565

1563-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1563:10=}}
1566+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1561:13-1566:10=}}
15641567

1565-
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=}}
1568+
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=}}
15661569
"").isEmpty {}
15671570

15681571
if ("" // This is a comment
1569-
?? "").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=}}
1572+
?? "").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=}}
15701573
}

validation-test/stdlib/SequenceType.swift.gyb

+34
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,40 @@ SequenceTypeTests.test("allSatisfy/Predicate") {
628628
}
629629
}
630630

631+
//===----------------------------------------------------------------------===//
632+
// count(where:)
633+
//===----------------------------------------------------------------------===//
634+
635+
SequenceTypeTests.test("count/Predicate") {
636+
for test in predicateCountTests {
637+
let s = MinimalSequence<OpaqueValue<Int>>(
638+
elements: test.sequence.map { OpaqueValue($0) })
639+
expectEqual(
640+
test.expected,
641+
s.count(where: { test.includeElement($0.value) }),
642+
stackTrace: SourceLocStack().with(test.loc))
643+
}
644+
}
645+
646+
SequenceTypeTests.test("count/Predicate/throws") {
647+
struct E: Error, Equatable {}
648+
649+
// FIXME: remove `throws(E)` annotations once error type is inferred
650+
do throws(E) {
651+
let c = try ([] as [Int]).count(where: { (_) throws(E) in throw E() })
652+
expectEqual(c, 0)
653+
} catch {
654+
expectUnreachable()
655+
}
656+
657+
do throws(E) {
658+
let c = try [1, 2, 3].count(where: { (_) throws(E) in throw E() })
659+
expectUnreachable()
660+
} catch {
661+
expectEqual(error, E())
662+
}
663+
}
664+
631665
//===----------------------------------------------------------------------===//
632666
// reduce()
633667
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)