674 lines
26 KiB
Scheme
674 lines
26 KiB
Scheme
#!r6rs
|
|
|
|
(library (srfi :214 impl)
|
|
(export
|
|
;; Constructors
|
|
make-flexvector flexvector
|
|
flexvector-unfold flexvector-unfold-right
|
|
flexvector-copy flexvector-reverse-copy
|
|
flexvector-append flexvector-concatenate flexvector-append-subvectors
|
|
|
|
;; Predicates
|
|
flexvector? flexvector-empty? flexvector=?
|
|
|
|
;; Selectors
|
|
flexvector-ref flexvector-front flexvector-back flexvector-length
|
|
|
|
;; Mutators
|
|
flexvector-add! flexvector-add-front! flexvector-add-back!
|
|
flexvector-remove! flexvector-remove-front! flexvector-remove-back!
|
|
flexvector-add-all! flexvector-remove-range! flexvector-clear!
|
|
flexvector-set! flexvector-swap!
|
|
flexvector-fill! flexvector-reverse!
|
|
flexvector-copy! flexvector-reverse-copy!
|
|
flexvector-append!
|
|
|
|
;; Iteration
|
|
flexvector-fold flexvector-fold-right
|
|
flexvector-map flexvector-map! flexvector-map/index flexvector-map/index!
|
|
flexvector-append-map flexvector-append-map/index
|
|
flexvector-filter flexvector-filter! flexvector-filter/index flexvector-filter/index!
|
|
flexvector-for-each flexvector-for-each/index
|
|
flexvector-count flexvector-cumulate
|
|
|
|
;; Searching
|
|
flexvector-index flexvector-index-right
|
|
flexvector-skip flexvector-skip-right
|
|
flexvector-binary-search
|
|
flexvector-any flexvector-every flexvector-partition
|
|
|
|
;; Conversion
|
|
flexvector->vector flexvector->list flexvector->string
|
|
vector->flexvector list->flexvector string->flexvector
|
|
reverse-flexvector->list reverse-list->flexvector
|
|
generator->flexvector flexvector->generator)
|
|
(import (except (rnrs) vector-fill!)
|
|
(srfi :26)
|
|
(srfi :214 parameters)
|
|
(except (srfi :133 vectors) vector->list list->vector)
|
|
(srfi :158))
|
|
|
|
;;; Utilities
|
|
|
|
;; Checks if number is non-negative
|
|
(define (nonnegative? num)
|
|
(and (number? num) (>= num 0)))
|
|
|
|
;; Returns negated predicate.
|
|
(define (negate pred?)
|
|
(lambda args
|
|
(not (apply pred? args))))
|
|
|
|
;; Asserts that index is valid for the given flexvector.
|
|
(define (assert-index-validity fv . ids)
|
|
(let ([len (flexvector-len fv)])
|
|
(for-each (lambda (i)
|
|
(assert (and (>= i 0) (< i len))))
|
|
ids)))
|
|
|
|
;; Collects groups of `num` length in lst into a new list.
|
|
(define (group lst num)
|
|
(define (split l n)
|
|
(let loop ([acc (list)]
|
|
[ls l]
|
|
[count 0])
|
|
(cond [(>= count n) (values (reverse acc) ls)]
|
|
[(null? ls) (error group "Not enough elements for a group" lst num)]
|
|
[else (loop (cons (car ls) acc)
|
|
(cdr ls)
|
|
(+ count 1))])))
|
|
(assert (positive? num))
|
|
(let loop ([acc (list)]
|
|
[source lst])
|
|
(cond [(null? source) (reverse acc)]
|
|
[else (let-values ([(grp rest) (split source num)])
|
|
(loop (cons grp acc) rest))])))
|
|
|
|
;; Flexvector is represented as backing storage and number of used slots within.
|
|
(define-record-type (%flexvector %make-flexvector flexvector?)
|
|
(nongenerative flexvector-vtlmh5fxbj)
|
|
(fields (mutable vec flexvector-vec flexvector-vec-set!)
|
|
(mutable len flexvector-len flexvector-len-set!)))
|
|
|
|
;; Convenience wrapper to deconstruct flexvectors into parts.
|
|
(define-syntax with-flexvectors
|
|
(syntax-rules ()
|
|
[(_ ([(vec len) fv] rest ...) body ...)
|
|
(let* ([fv* fv]
|
|
[vec (flexvector-vec fv*)]
|
|
[len (flexvector-len fv*)])
|
|
(with-flexvectors (rest ...) body ...))]
|
|
[(_ () body ...)
|
|
(let ()
|
|
body ...)]))
|
|
|
|
;; Calls body with start and end clamped to dimensions of the flexvector.
|
|
(define-syntax with-clamped-range
|
|
(syntax-rules ()
|
|
[(_ (fv start end) body ...)
|
|
(let ([start (max 0 start)]
|
|
[end (min end (flexvector-len fv))])
|
|
(assert (<= start end))
|
|
(let ()
|
|
body ...))]))
|
|
|
|
;; Convenience definition facility for procedures that accept [start, [end]] optional arguments.
|
|
(define-syntax define-with-range
|
|
(syntax-rules (of)
|
|
[(_ (name fv ... start (end of what)) body ...)
|
|
(define name
|
|
(case-lambda
|
|
[(fv ...)
|
|
(name fv ... 0)]
|
|
[(fv ... start)
|
|
(name fv ... start (flexvector-len what))]
|
|
[(fv ... start end)
|
|
(with-clamped-range (what start end)
|
|
body ...)]))]))
|
|
|
|
;; Returns shortest length of given vectors.
|
|
(define (shortest-length vecs)
|
|
(apply min (map flexvector-len vecs)))
|
|
|
|
;; Shortcut macro for over-vectors iterations.
|
|
(define-syntax with-shortest-length
|
|
(syntax-rules ()
|
|
[(_ [(vecs shortest-len) vecs-expr] body ...)
|
|
(let* ([vecs vecs-expr]
|
|
[shortest-len (shortest-length vecs)])
|
|
body ...)]))
|
|
|
|
;; Returns flexvector capacity.
|
|
(define (flexvector-cap fv)
|
|
(vector-length (flexvector-vec fv)))
|
|
|
|
;; Makes sure that the flexvector has enough capacity
|
|
(define (ensure-capacity! fv required-cap)
|
|
(let ([current-cap (flexvector-cap fv)])
|
|
(unless (>= current-cap required-cap)
|
|
(let* ([vec (flexvector-vec fv)]
|
|
[new-cap ((flexvector-capacity-estimator) current-cap required-cap)]; (exact (expt 2 (+ (floor (log required-cap 2)) 1)))]
|
|
[new-vec (make-vector new-cap)])
|
|
(vector-copy! new-vec 0 vec 0 (vector-length vec))
|
|
(flexvector-vec-set! fv new-vec)))))
|
|
|
|
;; Makes sure capacity requested for flexvector creation is no less than
|
|
;; allowed minimal one.
|
|
(define (ensure-valid-capacity requested-size)
|
|
(assert (and (exact? requested-size) (>= requested-size 0)))
|
|
(max requested-size (flexvector-min-capacity)))
|
|
|
|
;; Constructs flexvector with given size and fill.
|
|
(define make-flexvector
|
|
(case-lambda
|
|
[(size)
|
|
(assert (nonnegative? size))
|
|
(%make-flexvector (make-vector (ensure-valid-capacity size)) size)]
|
|
[(size fill)
|
|
(assert (nonnegative? size))
|
|
(%make-flexvector (make-vector (ensure-valid-capacity size) fill) size)]))
|
|
|
|
;; Constructs flexvector from given elements.
|
|
(define (flexvector . els)
|
|
(cond [(null? els) (make-flexvector 0)]
|
|
[else (list->flexvector els)]))
|
|
|
|
;; Generates flexvector by applying func to seeds generated by gen until pred returns true.
|
|
(define (flexvector-unfold pred func gen . seeds)
|
|
(let ([fv (flexvector)])
|
|
(do [(seeds seeds (let-values [(seeds (apply gen seeds))]
|
|
seeds))]
|
|
[(apply pred seeds) fv]
|
|
(flexvector-add-back! fv (apply func seeds)))))
|
|
|
|
;; Generates flexvector like flexvector-unfold does but fill the resulting vector starting
|
|
;; from the right end.
|
|
(define (flexvector-unfold-right pred func gen . seeds)
|
|
(let ([fv (apply flexvector-unfold pred func gen seeds)])
|
|
(flexvector-reverse! fv)
|
|
fv))
|
|
|
|
;; Makes a copy of the flexvector.
|
|
(define-with-range (flexvector-copy fv start (end of fv))
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let ([result (make-flexvector (- end start))])
|
|
(vector-copy! (flexvector-vec result) 0 vec start end)
|
|
result)))
|
|
|
|
;; Makes a reverse copy of the flexvector.
|
|
(define (flexvector-reverse-copy . args)
|
|
(let ([copy (apply flexvector-copy args)])
|
|
(flexvector-reverse! copy)
|
|
copy))
|
|
|
|
;; Appends flexvectors together.
|
|
(define (flexvector-append fv . rest)
|
|
(flexvector-concatenate (cons fv rest)))
|
|
|
|
;; Concatenates given list of flexvectors together.
|
|
(define (flexvector-concatenate fvs)
|
|
(let* ([total-len (fold-left + 0 (map flexvector-len fvs))]
|
|
[result (make-flexvector total-len)])
|
|
(let loop ([vecs fvs]
|
|
[offset 0])
|
|
(cond [(null? vecs) result]
|
|
[else
|
|
(let ([current (car vecs)])
|
|
(flexvector-copy! result offset current)
|
|
(loop (cdr vecs) (+ offset (flexvector-len current))))]))))
|
|
|
|
;; Appends sequence of subvectors specified by vector + offset + count.
|
|
(define (flexvector-append-subvectors . args)
|
|
(let* ([triplets (group args 3)]
|
|
[subvecs (map (lambda (triplet)
|
|
(apply flexvector-copy triplet))
|
|
triplets)])
|
|
(flexvector-concatenate subvecs)))
|
|
|
|
;; Is the flexvector empty?
|
|
(define (flexvector-empty? fv)
|
|
(zero? (flexvector-len fv)))
|
|
|
|
;; Compares flexvectors. They should have same lengths and their
|
|
;; elements should be equal according to elt=?.
|
|
(define (flexvector=? elt=? . fvs)
|
|
(define (combine result . es)
|
|
(and result (apply elt=? es)))
|
|
(let ([lens (map flexvector-len fvs)])
|
|
(or (null? fvs) (null? (cdr fvs))
|
|
(and (apply = lens)
|
|
(apply flexvector-fold combine #t fvs)))))
|
|
|
|
;; References element at given index in the flexvector.
|
|
(define (flexvector-ref fv index)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(assert-index-validity fv index)
|
|
(vector-ref vec index)))
|
|
|
|
;; References the first element of an (assumed) non empty flexvector.
|
|
(define (flexvector-front fv)
|
|
(flexvector-ref fv 0))
|
|
|
|
;; References the last element of an (assumed) non empty flexvector.
|
|
(define (flexvector-back fv)
|
|
(let ([len (flexvector-len fv)])
|
|
(flexvector-ref fv (- len 1))))
|
|
|
|
;; Returns the length of the flexvector.
|
|
(define flexvector-length flexvector-len)
|
|
|
|
;; Adds elements els at position i shifting existing elements to the right.
|
|
(define (flexvector-add! fv i . els)
|
|
(flexvector-add-all! fv i els))
|
|
|
|
;; Adds elements els at the beginning of the flexvector.
|
|
(define (flexvector-add-front! fv . els)
|
|
(flexvector-add-all! fv 0 els))
|
|
|
|
;; Adds elements els at the end of the flexvector.
|
|
(define (flexvector-add-back! fv . els)
|
|
(flexvector-add-all! fv (flexvector-len fv) els))
|
|
|
|
;; Adds elements to the flexvector starting at index i.
|
|
(define (flexvector-add-all! fv i els)
|
|
(let* ([count (length els)]
|
|
[len (flexvector-len fv)]
|
|
[total-len (+ len count)])
|
|
(ensure-capacity! fv total-len)
|
|
(let ([vec (flexvector-vec fv)])
|
|
(vector-copy! vec (+ i count) vec i len)
|
|
(let loop ([ls els]
|
|
[offset 0])
|
|
(cond [(null? ls)
|
|
(flexvector-len-set! fv total-len)
|
|
fv]
|
|
[else (let ([el (car ls)])
|
|
(vector-set! vec (+ i offset) el)
|
|
(loop (cdr ls) (+ offset 1)))])))))
|
|
|
|
;; Appends flexvector to the first one.
|
|
(define (flexvector-append! fv . fvs)
|
|
(let* ([len (flexvector-len fv)]
|
|
[total-len (fold-left + len (map flexvector-len fvs))])
|
|
(ensure-capacity! fv total-len)
|
|
(let ([vec (flexvector-vec fv)])
|
|
(let loop ([fvs fvs]
|
|
[offset len])
|
|
(cond [(null? fvs)
|
|
(flexvector-len-set! fv total-len)
|
|
fv]
|
|
[else (with-flexvectors ([(current-vec current-len) (car fvs)])
|
|
(vector-copy! vec offset current-vec 0 current-len)
|
|
(loop (cdr fvs) (+ offset current-len)))])))))
|
|
|
|
;; Removes element at position i shifting remaining elements accordingly.
|
|
(define (flexvector-remove! fv i)
|
|
(let ([value (flexvector-ref fv i)])
|
|
(flexvector-remove-range! fv i (+ i 1))
|
|
value))
|
|
|
|
;; Removes the first element from the flexvector.
|
|
(define (flexvector-remove-front! fv)
|
|
(flexvector-remove! fv 0))
|
|
|
|
;; Removes element from the back of flexvector.
|
|
(define (flexvector-remove-back! fv)
|
|
(flexvector-remove! fv (- (flexvector-len fv) 1)))
|
|
|
|
;; Removes a range of elements from the vector.
|
|
(define flexvector-remove-range!
|
|
(case-lambda
|
|
[(fv start)
|
|
(flexvector-remove-range! fv start (flexvector-len fv))]
|
|
[(fv start end)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let* ([start (max start 0)]
|
|
[end (min len end)]
|
|
[move-count (- len end)]
|
|
[len-delta (- end start)])
|
|
(assert (<= start end))
|
|
(unless (zero? move-count)
|
|
(vector-copy! vec start vec end (+ end move-count)))
|
|
(flexvector-len-set! fv (- len len-delta))
|
|
fv))]))
|
|
|
|
;; Clears the flexvector.
|
|
(define (flexvector-clear! fv)
|
|
(flexvector-len-set! fv 0)
|
|
fv)
|
|
|
|
;; Sets the value at index i to el.
|
|
(define (flexvector-set! fv i el)
|
|
(assert-index-validity fv i)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let* ([val (vector-ref vec i)])
|
|
(vector-set! vec i el)
|
|
val)))
|
|
|
|
;; Swaps elements of flexvector.
|
|
(define (flexvector-swap! fv i j)
|
|
(assert-index-validity fv i j)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(vector-swap! vec i j)))
|
|
|
|
;; Fills elements between start and end of the flexvector with given fill value.
|
|
(define-with-range (flexvector-fill! fv fill start (end of fv))
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let ([start (max 0 start)]
|
|
[end (min end len)])
|
|
(vector-fill! vec fill start end)
|
|
fv)))
|
|
|
|
;; Reverses the flexvector in place.
|
|
(define-with-range (flexvector-reverse! fv start (end of fv))
|
|
(let* ([len (- end start)]
|
|
[vec (flexvector-vec fv)]
|
|
[half (floor (/ len 2))])
|
|
(do [(index 0 (+ index 1))]
|
|
[(>= index half) fv]
|
|
(let ([jndex (- len index 1)])
|
|
(vector-swap! vec (+ start index) (+ start jndex))))))
|
|
|
|
;; Copies section of flexvector `from` defined by `[start, end]` to flexvector `to` starting at index `at`.
|
|
(define-with-range (flexvector-copy! to at from start (end of from))
|
|
(let* ([len (flexvector-len to)]
|
|
[delta (- end start)]
|
|
[new-len (+ len delta)])
|
|
(assert (and (>= at 0) (<= at len)))
|
|
(ensure-capacity! to new-len)
|
|
(with-flexvectors ([(to-vec to-len) to]
|
|
[(from-vec from-len) from])
|
|
(vector-copy! to-vec at from-vec start end)
|
|
(flexvector-len-set! to (max len (+ at delta)))
|
|
to)))
|
|
|
|
;; Copies section of flexvector `from` defined by `[start, end]` in reverse order to flexvector `to` starting at index `at`.
|
|
(define-with-range (flexvector-reverse-copy! to at from start (end of from))
|
|
(flexvector-copy! to at from start end)
|
|
(flexvector-reverse! to at (+ at (- end start))))
|
|
|
|
;; Implementation of fold to reuse in left and right folds.
|
|
(define (flexvector-fold-impl index-proc reductor initial fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0]
|
|
[state initial])
|
|
(cond [(>= index shortest-len) state]
|
|
[else (loop (+ index 1)
|
|
(apply reductor state (map (cut flexvector-ref <> (index-proc index shortest-len)) vecs)))]))))
|
|
|
|
;; Folds flexvectors over initial value with reductor
|
|
(define (flexvector-fold reductor initial fv . rest)
|
|
(define (left-to-right index len)
|
|
index)
|
|
(apply flexvector-fold-impl left-to-right reductor initial fv rest))
|
|
|
|
;; Folds flexvectors over initial value with reductor from right to left.
|
|
(define (flexvector-fold-right reductor initial fv . rest)
|
|
(define (right-to-left index len)
|
|
(- len index 1))
|
|
(apply flexvector-fold-impl right-to-left reductor initial fv rest))
|
|
|
|
;; Helper map building procedure.
|
|
(define (flexvector-map/index-into! dst proc fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0])
|
|
(cond [(>= index shortest-len) dst]
|
|
[else (let ([value (apply proc index (map (cut flexvector-ref <> index) vecs))])
|
|
(flexvector-set! dst index value)
|
|
(loop (+ index 1)))]))))
|
|
|
|
;; Maps results of application of proc to index and elements of fv + rest back to fv.
|
|
(define (flexvector-map/index! proc fv . rest)
|
|
(apply flexvector-map/index-into! fv proc fv rest))
|
|
|
|
;; Maps results of application of proc to elements of fv + rest back to fv.
|
|
(define (flexvector-map! proc fv . rest)
|
|
(define (ignore-index . args)
|
|
(apply proc (cdr args)))
|
|
(apply flexvector-map/index! ignore-index fv rest))
|
|
|
|
;; Constructs a new flexvector from applications of proc to indices and elements of fv and rest.
|
|
(define (flexvector-map/index proc fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let ([result (make-flexvector shortest-len)])
|
|
(apply flexvector-map/index-into! result proc fv rest))))
|
|
|
|
;; Maps results of application of proc to elements of fv + rest into fresh flexvector.
|
|
(define (flexvector-map proc fv . rest)
|
|
(define (ignore-index . args)
|
|
(apply proc (cdr args)))
|
|
(apply flexvector-map/index ignore-index fv rest))
|
|
|
|
;; Appends results (which should be flexvectors) of application of proc to flexvectors (using index).
|
|
(define (flexvector-append-map/index proc fv . rest)
|
|
(flexvector-fold flexvector-append!
|
|
(flexvector)
|
|
(apply flexvector-map/index proc fv rest)))
|
|
|
|
;; Appends results (which should be flexvectors) of application of proc to flexvectors.
|
|
(define (flexvector-append-map proc fv . rest)
|
|
(flexvector-fold flexvector-append!
|
|
(flexvector)
|
|
(apply flexvector-map proc fv rest)))
|
|
|
|
;; Destructively updates fv to retain only those elements for which pred? returns true.
|
|
;; pred? is given an index as first argument.
|
|
(define (flexvector-filter/index! pred? fv)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let loop ([check-index 0]
|
|
[fill-index 0])
|
|
(cond [(>= check-index len)
|
|
(flexvector-len-set! fv fill-index)
|
|
fv]
|
|
[(pred? check-index (flexvector-ref fv check-index))
|
|
(flexvector-set! fv fill-index (flexvector-ref fv check-index))
|
|
(loop (+ check-index 1) (+ fill-index 1))]
|
|
[else (loop (+ check-index 1) fill-index)]))))
|
|
|
|
;; Destructively updates fv to retain only those elements for which pred? returns true.
|
|
(define (flexvector-filter! pred? fv)
|
|
(define (ignore-index index value)
|
|
(pred? value))
|
|
(flexvector-filter/index! ignore-index fv))
|
|
|
|
;; Create a new vector that has only those elements for which pred? returns true.
|
|
;; pred? is given an index as first argument.
|
|
(define (flexvector-filter/index pred? fv)
|
|
(flexvector-filter/index! pred? (flexvector-copy fv)))
|
|
|
|
;; Create a new vector that has only those elements for which pred? returns true.
|
|
(define (flexvector-filter pred? fv)
|
|
(flexvector-filter! pred? (flexvector-copy fv)))
|
|
|
|
;; Applies procedure proc to each element of vectors (stopping at shortest one).
|
|
;; proc is given an index as first argument.
|
|
(define (flexvector-for-each/index proc fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(do [(index 0 (+ index 1))]
|
|
[(>= index shortest-len)]
|
|
(apply proc index (map (cut flexvector-ref <> index) vecs)))))
|
|
|
|
;; Applies procedure proc to each element of vectors (stopping at shortest one).
|
|
(define (flexvector-for-each proc fv . rest)
|
|
(define (ignore-index . args)
|
|
(apply proc (cdr args)))
|
|
(apply flexvector-for-each/index ignore-index fv rest))
|
|
|
|
;; Counts elements for which pred? returns true.
|
|
(define (flexvector-count pred? fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0]
|
|
[count 0])
|
|
(cond [(>= index shortest-len) count]
|
|
[(apply pred? (map (cut flexvector-ref <> index) vecs))
|
|
(loop (+ index 1) (+ count 1))]
|
|
[else (loop (+ index 1) count)]))))
|
|
|
|
;; Constructs new vector using following rule - result[i] = (reductor result[i-1] fv[i])
|
|
;; where result[-1] = initial;
|
|
(define (flexvector-cumulate reductor initial fv)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let* ([result (make-flexvector len)]
|
|
[new-vec (flexvector-vec result)])
|
|
(let loop ([index 0]
|
|
[state initial])
|
|
(cond [(>= index len) result]
|
|
[else (let ([new-state (reductor state (vector-ref vec index))])
|
|
(vector-set! new-vec index new-state)
|
|
(loop (+ index 1) new-state))])))))
|
|
|
|
;; Finds first index that matches predicate.
|
|
(define (flexvector-index pred? fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0])
|
|
(cond [(>= index shortest-len) #f]
|
|
[(apply pred? (map (cut flexvector-ref <> index) vecs)) index]
|
|
[else (loop (+ index 1))]))))
|
|
|
|
;; Finds last index that matches predicate.
|
|
(define (flexvector-index-right pred? fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0])
|
|
(cond [(>= index shortest-len) #f]
|
|
[(apply pred? (map (cut flexvector-ref <> (- shortest-len index 1)) vecs)) (- shortest-len index 1)]
|
|
[else (loop (+ index 1))]))))
|
|
|
|
;; Skips elements matching predicate returning first index of non-matching element.
|
|
(define (flexvector-skip pred? fv . rest)
|
|
(apply flexvector-index (negate pred?) fv rest))
|
|
|
|
;; Skips elements matching predicate returning first index of non-matching element moving from right to left.
|
|
(define (flexvector-skip-right pred? fv . rest)
|
|
(apply flexvector-index-right (negate pred?) fv rest))
|
|
|
|
;; Performs binary search of a value using given direction computation function.
|
|
(define-with-range (flexvector-binary-search fv value comp start (end of fv))
|
|
(let ([vec (flexvector-vec fv)])
|
|
(vector-binary-search vec value comp start end)))
|
|
|
|
;; Searches first element for which pred? returns generalized true value and returns that value. If no such value found returns #f.
|
|
(define (flexvector-any pred? fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0])
|
|
(cond [(>= index shortest-len) #f]
|
|
[(apply pred? (map (cut flexvector-ref <> index) vecs))]
|
|
[else (loop (+ index 1))]))))
|
|
|
|
;; Checks if all elements match given predicate and returns last result from it if they do. Otherwise returns #f.
|
|
(define (flexvector-every pred? fv . rest)
|
|
(with-shortest-length [(vecs shortest-len) (cons fv rest)]
|
|
(let loop ([index 0]
|
|
[last-value #t])
|
|
(cond [(>= index shortest-len) last-value]
|
|
[(apply pred? (map (cut flexvector-ref <> index) vecs)) => (lambda (val)
|
|
(loop (+ index 1) val))]
|
|
[else #f]))))
|
|
|
|
;; Partitions the flexvector into flexvectors of elements that match predicate and those that do not match.
|
|
(define (flexvector-partition pred? fv)
|
|
(let ([matching (flexvector)]
|
|
[non-matching (flexvector)])
|
|
(flexvector-for-each (lambda (el)
|
|
(flexvector-add-back! (if (pred? el) matching non-matching) el))
|
|
fv)
|
|
(values matching non-matching)))
|
|
|
|
;;; Conversion
|
|
|
|
;; Creates a vector from given flexvector.
|
|
(define-with-range (flexvector->vector fv start (end of fv))
|
|
(let ([vec (flexvector-vec fv)])
|
|
(vector-copy vec start end)))
|
|
|
|
;; Creates a flexvector from a given vector.
|
|
(define vector->flexvector
|
|
(case-lambda
|
|
[(vec)
|
|
(vector->flexvector vec 0)]
|
|
[(vec start)
|
|
(vector->flexvector vec start (vector-length vec))]
|
|
[(vec start end)
|
|
(let* ([len (- end start)]
|
|
[result (make-flexvector len)]
|
|
[fvec (flexvector-vec result)])
|
|
(vector-copy! fvec 0 vec start end)
|
|
result)]))
|
|
|
|
;; Common implementation for flexvector->list and reverse-flexvector->list
|
|
(define (flexvector->list-impl finalizer fv start end)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let loop ([acc (list)]
|
|
[index 0])
|
|
(cond [(>= index len) (finalizer acc)]
|
|
[else (loop (cons (vector-ref vec index) acc)
|
|
(+ index 1))]))))
|
|
|
|
;; Turns flexvector into list.
|
|
(define-with-range (flexvector->list fv start (end of fv))
|
|
(flexvector->list-impl reverse fv start end))
|
|
|
|
;; Turns reversed flexvector into list.
|
|
(define-with-range (reverse-flexvector->list fv start (end of fv))
|
|
(define (identity l) l)
|
|
(flexvector->list-impl identity fv start end))
|
|
|
|
;; Conversion helper from list to flexvector.
|
|
(define (list->flexvector-impl lst index-func)
|
|
(let* ([len (length lst)]
|
|
[fv (make-flexvector len)])
|
|
(let loop ([lst lst]
|
|
[index 0])
|
|
(cond [(null? lst) fv]
|
|
[else (flexvector-set! fv (index-func len index) (car lst))
|
|
(loop (cdr lst) (+ index 1))]))))
|
|
|
|
;; Converts list into flexvector.
|
|
(define (list->flexvector lst)
|
|
(list->flexvector-impl lst (lambda (len index) index)))
|
|
|
|
;; Converts reversed list into flexvector.
|
|
(define (reverse-list->flexvector lst)
|
|
(list->flexvector-impl lst (lambda (len index) (- len index 1))))
|
|
|
|
;; Converts flexvector of chars to string.
|
|
(define-with-range (flexvector->string fv start (end of fv))
|
|
(let-values ([(out fin) (open-string-output-port)])
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let loop ([index start])
|
|
(cond [(>= index end) (fin)]
|
|
[else (put-char out (vector-ref vec index))
|
|
(loop (+ index 1))])))))
|
|
|
|
;; Converts string into a flexvector.
|
|
(define string->flexvector
|
|
(case-lambda
|
|
[(str)
|
|
(string->flexvector str 0)]
|
|
[(str start)
|
|
(string->flexvector str start (string-length str))]
|
|
[(str start end)
|
|
(let ([in (open-string-input-port (substring str start end))]
|
|
[fv (flexvector)])
|
|
(let loop ([ch (get-char in)])
|
|
(cond [(eof-object? ch) fv]
|
|
[else (flexvector-add-back! fv ch)
|
|
(loop (get-char in))])))]))
|
|
|
|
;; Converts flexvector into generator.
|
|
(define (flexvector->generator fv)
|
|
(with-flexvectors ([(vec len) fv])
|
|
(let ([index 0])
|
|
(lambda ()
|
|
(cond [(>= index len) (eof-object)]
|
|
[else
|
|
(let ([value (vector-ref vec index)])
|
|
(set! index (+ index 1))
|
|
value)])))))
|
|
|
|
;; Converts generator into a flexvector.
|
|
(define (generator->flexvector gen)
|
|
(let ([fv (flexvector)])
|
|
(generator-fold (lambda (v r) (flexvector-add-back! r v))
|
|
fv
|
|
gen))))
|