|
21 | 21 | (right
|
22 | 22 | :initarg :right
|
23 | 23 | :initform nil
|
24 |
| - :accessor branch-right))) |
| 24 | + :accessor branch-right)) |
| 25 | + (:documentation "A node with left and right children.")) |
25 | 26 |
|
26 | 27 | (defclass leaf (rope)
|
27 | 28 | ((string
|
28 | 29 | :initarg :string
|
29 | 30 | :initform ""
|
30 |
| - :accessor leaf-string))) |
| 31 | + :accessor leaf-string)) |
| 32 | + (:documentation "A string segment of a rope.")) |
31 | 33 |
|
32 | 34 | ;;-------;;
|
33 | 35 | ;; Utils ;;
|
34 | 36 | ;;-------;;
|
35 | 37 |
|
36 | 38 | (defgeneric make-rope (source)
|
| 39 | + (:documentation "Create a new rope from a string.") |
| 40 | + (:method ((source rope)) |
| 41 | + source) |
37 | 42 | (:method ((source string))
|
38 | 43 | (let ((length (length source)))
|
39 | 44 | (if (<= *long-leaf* length)
|
|
58 | 63 | ;;-----------;;
|
59 | 64 |
|
60 | 65 | (defgeneric walk-rope (rope func)
|
| 66 | + (:documentation "Call `func' on each leaf of a rope in order.") |
61 | 67 | (:method ((rope leaf) func)
|
62 | 68 | (funcall func rope)
|
63 | 69 | (values))
|
|
66 | 72 | (walk-rope (branch-right rope) func)))
|
67 | 73 |
|
68 | 74 | (defun write-rope (rope out)
|
| 75 | + "Write a rope to a stream or string, like `format', nil output returns a string." |
69 | 76 | (if (null out)
|
70 | 77 | (with-output-to-string (s) (write-rope rope s))
|
71 | 78 | (walk-rope rope
|
|
77 | 84 | (walk-rope rope (lambda (leaf) (push leaf leaves)))
|
78 | 85 | (nreverse leaves)))
|
79 | 86 |
|
| 87 | +;;-----------;; |
| 88 | +;; Balancing ;; |
| 89 | +;;-----------;; |
| 90 | + |
80 | 91 | (defun normalize-leaves (leaves &optional carry)
|
81 | 92 | (let ((leaf (car leaves)))
|
82 | 93 | (cond ((and carry (null leaf))
|
|
91 | 102 | (t
|
92 | 103 | (cons leaf (normalize-leaves (cdr leaves)))))))
|
93 | 104 |
|
94 |
| -;;-----------;; |
95 |
| -;; Balancing ;; |
96 |
| -;;-----------;; |
97 |
| - |
98 | 105 | (defgeneric balancedp (rope)
|
| 106 | + (:documentation "Check if a rope is a height-balanced tree.") |
99 | 107 | (:method ((rope leaf))
|
100 | 108 | t)
|
101 | 109 | (:method ((rope branch))
|
|
114 | 122 | (merge-leaves leaves mid end)))))))
|
115 | 123 |
|
116 | 124 | (defun balance-rope (rope &optional forcep)
|
| 125 | + "Balance a rope by reconstructing it from the bottom up." |
117 | 126 | (if (and (balancedp rope) (not forcep))
|
118 | 127 | rope
|
119 | 128 | (let ((leaves (normalize-leaves (collect-rope rope))))
|
|
124 | 133 | ;;--------;;
|
125 | 134 |
|
126 | 135 | (defgeneric prepend-rope (rope source)
|
| 136 | + (:documentation "Return a new rope with a string or rope inserted at the beginning of a rope.") |
127 | 137 | (:method (rope (source string))
|
128 | 138 | (concat-rope (make-rope source) rope))
|
129 | 139 | (:method (rope (source rope))
|
130 | 140 | (concat-rope source rope)))
|
131 | 141 |
|
132 | 142 | (defgeneric append-rope (rope source)
|
| 143 | + (:documentation "Return a new rope with a string or rope inserted at the end of a rope.") |
133 | 144 | (:method (rope (source string))
|
134 | 145 | (concat-rope rope (make-rope source)))
|
135 | 146 | (:method (rope (source rope))
|
136 | 147 | (concat-rope rope source)))
|
137 | 148 |
|
138 | 149 | (defun insert-rope (rope index str)
|
| 150 | + "Return a new rope with a string or rope inserted at the specified index of a rope." |
139 | 151 | (cond ((= index 0) (prepend-rope rope str))
|
140 | 152 | ((= index (rope-length rope)) (append-rope rope str))
|
141 | 153 | (t (multiple-value-bind (ante post) (split-rope rope index)
|
|
146 | 158 | ;;-------;;
|
147 | 159 |
|
148 | 160 | (defgeneric index-rope (rope index)
|
| 161 | + (:documentation "Get a character at the specified index of a rope.") |
149 | 162 | (:method ((rope leaf) index)
|
150 | 163 | (char (leaf-string rope) index))
|
151 | 164 | (:method ((rope branch) index)
|
|
158 | 171 | ;; Concat ;;
|
159 | 172 | ;;--------;;
|
160 | 173 |
|
161 |
| -(defmethod concat-rope (left right) |
| 174 | +(defun concat-rope (left right) |
| 175 | + "Returns a balanced concatenation of two ropes." |
162 | 176 | (balance-rope
|
163 | 177 | (make-instance 'branch
|
164 | 178 | :length (+ (rope-length left) (rope-length right))
|
|
171 | 185 | ;;-------;;
|
172 | 186 |
|
173 | 187 | (defgeneric split-rope (rope index)
|
| 188 | + (:documentation "Return balanced ropes split at index as multiple values.") |
174 | 189 | (:method ((rope leaf) index)
|
175 | 190 | (values (make-rope (subseq (leaf-string rope) 0 index))
|
176 | 191 | (make-rope (subseq (leaf-string rope) index))))
|
|
193 | 208 | ;;------;;
|
194 | 209 |
|
195 | 210 | (defun kill-rope (rope from &optional to)
|
| 211 | + "Return a new rope without the characters in the specified range." |
196 | 212 | (multiple-value-bind (ante _) (split-rope rope from)
|
197 | 213 | (declare (ignore _))
|
198 | 214 | (multiple-value-bind (_ post) (split-rope rope (or to from))
|
|
0 commit comments