Skip to content

Commit 8e7f8fc

Browse files
committed
Expand index traversal tests, remove formIndex(_:offsetBy:)
The current index traversal tests didn't invoke every single index method, so we need a few additional tests. Also run them all on the `Deque.Indices` collection too. `formIndex(_:offsetBy:)` turns out not to actually be declared in any stdlib collection protocol, instead it's just an extension on `Collection`. Remove our implementations of it in favor of just using the standard extension. This way the same code is invoked when calling it on the `Deque` directly as when calling it on a generic type bound by `Collection`.
1 parent 6f4dc64 commit 8e7f8fc

File tree

2 files changed

+44
-36
lines changed

2 files changed

+44
-36
lines changed

Diff for: Sources/Deque/Deque.swift

+17-29
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,8 @@ public struct Deque<Element>: RandomAccessCollection, MutableCollection {
189189
return _storage.header.index(before: i)
190190
}
191191

192-
@inlinable
193-
public func formIndex(_ i: inout Index, offsetBy distance: Int) {
194-
_storage.header.formIndex(&i, offsetBy: distance)
195-
}
192+
// Note: formIndex(_:offsetBy:) is not actually declared in any collection protocol, it's
193+
// instead provided as an extension using index(_:offsetBy:), so we can skip it.
196194

197195
@inlinable
198196
public func index(_ i: Index, offsetBy distance: Int) -> Index {
@@ -854,11 +852,6 @@ public struct Deque<Element>: RandomAccessCollection, MutableCollection {
854852
return _header.index(before: i)
855853
}
856854

857-
@inlinable
858-
public func formIndex(_ i: inout Index, offsetBy distance: Int) {
859-
_header.formIndex(&i, offsetBy: distance)
860-
}
861-
862855
@inlinable
863856
public func index(_ i: Index, offsetBy distance: Int) -> Index {
864857
return _header.index(i, offsetBy: distance)
@@ -1267,36 +1260,31 @@ internal struct _DequeHeader {
12671260
}
12681261

12691262
@inlinable
1270-
func formIndex(_ i: inout Index, offsetBy distance: Int) {
1263+
func index(_ i: Index, offsetBy distance: Int) -> Index {
1264+
var rawValue = i._rawValue
12711265
if distance > 0 {
1272-
let wasHead = i._rawValue < Index._tailFlag
1273-
i._rawValue += UInt(bitPattern: distance)
1274-
if wasHead && i._rawValue >= UInt(bitPattern: capacity) && tailCount > 0 {
1266+
let wasHead = rawValue < Index._tailFlag
1267+
rawValue += UInt(bitPattern: distance)
1268+
if wasHead && rawValue >= UInt(bitPattern: capacity) && tailCount > 0 {
12751269
// Wrap around
1276-
i._rawValue = (i._rawValue &- UInt(bitPattern: capacity)) | Index._tailFlag
1270+
rawValue = (rawValue &- UInt(bitPattern: capacity)) | Index._tailFlag
12771271
}
12781272
} else if distance < 0 {
1279-
if i._rawValue >= Index._tailFlag {
1280-
i._rawValue &+= UInt(bitPattern: distance) // equivalent to signed addition
1281-
if i._rawValue < Index._tailFlag {
1273+
if rawValue >= Index._tailFlag {
1274+
rawValue &+= UInt(bitPattern: distance) // equivalent to signed addition
1275+
if rawValue < Index._tailFlag {
12821276
// We subtracted past the beginning of the tail
1283-
let result = UInt(bitPattern: capacity).subtractingReportingOverflow(Index._tailFlag &- i._rawValue)
1277+
let result = UInt(bitPattern: capacity).subtractingReportingOverflow(Index._tailFlag &- rawValue)
12841278
precondition(!result.overflow, "Attempted to create invalid index") // Report better error on overflow
1285-
i._rawValue = result.partialValue
1279+
rawValue = result.partialValue
12861280
}
12871281
} else {
1288-
let newValue = i._rawValue &+ UInt(bitPattern: distance) // equivalent to signed addition
1289-
precondition(newValue < i._rawValue, "Attempted to create invalid index") // Report error on overflow
1290-
i._rawValue = newValue
1282+
let newValue = rawValue &+ UInt(bitPattern: distance) // equivalent to signed addition
1283+
precondition(newValue < rawValue, "Attempted to create invalid index") // Report error on overflow
1284+
rawValue = newValue
12911285
}
12921286
}
1293-
}
1294-
1295-
@inlinable
1296-
func index(_ i: Index, offsetBy distance: Int) -> Index {
1297-
var i = i
1298-
formIndex(&i, offsetBy: distance)
1299-
return i
1287+
return Index(_rawValue: rawValue)
13001288
}
13011289

13021290
@inlinable

Diff for: Tests/DequeTests/DequeTests.swift

+27-7
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,33 @@ final class DequeTests: XCTestCase {
236236
XCTAssertEqual(buf.count, buf.capacity, "buffer count should equal capacity")
237237
})
238238

239-
// call this function multiple times so we know which input produced which errors
240-
validateIndexTraversals(emptyDeque)
241-
validateIndexTraversals(oneElemDeque)
242-
validateIndexTraversals(dequeWithCapacity)
243-
validateIndexTraversals(dequeWithLeadingCapacity)
244-
validateIndexTraversals(dequeWithTail)
245-
validateIndexTraversals(dequeWithTailNoGap)
239+
func runTests(_ deque: Deque<IntClass>, line: UInt = #line) {
240+
func validate<C: RandomAccessCollection>(_ collection: C, line: UInt) {
241+
validateIndexTraversals(collection, line: line)
242+
// validateIndexTraversals doesn't test all index methods. In particular, for every
243+
// nonmutating/mutating pair (such as index(before:) and formIndex(before:)) it only
244+
// picks one of them. Add a few tests of our own to ensure coverage.
245+
if !collection.isEmpty {
246+
var idx = collection.startIndex
247+
collection.formIndex(after: &idx)
248+
XCTAssertEqual(idx, collection.index(after: collection.startIndex), "formIndex(after:) vs index(after:)", line: line)
249+
idx = collection.endIndex
250+
collection.formIndex(before: &idx)
251+
XCTAssertEqual(idx, collection.index(before: collection.endIndex), "formIndex(before:) vs index(before:)", line: line)
252+
// formIndex(_:offsetBy:) is not actually part of the protocol (it's an
253+
// extension) so we can skip it.
254+
}
255+
}
256+
validate(deque, line: line)
257+
validate(deque.indices, line: line)
258+
}
259+
260+
runTests(emptyDeque)
261+
runTests(oneElemDeque)
262+
runTests(dequeWithCapacity)
263+
runTests(dequeWithLeadingCapacity)
264+
runTests(dequeWithTail)
265+
runTests(dequeWithTailNoGap)
246266
}
247267

248268
func testAppendReallocation() {

0 commit comments

Comments
 (0)