I have implemented a linked list in Swift. Code that uses this data structure can append, insert, etc., a new node into the list by providing an element of the generic type. In other words, the list holds nodes and each node holds a reference or instance of the type, and callers simply pass the T type element to insert into the list (not wasting lines of code creating a node they don't need to know about). Here are some pieces of the code defining the linked list (with tons of irrelevant stuff removed):
public class LinkedListNode<T> {
init( value: T ) {
self.value = value
}
public var next: LinkedListNode?
public weak var previous: LinkedListNode?
public var value: T
}
struct LinkedList<T>: Sequence {
internal var head: LinkedListNode<T>?
internal unowned var tail: LinkedListNode<T>?
@discardableResult public mutating func insert( _ value: T, after: LinkedListNode<T> ) -> LinkedListNode<T> {
if after === tail {
return append( value )
} else {
let node = LinkedListNode<T>( value: value )
insertBetween( node, after: after, before: after.previous )
return node
}
}
...
}
This all works great. I only had a medium amount of trouble finding documentation that explained how to make the Sequence protocol work right.
Now I want to add a function to add or replace an element in the list. I want the caller to pass in something of type T and I want to check to see if it exists so it can be replaced. I want to add the new element if it doesn't already exist. The problem is that I want to compare two T types to see if they are the same instance of an object of the list has objects in it (within the nodes) but compare for content equality if the list has structs or just native types like Int, within it.
I can do this outside of the linked list code because I have a first() function. Maybe that's a better choice. But I would still like to know if it's possible to write code that let's me do an appropriate equality test depending on the type of thing that the list contains.
This is what I was working on when I got to this problem:
@discardableResult public mutating func replaceOrAppend( _ value: T ) -> LinkedListNode<T> {
var node = first( where: { $0.value === value } )
if node == nil {
node = LinkedListNode<T>( value: value )
insertBetween( node!, after: tail, before: tail?.next )
tail = node
}
return node!
}
Notice that I used === for the comparison. Unless I define T as T:AnyObject, this will fail to compile. I want this to work to compare the content of structs and native types and the references for class objects.