Last active
July 6, 2020 23:46
-
-
Save khanlou/3e7af245367e4ebfc649da030756ed77 to your computer and use it in GitHub Desktop.
A little...ropes course
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Rope { | |
enum Node: ExpressibleByStringLiteral { | |
case leaf(String, length: Int) | |
indirect case branch(left: Node, right: Node?, length: Int) | |
public init(stringLiteral value: StaticString) { | |
let string = "\(value)" | |
self = .leaf(string, length: string.count) | |
} | |
static func branch(left: Node, right: Node? = nil) -> Node { | |
return .branch(left: left, right: right, length: left.length + (right?.length ?? 0)) | |
} | |
var length: Int { | |
switch self { | |
case let .leaf(_, length): | |
return length | |
case let .branch(left: _, right: _, length): | |
return length | |
} | |
} | |
func character(at index: Int) -> Character { | |
switch self { | |
case let .leaf(string, length) where index < length: | |
return string[string.index(string.startIndex, offsetBy: index)] | |
case let .leaf(string, _): | |
fatalError("Trying to index into a leaf node beyond its bounds. Index: \(index), bounds: \(string.count)") | |
case let .branch(left, right?, _) where left.length <= index: | |
return right.character(at: index - left.length) | |
case let .branch(left, _, _): | |
return left.character(at: index) | |
} | |
} | |
mutating func append(_ node: Node) { | |
self = .branch(left: self, right: node) | |
} | |
func split(at index: Int) -> (left: Node, right: Node) { | |
switch self { | |
case let .leaf(string, length) where index < length: | |
return ( | |
left: .leaf(String(string.prefix(index)), length: index), | |
right: .leaf(String(string.suffix(length-index)), length: length-index) | |
) | |
case let .leaf(string, _): | |
fatalError("Trying to index into a leaf node beyond its bounds. Index: \(index), bounds: \(string.count)") | |
case let .branch(left, right?, _) where left.length <= index: | |
let (rightsLeft, rightsRight) = right.split(at: index - left.length) | |
return ( | |
left: .branch(left: left, right: rightsLeft, length: left.length + rightsLeft.length), | |
right: rightsRight | |
) | |
case let .branch(left, right, _) where index < left.length: | |
let (leftsLeft, leftsRight) = left.split(at: index) | |
return ( | |
left: leftsLeft, | |
right: .branch(left: leftsRight, right: right, length: leftsRight.length + (right?.length ?? 0)) | |
) | |
case .branch: | |
fatalError("Out of bounds split.") | |
} | |
} | |
mutating func insert(_ string: String, at index: Int) { | |
var (left, right) = self.split(at: index) | |
left.append(.leaf(string, length: string.count)) | |
left.append(right) | |
self = left | |
} | |
} | |
private var node: Node | |
init(node: Node) { | |
self.node = node | |
} | |
var length: Int { | |
node.length | |
} | |
func character(at index: Int) -> Character { | |
node.character(at: index) | |
} | |
mutating func append(_ rope: Rope) { | |
self.node.append(rope.node) | |
} | |
mutating func append(_ string: String) { | |
self.append(Rope(node: .leaf(string, length: string.count))) | |
} | |
mutating func split(at index: Int) -> Rope { | |
let (left, right) = self.node.split(at: index) | |
self = Rope(node: left) | |
return Rope(node: right) | |
} | |
mutating func insert(_ string: String, at index: Int) { | |
self.node.insert(string, at: index) | |
} | |
} | |
extension Rope: Collection { | |
var startIndex: Int { 0 } | |
var endIndex: Int { length } | |
subscript(index: Int) -> Character { | |
character(at: index) | |
} | |
func index(after i: Int) -> Int { | |
i + 1 | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment