Skip to content

Commit c2c1b84

Browse files
committed
Add overloads for range types to IndexSet
The Swift 3 refactoring of the range type has led to its split into 4 different types. The IndexSet API should accept any of these as long as they contain the element type (Int, which is inherently Countable). This allows callers to use both the ... and ..< syntax, for example. This commit also adds additional unit tests for some of the IndexSet API, and turns a few methods with optional/default args into properties or a method family, since otherwise callers would end up with an ambigious method call as the range argument would have been defaulted to nil. <rdar://problem/26532614> Add overloads for range types to IndexSet
1 parent b9adb29 commit c2c1b84

File tree

2 files changed

+185
-21
lines changed

2 files changed

+185
-21
lines changed

stdlib/public/SDK/Foundation/IndexSet.swift

Lines changed: 120 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,13 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
307307
_handle = _MutablePairHandle(NSIndexSet(indexesIn: _toNSRange(range)), copying: false)
308308
}
309309

310+
/// Initialize an `IndexSet` with a range of integers.
311+
public init(integersIn range: ClosedRange<Element>) { self.init(integersIn: Range(range)) }
312+
/// Initialize an `IndexSet` with a range of integers.
313+
public init(integersIn range: CountableClosedRange<Element>) { self.init(integersIn: Range(range)) }
314+
/// Initialize an `IndexSet` with a range of integers.
315+
public init(integersIn range: CountableRange<Element>) { self.init(integersIn: Range(range)) }
316+
310317
/// Initialize an `IndexSet` with a single integer.
311318
public init(integer: Element) {
312319
_handle = _MutablePairHandle(NSIndexSet(index: integer), copying: false)
@@ -329,14 +336,35 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
329336
public func makeIterator() -> IndexingIterator<IndexSet> {
330337
return IndexingIterator(_elements: self)
331338
}
332-
339+
340+
/// Returns a `Range`-based view of the entire contents of `self`.
341+
///
342+
/// - seealso: rangeView(of:)
343+
public var rangeView : RangeView {
344+
return RangeView(indexSet: self, intersecting: nil)
345+
}
346+
333347
/// Returns a `Range`-based view of `self`.
334348
///
335-
/// - parameter range: A subrange of `self` to view. The default value is `nil`, which means that the entire `IndexSet` is used.
336-
public func rangeView(of range : Range<Element>? = nil) -> RangeView {
349+
/// - parameter range: A subrange of `self` to view.
350+
public func rangeView(of range : Range<Element>) -> RangeView {
337351
return RangeView(indexSet: self, intersecting: range)
338352
}
339353

354+
/// Returns a `Range`-based view of `self`.
355+
///
356+
/// - parameter range: A subrange of `self` to view.
357+
public func rangeView(of range : ClosedRange<Element>) -> RangeView { return self.rangeView(of: Range(range)) }
358+
/// Returns a `Range`-based view of `self`.
359+
///
360+
/// - parameter range: A subrange of `self` to view.
361+
public func rangeView(of range : CountableClosedRange<Element>) -> RangeView { return self.rangeView(of: Range(range)) }
362+
/// Returns a `Range`-based view of `self`.
363+
///
364+
/// - parameter range: A subrange of `self` to view.
365+
public func rangeView(of range : CountableRange<Element>) -> RangeView { return self.rangeView(of: Range(range)) }
366+
367+
340368
private func _indexOfRange(containing integer : Element) -> RangeView.Index? {
341369
let result = _handle.map {
342370
__NSIndexSetIndexOfRangeContainingIndex($0, UInt(integer))
@@ -440,12 +468,39 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
440468
let resultLast = Index(indexSet: self, index: integerLessThanOrEqualTo(range.upperBound - 1))
441469
return resultFirst..<resultLast.successor()
442470
}
471+
472+
/// Return a `Range<IndexSet.Index>` which can be used to subscript the index set.
473+
///
474+
/// The resulting range is the range of the intersection of the integers in `range` with the index set.
475+
///
476+
/// - parameter range: The range of integers to include.
477+
public func indexRange(in range: CountableRange<Element>) -> Range<Index> { return self.indexRange(in: Range(range)) }
478+
/// Return a `Range<IndexSet.Index>` which can be used to subscript the index set.
479+
///
480+
/// The resulting range is the range of the intersection of the integers in `range` with the index set.
481+
///
482+
/// - parameter range: The range of integers to include.
483+
public func indexRange(in range: ClosedRange<Element>) -> Range<Index> { return self.indexRange(in: Range(range)) }
484+
/// Return a `Range<IndexSet.Index>` which can be used to subscript the index set.
485+
///
486+
/// The resulting range is the range of the intersection of the integers in `range` with the index set.
487+
///
488+
/// - parameter range: The range of integers to include.
489+
public func indexRange(in range: CountableClosedRange<Element>) -> Range<Index> { return self.indexRange(in: Range(range)) }
490+
443491

444492
/// Returns the count of integers in `self` that intersect `range`.
445493
public func count(in range: Range<Element>) -> Int {
446494
return _handle.map { $0.countOfIndexes(in: _toNSRange(range)) }
447495
}
448-
496+
497+
/// Returns the count of integers in `self` that intersect `range`.
498+
public func count(in range: CountableRange<Element>) -> Int { return self.count(in: Range(range)) }
499+
/// Returns the count of integers in `self` that intersect `range`.
500+
public func count(in range: ClosedRange<Element>) -> Int { return self.count(in: Range(range)) }
501+
/// Returns the count of integers in `self` that intersect `range`.
502+
public func count(in range: CountableClosedRange<Element>) -> Int { return self.count(in: Range(range)) }
503+
449504
/// Returns `true` if `self` contains `integer`.
450505
public func contains(_ integer: Element) -> Bool {
451506
return _handle.map { $0.contains(integer) }
@@ -455,6 +510,14 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
455510
public func contains(integersIn range: Range<Element>) -> Bool {
456511
return _handle.map { $0.contains(in: _toNSRange(range)) }
457512
}
513+
514+
/// Returns `true` if `self` contains all of the integers in `range`.
515+
public func contains(integersIn range: CountableRange<Element>) -> Bool { return self.contains(integersIn: Range(range)) }
516+
/// Returns `true` if `self` contains all of the integers in `range`.
517+
public func contains(integersIn range: ClosedRange<Element>) -> Bool { return self.contains(integersIn: Range(range)) }
518+
/// Returns `true` if `self` contains all of the integers in `range`.
519+
public func contains(integersIn range: CountableClosedRange<Element>) -> Bool { return self.contains(integersIn: Range(range)) }
520+
458521

459522
/// Returns `true` if `self` contains any of the integers in `indexSet`.
460523
public func contains(integersIn indexSet: IndexSet) -> Bool {
@@ -465,7 +528,14 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
465528
public func intersects(integersIn range: Range<Element>) -> Bool {
466529
return _handle.map { $0.intersects(in: _toNSRange(range)) }
467530
}
468-
531+
532+
/// Returns `true` if `self` intersects any of the integers in `range`.
533+
public func intersects(integersIn range: CountableRange<Element>) -> Bool { return self.intersects(integersIn: Range(range)) }
534+
/// Returns `true` if `self` intersects any of the integers in `range`.
535+
public func intersects(integersIn range: ClosedRange<Element>) -> Bool { return self.intersects(integersIn: Range(range)) }
536+
/// Returns `true` if `self` intersects any of the integers in `range`.
537+
public func intersects(integersIn range: CountableClosedRange<Element>) -> Bool { return self.intersects(integersIn: Range(range)) }
538+
469539
// MARK: -
470540
// Indexable
471541

@@ -498,11 +568,11 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
498568
// This algorithm is naïve but it works. We could avoid calling insert in some cases.
499569

500570
var result = IndexSet()
501-
for r in self.rangeView() {
571+
for r in self.rangeView {
502572
result.insert(integersIn: Range(r))
503573
}
504574

505-
for r in other.rangeView() {
575+
for r in other.rangeView {
506576
result.insert(integersIn: Range(r))
507577
}
508578
return result
@@ -610,23 +680,37 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
610680
public mutating func insert(integersIn range: Range<Element>) {
611681
_applyMutation { $0.add(in: _toNSRange(range)) }
612682
}
613-
683+
684+
/// Insert a range of integers into the `IndexSet`.
685+
public mutating func insert(integersIn range: CountableRange<Element>) { self.insert(integersIn: Range(range)) }
686+
/// Insert a range of integers into the `IndexSet`.
687+
public mutating func insert(integersIn range: ClosedRange<Element>) { self.insert(integersIn: Range(range)) }
688+
/// Insert a range of integers into the `IndexSet`.
689+
public mutating func insert(integersIn range: CountableClosedRange<Element>) { self.insert(integersIn: Range(range)) }
690+
614691
/// Remove a range of integers from the `IndexSet`.
615692
public mutating func remove(integersIn range: Range<Element>) {
616693
_applyMutation { $0.remove(in: _toNSRange(range)) }
617694
}
618695

696+
/// Remove a range of integers from the `IndexSet`.
697+
public mutating func remove(integersIn range: CountableRange<Element>) { self.remove(integersIn: Range(range)) }
698+
/// Remove a range of integers from the `IndexSet`.
699+
public mutating func remove(integersIn range: ClosedRange<Element>) { self.remove(integersIn: Range(range)) }
700+
/// Remove a range of integers from the `IndexSet`.
701+
public mutating func remove(integersIn range: CountableClosedRange<Element>) { self.remove(integersIn: Range(range)) }
702+
619703
/// Returns `true` if self contains no values.
620704
public var isEmpty : Bool {
621705
return self.count == 0
622706
}
623707

624708
/// Returns an IndexSet filtered according to the result of `includeInteger`.
625709
///
626-
/// - parameter range: A range of integers. For each integer in the range that intersects the integers in the IndexSet, then the `includeInteger predicate will be invoked. Pass `nil` (the default) to use the entire range.
710+
/// - parameter range: A range of integers. For each integer in the range that intersects the integers in the IndexSet, then the `includeInteger` predicate will be invoked.
627711
/// - parameter includeInteger: The predicate which decides if an integer will be included in the result or not.
628-
public func filteredIndexSet(in range : Range<Element>? = nil, includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet {
629-
let r : NSRange = range != nil ? _toNSRange(range!) : NSMakeRange(0, NSNotFound - 1)
712+
public func filteredIndexSet(in range : Range<Element>, includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet {
713+
let r : NSRange = _toNSRange(range)
630714
return try _handle.map {
631715
var error : ErrorProtocol? = nil
632716
let result = $0.indexes(in: r, options: [], passingTest: { (i, stop) -> Bool in
@@ -647,6 +731,29 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio
647731
}
648732
}
649733

734+
/// Returns an IndexSet filtered according to the result of `includeInteger`.
735+
///
736+
/// - parameter range: A range of integers. For each integer in the range that intersects the integers in the IndexSet, then the `includeInteger` predicate will be invoked.
737+
/// - parameter includeInteger: The predicate which decides if an integer will be included in the result or not.
738+
public func filteredIndexSet(in range : CountableRange<Element>, includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet { return try self.filteredIndexSet(in: Range(range), includeInteger: includeInteger) }
739+
/// Returns an IndexSet filtered according to the result of `includeInteger`.
740+
///
741+
/// - parameter range: A range of integers. For each integer in the range that intersects the integers in the IndexSet, then the `includeInteger` predicate will be invoked.
742+
/// - parameter includeInteger: The predicate which decides if an integer will be included in the result or not.
743+
public func filteredIndexSet(in range : ClosedRange<Element>, includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet { return try self.filteredIndexSet(in: Range(range), includeInteger: includeInteger) }
744+
/// Returns an IndexSet filtered according to the result of `includeInteger`.
745+
///
746+
/// - parameter range: A range of integers. For each integer in the range that intersects the integers in the IndexSet, then the `includeInteger` predicate will be invoked.
747+
/// - parameter includeInteger: The predicate which decides if an integer will be included in the result or not.
748+
public func filteredIndexSet(in range : CountableClosedRange<Element>, includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet { return try self.filteredIndexSet(in: Range(range), includeInteger: includeInteger) }
749+
750+
/// Returns an IndexSet filtered according to the result of `includeInteger`.
751+
///
752+
/// - parameter includeInteger: The predicate which decides if an integer will be included in the result or not.
753+
public func filteredIndexSet(includeInteger: @noescape (Element) throws -> Bool) rethrows -> IndexSet {
754+
return try self.filteredIndexSet(in: 0..<NSNotFound-1, includeInteger: includeInteger)
755+
}
756+
650757
/// For a positive delta, shifts the indexes in [index, INT_MAX] to the right, thereby inserting an "empty space" [index, delta], for a negative delta, shifts the indexes in [index, INT_MAX] to the left, thereby deleting the indexes in the range [index - delta, delta].
651758
public mutating func shift(startingAt integer: Element, by delta: IndexSet.IndexDistance) {
652759
_applyMutation { $0.shiftIndexesStarting(at: integer, by: delta) }
@@ -716,8 +823,8 @@ private struct IndexSetBoundaryIterator : IteratorProtocol {
716823
private var i2UsedFirst : Bool
717824

718825
private init(_ is1 : IndexSet, _ is2 : IndexSet) {
719-
i1 = is1.rangeView().makeIterator()
720-
i2 = is2.rangeView().makeIterator()
826+
i1 = is1.rangeView.makeIterator()
827+
i2 = is2.rangeView.makeIterator()
721828

722829
i1Range = i1.next()
723830
i2Range = i2.next()

test/1_stdlib/TestIndexSet.swift

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TestIndexSetSuper { }
2323
class TestIndexSet : TestIndexSetSuper {
2424

2525
func testEnumeration() {
26-
let someIndexes = IndexSet(integersIn: 3..<5)
26+
let someIndexes = IndexSet(integersIn: 3...4)
2727
let first = someIndexes.startIndex
2828
let last = someIndexes.endIndex
2929

@@ -99,6 +99,62 @@ class TestIndexSet : TestIndexSetSuper {
9999
someIndexes.insert(11)
100100

101101
expectEqual(someIndexes.count, 7)
102+
103+
someIndexes.remove(11)
104+
105+
expectEqual(someIndexes.count, 6)
106+
107+
someIndexes.insert(integersIn: 100...101)
108+
expectEqual(8, someIndexes.count)
109+
expectEqual(2, someIndexes.count(in: 100...101))
110+
111+
someIndexes.remove(integersIn: 100...101)
112+
expectEqual(6, someIndexes.count)
113+
expectEqual(0, someIndexes.count(in: 100...101))
114+
115+
someIndexes.insert(integersIn: 200..<202)
116+
expectEqual(8, someIndexes.count)
117+
expectEqual(2, someIndexes.count(in: 200..<202))
118+
119+
someIndexes.remove(integersIn: 200..<202)
120+
expectEqual(6, someIndexes.count)
121+
expectEqual(0, someIndexes.count(in: 200..<202))
122+
}
123+
124+
func testContainsAndIntersects() {
125+
let someIndexes = IndexSet(integersIn: 1..<10)
126+
127+
expectTrue(someIndexes.contains(integersIn: 1..<10))
128+
expectTrue(someIndexes.contains(integersIn: 1...9))
129+
expectTrue(someIndexes.contains(integersIn: 2..<10))
130+
expectTrue(someIndexes.contains(integersIn: 2...9))
131+
expectTrue(someIndexes.contains(integersIn: 1..<9))
132+
expectTrue(someIndexes.contains(integersIn: 1...8))
133+
134+
expectFalse(someIndexes.contains(integersIn: 0..<10))
135+
expectFalse(someIndexes.contains(integersIn: 0...9))
136+
expectFalse(someIndexes.contains(integersIn: 2..<11))
137+
expectFalse(someIndexes.contains(integersIn: 2...10))
138+
expectFalse(someIndexes.contains(integersIn: 0..<9))
139+
expectFalse(someIndexes.contains(integersIn: 0...8))
140+
141+
expectTrue(someIndexes.intersects(integersIn: 1..<10))
142+
expectTrue(someIndexes.intersects(integersIn: 1...9))
143+
expectTrue(someIndexes.intersects(integersIn: 2..<10))
144+
expectTrue(someIndexes.intersects(integersIn: 2...9))
145+
expectTrue(someIndexes.intersects(integersIn: 1..<9))
146+
expectTrue(someIndexes.intersects(integersIn: 1...8))
147+
148+
expectTrue(someIndexes.intersects(integersIn: 0..<10))
149+
expectTrue(someIndexes.intersects(integersIn: 0...9))
150+
expectTrue(someIndexes.intersects(integersIn: 2..<11))
151+
expectTrue(someIndexes.intersects(integersIn: 2...10))
152+
expectTrue(someIndexes.intersects(integersIn: 0..<9))
153+
expectTrue(someIndexes.intersects(integersIn: 0...8))
154+
155+
expectFalse(someIndexes.intersects(integersIn: 0..<0))
156+
expectFalse(someIndexes.intersects(integersIn: 10...12))
157+
expectFalse(someIndexes.intersects(integersIn: 10..<12))
102158
}
103159

104160
func testIteration() {
@@ -148,7 +204,7 @@ class TestIndexSet : TestIndexSetSuper {
148204
someIndexes.insert(15)
149205

150206
var count = 0
151-
for r in someIndexes.rangeView() {
207+
for r in someIndexes.rangeView {
152208
// print("\(r)")
153209
count += 1
154210
if count == 3 {
@@ -159,7 +215,7 @@ class TestIndexSet : TestIndexSetSuper {
159215

160216
// Backwards
161217
count = 0
162-
for r in someIndexes.rangeView().reversed() {
218+
for r in someIndexes.rangeView.reversed() {
163219
// print("\(r)")
164220
count += 1
165221
if count == 3 {
@@ -177,7 +233,7 @@ class TestIndexSet : TestIndexSetSuper {
177233
someIndexes.insert(integersIn: 60..<80)
178234

179235
var count = 0
180-
for _ in someIndexes.rangeView() {
236+
for _ in someIndexes.rangeView {
181237
count += 1
182238
}
183239
expectEqual(5, count)
@@ -196,7 +252,7 @@ class TestIndexSet : TestIndexSetSuper {
196252
expectEqual(3, count)
197253

198254
count = 0
199-
for r in someIndexes.rangeView(of: 0..<35) {
255+
for r in someIndexes.rangeView(of: 0...34) {
200256
if count == 0 {
201257
expectEqual(r, 2..<5)
202258
}
@@ -249,7 +305,7 @@ class TestIndexSet : TestIndexSetSuper {
249305
expectEqual(8, someIndexes.count(in: 5..<25))
250306
expectEqual(8, count)
251307

252-
r = someIndexes.indexRange(in: 100..<200)
308+
r = someIndexes.indexRange(in: 100...199)
253309
expectTrue(r.isEmpty)
254310

255311
let emptySlice = someIndexes[r]
@@ -280,7 +336,7 @@ class TestIndexSet : TestIndexSetSuper {
280336
expectEqual(count, 0)
281337

282338
count = 0
283-
for _ in empty.rangeView() {
339+
for _ in empty.rangeView {
284340
count += 1
285341
}
286342

@@ -337,7 +393,7 @@ class TestIndexSet : TestIndexSetSuper {
337393
someIndexes.insert(integersIn: 8..<11)
338394
someIndexes.insert(15)
339395

340-
let resultArray = someIndexes.rangeView().filter { $0.count > 1 }
396+
let resultArray = someIndexes.rangeView.filter { $0.count > 1 }
341397
expectEqual(resultArray.count, 2)
342398
}
343399

@@ -701,6 +757,7 @@ IndexSetTests.test("testEnumeration") { TestIndexSet().testEnumeration() }
701757
IndexSetTests.test("testSubsequence") { TestIndexSet().testSubsequence() }
702758
IndexSetTests.test("testIndexRange") { TestIndexSet().testIndexRange() }
703759
IndexSetTests.test("testMutation") { TestIndexSet().testMutation() }
760+
IndexSetTests.test("testContainsAndIntersects") { TestIndexSet().testContainsAndIntersects() }
704761
IndexSetTests.test("testIteration") { TestIndexSet().testIteration() }
705762
IndexSetTests.test("testRangeIteration") { TestIndexSet().testRangeIteration() }
706763
IndexSetTests.test("testSubrangeIteration") { TestIndexSet().testSubrangeIteration() }

0 commit comments

Comments
 (0)