Skip to content

Commit 8537f01

Browse files
author
Dave Abrahams
committed
[stdlib] Add lazy and Array filter algorithm
This came up during API review Swift SVN r18364
1 parent 41439be commit 8537f01

File tree

5 files changed

+203
-0
lines changed

5 files changed

+203
-0
lines changed

stdlib/core/Arrays.swift.gyb

+6
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ extension ${Self} : ArrayType {
232232

233233
return result
234234
}
235+
236+
/// Return a ${Self} containg the elements `x` of `self` for which
237+
/// `includeElement(x)` is `true`
238+
func filter(includeElement: (T)->Bool) -> ${Self} {
239+
return ${Self}(Swift.filter(self, includeElement))
240+
}
235241
}
236242

237243
extension ${Self} : Reflectable {

stdlib/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ set(SWIFTLIB_ESSENTIAL
3838
Dictionary.swift
3939
EmptyCollection.swift
4040
Existential.swift
41+
Filter.swift
4142
FixedPoint.swift.gyb
4243
FloatingPoint.swift.gyb
4344
FloatingPointOperations.swift

stdlib/core/Filter.swift

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===--- Filter.swift - Lazily filter the elements of a Sequence ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// The `Generator` used by `FilterSequenceView` and
14+
/// `FilterCollectionView`
15+
struct FilterGenerator<Base: Generator> : Generator, Sequence {
16+
mutating func next() -> Base.Element? {
17+
var n: Base.Element?
18+
for/*ever*/;; {
19+
n = _base.next()
20+
if n ? _include(n!) : true {
21+
return n
22+
}
23+
}
24+
}
25+
26+
func generate() -> FilterGenerator {
27+
return self
28+
}
29+
30+
var _base: Base
31+
var _include: (Base.Element)->Bool
32+
}
33+
34+
/// The lazy `Sequence` returned by `filter(c)` where `c` is a
35+
/// `Sequence`
36+
struct FilterSequenceView<Base: Sequence> : Sequence {
37+
func generate() -> FilterGenerator<Base.GeneratorType> {
38+
return FilterGenerator(_base: _base.generate(), _include: _include)
39+
}
40+
41+
var _base: Base
42+
var _include: (Base.GeneratorType.Element)->Bool
43+
}
44+
45+
/// The `IndexType` used for subscripting a `FilterCollectionView`
46+
struct FilterCollectionViewIndex<Base: Collection> : ForwardIndex {
47+
func succ() -> FilterCollectionViewIndex {
48+
for nextPos in _pos.succ().._end {
49+
if _include(_base[nextPos]) {
50+
return FilterCollectionViewIndex(
51+
_pos: nextPos, _end: _end,
52+
_base: _base, _include: _include)
53+
}
54+
}
55+
return FilterCollectionViewIndex(
56+
_pos: _end, _end: _end, _base: _base, _include: _include)
57+
}
58+
var _pos: Base.IndexType
59+
var _end: Base.IndexType
60+
var _base: Base
61+
var _include: (Base.GeneratorType.Element)->Bool
62+
}
63+
64+
func == <Base: Collection>(
65+
lhs: FilterCollectionViewIndex<Base>,
66+
rhs: FilterCollectionViewIndex<Base>
67+
) -> Bool {
68+
return lhs._pos == rhs._pos
69+
}
70+
71+
/// The lazy `Collection` returned by `filter(c)` where `c` is a
72+
/// `Collection`
73+
struct FilterCollectionView<Base: Collection> : Collection {
74+
75+
typealias IndexType = FilterCollectionViewIndex<Base>
76+
var startIndex: IndexType {
77+
var first = _base.startIndex
78+
while first != _base.endIndex {
79+
if _include(_base[first]) {
80+
break
81+
}
82+
++first
83+
}
84+
return FilterCollectionViewIndex(
85+
_pos: first, _end: _base.endIndex, _base: _base, _include: _include)
86+
}
87+
88+
var endIndex: IndexType {
89+
return FilterCollectionViewIndex(
90+
_pos: _base.endIndex, _end: _base.endIndex,
91+
_base: _base, _include: _include)
92+
}
93+
94+
subscript(index: IndexType) -> Base.GeneratorType.Element {
95+
return _base[index._pos]
96+
}
97+
98+
func generate() -> FilterGenerator<Base.GeneratorType> {
99+
return FilterGenerator(_base: _base.generate(), _include: _include)
100+
}
101+
102+
var _base: Base
103+
var _include: (Base.GeneratorType.Element)->Bool
104+
}
105+
106+
/// Return a lazy Sequence containing the elements `x` of `source` for
107+
/// which `includeElement(x)` is `true`
108+
func filter<S:Sequence>(
109+
source: S, includeElement: (S.GeneratorType.Element)->Bool
110+
) -> FilterSequenceView<S> {
111+
return FilterSequenceView(_base: source, _include: includeElement)
112+
}
113+
114+
/// Return a lazy Collection containing the elements `x` of `source` for
115+
/// which `includeElement(x)` is `true`
116+
func filter<C:Collection>(
117+
source: C, includeElement: (C.GeneratorType.Element)->Bool
118+
) -> FilterCollectionView<C> {
119+
return FilterCollectionView(_base: source, _include: includeElement)
120+
}

test/stdlib/Array.swift

+7
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,12 @@ func testCopy() {
7979
}
8080
testCopy()
8181

82+
func testFilter() {
83+
let a = Array(3..16)
84+
println(a.filter { $0 % 4 == 0 })
85+
// CHECK-NEXT: [4, 8, 12]
86+
}
87+
testFilter()
88+
8289
println("done!") // CHECK-NEXT: {{^done!$}}
8390

test/stdlib/Filter.swift

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===--- Filter.swift - tests for lazy filtering --------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// RUN: %target-run-simple-swift | FileCheck %s
13+
14+
// CHECK: testing...
15+
println("testing...")
16+
17+
func printlnByGenerating<S: Sequence>(s: S) {
18+
print("<")
19+
var prefix = ""
20+
for x in s {
21+
print("\(prefix)\(x)")
22+
prefix = ", "
23+
}
24+
println(">")
25+
}
26+
27+
func printlnByIndexing<C: Collection>(c: C) {
28+
printlnByGenerating(
29+
PermutationGenerator(elements: c, indices: indices(c))
30+
)
31+
}
32+
33+
// Test filtering Collections
34+
if true {
35+
let f0 = filter(0..30) { $0 % 7 == 0 }
36+
37+
// CHECK-NEXT: <0, 7, 14, 21, 28>
38+
printlnByGenerating(f0)
39+
// CHECK-NEXT: <0, 7, 14, 21, 28>
40+
printlnByIndexing(f0)
41+
42+
// Also try when the first element of the underlying sequence
43+
// doesn't pass the filter
44+
let f1 = filter(1..30) { $0 % 7 == 0 }
45+
46+
// CHECK-NEXT: <7, 14, 21, 28>
47+
printlnByGenerating(f1)
48+
// CHECK-NEXT: <7, 14, 21, 28>
49+
printlnByIndexing(f1)
50+
}
51+
52+
53+
// Test filtering Sequences
54+
if true {
55+
let f0 = filter((0..30).generate()) { $0 % 7 == 0 }
56+
57+
// CHECK-NEXT: <0, 7, 14, 21, 28>
58+
printlnByGenerating(f0)
59+
60+
// Also try when the first element of the underlying sequence
61+
// doesn't pass the filter
62+
let f1 = filter((1..30).generate()) { $0 % 7 == 0 }
63+
64+
// CHECK-NEXT: <7, 14, 21, 28>
65+
printlnByGenerating(f1)
66+
}
67+
68+
// CHECK-NEXT: all done.
69+
println("all done.")

0 commit comments

Comments
 (0)