Skip to content

Commit 39a0c07

Browse files
committed
Restore the .concurrent options for block-based enumerateObjects(…) methods in NSArray.
- These methods are implemented as (relevant NSIndexSet).enumerate(options: options…), so the fix goes in NSIndexSet. - Includes NSArray tests.
1 parent ce0122b commit 39a0c07

File tree

2 files changed

+110
-4
lines changed

2 files changed

+110
-4
lines changed

Diff for: Foundation/NSIndexSet.swift

-4
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,6 @@ open class NSIndexSet : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
377377
}
378378

379379
internal func _enumerateWithOptions<P, R>(_ opts : NSEnumerationOptions, range: NSRange, paramType: P.Type, returnType: R.Type, block: (P, UnsafeMutablePointer<ObjCBool>) -> R) -> Int? {
380-
guard !opts.contains(.concurrent) else {
381-
NSUnimplemented()
382-
}
383-
384380
guard let startRangeIndex = self._indexOfRangeAfterOrContainingIndex(range.location), let endRangeIndex = _indexOfRangeBeforeOrContainingIndex(NSMaxRange(range) - 1) else {
385381
return nil
386382
}

Diff for: TestFoundation/TestNSArray.swift

+110
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class TestNSArray : XCTestCase {
2727
("test_constructors", test_constructors),
2828
("test_constructorWithCopyItems", test_constructorWithCopyItems),
2929
("test_enumeration", test_enumeration),
30+
("test_enumerationUsingBlock", test_enumerationUsingBlock),
3031
("test_sequenceType", test_sequenceType),
3132
("test_objectAtIndex", test_objectAtIndex),
3233
("test_binarySearch", test_binarySearch),
@@ -123,6 +124,115 @@ class TestNSArray : XCTestCase {
123124
XCTAssertNil(reverseEmpty.nextObject())
124125
}
125126

127+
func test_enumerationUsingBlock() {
128+
let array : NSArray = NSArray(array: Array(0..<100))
129+
let createIndexesArrayHavingSeen = { (havingSeen: IndexSet) in
130+
return (0 ..< array.count).map { havingSeen.contains($0) }
131+
}
132+
133+
let noIndexes = IndexSet()
134+
let allIndexes = IndexSet(integersIn: 0 ..< array.count)
135+
let firstHalfOfIndexes = IndexSet(integersIn: 0 ..< array.count / 2)
136+
let lastHalfOfIndexes = IndexSet(integersIn: array.count / 2 ..< array.count)
137+
let evenIndexes : IndexSet = {
138+
var indexes = IndexSet()
139+
for index in allIndexes.filter({ $0 % 2 == 0 }) {
140+
indexes.insert(index)
141+
}
142+
return indexes
143+
}()
144+
145+
let testExpectingToSee = { (expectation: IndexSet, block: (inout UnsafeMutableBufferPointer<Bool>) -> Void) in
146+
var indexesSeen = createIndexesArrayHavingSeen(noIndexes)
147+
indexesSeen.withUnsafeMutableBufferPointer(block)
148+
XCTAssertEqual(indexesSeen, createIndexesArrayHavingSeen(expectation))
149+
}
150+
151+
// Test enumerateObjects(_:), allowing it to run to completion...
152+
153+
testExpectingToSee(allIndexes) { (indexesSeen) in
154+
array.enumerateObjects { (value, index, stop) in
155+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
156+
indexesSeen[index] = true
157+
}
158+
}
159+
160+
// ... and stopping after the first half:
161+
162+
testExpectingToSee(firstHalfOfIndexes) { (indexesSeen) in
163+
array.enumerateObjects { (value, index, stop) in
164+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
165+
166+
if firstHalfOfIndexes.contains(index) {
167+
indexesSeen[index] = true
168+
} else {
169+
stop.pointee = true
170+
}
171+
}
172+
}
173+
174+
// -----
175+
// Test enumerateObjects(options:using) and enumerateObjects(at:options:using:):
176+
177+
// Test each of these options combinations:
178+
let optionsToTest : [NSEnumerationOptions] = [
179+
[],
180+
[.concurrent],
181+
[.reverse],
182+
[.concurrent, .reverse],
183+
]
184+
185+
for options in optionsToTest {
186+
// Run to completion,
187+
testExpectingToSee(allIndexes) { (indexesSeen) in
188+
array.enumerateObjects(options: options, using: { (value, index, stop) in
189+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
190+
indexesSeen[index] = true
191+
})
192+
}
193+
194+
// run it only for half the indexes (use the right half depending on where we start),
195+
let indexesForHalfEnumeration = options.contains(.reverse) ? lastHalfOfIndexes : firstHalfOfIndexes
196+
197+
testExpectingToSee(indexesForHalfEnumeration) { (indexesSeen) in
198+
array.enumerateObjects(options: options, using: { (value, index, stop) in
199+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
200+
201+
if indexesForHalfEnumeration.contains(index) {
202+
indexesSeen[index] = true
203+
} else {
204+
stop.pointee = true
205+
}
206+
})
207+
}
208+
209+
// run only for a specific index set to test the at:… variant,
210+
testExpectingToSee(evenIndexes) { (indexesSeen) in
211+
array.enumerateObjects(at: evenIndexes, options: options, using: { (value, index, stop) in
212+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
213+
indexesSeen[index] = true
214+
})
215+
}
216+
217+
// and run for some indexes only to test stopping.
218+
var indexesForStaggeredEnumeration = indexesForHalfEnumeration
219+
indexesForStaggeredEnumeration.formIntersection(evenIndexes)
220+
221+
testExpectingToSee(indexesForStaggeredEnumeration) { (indexesSeen) in
222+
array.enumerateObjects(at: evenIndexes, options: options, using: { (value, index, stop) in
223+
XCTAssertEqual(value as! NSNumber, array[index] as! NSNumber)
224+
225+
if (indexesForStaggeredEnumeration.contains(index)) {
226+
indexesSeen[index] = true
227+
} else {
228+
stop.pointee = true
229+
}
230+
})
231+
}
232+
}
233+
234+
}
235+
126236
func test_sequenceType() {
127237
let array : NSArray = ["foo", "bar", "baz"]
128238
var res = [String]()

0 commit comments

Comments
 (0)