Skip to content

Commit

Permalink
Defines a split function for strings, lists, vecs, seqs
Browse files Browse the repository at this point in the history
  • Loading branch information
Izaakwltn committed May 10, 2024
1 parent d286a4c commit 298d972
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 32 deletions.
2 changes: 1 addition & 1 deletion examples/small-coalton-programs/src/brainfold.lisp
Expand Up @@ -187,7 +187,7 @@
(let cmds = (vec:new))
(let vecs = (vec:new))
(let ((parser (fn (input-string v)
(let ((head-tail (str:split 1 input-string)))
(let ((head-tail (str:bisect 1 input-string)))
(match (fst head-tail)
("" cmds)
(">"
Expand Down
42 changes: 30 additions & 12 deletions library/list.lisp
Expand Up @@ -241,11 +241,11 @@
(define (nth-cdr n l)
"Returns the nth-cdr of a list."
(cond ((null? l)
Nil)
((arith:zero? n)
l)
(True
(nth-cdr (arith:1- n) (cdr l)))))
Nil)
((arith:zero? n)
l)
(True
(nth-cdr (arith:1- n) (cdr l)))))

(declare elemIndex (Eq :a => :a -> List :a -> Optional UFix))
(define (elemIndex x xs)
Expand Down Expand Up @@ -604,13 +604,6 @@
(any f xs)))
((Nil) False)))

(declare split (Char -> String -> (List String)))
(define (split c str)
(lisp (List String) (c str)
(cl:let ((split-chars (cl:list c)))
(cl:declare (cl:dynamic-extent split-chars))
(uiop:split-string str :separator split-chars))))

(declare perms (List :a -> (List (List :a))))
(define (perms l)
"Produce all permutations of the list L."
Expand Down Expand Up @@ -643,6 +636,29 @@ This function is equivalent to all size-N elements of `(COMBS L)`."
(map (Cons x) (combsOf (- n 1) xs)) ; combs with X
(combsOf n xs))))))) ; and without x

(declare split ((Eq :a) => :a -> (List :a) -> (iter:Iterator (List :a))))
(define (split delim xs)
(let ((blocks (cell:new Nil))
(current-block (cell:new Nil))
(iter (iter:into-iter xs)))

(iter:for-each! (fn (x)
(cond
((== x delim)
(cell:push! blocks (reverse (cell:read current-block)))
(cell:write! current-block nil)
Unit)
(True
(cell:push! current-block x)
Unit)))
iter)

(unless (null? (cell:read current-block))
(cell:push! blocks (reverse (cell:read current-block)))
Unit)

(iter:into-iter (reverse (cell:read blocks)))))

;;
;; Instances
;;
Expand Down Expand Up @@ -764,5 +780,7 @@ This function is equivalent to all size-N elements of `(COMBS L)`."
(define-instance (Default (List :a))
(define (default) Nil)))



#+sb-package-locks
(sb-ext:lock-package "COALTON-LIBRARY/LIST")
42 changes: 35 additions & 7 deletions library/seq.lisp
Expand Up @@ -10,7 +10,8 @@
(#:optional #:coalton-library/optional)
(#:cell #:coalton-library/cell)
(#:vector #:coalton-library/vector)
(#:iter #:coalton-library/iterator))
(#:iter #:coalton-library/iterator)
(#:list #:coalton-library/list))
(:export
#:Seq
#:new
Expand All @@ -21,6 +22,7 @@
#:put
#:empty?
#:conc
#:split
#:make))

(in-package #:coalton-library/seq)
Expand Down Expand Up @@ -60,7 +62,7 @@
UFix ; height
UFix ; cached full subtree size
(vector:Vector UFix) ; cumulative size table
(vector:Vector (Seq :a))) ; subtrees
(vector:Vector (Seq :a))) ; subtrees
(LeafArray (vector:Vector :a)))

(declare new (types:RuntimeRepr :a => Unit -> Seq :a))
Expand Down Expand Up @@ -139,14 +141,14 @@ a new `Seq` instance."
(do
((Tuple leaf newsub) <- (pop (vector:last-unsafe sts)))
(let newsts = (vector:copy sts))
(let newcst = (vector:copy cst))
(let last-idx = (- (vector:length cst) 1))
(let seq-size = (size seq))
(let newcst = (vector:copy cst))
(let last-idx = (- (vector:length cst) 1))
(let seq-size = (size seq))
(pure
(cond
;; this was the only thing left in seq
((== 1 seq-size)
(Tuple leaf newsub)) ; newsub is empty
(Tuple leaf newsub)) ; newsub is empty

;; the seq was exactly one larger than the subtree size
;; for the current height, this means we can reduce the tree height
Expand All @@ -164,7 +166,7 @@ a new `Seq` instance."
(vector:set! last-idx newsub newsts)
(Tuple leaf (RelaxedNode h fss newcst newsts)))))))))

