I'm looking at the Linked List implementation from here, and it shows how the class conforms to the Collection protocol:
extension LinkedList: Collection {
public typealias Index = LinkedListIndex<T>
public var startIndex: Index {
get {
return LinkedListIndex<T>(node: head, tag: 0)
}
}
public var endIndex: Index {
get {
if let h = self.head {
return LinkedListIndex<T>(node: h, tag: count)
} else {
return LinkedListIndex<T>(node: nil, tag: startIndex.tag)
}
}
}
public subscript(position: Index) -> T {
get {
return position.node!.value
}
}
public func index(after idx: Index) -> Index {
return LinkedListIndex<T>(node: idx.node?.next, tag: idx.tag + 1)
}
}
In order to conform to the Collection protocol, the code provided three things: startIndex/endIndex, read-only subscript to get an element, and index(after:).
And order to make this possible, the code also provided LinkedListIndex which is a wrapper object of the linked list in question to make it conform to Comparable:
public struct LinkedListIndex<T>: Comparable {
fileprivate let node: LinkedList<T>.LinkedListNode<T>?
fileprivate let tag: Int
public static func==<T>(lhs: LinkedListIndex<T>, rhs: LinkedListIndex<T>) -> Bool {
return (lhs.tag == rhs.tag)
}
public static func< <T>(lhs: LinkedListIndex<T>, rhs: LinkedListIndex<T>) -> Bool {
return (lhs.tag < rhs.tag)
}
}
I have two questions:
- Why do the elements have to conform to
Comparable? Unlike firstIndex(of:), which requires the elements to beEquatable, I can't seem to find anything on Apple documentation about needing to conform toComparable, or evenEquatable, for things likestartIndex. - How do these tags refer to a specific node? I'm not quite understanding the association between this arbitrary property
tagand index.
Testing
final class LinkListTest: XCTestCase {
func test_linkedList() {
let linkedList = LinkedList<Int>()
for i in stride(from: 0, to: 100, by: 10) {
linkedList.append(i)
}
let startIndex = linkedList.startIndex // startIndex has a tag of 0 because that's how it was instantiated
let expectedStartIndex = LinkedListIndex<Int>(node: linkedList.head, tag: 0)
XCTAssertEqual(startIndex, expectedStartIndex)
let endIndex = linkedList.endIndex // endIndex also has a tag of the count because that's how it was instantiated
let expectedEndIndex = LinkedListIndex<Int>(node: linkedList.last, tag: 10)
XCTAssertEqual(endIndex, expectedEndIndex)
let node = LinkedList.Node(value: 50)
let testIndex = linkedList.index(after: LinkedListIndex<Int>(node: node, tag: 50))
print("testIndex", testIndex) // LinkedListIndex<Int>(node: nil, tag: 51)
}
}
There is no iteration going through every node and associating it with LinkedListIndex to say node C has a tag of 3, D has a tag of 4. How does index(after:) know which node comes after LinkedListIndex<Int>(node: node, tag: 50)?