I have given a thought to intrusive lists and I have come up with these protocols.
public protocol Node where Alternate == Self {
associatedtype Alternate
init()
func makeCopy() -> Self
func pinReference()
func unpinReference()
}
public protocol ForwardNode: Node {
var next: Alternate? { get set }
}
public protocol DualNode: ForwardNode {
var previous: Alternate? { get set }
}
init()
is needed to make the empty head node.
makeCopy()
is required to implement copy-on-write.
pinReference()
would be called when a node is added into a collection.
unpinReference()
would be called when a node is removed from a collection.
The implementation of a managed forward node would be following.
final class UnsafeForwardNode<Element> {
var element: Element!
var next: ManagedForwardNode<Element>?
init(_ element: Element! = nil) {
self.element = element
}
}
public struct ManagedForwardNode<Element>: ForwardNode {
public typealias Alternate = ManagedForwardNode<Element>
unowned(unsafe) let instance: UnsafeForwardNode<Element>
public init() {
instance = UnsafeForwardNode<Element>()
}
public init(_ element: Element) {
self.init()
self.element = element
}
private init(_ instance: UnsafeForwardNode<Element>) {
self.instance = instance
}
public var next: ManagedForwardNode<Element>? {
get {
return instance.next
}
set {
instance.next = newValue
}
}
public var element: Element! {
get {
return instance.element
}
set {
instance.element = newValue
}
}
public func makeCopy() -> ManagedForwardNode<Element> {
let copy = ManagedForwardNode<Element>()
copy.instance.element = self.instance.element
copy.instance.next = self.instance.next
return copy
}
public func pinReference() {
let _ = Unmanaged.passRetained(instance)
}
public func unpinReference() {
Unmanaged.passUnretained(instance).release()
}
}
This way a collection could be built where nodes are directly used. I'll be coming up with a reference implementation.