mirror of
https://github.com/samsonjs/CacheCreek.git
synced 2026-03-25 09:05:53 +00:00
160 lines
3.9 KiB
Swift
160 lines
3.9 KiB
Swift
//
|
|
// DoublyLinkedList.swift
|
|
// CacheCreek
|
|
//
|
|
// Created by Sami Samhuri on 2016-08-10.
|
|
//
|
|
|
|
import Dispatch
|
|
import UIKit
|
|
|
|
extension NSIndexPath {
|
|
override public var description: String {
|
|
return "{\(section),\(item)}"
|
|
}
|
|
}
|
|
|
|
struct DoublyLinkedList {
|
|
|
|
typealias Node = DoublyLinkedListNode
|
|
|
|
private(set) var head: Node?
|
|
|
|
private(set) var tail: Node?
|
|
|
|
private(set) var count = 0
|
|
|
|
var isEmpty: Bool {
|
|
return head == nil
|
|
}
|
|
|
|
private func log(m: String) {
|
|
print("[List] \(m) (count=\(count) head=\(head?.description) tail=\(tail?.description))")
|
|
}
|
|
|
|
private func look() {
|
|
print("new look: \(description)")
|
|
}
|
|
|
|
var description: String {
|
|
var nodeDescriptions: [String] = []
|
|
var node = head
|
|
var prev: Node? = nil
|
|
while node != nil {
|
|
if prev !== node!.prev {
|
|
fatalError("prev(\(prev?.description)) !== node.prev(\(node!.prev?.description))")
|
|
}
|
|
nodeDescriptions.append("[\(node!.key.description)]")
|
|
prev = node
|
|
node = node!.next
|
|
if prev!.next !== node {
|
|
fatalError("prev.next(\(prev!.next?.description)) !== node(\(node?.description))")
|
|
}
|
|
}
|
|
if nodeDescriptions.count > 10 {
|
|
let firstRange = nodeDescriptions.startIndex..<nodeDescriptions.startIndex.advancedBy(6)
|
|
let lastRange = nodeDescriptions.endIndex.advancedBy(-6)..<nodeDescriptions.endIndex
|
|
var truncated = Array(nodeDescriptions[firstRange])
|
|
truncated.append("...")
|
|
truncated.appendContentsOf(nodeDescriptions[lastRange])
|
|
nodeDescriptions = truncated
|
|
}
|
|
return "<List:\(nodeDescriptions.joinWithSeparator(" -> "))>"
|
|
}
|
|
|
|
mutating func prepend(key key: AnyKey, value: Any) -> Node {
|
|
log("prepend key \(key.description)")
|
|
let node = Node(key: key, value: value)
|
|
node.next = head
|
|
head?.prev = node
|
|
head = node
|
|
if tail == nil {
|
|
tail = node
|
|
}
|
|
count += 1
|
|
look()
|
|
return node
|
|
}
|
|
|
|
mutating func append(key key: AnyKey, value: Any) -> Node {
|
|
log("append key \(key.description)")
|
|
let node = Node(key: key, value: value)
|
|
node.prev = tail
|
|
tail?.next = node
|
|
tail = node
|
|
if head == nil {
|
|
head = node
|
|
}
|
|
count += 1
|
|
look()
|
|
return node
|
|
}
|
|
|
|
mutating func removeAll() {
|
|
log("remove all")
|
|
head = nil
|
|
tail = nil
|
|
count = 0
|
|
look()
|
|
}
|
|
|
|
mutating func removeLast() -> Node? {
|
|
log("remove last")
|
|
if let node = tail {
|
|
remove(node: node)
|
|
look()
|
|
return node
|
|
}
|
|
look()
|
|
return nil
|
|
}
|
|
|
|
mutating func remove(node node: Node) {
|
|
log("remove node \(node.description)")
|
|
if node === head {
|
|
head = node.next
|
|
}
|
|
if node === tail {
|
|
tail = node.prev
|
|
}
|
|
|
|
node.prev?.next = node.next
|
|
node.next?.prev = node.prev
|
|
node.next = nil
|
|
node.prev = nil
|
|
count -= 1
|
|
if head == nil && tail == nil && count > 0 {
|
|
log("removal fucked up: \(node.description)")
|
|
fatalError("fucked")
|
|
}
|
|
look()
|
|
}
|
|
|
|
mutating func moveToHead(node node: Node) {
|
|
log("move to head: \(node.description)")
|
|
remove(node: node)
|
|
prepend(key: node.key, value: node.value)
|
|
}
|
|
|
|
}
|
|
|
|
class DoublyLinkedListNode {
|
|
|
|
let key: AnyKey
|
|
|
|
let value: Any
|
|
|
|
var next: DoublyLinkedListNode?
|
|
|
|
weak var prev: DoublyLinkedListNode?
|
|
|
|
init(key: AnyKey, value: Any) {
|
|
self.key = key
|
|
self.value = value
|
|
}
|
|
|
|
var description: String {
|
|
return "<Node: key=\(key.description) prev=\(prev?.key.description) next=\(next?.key.description)>"
|
|
}
|
|
|
|
}
|