From 3bf289f50871c10d814fde7219c1fea2cfc19766 Mon Sep 17 00:00:00 2001 From: "Scott L. Burson" Date: Sun, 23 Feb 2025 01:00:52 -0800 Subject: [PATCH] Functional iterators! Fun!! --- Code/defs.lisp | 4 + Code/fset.lisp | 87 ++++++++- Code/testing.lisp | 30 +++ Code/wb-trees.lisp | 471 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 584 insertions(+), 8 deletions(-) diff --git a/Code/defs.lisp b/Code/defs.lisp index f9fb37d..64a2525 100644 --- a/Code/defs.lisp +++ b/Code/defs.lisp @@ -84,6 +84,8 @@ #:? ; for `query' on 'list-relation' ;; Used by the bag methods that convert to and from lists. #:alist + ;; Miscellaneous GMap arg types + #:fun-sequence #:fun-bag-pairs #:fun-map ;; Miscellaneous GMap result types #:map-to-sets #:append-unique ;; Bounded sets @@ -189,6 +191,8 @@ #:? ; for `query' on 'list-relation' ;; Used by the bag methods that convert to and from lists. #:alist + ;; Miscellaneous GMap arg types + #:fun-sequence #:fun-bag-pairs #:fun-map ;; Miscellaneous GMap result types #:map-to-sets #:append-unique ;; Bounded sets diff --git a/Code/fset.lisp b/Code/fset.lisp index 8a35203..17caa45 100644 --- a/Code/fset.lisp +++ b/Code/fset.lisp @@ -462,14 +462,30 @@ take additional keyword arguments to further specify the kind of conversion.")) ;;; to check termination; if it might contain `nil', you can use the extra value. (defgeneric iterator (collection &key) (:documentation - "Returns an iterator for the collection. (These are stateful iterators and -are not thread-safe; if you want a pure iterator, your best bet is to `convert' -the collection to a list.) The iterator is a closure of one argument; given -`:done?', it returns true iff the iterator is exhausted; given `:more?', it -returns true iff the iterator is _not_ exhausted. Given `:get', if the iterator -is not exhausted, it returns the next element (or pair, for a map, as two values), -with the second value (third, for a map) being true, and advances one element; if -it is exhausted, it returns two `nil' values (three, for a map).")) + "Returns an iterator for the collection. \(These are stateful iterators and +are not thread-safe; if you want a pure iterator, see `fun-iterator'.\) The iterator +is a function of one argument; given `:done?', it returns true iff the iterator is +exhausted; given `:more?', it returns true iff the iterator is _not_ exhausted. +Given `:get', if the iterator is not exhausted, it returns the next element (or +pair, for a map, as two values), with the second value (third, for a map) being +true, and advances one element; if it is exhausted, it returns two `nil' values +\(three, for a map\). + +The bag method takes a `pairs?' keyword argument; if true, it returns each element +only once, with its multiplicity as the second value, as for a map.")) + +(defgeneric fun-iterator (collection &key from-end?) + (:documentation + "Returns a functional iterator for the collection. \(These iterators are +thread-safe.\) The iterator is a function of one argument; given `:empty?', it +returns true iff the iterator is exhausted; given `:more?', it returns true iff +the iterator is _not_ exhausted. Given `:first', if it is not exhausted, it +returns the next element \(or pair, for a map, as two values\), with an additional +true value; if it is exhausted, it returns two or three `nil' values. + +If `from-end?' is true, the collection is iterated in reverse order. The bag +method also takes a `pairs?' keyword argument; if true, it returns each element +only once, with its multiplicity as the second value, as for a map.")) ;;; The `&allow-other-keys' is to persuade SBCL not to issue warnings about keywords ;;; that are accepted by some methods of `iterator'. @@ -546,6 +562,19 @@ as an FSet seq, or a set or bag as well." #'(lambda (it) (declare (type function it)) (funcall it ':done?)) #'(lambda (it) (declare (type function it)) (funcall it ':get)))) +;;; The new (for 1.4.7) functional iterators all take a `:from-end?' option. +;;; Other than that, there's no reason to use them with `gmap'; they're slower +;;; (though not as much slower as you might expect; less than 2x) and generate +;;; lots of garbage. They were fun to write, though :-) +(gmap:def-arg-type fun-sequence (fun-iterable &key from-end?) + "Yields the elements of `fun-iterable', which can be an FSet seq, set, or bag. +If `:from-end?' is true, iterates in reverse order." + `((fun-iterator ,fun-iterable :from-end? ,from-end?) + #'(lambda (it) (funcall it ':empty?)) + #'(lambda (it) (funcall it ':first)) + #'(lambda (it) (funcall it ':rest)))) + + ;;; ================================================================================ ;;; Generic versions of Common Lisp sequence functions @@ -1235,6 +1264,11 @@ for the possibility of different set implementations; it is not for public use. (defmethod iterator ((s wb-set) &key) (Make-WB-Set-Tree-Iterator (wb-set-contents s))) +(defmethod fun-iterator ((s wb-set) &key from-end?) + (if from-end? + (WB-Set-Tree-Rev-Fun-Iter (wb-set-contents s)) + (WB-Set-Tree-Fun-Iter (wb-set-contents s)))) + (defmethod filter ((pred function) (s wb-set)) (wb-set-filter pred s)) @@ -1853,6 +1887,15 @@ different bag implementations; it is not for public use. `elt-fn' and (Make-WB-Bag-Tree-Pair-Iterator (wb-bag-contents b)) (Make-WB-Bag-Tree-Iterator (wb-bag-contents b)))) +(defmethod fun-iterator ((s wb-bag) &key pairs? from-end?) + (if pairs? + (if from-end? + (WB-Bag-Tree-Pair-Rev-Fun-Iter (wb-bag-contents s)) + (WB-Bag-Tree-Pair-Fun-Iter (wb-bag-contents s))) + (if from-end? + (WB-Bag-Tree-Rev-Fun-Iter (wb-bag-contents s)) + (WB-Bag-Tree-Fun-Iter (wb-bag-contents s))))) + (defmethod filter ((pred function) (b bag)) (bag-filter pred b)) @@ -2133,6 +2176,12 @@ of which may be repeated." #'WB-Bag-Tree-Pair-Iterator-Done? (:values 2 #'WB-Bag-Tree-Pair-Iterator-Get))) +(gmap:def-arg-type fun-bag-pairs (bag &key from-end?) + `((fun-iterator ,bag :pairs? t :from-end? ,from-end?) + #'(lambda (it) (funcall it ':empty?)) + (:values 2 #'(lambda (it) (funcall it ':first))) + #'(lambda (it) (funcall it ':rest)))) + (gmap:def-gmap-res-type bag (&key filterp) "Returns a bag of the values, optionally filtered by `filterp'." `(nil #'WB-Bag-Tree-With #'make-wb-bag ,filterp)) @@ -2309,6 +2358,11 @@ symbols.")) (defmethod iterator ((m wb-map) &key) (Make-WB-Map-Tree-Iterator (wb-map-contents m))) +(defmethod fun-iterator ((s wb-map) &key from-end?) + (if from-end? + (WB-Map-Tree-Rev-Fun-Iter (wb-map-contents s)) + (WB-Map-Tree-Fun-Iter (wb-map-contents s)))) + (defmethod filter ((pred function) (m wb-map)) (wb-map-filter pred m)) @@ -2439,6 +2493,12 @@ symbols.")) (push (funcall pair-fn key val) result)) (nreverse result))) +(defmethod convert ((to-type (eql 'alist)) (m map) &key) + (let ((result nil)) + (do-map (key val m) + (push (cons key val) result)) + (nreverse result))) + (defmethod convert ((to-type (eql 'seq)) (m map) &key (pair-fn #'cons)) (convert to-type (convert 'list m :pair-fn pair-fn))) @@ -2607,6 +2667,12 @@ symbols.")) #'WB-Map-Tree-Iterator-Done? (:values 2 #'WB-Map-Tree-Iterator-Get))) +(gmap:def-arg-type fun-map (map &key from-end?) + `((fun-iterator ,map :from-end? ,from-end?) + #'(lambda (it) (funcall it ':empty?)) + (:values 2 #'(lambda (it) (funcall it ':first))) + #'(lambda (it) (funcall it ':rest)))) + (gmap:def-gmap-res-type map (&key filterp default) "Consumes two values from the mapped function; returns a map of the pairs. Note that `filterp', if supplied, must take two arguments." @@ -3038,6 +3104,11 @@ not symbols.")) (defmethod iterator ((s wb-seq) &key) (Make-WB-Seq-Tree-Iterator (wb-seq-contents s))) +(defmethod fun-iterator ((s wb-seq) &key from-end?) + (if from-end? + (WB-Seq-Tree-Rev-Fun-Iter (wb-seq-contents s)) + (WB-Seq-Tree-Fun-Iter (wb-seq-contents s)))) + (defmethod domain-contains? ((s seq) x) (and (integerp x) (>= x 0) (< x (size s)))) diff --git a/Code/testing.lisp b/Code/testing.lisp index 4aba9b7..baea810 100644 --- a/Code/testing.lisp +++ b/Code/testing.lisp @@ -2420,6 +2420,12 @@ (error "Set iterator failed (fs0) on iteration ~D" i)) (unless (equal? fs1 (gmap (:result set) nil (:arg list (convert 'list fs1)))) (error "Set iterator or accumulator failed (fs1) on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fs0)) + (convert 'list fs0)) + (error "Set fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fs0 :from-end? t)) + (reverse (convert 'list fs0))) + (error "Set rev-fun-iterator failed on iteration ~D" i)) (let ((fsu (union fs0 fs1)) (su (cl:union s0 s1 :test #'equal?))) (unless (and (verify fsu) (equal? fsu (convert 'set su))) @@ -2549,6 +2555,12 @@ (error "Map iterator failed (fm0) on iteration ~D" i)) (unless (equal? fm1 (gmap (:result map) nil (:arg alist (convert 'list fm1)))) (error "Map iterator/accumulator failed (fm1) on iteration ~D" i)) + (unless (equal? (gmap (:result alist) nil (:arg fun-map fm0)) + (convert 'alist fm0)) + (error "Map fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result alist) nil (:arg fun-map fm0 :from-end? t)) + (reverse (convert 'alist fm0))) + (error "Map rev-fun-iterator failed on iteration ~D" i)) (unless (eq (Map-Compare (convert 'list fm0) m0) ':equal) (error "Map equal? failed (fm1) on iteration ~D" i)) (unless (eq (Map-Compare (convert 'list fm1) m1) ':equal) @@ -2710,6 +2722,18 @@ (error "Bag pair iterator failed (fb0) on iteration ~D" i)) (unless (equal? fb1 (gmap (:result bag-pairs) nil (:arg alist (convert 'alist fb1)))) (error "Bag pair iterator/accumulator failed (fb1) on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fb0)) + (convert 'list fb0)) + (error "Bag fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result alist) nil (:arg fun-bag-pairs fb0)) + (convert 'alist fb0)) + (error "Bag pair fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fb0 :from-end? t)) + (reverse (convert 'list fb0))) + (error "Bag rev-fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result alist) nil (:arg fun-bag-pairs fb0 :from-end? t)) + (reverse (convert 'alist fb0))) + (error "Bag pair fun-iterator failed on iteration ~D" i)) (let ((fbu (union fb0 fb1)) (bu (Alist-Bag-Union b0 b1))) (unless (and (verify fbu) (equal? fbu (convert 'bag bu :from-type 'alist))) @@ -2828,6 +2852,12 @@ (error "Seq equality failed (fs0, B), on iteration ~D" i)) (unless (gmap (:result and) #'equal? (:arg seq fs0) (:arg list s0)) (error "Seq iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fs0)) + (convert 'list fs0)) + (error "Seq fun-iterator failed on iteration ~D" i)) + (unless (equal? (gmap (:result list) nil (:arg fun-sequence fs0 :from-end? t)) + (reverse (convert 'list fs0))) + (error "Seq rev-fun-iterator failed on iteration ~D" i)) (unless (gmap (:result and) #'equal? (:arg seq fs0) (:arg sequence s0)) (error "Seq or list iterator failed on iteration ~D" i)) (unless (gmap (:result and) #'equal? (:arg seq fs0) (:arg sequence (coerce s0 'simple-vector))) diff --git a/Code/wb-trees.lisp b/Code/wb-trees.lisp index b6647c8..94d5d9b 100644 --- a/Code/wb-trees.lisp +++ b/Code/wb-trees.lisp @@ -1630,6 +1630,97 @@ to those members above `lo' and below `hi'." t))))) +;;; ---------------- +;;; Functional iterators. Fun!!! + +(defun WB-Set-Tree-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((simple-vector-p node) + (let ((len (length node))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (lambda (op) + (ecase op + (:first (values (svref node i) t)) + (:rest (iter (1+ i))) + (:empty? nil) + (:more? t))) + cont))))) + (t + (walk (WB-Set-Tree-Node-Left node) + (let ((value (WB-Set-Tree-Node-Value node))) + (if (Equivalent-Set? value) + (rlabels (iter (Equivalent-Set-Members value)) + (iter (mems) + (if mems + (lambda (op) + (ecase op + (:first (values (car mems) t)) + (:rest (iter (cdr mems))) + (:empty? nil) + (:more? t))) + (walk (WB-Set-Tree-Node-Right node) cont)))) + (lambda (op) + (ecase op + (:first (values value t)) + (:rest (walk (WB-Set-Tree-Node-Right node) cont)) + (:empty? nil) + (:more? t))))))))))) + +(defun WB-Set-Tree-Rev-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((simple-vector-p node) + (rlabels (iter (1- (length node))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (lambda (op) + (ecase op + (:first (values (svref node i) t)) + (:rest (iter (1- i))) + (:empty? nil) + (:more? t))) + cont)))) + (t + (walk (WB-Set-Tree-Node-Right node) + (let ((value (WB-Set-Tree-Node-Value node))) + (if (Equivalent-Set? value) + (rlabels (iter (reverse (Equivalent-Set-Members value))) + (iter (mems) + (if mems + (lambda (op) + (ecase op + (:first (values (car mems) t)) + (:rest (iter (cdr mems))) + (:empty? nil) + (:more? t))) + (walk (WB-Set-Tree-Node-Left node) cont)))) + (lambda (op) + (ecase op + (:first (values value t)) + (:rest (walk (WB-Set-Tree-Node-Left node) cont)) + (:empty? nil) + (:more? t))))))))))) + + ;;; ---------------- ;;; Utilities used by all tree types in this file @@ -3454,6 +3545,214 @@ value and `count-var' to its member count." (values (car pr) (cdr pr) t)) (values val (WB-Bag-Tree-Node-Count node) t)))))))) +;;; ---------------- +;;; Functional iterators. Fun!!! + +(defun WB-Bag-Tree-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (let ((len (length (the simple-array (car node))))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (copies i 0) + cont)) + (copies (i j) + (declare (fixnum i j)) + (if (< j (the fixnum (svref (cdr node) i))) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) t)) + (:rest (copies i (1+ j))) + (:empty? nil) + (:more? t))) + (iter (1+ i))))))) + (t + (walk (WB-Bag-Tree-Node-Left node) + (let ((value (WB-Bag-Tree-Node-Value node))) + (if (Equivalent-Bag? value) + (rlabels (iter (Equivalent-Bag-Alist value)) + (iter (prs) + (if prs + (copies prs 0) + (walk (WB-Bag-Tree-Node-Right node) cont))) + (copies (prs j) + (declare (fixnum j)) + (if (< j (the fixnum (cdar prs))) + (lambda (op) + (ecase op + (:first (values (caar prs) t)) + (:rest (copies prs (1+ j))) + (:empty? nil) + (:more? t))) + (iter (cdr prs))))) + (rlabels (copies 0) + (copies (j) + (declare (fixnum j)) + (if (< j (WB-Bag-Tree-Node-Count node)) + (lambda (op) + (ecase op + (:first (values value t)) + (:rest (copies (1+ j))) + (:empty? nil) + (:more? t))) + (walk (WB-Bag-Tree-Node-Right node) cont)))))))))))) + +(defun WB-Bag-Tree-Rev-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (rlabels (iter (1- (length (the simple-array (car node))))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (copies i 0) + cont)) + (copies (i j) + (declare (fixnum i j)) + (if (< j (the fixnum (svref (cdr node) i))) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) t)) + (:rest (copies i (1+ j))) + (:empty? nil) + (:more? t))) + (iter (1- i)))))) + (t + (walk (WB-Bag-Tree-Node-Right node) + (let ((value (WB-Bag-Tree-Node-Value node))) + (if (Equivalent-Bag? value) + (rlabels (iter (reverse (Equivalent-Bag-Alist value))) + (iter (prs) + (if prs + (copies prs 0) + (walk (WB-Bag-Tree-Node-Left node) cont))) + (copies (prs j) + (declare (fixnum j)) + (if (< j (the fixnum (cdar prs))) + (lambda (op) + (ecase op + (:first (values (caar prs) t)) + (:rest (copies prs (1+ j))) + (:empty? nil) + (:more? t))) + (iter (cdr prs))))) + (rlabels (copies 0) + (copies (j) + (declare (fixnum j)) + (if (< j (WB-Bag-Tree-Node-Count node)) + (lambda (op) + (ecase op + (:first (values value t)) + (:rest (copies (1+ j))) + (:empty? nil) + (:more? t))) + (walk (WB-Bag-Tree-Node-Left node) cont)))))))))))) + +(defun WB-Bag-Tree-Pair-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (let ((len (length (the simple-array (car node))))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) (svref (cdr node) i) t)) + (:rest (iter (1+ i))) + (:empty? nil) + (:more? t))) + cont))))) + (t + (walk (WB-Bag-Tree-Node-Left node) + (let ((value (WB-Bag-Tree-Node-Value node))) + (if (Equivalent-Bag? value) + (rlabels (iter (Equivalent-Bag-Alist value)) + (iter (prs) + (if prs + (lambda (op) + (ecase op + (:first (values (caar prs) (cdar prs) t)) + (:rest (iter (cdr prs))) + (:empty? nil) + (:more? t))) + (walk (WB-Bag-Tree-Node-Right node) cont)))) + (lambda (op) + (ecase op + (:first (values value (WB-Bag-Tree-Node-Count node) t)) + (:rest (walk (WB-Bag-Tree-Node-Right node) cont)) + (:empty? nil) + (:more? t))))))))))) + +(defun WB-Bag-Tree-Pair-Rev-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (rlabels (iter (1- (length (the simple-array (car node))))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) (svref (cdr node) i) t)) + (:rest (iter (1- i))) + (:empty? nil) + (:more? t))) + cont)))) + (t + (walk (WB-Bag-Tree-Node-Right node) + (let ((value (WB-Bag-Tree-Node-Value node))) + (if (Equivalent-Bag? value) + (rlabels (iter (reverse (Equivalent-Bag-Alist value))) + (iter (prs) + (if prs + (lambda (op) + (ecase op + (:first (values (caar prs) (cdar prs) t)) + (:rest (iter (cdr prs))) + (:empty? nil) + (:more? t))) + (walk (WB-Bag-Tree-Node-Left node) cont)))) + (lambda (op) + (ecase op + (:first (values value (WB-Bag-Tree-Node-Count node) t)) + (:rest (walk (WB-Bag-Tree-Node-Left node) cont)) + (:empty? nil) + (:more? t))))))))))) + + ;;; ================================================================================ ;;; Equivalent-Bag routines @@ -5146,6 +5445,97 @@ between equal trees." (values key (WB-Map-Tree-Node-Value node) t)))))))) +;;; ---------------- +;;; Functional iterators. Fun!!! + +(defun WB-Map-Tree-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (let ((len (length (the simple-array (car node))))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) (svref (cdr node) i) t)) + (:rest (iter (1+ i))) + (:empty? nil) + (:more? t))) + cont))))) + (t + (walk (WB-Map-Tree-Node-Left node) + (let ((key (WB-Map-Tree-Node-Key node))) + (if (Equivalent-Map? key) + (rlabels (iter (Equivalent-Map-Alist key)) + (iter (prs) + (if prs + (lambda (op) + (ecase op + (:first (values (caar prs) (cdar prs) t)) + (:rest (iter (cdr prs))) + (:empty? nil) + (:more? t))) + (walk (WB-Map-Tree-Node-Right node) cont)))) + (lambda (op) + (ecase op + (:first (values key (WB-Map-Tree-Node-Value node) t)) + (:rest (walk (WB-Map-Tree-Node-Right node) cont)) + (:empty? nil) + (:more? t))))))))))) + +(defun WB-Map-Tree-Rev-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((consp node) + (rlabels (iter (1- (length (the simple-array (car node))))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (lambda (op) + (ecase op + (:first (values (svref (car node) i) (svref (cdr node) i) t)) + (:rest (iter (1- i))) + (:empty? nil) + (:more? t))) + cont)))) + (t + (walk (WB-Map-Tree-Node-Right node) + (let ((key (WB-Map-Tree-Node-Key node))) + (if (Equivalent-Map? key) + (rlabels (iter (reverse (Equivalent-Map-Alist key))) + (iter (prs) + (if prs + (lambda (op) + (ecase op + (:first (values (caar prs) (cdar prs) t)) + (:rest (iter (cdr prs))) + (:empty? nil) + (:more? t))) + (walk (WB-Map-Tree-Node-Left node) cont)))) + (lambda (op) + (ecase op + (:first (values key (WB-Map-Tree-Node-Value node) t)) + (:rest (walk (WB-Map-Tree-Node-Left node) cont)) + (:empty? nil) + (:more? t))))))))))) + + ;;; ================================================================================ ;;; Equivalent-Map routines @@ -6396,6 +6786,87 @@ the result, inserts `val', returning the new vector." (WB-Seq-Tree-Iterator-Canonicalize iter) (values (if (simple-string-p node) (schar node idx) (svref node idx)) t))))) +;;; ---------------- +;;; Functional iterators. Fun!!! + +(defun WB-Seq-Tree-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((simple-string-p node) + (let ((len (length node))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (lambda (op) + (ecase op + (:first (values (schar node i) t)) + (:rest (iter (1+ i))) + (:empty? nil) + (:more? t))) + cont))))) + ((simple-vector-p node) + (let ((len (length node))) + (rlabels (iter 0) + (iter (i) + (declare (fixnum i)) + (if (< i len) + (lambda (op) + (ecase op + (:first (values (svref node i) t)) + (:rest (iter (1+ i))) + (:empty? nil) + (:more? t))) + cont))))) + (t + (walk (WB-Seq-Tree-Node-Left node) + (walk (WB-Seq-Tree-Node-Right node) cont))))))) + +(defun WB-Seq-Tree-Rev-Fun-Iter (tree) + (declare (optimize (speed 3) (safety 0))) + (rlabels (walk tree (lambda (op) + (ecase op + ((:first :rest) (values nil nil)) + (:empty? t) + (:more? nil)))) + (walk (node cont) + (cond ((null node) + cont) + ((simple-string-p node) + (rlabels (iter (1- (length node))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (lambda (op) + (ecase op + (:first (values (schar node i) t)) + (:rest (iter (1- i))) + (:empty? nil) + (:more? t))) + cont)))) + ((simple-vector-p node) + (rlabels (iter (1- (length node))) + (iter (i) + (declare (fixnum i)) + (if (>= i 0) + (lambda (op) + (ecase op + (:first (values (svref node i) t)) + (:rest (iter (1- i))) + (:empty? nil) + (:more? t))) + cont)))) + (t + (walk (WB-Seq-Tree-Node-Right node) + (walk (WB-Seq-Tree-Node-Left node) cont))))))) + ;;; ================================================================================ ;;; Verifier