|
35 | 35 | ;; Utils ;;
|
36 | 36 | ;;-------;;
|
37 | 37 |
|
| 38 | +(defun branch-weight (branch) |
| 39 | + (rope-length (branch-left branch))) |
| 40 | + |
| 41 | +(defun leaf-short-p (leaf) |
| 42 | + (>= *short-leaf* (rope-length leaf))) |
| 43 | + |
| 44 | +(defun strcat (a b) |
| 45 | + (concatenate 'string a b)) |
| 46 | + |
| 47 | +(defun make-leaf (string &optional length) |
| 48 | + (make-instance 'leaf :string string :length (or length (length string)))) |
| 49 | + |
38 | 50 | (defgeneric make-rope (source)
|
39 | 51 | (:documentation "Create a new rope from a string, stream, or pathname.")
|
40 | 52 | (:method ((source rope))
|
|
43 | 55 | (labels ((read-leaves (&optional acc)
|
44 | 56 | (let* ((string (make-string *long-leaf*))
|
45 | 57 | (length (read-sequence string source))
|
46 |
| - (leaf (make-instance 'leaf :length length :string (subseq string 0 length)))) |
| 58 | + (leaf (make-leaf (subseq string 0 length) length))) |
47 | 59 | (if (= *long-leaf* length)
|
48 | 60 | (read-leaves (cons leaf acc))
|
49 | 61 | (cons leaf acc)))))
|
|
57 | 69 | (if (<= *long-leaf* length)
|
58 | 70 | (concat-rope (make-rope (subseq source 0 (round length 2)))
|
59 | 71 | (make-rope (subseq source (round length 2))))
|
60 |
| - (make-instance 'leaf :length length :string source))))) |
61 |
| - |
62 |
| -(defgeneric rope-weight (rope) |
63 |
| - (:method ((rope leaf)) |
64 |
| - (rope-length rope)) |
65 |
| - (:method ((rope branch)) |
66 |
| - (rope-length (branch-left rope)))) |
67 |
| - |
68 |
| -(defun leaf-short-p (leaf) |
69 |
| - (>= *short-leaf* (rope-length leaf))) |
70 |
| - |
71 |
| -(defun strcat (a b) |
72 |
| - (concatenate 'string a b)) |
| 72 | + (make-leaf source length))))) |
73 | 73 |
|
74 | 74 | ;;-----------;;
|
75 | 75 | ;; Iteration ;;
|
|
101 | 101 | ;; Balancing ;;
|
102 | 102 | ;;-----------;;
|
103 | 103 |
|
| 104 | +(defgeneric balance-factor (rope) |
| 105 | + (:method ((rope leaf)) |
| 106 | + 0) |
| 107 | + (:method ((rope branch)) |
| 108 | + (- (rope-depth (branch-left rope)) |
| 109 | + (rope-depth (branch-right rope))))) |
| 110 | + |
| 111 | +(defun rotate-left (rope) |
| 112 | + (with-slots (left right) rope |
| 113 | + (concat-rope* |
| 114 | + (concat-rope left (branch-left right)) |
| 115 | + (branch-right right)))) |
| 116 | + |
| 117 | +(defun rotate-right (rope) |
| 118 | + (with-slots (left right) rope |
| 119 | + (concat-rope* |
| 120 | + (branch-left left) |
| 121 | + (concat-rope (branch-right left) right)))) |
| 122 | + |
| 123 | +(defun rotate-left-right (rope) |
| 124 | + (with-slots (left right) rope |
| 125 | + (rotate-right (concat-rope* (rotate-left left) right)))) |
| 126 | + |
| 127 | +(defun rotate-right-left (rope) |
| 128 | + (with-slots (left right) rope |
| 129 | + (rotate-left (concat-rope* left (rotate-right right))))) |
| 130 | + |
| 131 | +(defun balance-children (rope) |
| 132 | + (with-slots (left right) rope |
| 133 | + (concat-rope* (balance-rope left) |
| 134 | + (balance-rope right)))) |
| 135 | + |
| 136 | +(defgeneric balance-rope (rope) |
| 137 | + (:method ((rope leaf)) |
| 138 | + rope) |
| 139 | + (:method ((rope branch)) |
| 140 | + (with-slots (left right) rope |
| 141 | + (let ((bf (balance-factor rope))) |
| 142 | + (cond ((< 0 bf) |
| 143 | + (if (minusp (balance-factor left)) |
| 144 | + (rotate-left-right rope) |
| 145 | + (rotate-right rope))) |
| 146 | + ((> 0 bf) |
| 147 | + (if (plusp (balance-factor right)) |
| 148 | + (rotate-right-left rope) |
| 149 | + (rotate-left rope))) |
| 150 | + (t |
| 151 | + rope)))))) |
| 152 | + |
| 153 | +;;---------;; |
| 154 | +;; Rebuild ;; |
| 155 | +;;---------;; |
| 156 | + |
104 | 157 | (defun normalize-leaves (leaves &optional carry)
|
105 | 158 | (let ((leaf (car leaves)))
|
106 | 159 | (cond ((and carry (null leaf))
|
|
115 | 168 | (t
|
116 | 169 | (cons leaf (normalize-leaves (cdr leaves)))))))
|
117 | 170 |
|
118 |
| -(defgeneric balancedp (rope) |
119 |
| - (:documentation "Check if a rope is a height-balanced tree.") |
120 |
| - (:method ((rope leaf)) |
121 |
| - t) |
122 |
| - (:method ((rope branch)) |
123 |
| - (with-slots (left right) rope |
124 |
| - (and (balancedp left) |
125 |
| - (balancedp right) |
126 |
| - (>= 2 (abs (- (rope-depth left) (rope-depth right)))))))) |
127 |
| - |
128 | 171 | (defun merge-leaves (leaves start end)
|
129 | 172 | (let ((range (- end start)))
|
130 | 173 | (case range
|
|
134 | 177 | (concat-rope (merge-leaves leaves start mid)
|
135 | 178 | (merge-leaves leaves mid end)))))))
|
136 | 179 |
|
137 |
| -(defun balance-rope (rope &optional forcep) |
| 180 | +(defun rebuild-rope (rope) |
138 | 181 | "Balance a rope by reconstructing it from the bottom up."
|
139 |
| - (if (and (balancedp rope) (not forcep)) |
140 |
| - rope |
141 |
| - (let ((leaves (normalize-leaves (collect-rope rope)))) |
142 |
| - (merge-leaves leaves 0 (length leaves))))) |
| 182 | + (let ((leaves (normalize-leaves (collect-rope rope)))) |
| 183 | + (merge-leaves leaves 0 (length leaves)))) |
143 | 184 |
|
144 | 185 | ;;--------;;
|
145 | 186 | ;; Insert ;;
|
146 | 187 | ;;--------;;
|
147 | 188 |
|
148 | 189 | (defgeneric prepend-rope (rope source)
|
149 | 190 | (:documentation "Return a new rope with a string or rope inserted at the beginning of a rope.")
|
150 |
| - (:method (rope (source string)) |
151 |
| - (concat-rope (make-rope source) rope)) |
152 | 191 | (:method (rope (source rope))
|
153 |
| - (concat-rope source rope))) |
| 192 | + (concat-rope source rope)) |
| 193 | + (:method (rope (source t)) |
| 194 | + (concat-rope (make-rope source) rope))) |
154 | 195 |
|
155 | 196 | (defgeneric append-rope (rope source)
|
156 | 197 | (:documentation "Return a new rope with a string or rope inserted at the end of a rope.")
|
157 |
| - (:method (rope (source string)) |
158 |
| - (concat-rope rope (make-rope source))) |
159 | 198 | (:method (rope (source rope))
|
160 |
| - (concat-rope rope source))) |
| 199 | + (concat-rope rope source)) |
| 200 | + (:method (rope (source t)) |
| 201 | + (concat-rope rope (make-rope source)))) |
161 | 202 |
|
162 | 203 | (defun insert-rope (rope index str)
|
163 | 204 | "Return a new rope with a string or rope inserted at the specified index of a rope."
|
|
175 | 216 | (:method ((rope leaf) index)
|
176 | 217 | (char (leaf-string rope) index))
|
177 | 218 | (:method ((rope branch) index)
|
178 |
| - (let ((weight (rope-weight rope))) |
| 219 | + (let ((weight (branch-weight rope))) |
179 | 220 | (if (< index weight)
|
180 | 221 | (index-rope (branch-left rope) index)
|
181 | 222 | (index-rope (branch-right rope) (- index weight))))))
|
|
192 | 233 | ;; Concat ;;
|
193 | 234 | ;;--------;;
|
194 | 235 |
|
| 236 | +(defun concat-rope* (left right) |
| 237 | + "Concatenates without balancing." |
| 238 | + (make-instance 'branch |
| 239 | + :length (+ (rope-length left) (rope-length right)) |
| 240 | + :depth (1+ (max (rope-depth left) (rope-depth right))) |
| 241 | + :left left |
| 242 | + :right right)) |
| 243 | + |
195 | 244 | (defun concat-rope (left right)
|
196 | 245 | "Returns a balanced concatenation of two ropes."
|
197 |
| - (balance-rope |
198 |
| - (make-instance 'branch |
199 |
| - :length (+ (rope-length left) (rope-length right)) |
200 |
| - :depth (1+ (max (rope-depth left) (rope-depth right))) |
201 |
| - :left left |
202 |
| - :right right))) |
| 246 | + (balance-rope (concat-rope* left right))) |
203 | 247 |
|
204 | 248 | ;;-------;;
|
205 | 249 | ;; Split ;;
|
|
212 | 256 | (make-rope (subseq (leaf-string rope) index))))
|
213 | 257 | (:method ((rope branch) index)
|
214 | 258 | (with-slots (left right) rope
|
215 |
| - (let ((weight (rope-weight rope))) |
| 259 | + (let ((weight (branch-weight rope))) |
216 | 260 | (cond ((= index weight)
|
217 | 261 | (values left right))
|
218 | 262 | ((< index weight)
|
219 | 263 | (multiple-value-bind (ante post) (split-rope left index)
|
220 | 264 | (values (balance-rope ante)
|
221 |
| - (balance-rope (concat-rope post right))))) |
| 265 | + (concat-rope post right)))) |
222 | 266 | ((> index weight)
|
223 | 267 | (multiple-value-bind (ante post) (split-rope right (- index weight))
|
224 |
| - (values (balance-rope (concat-rope left ante)) |
| 268 | + (values (concat-rope left ante) |
225 | 269 | (balance-rope post)))))))))
|
226 | 270 |
|
227 | 271 | ;;------;;
|
|
0 commit comments