(define (conc left right)
(define (conc left right)
"Concatenate two `Seq`s"
(cond
((empty? left) right)
Expand Down Expand Up @@ -207,6 +209,30 @@ a new `Seq` instance."
(rebalance-branches
(fold <> (butlast lsubts) (make-list nsubts (butfirst rsubts))))))))))))

(declare split ((Eq :a) (types:RuntimeRepr :a) => :a -> (Seq :a) -> (iter:Iterator (Seq :a))))
(define (split delim xs)
(let ((blocks (cell:new Nil))
(current-block (cell:new (new)))
(iter (iter:into-iter xs)))

(iter:for-each!
(fn (x)
(cond
((== x delim)
(cell:push! blocks (cell:read current-block))
(cell:write! current-block (new))
Unit)
(True
(cell:write! current-block (push (cell:read current-block) x))
Unit)))
iter)

(unless (empty? (cell:read current-block))
(cell:push! blocks (cell:read current-block))
Unit)

(iter:into-iter (list:reverse (cell:read blocks)))))

;;
;; Instances
;;
Expand Down Expand Up @@ -253,6 +279,8 @@ a new `Seq` instance."
(iter:zip! (iter:into-iter a)
(iter:into-iter b)))))))



;;
;; Helpers
;;
Expand Down
20 changes: 14 additions & 6 deletions library/string.lisp
Expand Up @@ -11,21 +11,23 @@
#:Vector)
(:local-nicknames
(#:cell #:coalton-library/cell)
(#:iter #:coalton-library/iterator))
(#:iter #:coalton-library/iterator)
(#:list #:coalton-library/list))
(:export
#:concat
#:reverse
#:length
#:substring
#:split
#:bisect
#:strip-prefix
#:strip-suffix
#:parse-int
#:ref
#:ref-unchecked
#:substring-index
#:substring?
#:chars))
#:chars
#:split))


(in-package #:coalton-library/string)
Expand Down Expand Up @@ -65,9 +67,9 @@
(lisp String (real-start real-end str)
(cl:subseq str real-start real-end))))

(declare split (UFix -> String -> (Tuple String String)))
(define (split n str)
"Splits a string into a head and tail at the nth index."
(declare bisect (UFix -> String -> (Tuple String String)))
(define (bisect n str)
"Bisects a string into a head and tail at the nth index."
(Tuple (substring str 0 n)
(substring str n (length str))))

Expand Down Expand Up @@ -134,6 +136,12 @@ does not have that suffix."
(define (chars str)
"Returns an iterator over the characters in `str`."
(iter:into-iter str))

(declare split (Char -> String -> (List String)))
(define (split ch str)
"Splits a string with a specified single-character delimeter."
(map (fn (x) (the String (into x)))
(iter:collect! (list:split ch (the (List Char) (into str))))))

;;
;; Instances
Expand Down
13 changes: 13 additions & 0 deletions library/vector.lisp
Expand Up @@ -32,6 +32,7 @@
#:last
#:last-unsafe
#:extend!
#:split
#:find-elem
#:append
#:swap-remove!
Expand Down Expand Up @@ -247,6 +248,18 @@
iter)
Unit)

(declare list->vec (List :a -> Vector :a))
(define (list->vec x)
(into x))

(declare vec->list (Vector :a -> List :a))
(define (vec->list x)
(into x))

(declare split ((Eq :a) => :a -> (Vector :a) -> (iter:Iterator (Vector :a))))
(define (split delim v)
(map list->vec (list:split delim (vec->list v))))

;;
;; Instances
;;
Expand Down
3 changes: 0 additions & 3 deletions tests/list-tests.lisp
Expand Up @@ -209,9 +209,6 @@
Unit)

(define-test test-combinatorics ()
(is (== (list:split #\, "one,two,three") (make-list "one" "two" "three")))
(is (== (list:split #\, "one,,three") (make-list "one" "" "three")))

(is (set== (list:perms x)
(make-list
(make-list 1 2 3)
Expand Down
56 changes: 56 additions & 0 deletions tests/split-tests.lisp
@@ -0,0 +1,56 @@
(cl:in-package #:coalton-native-tests)

(coalton-toplevel
(define *split-path* "wow/ok/dir/file.txt")

(define *split-path-undotted* (make-list
(make-list #\w #\o #\w #\/ #\o #\k #\/ #\d #\i #\r #\/ #\f #\i #\l #\e)
(make-list #\t #\x #\t)))

(define *split-path-unslashed* (make-list
(make-list #\w #\o #\w)
(make-list #\o #\k)
(make-list #\d #\i #\r)
(make-list #\f #\i #\l #\e #\. #\t #\x #\t))))

;;;
;;; splitting lists
;;;

(define-test split-list ()
(is (== (iter:collect! (list:split #\. (iter:collect! (string:chars *split-path*)))) *split-path-undotted*))
(is (== (iter:collect! (list:split #\/ (iter:collect! (string:chars *split-path*)))) *split-path-unslashed*))
(is (== (iter:collect! (list:split 2 (make-list 1 2 3 4 2 5 2))) (make-list (make-list 1)
(make-list 3 4)
(make-list 5))))
(is (== (iter:collect! (list:split #\A (iter:collect! (string:chars "BANANA"))))
(make-list (make-list #\B)
(make-list #\N)
(make-list #\N)))))

;;;
;;; splitting vectors
;;;


(define-test split-vector ()
(is (== (iter:collect! (vector:split #\. (list->vec (iter:collect! (string:chars *split-path*)))))
(map list->vec *split-path-undotted*)))
(is (== (iter:collect! (vector:split #\/ (list->vec (iter:collect! (string:chars *split-path*)))))
(map list->vec *split-path-unslashed*))))

;;;
;;; splitting vector
;;;


(coalton-toplevel

(define (seq-num-list)
(the (seq:Seq Integer) (iter:collect! (iter:up-to 10)))))

(define-test split-seq ()
(is (== (the (List (seq:Seq Integer))
(iter:collect! (seq:split 5 (seq-num-list))))
(make-list (the (seq:Seq Integer) (iter:collect! (iter:up-to 5)))
(the (seq:Seq Integer) (iter:collect! (map (fn (x) (+ x 6)) (iter:up-to 4))))))))
16 changes: 13 additions & 3 deletions tests/string-tests.lisp
Expand Up @@ -19,11 +19,11 @@
(is (== (substring "foobar" 3 6)
"bar")))

(define-test string-split ()
(define-test bisect-string ()
(let str = "teststring")
(is (== (string:split 1 str)
(is (== (string:bisect 1 str)
(Tuple "t" "eststring")))
(is (== (string:split 4 str)
(is (== (string:bisect 4 str)
(Tuple "test" "string"))))

(define-test strip-fixes ()
Expand Down Expand Up @@ -76,3 +76,13 @@
(let has-empty? = (string:substring? ""))
(is (has-empty? ""))
(is (has-empty? "foo")))

(define-test string-split ()
(is (== (string:split #\, "one,two,three") (make-list "one" "two" "three")))
(is (== (string:split #\, "one,,three") (make-list "one" "" "three")))

(let path = "wow/ok/dir/file.txt")
(is (== (string:split #\. path) (make-list "wow/ok/dir/file" "txt")))
(is (== (string:split #\/ path) (make-list "wow" "ok" "dir" "file.txt")))
(is (== (string:split #\d "thisddddworks") (make-list "this" "" "" "" "works"))))

0 comments on commit 298d972

Please sign in to comment.