Skip to content

Commit ba24df1

Browse files
committed
spirit-airlines
1 parent c16065e commit ba24df1

File tree

6 files changed

+168
-68
lines changed

6 files changed

+168
-68
lines changed

dev/graphviz.lisp

+6-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@
2424

2525
(defmethod graph-object-node ((self (eql 'rope)) (obj rope::branch))
2626
(make-instance 'node
27-
:attributes `(:label ,(format nil "length: ~a~%depth: ~a"
27+
:attributes `(:label ,(format nil "length: ~a~%bf: ~a~%depth: ~a"
2828
(rope-length obj)
29-
(rope::rope-depth obj)))))
29+
(rope::balance-factor obj)
30+
(rope::rope-depth obj))
31+
:style ,(if (>= 1 (abs (rope::balance-factor obj)))
32+
:solid
33+
:filled))))
3034

3135
(defmethod graph-object-points-to ((self (eql 'rope)) (obj rope::branch))
3236
(list (make-instance 'attributed

rope.asd

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
(asdf:defsystem #:rope/test
1010
:depends-on (#:alexandria #:fiasco #:rope)
1111
:components ((:module "test"
12-
:components ((:file "basic")
12+
:components ((:file "util")
13+
(:file "basic")
1314
(:file "fuzz"))))
1415
:perform (asdf:test-op
1516
(o c)

rope.lisp

+53-20
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@
3838
(defun branch-weight (branch)
3939
(rope-length (branch-left branch)))
4040

41-
(defun leaf-short-p (leaf)
42-
(>= *short-leaf* (rope-length leaf)))
41+
(defun leaf-short-p (leaf &optional other)
42+
(>= *short-leaf*
43+
(if other
44+
(+ (rope-length leaf) (rope-length other))
45+
(rope-length leaf))))
4346

4447
(defun strcat (a b)
4548
(concatenate 'string a b))
@@ -128,25 +131,27 @@
128131
(with-slots (left right) rope
129132
(rotate-left (concat-rope* left (rotate-right right)))))
130133

131-
(defun balance-children (rope)
132-
(with-slots (left right) rope
133-
(concat-rope* (balance-rope left)
134-
(balance-rope right))))
134+
;; (defun balance-children (rope)
135+
;; (with-slots (left right) rope
136+
;; (concat-rope* (balance-rope left)
137+
;; (balance-rope right))))
135138

136139
(defgeneric balance-rope (rope)
137140
(:method ((rope leaf))
138141
rope)
139142
(:method ((rope branch))
140143
(with-slots (left right) rope
141144
(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)))
145+
(cond ((< 1 bf)
146+
(balance-rope
147+
(if (minusp (balance-factor left))
148+
(rotate-left-right rope)
149+
(rotate-right rope))))
150+
((> -1 bf)
151+
(balance-rope
152+
(if (plusp (balance-factor right))
153+
(rotate-right-left rope)
154+
(rotate-left rope))))
150155
(t
151156
rope))))))
152157

@@ -188,17 +193,45 @@
188193

189194
(defgeneric prepend-rope (rope source)
190195
(:documentation "Return a new rope with a string or rope inserted at the beginning of a rope.")
191-
(:method (rope (source rope))
192-
(concat-rope source rope))
193196
(:method (rope (source t))
194-
(concat-rope (make-rope source) rope)))
197+
(prepend-rope rope (make-rope source)))
198+
(:method (rope (source branch))
199+
(concat-rope source rope))
200+
(:method ((rope leaf) (source leaf))
201+
(if (leaf-short-p rope source)
202+
(make-leaf (strcat (leaf-string source) (leaf-string rope)))
203+
(concat-rope* source rope)))
204+
(:method ((rope branch) (source leaf))
205+
(with-slots (left right) rope
206+
(concat-rope* (prepend-rope left source) right))))
195207

196208
(defgeneric append-rope (rope source)
197209
(:documentation "Return a new rope with a string or rope inserted at the end of a rope.")
198-
(:method (rope (source rope))
199-
(concat-rope rope source))
200210
(:method (rope (source t))
201-
(concat-rope rope (make-rope source))))
211+
(append-rope rope (make-rope source)))
212+
(:method (rope (source branch))
213+
(concat-rope rope source))
214+
(:method ((rope leaf) (source leaf))
215+
(if (leaf-short-p rope source)
216+
(make-leaf (strcat (leaf-string rope) (leaf-string source)))
217+
(concat-rope* rope source)))
218+
(:method ((rope branch) (source leaf))
219+
(with-slots (left right) rope
220+
(concat-rope* left (append-rope right source)))))
221+
222+
;; (defgeneric prepend-rope (rope source)
223+
;; (:documentation "Return a new rope with a string or rope inserted at the beginning of a rope.")
224+
;; (:method (rope (source rope))
225+
;; (concat-rope source rope))
226+
;; (:method (rope (source t))
227+
;; (concat-rope (make-rope source) rope)))
228+
229+
;; (defgeneric append-rope (rope source)
230+
;; (:documentation "Return a new rope with a string or rope inserted at the end of a rope.")
231+
;; (:method (rope (source rope))
232+
;; (concat-rope rope source))
233+
;; (:method (rope (source t))
234+
;; (concat-rope rope (make-rope source))))
202235

203236
(defun insert-rope (rope index str)
204237
"Return a new rope with a string or rope inserted at the specified index of a rope."

test/basic.lisp

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
(fiasco:define-test-package :rope/test/basic)
1+
(fiasco:define-test-package :rope/test/basic
2+
(:use #:rope/test/util))
23
(in-package :rope/test/basic)
34

45
(defparameter *string-1*
@@ -19,15 +20,19 @@ can be done efficiently.")
1920
(is (= (length *string-1*) (rope:rope-length rope-1)))
2021
(is (= (length *string-2*) (rope:rope-length rope-2)))
2122
(is (string= *string-1* (rope:write-rope rope-1 nil)))
22-
(is (string= *string-2* (rope:write-rope rope-2 nil)))))
23+
(is (string= *string-2* (rope:write-rope rope-2 nil)))
24+
(is (balancedp rope-1))
25+
(is (balancedp rope-2))))
2326

2427
(deftest split ()
2528
"Test splitting ropes and check to ensure it is the same as splitting strings."
2629
(dotimes (i (length *string-2*))
2730
(let ((rope (rope:make-rope *string-2*)))
2831
(multiple-value-bind (ante post) (rope:split-rope rope i)
2932
(is (string= (subseq *string-2* 0 i) (rope:write-rope ante nil)))
30-
(is (string= (subseq *string-2* i) (rope:write-rope post nil)))))))
33+
(is (string= (subseq *string-2* i) (rope:write-rope post nil)))
34+
(is (balancedp ante))
35+
(is (balancedp post))))))
3136

