Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active July 6, 2020 23:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/3e7af245367e4ebfc649da030756ed77 to your computer and use it in GitHub Desktop.
Save khanlou/3e7af245367e4ebfc649da030756ed77 to your computer and use it in GitHub Desktop.
A little...ropes course
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