3237
(deftest delete-and-insert ()
3338
"Make a rope, then a rope with a part deleted, then inserted."
@@ -38,7 +43,10 @@ can be done efficiently.")
3843
(is (string= "Hello, rope!" (rope:write-rope rope nil)))
3944
(is (string= ", rope!" (rope:write-rope killed nil)))
4045
(is (string= "Goodbye, rope!" (rope:write-rope inserted nil)))
41-
(is (string= "Hello, super rope!" (rope:write-rope super nil)))))
46+
(is (string= "Hello, super rope!" (rope:write-rope super nil)))
47+
(is (balancedp killed))
48+
(is (balancedp inserted))
49+
(is (balancedp super))))
4250

4351
(deftest index-rope ()
4452
"Test accessing characters and strings by index"
@@ -53,7 +61,9 @@ can be done efficiently.")
5361
"Test reading a file to a rope."
5462
(let* ((pathname (merge-pathnames "README.md" (asdf:system-source-directory :rope)))
5563
(rope (rope:make-rope pathname)))
56-
(is (string= (uiop:read-file-string pathname) (rope:write-rope rope nil))))
64+
(is (string= (uiop:read-file-string pathname) (rope:write-rope rope nil)))
65+
(is (balancedp rope)))
5766
(let* ((stream (make-string-input-stream *string-2*))
5867
(rope (rope:make-rope stream)))
59-
(is (string= *string-2* (rope:write-rope rope nil)))))
68+
(is (string= *string-2* (rope:write-rope rope nil)))
69+
(is (balancedp rope))))

test/fuzz.lisp

+16-39
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,7 @@
11
(fiasco:define-test-package :rope/test/fuzz
2-
(:local-nicknames (#:a #:alexandria)))
2+
(:use #:rope/test/util))
33
(in-package :rope/test/fuzz)
44

5-
(defvar *charset* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
6-
7-
(defun random-string (&key (length 128) (acc ""))
8-
(if (= 0 length)
9-
acc
10-
(random-string
11-
:length (1- length)
12-
:acc (rope::strcat acc (string (a:random-elt *charset*))))))
13-
14-
(defun random-rope (total-length)
15-
(with-open-file (source "/dev/urandom" :element-type '(unsigned-byte 8))
16-
(labels ((read-leaves (&optional acc (acc-length 0))
17-
(let* ((string* (make-array (min rope::*long-leaf* (- total-length acc-length))
18-
:element-type '(unsigned-byte 8)))
19-
(length (read-sequence string* source))
20-
(string (map 'string #'code-char string*))
21-
(leaf (rope::make-leaf (subseq string 0 length) length)))
22-
(if (and (= rope::*long-leaf* length)
23-
(not (= total-length (+ length acc-length))))
24-
(read-leaves (cons leaf acc) (+ length acc-length))
25-
(cons leaf acc)))))
26-
(let ((leaves (nreverse (read-leaves))))
27-
(rope::merge-leaves leaves 0 (length leaves))))))
28-
29-
(defgeneric balancedp (rope)
30-
(:method ((rope rope::leaf))
31-
t)
32-
(:method ((rope rope::branch))
33-
(and (>= 1 (abs (rope::balance-factor rope)))
34-
(balancedp (rope::branch-left rope))
35-
(balancedp (rope::branch-right rope)))))
36-
375
(deftest fuzz-basic-tests ()
386
"Run the basic test suite with different leaf sizes."
397
(loop :for i :from 1 :to 64
@@ -85,16 +53,25 @@
8553
(is (balancedp new-rope))
8654
(is (string= new-string (rope:write-rope new-rope nil))))))
8755

88-
#+ignore
8956
(deftest fuzz-insert-balance ()
9057
(setf rope::*long-leaf* 128)
9158
(dotimes (i 10)
92-
(let ((rope (random-rope 1000)))
93-
(dotimes (i 100)
59+
(let ((rope (random-rope 10)))
60+
(dotimes (i 1000)
9461
(setf rope
9562
(rope:insert-rope rope
9663
(random (rope:rope-length rope))
97-
(random-string :length (random 512))))
98-
(unless (balancedp rope)
99-
(return-from fuzz-insert-balance rope))
64+
(random-string :length (random 5))))
10065
(is (balancedp rope))))))
66+
67+
;; (deftest fuzz-random-actions-balance
68+
;; (&key (rope (random-rope (random 256)))
69+
;; (iterations 1000))
70+
;; (cond ((> 50000 (rope:rope-length rope))
71+
;; (fuzz-random-actions-balance
72+
;; :rope (random-insert rope)
73+
;; :iterations (1- iterations)))
74+
;; ((< 12 (rope:rope-length rope))
75+
;; (fuzz-random-actions-balance
76+
;; :rope (random-kill rope)
77+
;; :iterations (1- iterations)))))

test/util.lisp

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
(defpackage :rope/test/util
2+
(:use #:cl)
3+
(:local-nicknames
4+
(#:a #:alexandria))
5+
(:export
6+
#:balancedp
7+
#:random-string
8+
#:random-rope
9+
#:random-path
10+
#:random-insert
11+
#:random-kill))
12+
(in-package :rope/test/util)
13+
14+
(defgeneric balancedp (rope)
15+
(:method ((rope rope::leaf))
16+
t)
17+
(:method ((rope rope::branch))
18+
(and (>= 1 (abs (rope::balance-factor rope)))
19+
(balancedp (rope::branch-left rope))
20+
(balancedp (rope::branch-right rope)))))
21+
22+
(defvar *charset* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
23+
24+
(defun random-string (&key (length 128) (acc ""))
25+
(if (= 0 length)
26+
acc
27+
(random-string
28+
:length (1- length)
29+
:acc (rope::strcat acc (string (a:random-elt *charset*))))))
30+
31+
(defun random-rope (total-length)
32+
(with-open-file (source "/dev/urandom" :element-type '(unsigned-byte 8))
33+
(labels ((read-leaves (&optional acc (acc-length 0))
34+
(let* ((string* (make-array (min rope::*long-leaf* (- total-length acc-length))
35+
:element-type '(unsigned-byte 8)))
36+
(length (read-sequence string* source))
37+
(string (map 'string #'code-char string*))
38+
(leaf (rope::make-leaf (subseq string 0 length) length)))
39+
(if (and (= rope::*long-leaf* length)
40+
(not (= total-length (+ length acc-length))))
41+
(read-leaves (cons leaf acc) (+ length acc-length))
42+
(cons leaf acc)))))
43+
(let ((leaves (nreverse (read-leaves))))
44+
(rope::merge-leaves leaves 0 (length leaves))))))
45+
46+
(defmacro random-path (&body forms)
47+
`(case (random ,(length forms))
48+
,@(loop :with i := 0
49+
:for form :in forms
50+
:collect (list i form)
51+
:do (incf i))))
52+
53+
(defun random-insert (rope)
54+
(random-path
55+
(rope:insert-rope
56+
rope
57+
(random (rope:rope-length rope))
58+
(random-path
59+
(random-string :length (random 1024))
60+
(random-rope (random 1024))))
61+
(rope:append-rope
62+
rope
63+
(random-path
64+
(random-string :length (random 1024))
65+
(random-rope (random 1024))))
66+
(rope:prepend-rope
67+
rope
68+
(random-path
69+
(random-string :length (random 1024))
70+
(random-rope (random 1024))))))
71+
72+
(defun random-kill (rope)
73+
(random-path
74+
(rope:kill-rope rope (random (rope:rope-length rope)))
75+
))

0 commit comments

Comments
 (0)