unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [PATCH] Added srfi-214: flexvectors
@ 2022-01-19  2:34 Vijay Marupudi
  2022-01-19  9:00 ` Maxime Devos
  0 siblings, 1 reply; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-19  2:34 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 303 bytes --]

Hello,

I have attached to this email a patch to add support for srfi-214,
flexvectors.

I have made as few changes to the code from the sample implementation.

If this is accepted, I can work on adding to the documentation.

I have been using this for a while, and it has worked wonderfully.

~ Vijay


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 25382 bytes --]

From f52164919a50600960aad2df323a3a3f51cf1427 Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Tue, 18 Jan 2022 20:52:08 -0500
Subject: [PATCH] Added srfi-214: flexvectors

---
 module/Makefile.am       |   1 +
 module/srfi/srfi-214.scm | 730 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 731 insertions(+)
 create mode 100644 module/srfi/srfi-214.scm

diff --git a/module/Makefile.am b/module/Makefile.am
index f6f5a9bb8..799ef7bd6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -323,6 +323,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..d52eca958
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,730 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;;
+;;; This library is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU Lesser General Public
+;;; License as published by the Free Software Foundation; either
+;;; version 3 of the License, or (at your option) any later version.
+;;;
+;;; This library is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; Lesser General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU Lesser General Public
+;;; License along with this library; if not, write to the Free Software
+;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;; This code was largely written by Adam Nelson as a sample
+;; implementation for srfi-214
+
+(define-module (srfi srfi-214))
+
+(use-modules ((scheme base)
+              #:prefix r7:)
+             (scheme case-lambda)
+             (scheme write)
+             (srfi srfi-1)
+             (srfi srfi-9)
+             (srfi srfi-9 gnu)
+             (srfi srfi-11)
+             (rnrs io ports))
+
+
+(export ; Constructors
+        make-flexvector flexvector
+        flexvector-unfold flexvector-unfold-right
+        flexvector-copy flexvector-reverse-copy
+        flexvector-append flexvector-concatenate flexvector-append-subvectors
+        <flexvector>
+
+        ; 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)
+
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display "()" port)
+                                (begin
+                                  (format port "(~a" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ")" port)
+                                        (begin
+                                          (format port " ~a" (flexvector-ref obj i))
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (r7:vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (r7:vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (r7:vector-copy! v (+ i xvlen) v i len)
+    (r7:vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (r7:vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (r7:vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (r7:vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (r7:vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (r7:vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (r7:map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (r7:vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (r7:vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (r7:vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (r7:map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (r7:map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (r7:map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (r7:map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply r7:string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (r7:vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
+
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-19  2:34 [PATCH] Added srfi-214: flexvectors Vijay Marupudi
@ 2022-01-19  9:00 ` Maxime Devos
  2022-01-19 13:55   ` Vijay Marupudi
       [not found]   ` <87wnivzvd4.fsf@vijaymarupudi.com>
  0 siblings, 2 replies; 14+ messages in thread
From: Maxime Devos @ 2022-01-19  9:00 UTC (permalink / raw)
  To: Vijay Marupudi, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1253 bytes --]

Vijay Marupudi schreef op di 18-01-2022 om 21:34 [-0500]:
> Hello,
> 
> I have attached to this email a patch to add support for srfi-214,
> flexvectors.
> 
> I have made as few changes to the code from the sample implementation.
> 
> If this is accepted, I can work on adding to the documentation.
> 
> I have been using this for a while, and it has worked wonderfully.

How about including the tests
(https://github.com/scheme-requests-for-implementation/srfi-214/blob/master/implementation/tests.scm)
as well?

Guile doesn't use SRFI-64 in its own tests though, so some changes may
be necessary.

I noticed you started the patch with:

+;;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;; [LGPL blurb]

however, the README says ‘by Adam Nelson’.  Did you reach some kind of
agreement with Adam Nelson about copyright assignment?  And since SRFIs
are licensed under Expat (not 100% sure), wouldn't this need to be the
Expat license text?

Even if the Expat license allows this (I don't know), then I would
still recommend to keep the license the same, such that fixes can
easily be interchanged between Scheme implementations (e.g. there have
been some fixes to SRFI-64 a while ago).

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-19  9:00 ` Maxime Devos
@ 2022-01-19 13:55   ` Vijay Marupudi
       [not found]   ` <87wnivzvd4.fsf@vijaymarupudi.com>
  1 sibling, 0 replies; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-19 13:55 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1541 bytes --]

Thank you for taking a look Maxime. I have accidentally replied to just
you and not the whole list, so there might be a duplicate email.

> How about including the tests
> (https://github.com/scheme-requests-for-implementation/srfi-214/blob/master/implementation/tests.scm)
> as well?
>
> Guile doesn't use SRFI-64 in its own tests though, so some changes may
> be necessary.

I've converted and added the tests to the patch. It passes with no
issues on my end.

> however, the README says ‘by Adam Nelson’.  Did you reach some kind of
> agreement with Adam Nelson about copyright assignment?  And since SRFIs
> are licensed under Expat (not 100% sure), wouldn't this need to be the
> Expat license text?
>
> Even if the Expat license allows this (I don't know), then I would
> still recommend to keep the license the same, such that fixes can
> easily be interchanged between Scheme implementations (e.g. there have
> been some fixes to SRFI-64 a while ago).

There was no copyright assignment. The expat license is GPL compatible,
so I assumed GPL would be the preferred license for a contribution to
Guile. I can definitely change the license for my edits to whatever is
best for Guile. The license for srfi-214's sample implementation is
definitely expat, given the SRFI process errata
<https://srfi.schemers.org/srfi-process.html> and the working repository
of the implementation
<https://github.com/ar-nelson/scheme-flexvectors/blob/master/LICENSE>

I have attached the updated patch.

~ Vijay


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 43965 bytes --]

From ec49b052809bbe44ee47765db0dd887313702dcc Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Tue, 18 Jan 2022 20:52:08 -0500
Subject: [PATCH] Added srfi-214: flexvectors

---
 module/Makefile.am             |   1 +
 module/srfi/srfi-214.scm       | 730 +++++++++++++++++++++++++++++++++
 test-suite/Makefile.am         |   1 +
 test-suite/tests/srfi-214.test | 427 +++++++++++++++++++
 4 files changed, 1159 insertions(+)
 create mode 100644 module/srfi/srfi-214.scm
 create mode 100644 test-suite/tests/srfi-214.test

diff --git a/module/Makefile.am b/module/Makefile.am
index f6f5a9bb8..799ef7bd6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -323,6 +323,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..d52eca958
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,730 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;;
+;;; This library is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU Lesser General Public
+;;; License as published by the Free Software Foundation; either
+;;; version 3 of the License, or (at your option) any later version.
+;;;
+;;; This library is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; Lesser General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU Lesser General Public
+;;; License along with this library; if not, write to the Free Software
+;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;; This code was largely written by Adam Nelson as a sample
+;; implementation for srfi-214
+
+(define-module (srfi srfi-214))
+
+(use-modules ((scheme base)
+              #:prefix r7:)
+             (scheme case-lambda)
+             (scheme write)
+             (srfi srfi-1)
+             (srfi srfi-9)
+             (srfi srfi-9 gnu)
+             (srfi srfi-11)
+             (rnrs io ports))
+
+
+(export ; Constructors
+        make-flexvector flexvector
+        flexvector-unfold flexvector-unfold-right
+        flexvector-copy flexvector-reverse-copy
+        flexvector-append flexvector-concatenate flexvector-append-subvectors
+        <flexvector>
+
+        ; 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)
+
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display "()" port)
+                                (begin
+                                  (format port "(~a" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ")" port)
+                                        (begin
+                                          (format port " ~a" (flexvector-ref obj i))
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (r7:vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (r7:vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (r7:vector-copy! v (+ i xvlen) v i len)
+    (r7:vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (r7:vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (r7:vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (r7:vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (r7:vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (r7:vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (r7:map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (r7:vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (r7:vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (r7:vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (r7:map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (r7:map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (r7:map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (r7:map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply r7:string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (r7:vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
+
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 16fa2e952..a62ffcf6c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,6 +162,7 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
             tests/srfi-171.test                 \
+	    tests/srfi-214.test                 \
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-214.test b/test-suite/tests/srfi-214.test
new file mode 100644
index 000000000..26925e614
--- /dev/null
+++ b/test-suite/tests/srfi-214.test
@@ -0,0 +1,427 @@
+;;;; srfi-214.test --- Test suite for SRFI 214 -*- scheme -*-
+;;;;
+;;;;    Copyright (C) 2022 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (test-suite test-srfi-214)
+  #:use-module (srfi srfi-214)
+  #:use-module (test-suite lib)
+  #:use-module (rnrs io ports))
+
+(with-test-prefix "SRFI-214"
+
+  (pass-if "flexvector?"
+    (equal? #t (flexvector? (flexvector))))
+  (pass-if "flexvector-length"
+    (equal? 3 (flexvector-length (make-flexvector 3 #f))))
+  (pass-if "flexvector"
+    (equal? 3 (flexvector-length (flexvector 1 2 3))))
+
+  (let ((fv (flexvector 'a 'b 'c)))
+    (pass-if "flexvector-ref"
+      (equal? 'b (flexvector-ref fv 1)))
+    (pass-if "flexvector-front"
+      (equal? 'a (flexvector-front fv)))
+    (pass-if "flexvector-back"
+      (equal? 'c (flexvector-back fv)))
+    (pass-if "flexvector-set! return"
+      (equal? 'b (flexvector-set! fv 1 'd)))
+    (pass-if "flexvector-set! mutate"
+      (equal? 'd (flexvector-ref fv 1)))
+    (pass-if "flexvector-add-back! return"
+      (equal? fv (flexvector-add-back! fv 'e)))
+    (pass-if "flexvector-add-back! mutate"
+      (equal? '(4 . e)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv (- (flexvector-length fv) 1)))))
+    (pass-if "flexvector-remove! return"
+      (equal? 'd (flexvector-remove! fv 1)))
+    (pass-if "flexvector-remove! mutate"
+      (equal? '(3 . c)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv 1))))
+    (pass-if "flexvector-clear! return"
+      (equal? fv (flexvector-clear! fv)))
+    (pass-if "flexvector-clear! mutate"
+      (equal? 0 (flexvector-length fv)))
+    (pass-if "flexvector-empty?"
+      (equal? #t (flexvector-empty? fv))))
+
+  (pass-if "flexvector=? same symbols"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b))))
+  (pass-if "flexvector=? different symbols"
+    (equal? #f
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a))))
+  (pass-if "flexvector=? different lengths"
+    (equal? #f
+            (flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? same numbers"
+    (equal? #t
+            (flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? 0 arguments"
+    (equal? #t
+            (flexvector=? eq?)))
+  (pass-if "flexvector=? 1 argument"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a))))
+
+  (pass-if "make-flexvector"
+    (equal? #(a a a) (flexvector->vector (make-flexvector 3 'a))))
+
+  (pass-if "flexvector-unfold"
+    (equal?
+     #(1 4 9 16 25 36 49 64 81 100)
+     (flexvector->vector
+      (flexvector-unfold (lambda (x) (> x 10))
+                         (lambda (x) (* x x))
+                         (lambda (x) (+ x 1))
+                         1))))
+  (pass-if "flexvector-unfold-right"
+    (equal?
+     #(100 81 64 49 36 25 16 9 4 1)
+     (flexvector->vector
+      (flexvector-unfold-right (lambda (x) (> x 10))
+                               (lambda (x) (* x x))
+                               (lambda (x) (+ x 1))
+                               1))))
+
+
+  (pass-if "string->flexvector"
+    (equal? #(#\a #\b #\c)
+            (flexvector->vector (string->flexvector "abc"))))
+  (pass-if "flexvector->string"
+    (equal? "abc" (flexvector->string (flexvector #\a #\b #\c))))
+
+  (define genlist '(a b c))
+  (define (mock-generator)
+    (if (pair? genlist)
+        (let ((value (car genlist)))
+          (set! genlist (cdr genlist))
+          value)
+        (eof-object)))
+
+  (pass-if "generator->flexvector"
+    (equal? #(a b c)
+            (flexvector->vector (generator->flexvector mock-generator))))
+  (pass-if "flexvector->generator"
+    (equal? '(a b c #t)
+            (let* ((gen (flexvector->generator (flexvector 'a 'b 'c)))
+                   (one (gen))
+                   (two (gen))
+                   (three (gen))
+                   (four (eof-object? (gen))))
+              (list one two three four))))
+
+                                        ; Nondestructive operations on one vector
+  (let ((fv (flexvector 10 20 30)))
+    (pass-if "flexvector->vector"
+      (equal? #(10 20 30) (flexvector->vector fv)))
+    (pass-if "flexvector->list"
+      (equal? '(10 20 30) (flexvector->list fv)))
+    (pass-if "reverse-flexvector->list"
+      (equal? '(30 20 10) (reverse-flexvector->list fv)))
+    (pass-if "flexvector-copy"
+      (equal? #t
+              (let ((copy (flexvector-copy fv)))
+                (and (= (flexvector-length fv) (flexvector-length copy))
+                     (not (eq? fv copy))))))
+    (pass-if "flexvector-reverse-copy"
+      (equal? #(30 20 10)
+              (flexvector->vector (flexvector-reverse-copy fv))))
+    (pass-if "flexvector-copy start"
+      (equal? #(20 30)
+              (flexvector->vector (flexvector-copy fv 1))))
+    (pass-if "flexvector-copy start end"
+      (equal? #(20)
+              (flexvector->vector (flexvector-copy fv 1 2))))
+    (pass-if "flexvector-for-each"
+      (equal? '(30 20 10)
+              (let ((res '()))
+                (flexvector-for-each (lambda (x) (set! res (cons x res))) fv)
+                res)))
+    (pass-if "flexvector-for-each/index"
+      (equal? '(34 22 10)
+              (let ((res '()))
+                (flexvector-for-each/index
+                 (lambda (i x) (set! res (cons (+ x (* i 2)) res)))
+                 fv)
+                res)))
+    (pass-if "flexvector-map"
+      (equal? #(100 200 300)
+              (flexvector->vector (flexvector-map (lambda (x) (* x 10)) fv))))
+    (pass-if "flexvector-map/index"
+      (equal? #(10 22 34)
+              (flexvector->vector (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv))))
+    (pass-if "flexvector-append-map"
+      (equal? #(10 100 20 200 30 300)
+              (flexvector->vector
+               (flexvector-append-map (lambda (x) (flexvector x (* x 10))) fv))))
+    (pass-if "flexvector-append-map/index"
+      (equal? #(0 10 10 1 20 22 2 30 34)
+              (flexvector->vector
+               (flexvector-append-map/index
+                (lambda (i x) (flexvector i x (+ x (* i 2))))
+                fv))))
+    (pass-if "flexvector-filter"
+      (equal? #(10)
+              (flexvector->vector (flexvector-filter (lambda (x) (< x 15)) fv))))
+    (pass-if "flexvector-filter/index"
+      (equal? #(10 30)
+              (flexvector->vector (flexvector-filter/index (lambda (i x) (not (= i 1))) fv))))
+    (pass-if "flexvector-fold"
+      (equal? '(30 20 10)
+              (flexvector-fold (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-fold-right"
+      (equal? '(10 20 30)
+              (flexvector-fold-right (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-count"
+      (equal? 2
+              (flexvector-count (lambda (x) (< x 25)) fv)))
+    (pass-if "flexvector-cumulate"
+      (equal? #(3 4 8 9 14 23 25 30 36)
+              (flexvector->vector
+               (flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6)))))
+    (pass-if "flexvector-any"
+      (equal? '(#t . #f)
+              (cons (flexvector-any (lambda (x) (= x 20)) fv)
+                    (flexvector-any (lambda (x) (= x 21)) fv))))
+    (pass-if "flexvector-every"
+      (equal? '(#t . #f)
+              (cons (flexvector-every (lambda (x) (< x 40)) fv)
+                    (flexvector-every (lambda (x) (< x 30)) fv))))
+    (pass-if "flexvector-index"
+      (equal? 1
+              (flexvector-index (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-index-right"
+      (equal? 2
+              (flexvector-index-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-skip"
+      (equal? 1
+              (flexvector-skip (lambda (x) (< x 20)) fv)))
+    (pass-if "flexvector-skip-right"
+      (equal? 0
+              (flexvector-skip-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-partition"
+      (equal? '(#(10 20) #(30))
+              (call-with-values
+                  (lambda () (flexvector-partition (lambda (x) (< x 25)) fv))
+                (lambda vs ((@ (scheme base) map) flexvector->vector vs))))))
+
+  (let ((fv (flexvector #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j))
+        (cmp (lambda (char1 char2)
+               (cond ((char<? char1 char2) -1)
+                     ((char=? char1 char2) 0)
+                     (else 1)))))
+    (pass-if "flexvector-binary-search"
+      (equal? 3
+              (flexvector-binary-search fv #\d cmp)))
+    (pass-if "flexvector-binary-search first"
+      (equal? 0
+              (flexvector-binary-search fv #\a cmp)))
+    (pass-if "flexvector-binary-search last"
+      (equal? 9
+              (flexvector-binary-search fv #\j cmp)))
+    (pass-if "flexvector-binary-search not found"
+      (equal? #f
+              (flexvector-binary-search fv #\k cmp)))
+
+    (pass-if "flexvector-binary-search in range"
+      (equal? 5
+              (flexvector-binary-search fv #\f cmp 2 6)))
+    (pass-if "flexvector-binary-search out of range"
+      (equal? #f
+              (flexvector-binary-search fv #\f cmp 1 5))))
+
+                                        ; Nondestructive operations on multiple vectors
+  (pass-if "flexvector-append"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-append (flexvector 10 20)
+                                (flexvector)
+                                (flexvector 30 40)
+                                (flexvector 50 60)))))
+  (pass-if "flexvector-concatenate"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-concatenate
+              (list (flexvector 10 20)
+                    (flexvector)
+                    (flexvector 30 40)
+                    (flexvector 50 60))))))
+  (pass-if "flexvector-append-subvectors"
+    (equal? #(a b h i)
+            (flexvector->vector
+             (flexvector-append-subvectors
+              (flexvector 'a 'b 'c 'd 'e) 0 2
+              (flexvector 'f 'g 'h 'i 'j) 2 4))))
+
+
+                                        ; Destructive operations on one vector
+  (define-syntax mutate-as
+    (syntax-rules ()
+      ((_ name vec expr)
+       (let ((name (vector->flexvector vec)))
+         expr
+         (flexvector->vector name)))))
+
+  (pass-if "flexvector-add! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! start"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! start multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! middle"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo baz) (flexvector-add! x 1 'bar))))
+  (pass-if "flexvector-add! middle multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo quux) (flexvector-add! x 1 'bar 'baz 'qux))))
+  (pass-if "flexvector-add! end"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz))))
+  (pass-if "flexvector-add! end multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-add-all!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo qux) (flexvector-add-all! x 1 '(bar baz)))))
+
+  (pass-if "flexvector-add-front! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-front! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-front!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add-front! x 'foo 'bar 'baz))))
+
+  (pass-if "flexvector-add-back! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-back! x 'foo))))
+  (pass-if "flexvector-add-back! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-back! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-back!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz))))
+  (pass-if "flexvector-add-back! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-append!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux)))))
+  (pass-if "flexvector-append! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux) (flexvector 'quux)))))
+
+  (pass-if "flexvector-remove!"
+    (equal? '#(foo baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove! x 1))))
+  (pass-if "flexvector-remove! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove! x 0))))
+
+  (pass-if "flexvector-remove-front!"
+    (equal? '#(bar baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-front! x))))
+  (pass-if "flexvector-remove-front! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-front! x))))
+
+  (pass-if "flexvector-remove-back!"
+    (equal? '#(foo bar)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-back! x))))
+  (pass-if "flexvector-remove-back! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-back! x))))
+
+  (pass-if "flexvector-remove-range!"
+    (equal? '#(a e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 4))))
+  (pass-if "flexvector-remove-range! empty range"
+    (equal? '#(a b c d e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 1))))
+  (pass-if "flexvector-remove-range! overflow left"
+    (equal? '#(e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x -1 4))))
+  (pass-if "flexvector-remove-range! overflow right"
+    (equal? '#(a b)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 2 10))))
+
+  (pass-if "flexvector-map!"
+    (equal? '#(100 200 300)
+            (mutate-as fv '#(10 20 30) (flexvector-map! (lambda (x) (* x 10)) fv))))
+  (pass-if "flexvector-map/index!"
+    (equal? '#(10 22 34)
+            (mutate-as fv '#(10 20 30) (flexvector-map/index! (lambda (i x) (+ x (* i 2))) fv))))
+  (pass-if "flexvector-filter!"
+    (equal? '#(10)
+            (mutate-as fv '#(10 20 30) (flexvector-filter! (lambda (x) (< x 15)) fv))))
+  (pass-if "flexvector-filter/index!"
+    (equal? '#(10 30)
+            (mutate-as fv '#(10 20 30) (flexvector-filter/index! (lambda (i x) (not (= i 1))) fv))))
+
+  (pass-if "flexvector-swap!"
+    (equal? #(10 30 20)
+            (mutate-as fv '#(10 20 30) (flexvector-swap! fv 1 2))))
+  (pass-if "flexvector-reverse!"
+    (equal? #(30 20 10)
+            (mutate-as fv '#(10 20 30) (flexvector-reverse! fv))))
+
+  (pass-if "flexvector-copy!"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-copy! bounded"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-copy! overflow"
+    (equal? #(1 2 30 40 50)
+            (mutate-as fv '#(1 2 3) (flexvector-copy! fv 2 (flexvector 30 40 50)))))
+  (pass-if "flexvector-reverse-copy!"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-reverse-copy! bounded"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-reverse-copy! overflow"
+    (equal? #(1 2 50 40 30)
+            (mutate-as fv '#(1 2 3) (flexvector-reverse-copy! fv 2 (flexvector 30 40 50)))))
+
+  (pass-if "flexvector-fill!"
+    (equal? '#(foo foo foo)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'foo))))
+  (pass-if "flexvector-fill! start"
+    (equal? '#(1 2 bar bar bar)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'bar 2))))
+  (pass-if "flexvector-fill! start end"
+    (equal? '#(1 2 baz baz 5)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'baz 2 4))))
+  (pass-if "flexvector-fill! clamped"
+    (equal? '#(qux qux qux)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'qux -1 10)))))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
       [not found]   ` <87wnivzvd4.fsf@vijaymarupudi.com>
@ 2022-01-19 15:04     ` Maxime Devos
  2022-01-19 15:44       ` Vijay Marupudi
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-01-19 15:04 UTC (permalink / raw)
  To: Vijay Marupudi, guile-devel

[-- Attachment #1: Type: text/plain, Size: 2183 bytes --]

Vijay Marupudi schreef op wo 19-01-2022 om 08:51 [-0500]:
> > however, the README says ‘by Adam Nelson’.  Did you reach some kind
> > of
> > agreement with Adam Nelson about copyright assignment?  And since
> > SRFIs
> > are licensed under Expat (not 100% sure), wouldn't this need to be
> > the
> > Expat license text?
> > 
> > Even if the Expat license allows this (I don't know), then I would
> > still recommend to keep the license the same, such that fixes can
> > easily be interchanged between Scheme implementations (e.g. there
> > have
> > been some fixes to SRFI-64 a while ago).
> 
> There was no copyright assignment.

If no copyright assignment has happend, then the copyright still
belongs to the author
-- from the Git repository's LICENSE:  Copyright © Adam Nelson (2020)).
While possibly you might have made some small changes to flexvectors,
it seems that most code is preserved, so at most a ‘© FSF’ line could
be added (*), however, the copyright line ‘© Adam Nelson’ would need to
remain, otherwise the copyright lines are misleading.

(*) This assumes you did copyright assignment to the FSF, otherwise
‘© Vijay Marupudi’.

Furthermore, the license requires preserving existing copyright
notices:

> The above copyright notice and [...] (including [...]) shall be
> included in all copies or substantial portions of the Software.

>  The expat license is GPL compatible,
> so I assumed GPL would be the preferred license for a contribution to
> Guile. [...] I can definitely change the license for my edits to
> whatever is

The expat license is GPL compatible, but the expat license requires
preserving the license text:

> Permission is hereby granted [...]:
> 
> The above [...] and this permission notice (including the next
> paragraph) shall be included in all copies or substantial portions of
> the Software.
> 
> [warranty disclaimer]

Here, ‘this permission notice’ seems to be the text of the expat
license.  But I'm not seeing this text in the srfi-214.scm of your
patch.

> best for Guile.

That would be up to the maintainers I suppose.


Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-19 15:04     ` Maxime Devos
@ 2022-01-19 15:44       ` Vijay Marupudi
  2022-01-19 16:04         ` Maxime Devos
  0 siblings, 1 reply; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-19 15:44 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1454 bytes --]

> If no copyright assignment has happend, then the copyright still
> belongs to the author
> -- from the Git repository's LICENSE:  Copyright © Adam Nelson (2020)).
> While possibly you might have made some small changes to flexvectors,
> it seems that most code is preserved, so at most a ‘© FSF’ line could
> be added (*), however, the copyright line ‘© Adam Nelson’ would need to
> remain, otherwise the copyright lines are misleading.
>
> (*) This assumes you did copyright assignment to the FSF, otherwise
> ‘© Vijay Marupudi’.

That's fair, thanks for looking into it! I was unaware of where to
include that information. I have added Adam Nelson and my name (can
remove this if necessary, just did it to be complete) to the license
comments and switched the `srfi-214.scm' file to the expat license for
now.

Note that I kept the GPL license in the srfi-214.test file, given
that the README in test-suite/README says:

> Please write more Guile tests, and send them to bug-guile@gnu.org.
> We'll merge them into the distribution.  All test suites must be
> licensed for our use under the GPL, but I don't think I'm going to
> collect assignment papers for them.

I have not assigned my copyright to the FSF, but can do so if
necessary.

>> best for Guile.
>
> That would be up to the maintainers I suppose.

Great, will wait for that. I have attached the latest version of the
patch.

~ Vijay


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 44446 bytes --]

From 164b482a3191a19e1090e485a080834af5adce97 Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Tue, 18 Jan 2022 20:52:08 -0500
Subject: [PATCH] Added srfi-214: flexvectors

---
 module/Makefile.am             |   1 +
 module/srfi/srfi-214.scm       | 735 +++++++++++++++++++++++++++++++++
 test-suite/Makefile.am         |   1 +
 test-suite/tests/srfi-214.test | 428 +++++++++++++++++++
 4 files changed, 1165 insertions(+)
 create mode 100644 module/srfi/srfi-214.scm
 create mode 100644 test-suite/tests/srfi-214.test

diff --git a/module/Makefile.am b/module/Makefile.am
index f6f5a9bb8..799ef7bd6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -323,6 +323,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..cb5caf16e
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,735 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) Adam Nelson (2020).
+;;; Copyright (C) Vijay Marupudi (2022).
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy of
+;;; this software and associated documentation files (the "Software"), to deal in
+;;; the Software without restriction, including without limitation the rights to
+;;; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+;;; the Software, and to permit persons to whom the Software is furnished to do so,
+;;; subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice (including the next
+;;; paragraph) shall be included in all copies or substantial portions of the
+;;; Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+;;; FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+;;; COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+;;; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; Authorship: This code was largely written by Adam Nelson as a
+;; sample implementation for srfi-214 and adapted for Guile by Vijay
+;; Marupudi.
+
+(define-module (srfi srfi-214))
+
+(use-modules ((scheme base)
+              #:prefix r7:)
+             (scheme case-lambda)
+             (scheme write)
+             (srfi srfi-1)
+             (srfi srfi-9)
+             (srfi srfi-9 gnu)
+             (srfi srfi-11)
+             (rnrs io ports))
+
+
+(export ; Constructors
+        make-flexvector flexvector
+        flexvector-unfold flexvector-unfold-right
+        flexvector-copy flexvector-reverse-copy
+        flexvector-append flexvector-concatenate flexvector-append-subvectors
+        <flexvector>
+
+        ; 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)
+
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display "()" port)
+                                (begin
+                                  (format port "(~a" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ")" port)
+                                        (begin
+                                          (format port " ~a" (flexvector-ref obj i))
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (r7:vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (r7:vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (r7:vector-copy! v (+ i xvlen) v i len)
+    (r7:vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (r7:vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (r7:vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (r7:vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (r7:vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (r7:vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (r7:map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (r7:vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (r7:vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (r7:vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (r7:map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (r7:map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (r7:map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (r7:map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply r7:string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (r7:vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 16fa2e952..a62ffcf6c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,6 +162,7 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
             tests/srfi-171.test                 \
+	    tests/srfi-214.test                 \
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-214.test b/test-suite/tests/srfi-214.test
new file mode 100644
index 000000000..403105e8a
--- /dev/null
+++ b/test-suite/tests/srfi-214.test
@@ -0,0 +1,428 @@
+;;;; srfi-214.test --- Test suite for SRFI 214 -*- scheme -*-
+;;;;
+;;;;    Copyright (C) 2020 Adam Nelson.
+;;;;    Copyright (C) 2022 Vijay Marupudi.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (test-suite test-srfi-214)
+  #:use-module (srfi srfi-214)
+  #:use-module (test-suite lib)
+  #:use-module (rnrs io ports))
+
+(with-test-prefix "SRFI-214"
+
+  (pass-if "flexvector?"
+    (equal? #t (flexvector? (flexvector))))
+  (pass-if "flexvector-length"
+    (equal? 3 (flexvector-length (make-flexvector 3 #f))))
+  (pass-if "flexvector"
+    (equal? 3 (flexvector-length (flexvector 1 2 3))))
+
+  (let ((fv (flexvector 'a 'b 'c)))
+    (pass-if "flexvector-ref"
+      (equal? 'b (flexvector-ref fv 1)))
+    (pass-if "flexvector-front"
+      (equal? 'a (flexvector-front fv)))
+    (pass-if "flexvector-back"
+      (equal? 'c (flexvector-back fv)))
+    (pass-if "flexvector-set! return"
+      (equal? 'b (flexvector-set! fv 1 'd)))
+    (pass-if "flexvector-set! mutate"
+      (equal? 'd (flexvector-ref fv 1)))
+    (pass-if "flexvector-add-back! return"
+      (equal? fv (flexvector-add-back! fv 'e)))
+    (pass-if "flexvector-add-back! mutate"
+      (equal? '(4 . e)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv (- (flexvector-length fv) 1)))))
+    (pass-if "flexvector-remove! return"
+      (equal? 'd (flexvector-remove! fv 1)))
+    (pass-if "flexvector-remove! mutate"
+      (equal? '(3 . c)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv 1))))
+    (pass-if "flexvector-clear! return"
+      (equal? fv (flexvector-clear! fv)))
+    (pass-if "flexvector-clear! mutate"
+      (equal? 0 (flexvector-length fv)))
+    (pass-if "flexvector-empty?"
+      (equal? #t (flexvector-empty? fv))))
+
+  (pass-if "flexvector=? same symbols"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b))))
+  (pass-if "flexvector=? different symbols"
+    (equal? #f
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a))))
+  (pass-if "flexvector=? different lengths"
+    (equal? #f
+            (flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? same numbers"
+    (equal? #t
+            (flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? 0 arguments"
+    (equal? #t
+            (flexvector=? eq?)))
+  (pass-if "flexvector=? 1 argument"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a))))
+
+  (pass-if "make-flexvector"
+    (equal? #(a a a) (flexvector->vector (make-flexvector 3 'a))))
+
+  (pass-if "flexvector-unfold"
+    (equal?
+     #(1 4 9 16 25 36 49 64 81 100)
+     (flexvector->vector
+      (flexvector-unfold (lambda (x) (> x 10))
+                         (lambda (x) (* x x))
+                         (lambda (x) (+ x 1))
+                         1))))
+  (pass-if "flexvector-unfold-right"
+    (equal?
+     #(100 81 64 49 36 25 16 9 4 1)
+     (flexvector->vector
+      (flexvector-unfold-right (lambda (x) (> x 10))
+                               (lambda (x) (* x x))
+                               (lambda (x) (+ x 1))
+                               1))))
+
+
+  (pass-if "string->flexvector"
+    (equal? #(#\a #\b #\c)
+            (flexvector->vector (string->flexvector "abc"))))
+  (pass-if "flexvector->string"
+    (equal? "abc" (flexvector->string (flexvector #\a #\b #\c))))
+
+  (define genlist '(a b c))
+  (define (mock-generator)
+    (if (pair? genlist)
+        (let ((value (car genlist)))
+          (set! genlist (cdr genlist))
+          value)
+        (eof-object)))
+
+  (pass-if "generator->flexvector"
+    (equal? #(a b c)
+            (flexvector->vector (generator->flexvector mock-generator))))
+  (pass-if "flexvector->generator"
+    (equal? '(a b c #t)
+            (let* ((gen (flexvector->generator (flexvector 'a 'b 'c)))
+                   (one (gen))
+                   (two (gen))
+                   (three (gen))
+                   (four (eof-object? (gen))))
+              (list one two three four))))
+
+                                        ; Nondestructive operations on one vector
+  (let ((fv (flexvector 10 20 30)))
+    (pass-if "flexvector->vector"
+      (equal? #(10 20 30) (flexvector->vector fv)))
+    (pass-if "flexvector->list"
+      (equal? '(10 20 30) (flexvector->list fv)))
+    (pass-if "reverse-flexvector->list"
+      (equal? '(30 20 10) (reverse-flexvector->list fv)))
+    (pass-if "flexvector-copy"
+      (equal? #t
+              (let ((copy (flexvector-copy fv)))
+                (and (= (flexvector-length fv) (flexvector-length copy))
+                     (not (eq? fv copy))))))
+    (pass-if "flexvector-reverse-copy"
+      (equal? #(30 20 10)
+              (flexvector->vector (flexvector-reverse-copy fv))))
+    (pass-if "flexvector-copy start"
+      (equal? #(20 30)
+              (flexvector->vector (flexvector-copy fv 1))))
+    (pass-if "flexvector-copy start end"
+      (equal? #(20)
+              (flexvector->vector (flexvector-copy fv 1 2))))
+    (pass-if "flexvector-for-each"
+      (equal? '(30 20 10)
+              (let ((res '()))
+                (flexvector-for-each (lambda (x) (set! res (cons x res))) fv)
+                res)))
+    (pass-if "flexvector-for-each/index"
+      (equal? '(34 22 10)
+              (let ((res '()))
+                (flexvector-for-each/index
+                 (lambda (i x) (set! res (cons (+ x (* i 2)) res)))
+                 fv)
+                res)))
+    (pass-if "flexvector-map"
+      (equal? #(100 200 300)
+              (flexvector->vector (flexvector-map (lambda (x) (* x 10)) fv))))
+    (pass-if "flexvector-map/index"
+      (equal? #(10 22 34)
+              (flexvector->vector (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv))))
+    (pass-if "flexvector-append-map"
+      (equal? #(10 100 20 200 30 300)
+              (flexvector->vector
+               (flexvector-append-map (lambda (x) (flexvector x (* x 10))) fv))))
+    (pass-if "flexvector-append-map/index"
+      (equal? #(0 10 10 1 20 22 2 30 34)
+              (flexvector->vector
+               (flexvector-append-map/index
+                (lambda (i x) (flexvector i x (+ x (* i 2))))
+                fv))))
+    (pass-if "flexvector-filter"
+      (equal? #(10)
+              (flexvector->vector (flexvector-filter (lambda (x) (< x 15)) fv))))
+    (pass-if "flexvector-filter/index"
+      (equal? #(10 30)
+              (flexvector->vector (flexvector-filter/index (lambda (i x) (not (= i 1))) fv))))
+    (pass-if "flexvector-fold"
+      (equal? '(30 20 10)
+              (flexvector-fold (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-fold-right"
+      (equal? '(10 20 30)
+              (flexvector-fold-right (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-count"
+      (equal? 2
+              (flexvector-count (lambda (x) (< x 25)) fv)))
+    (pass-if "flexvector-cumulate"
+      (equal? #(3 4 8 9 14 23 25 30 36)
+              (flexvector->vector
+               (flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6)))))
+    (pass-if "flexvector-any"
+      (equal? '(#t . #f)
+              (cons (flexvector-any (lambda (x) (= x 20)) fv)
+                    (flexvector-any (lambda (x) (= x 21)) fv))))
+    (pass-if "flexvector-every"
+      (equal? '(#t . #f)
+              (cons (flexvector-every (lambda (x) (< x 40)) fv)
+                    (flexvector-every (lambda (x) (< x 30)) fv))))
+    (pass-if "flexvector-index"
+      (equal? 1
+              (flexvector-index (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-index-right"
+      (equal? 2
+              (flexvector-index-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-skip"
+      (equal? 1
+              (flexvector-skip (lambda (x) (< x 20)) fv)))
+    (pass-if "flexvector-skip-right"
+      (equal? 0
+              (flexvector-skip-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-partition"
+      (equal? '(#(10 20) #(30))
+              (call-with-values
+                  (lambda () (flexvector-partition (lambda (x) (< x 25)) fv))
+                (lambda vs ((@ (scheme base) map) flexvector->vector vs))))))
+
+  (let ((fv (flexvector #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j))
+        (cmp (lambda (char1 char2)
+               (cond ((char<? char1 char2) -1)
+                     ((char=? char1 char2) 0)
+                     (else 1)))))
+    (pass-if "flexvector-binary-search"
+      (equal? 3
+              (flexvector-binary-search fv #\d cmp)))
+    (pass-if "flexvector-binary-search first"
+      (equal? 0
+              (flexvector-binary-search fv #\a cmp)))
+    (pass-if "flexvector-binary-search last"
+      (equal? 9
+              (flexvector-binary-search fv #\j cmp)))
+    (pass-if "flexvector-binary-search not found"
+      (equal? #f
+              (flexvector-binary-search fv #\k cmp)))
+
+    (pass-if "flexvector-binary-search in range"
+      (equal? 5
+              (flexvector-binary-search fv #\f cmp 2 6)))
+    (pass-if "flexvector-binary-search out of range"
+      (equal? #f
+              (flexvector-binary-search fv #\f cmp 1 5))))
+
+                                        ; Nondestructive operations on multiple vectors
+  (pass-if "flexvector-append"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-append (flexvector 10 20)
+                                (flexvector)
+                                (flexvector 30 40)
+                                (flexvector 50 60)))))
+  (pass-if "flexvector-concatenate"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-concatenate
+              (list (flexvector 10 20)
+                    (flexvector)
+                    (flexvector 30 40)
+                    (flexvector 50 60))))))
+  (pass-if "flexvector-append-subvectors"
+    (equal? #(a b h i)
+            (flexvector->vector
+             (flexvector-append-subvectors
+              (flexvector 'a 'b 'c 'd 'e) 0 2
+              (flexvector 'f 'g 'h 'i 'j) 2 4))))
+
+
+                                        ; Destructive operations on one vector
+  (define-syntax mutate-as
+    (syntax-rules ()
+      ((_ name vec expr)
+       (let ((name (vector->flexvector vec)))
+         expr
+         (flexvector->vector name)))))
+
+  (pass-if "flexvector-add! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! start"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! start multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! middle"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo baz) (flexvector-add! x 1 'bar))))
+  (pass-if "flexvector-add! middle multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo quux) (flexvector-add! x 1 'bar 'baz 'qux))))
+  (pass-if "flexvector-add! end"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz))))
+  (pass-if "flexvector-add! end multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-add-all!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo qux) (flexvector-add-all! x 1 '(bar baz)))))
+
+  (pass-if "flexvector-add-front! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-front! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-front!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add-front! x 'foo 'bar 'baz))))
+
+  (pass-if "flexvector-add-back! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-back! x 'foo))))
+  (pass-if "flexvector-add-back! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-back! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-back!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz))))
+  (pass-if "flexvector-add-back! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-append!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux)))))
+  (pass-if "flexvector-append! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux) (flexvector 'quux)))))
+
+  (pass-if "flexvector-remove!"
+    (equal? '#(foo baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove! x 1))))
+  (pass-if "flexvector-remove! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove! x 0))))
+
+  (pass-if "flexvector-remove-front!"
+    (equal? '#(bar baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-front! x))))
+  (pass-if "flexvector-remove-front! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-front! x))))
+
+  (pass-if "flexvector-remove-back!"
+    (equal? '#(foo bar)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-back! x))))
+  (pass-if "flexvector-remove-back! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-back! x))))
+
+  (pass-if "flexvector-remove-range!"
+    (equal? '#(a e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 4))))
+  (pass-if "flexvector-remove-range! empty range"
+    (equal? '#(a b c d e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 1))))
+  (pass-if "flexvector-remove-range! overflow left"
+    (equal? '#(e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x -1 4))))
+  (pass-if "flexvector-remove-range! overflow right"
+    (equal? '#(a b)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 2 10))))
+
+  (pass-if "flexvector-map!"
+    (equal? '#(100 200 300)
+            (mutate-as fv '#(10 20 30) (flexvector-map! (lambda (x) (* x 10)) fv))))
+  (pass-if "flexvector-map/index!"
+    (equal? '#(10 22 34)
+            (mutate-as fv '#(10 20 30) (flexvector-map/index! (lambda (i x) (+ x (* i 2))) fv))))
+  (pass-if "flexvector-filter!"
+    (equal? '#(10)
+            (mutate-as fv '#(10 20 30) (flexvector-filter! (lambda (x) (< x 15)) fv))))
+  (pass-if "flexvector-filter/index!"
+    (equal? '#(10 30)
+            (mutate-as fv '#(10 20 30) (flexvector-filter/index! (lambda (i x) (not (= i 1))) fv))))
+
+  (pass-if "flexvector-swap!"
+    (equal? #(10 30 20)
+            (mutate-as fv '#(10 20 30) (flexvector-swap! fv 1 2))))
+  (pass-if "flexvector-reverse!"
+    (equal? #(30 20 10)
+            (mutate-as fv '#(10 20 30) (flexvector-reverse! fv))))
+
+  (pass-if "flexvector-copy!"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-copy! bounded"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-copy! overflow"
+    (equal? #(1 2 30 40 50)
+            (mutate-as fv '#(1 2 3) (flexvector-copy! fv 2 (flexvector 30 40 50)))))
+  (pass-if "flexvector-reverse-copy!"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-reverse-copy! bounded"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-reverse-copy! overflow"
+    (equal? #(1 2 50 40 30)
+            (mutate-as fv '#(1 2 3) (flexvector-reverse-copy! fv 2 (flexvector 30 40 50)))))
+
+  (pass-if "flexvector-fill!"
+    (equal? '#(foo foo foo)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'foo))))
+  (pass-if "flexvector-fill! start"
+    (equal? '#(1 2 bar bar bar)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'bar 2))))
+  (pass-if "flexvector-fill! start end"
+    (equal? '#(1 2 baz baz 5)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'baz 2 4))))
+  (pass-if "flexvector-fill! clamped"
+    (equal? '#(qux qux qux)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'qux -1 10)))))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-19 15:44       ` Vijay Marupudi
@ 2022-01-19 16:04         ` Maxime Devos
  2022-01-20 15:34           ` Vijay Marupudi
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-01-19 16:04 UTC (permalink / raw)
  To: Vijay Marupudi, guile-devel

[-- Attachment #1: Type: text/plain, Size: 2192 bytes --]

Vijay Marupudi schreef op wo 19-01-2022 om 10:44 [-0500]:
> > If no copyright assignment has happend, then the copyright still
> > belongs to the author
> > -- from the Git repository's LICENSE:  Copyright © Adam Nelson
> > (2020)).
> > While possibly you might have made some small changes to
> > flexvectors,
> > it seems that most code is preserved, so at most a ‘© FSF’ line
> > could
> > be added (*), however, the copyright line ‘© Adam Nelson’ would
> > need to
> > remain, otherwise the copyright lines are misleading.
> > 
> > (*) This assumes you did copyright assignment to the FSF, otherwise
> > ‘© Vijay Marupudi’.
> 
> That's fair, thanks for looking into it! I was unaware of where to
> include that information. I have added Adam Nelson and my name (can
> remove this if necessary, just did it to be complete) to the license
> comments and switched the `srfi-214.scm' file to the expat license
> for
> now.
> 
> Note that I kept the GPL license in the srfi-214.test file, given
> that the README in test-suite/README says:
> 
> > Please write more Guile tests, and send them to bug-guile@gnu.org.
> > We'll merge them into the distribution.  All test suites must be
> > licensed for our use under the GPL, but I don't think I'm going to
> > collect assignment papers for them.

Guile's README cannot override the law, so the expat license text
would need to remain.  I think test-suite/README is primarily
concerned license compatibility and consistency, so I guess
for code from external sources, the ‘let GPL be the license’
requirement can be relaxed somewhat.

For example, see tests/srfi-27.test and tests/srfi-41.test -- they
appear to be Expat.

Something I forgot to mention: documentation!  Would you be up
to documenting flexvectors in Guile (in ‘6.6 Datatypes’ I presume,
after ‘vlists’ maybe, with a cross-reference from
‘7.5 SRFI Support Modules’)?

> I have not assigned my copyright to the FSF, but can do so if
> necessary.

As I understand it, a maintainer will inform you on what you
need to sign, etc -- it's a process initiated by the maintainer,
not the contributor.



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-19 16:04         ` Maxime Devos
@ 2022-01-20 15:34           ` Vijay Marupudi
  2022-01-20 16:53             ` Maxime Devos
  0 siblings, 1 reply; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-20 15:34 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1308 bytes --]

> Guile's README cannot override the law, so the expat license text
> would need to remain.  I think test-suite/README is primarily
> concerned license compatibility and consistency, so I guess
> for code from external sources, the ‘let GPL be the license’
> requirement can be relaxed somewhat.
>
> For example, see tests/srfi-27.test and tests/srfi-41.test -- they
> appear to be Expat.

Thanks for providing the examples, I have updated the tests to follow
the requirement. The latest version of the patch is attached. Licenses
are tricky things!

> Something I forgot to mention: documentation!  Would you be up
> to documenting flexvectors in Guile (in ‘6.6 Datatypes’ I presume,
> after ‘vlists’ maybe, with a cross-reference from
> ‘7.5 SRFI Support Modules’)?

My latest patch now has documentation, mostly derived from the SRFI-214
documentation. Who would have figured that conversion to texinfo would be the
most time consuming part of this patch?

I would like advice on how to attribute the documentation to Adam Nelson.

> As I understand it, a maintainer will inform you on what you
> need to sign, etc -- it's a process initiated by the maintainer,
> not the contributor.

Sounds good.

Attached is the latest version of the patch.

~ Vijay


[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 75673 bytes --]

From b55a1e2295013ba6a9e0a1a98d188c17a0fd7058 Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Tue, 18 Jan 2022 20:52:08 -0500
Subject: [PATCH] Added srfi-214: flexvectors

---
 doc/ref/api-data.texi          | 814 ++++++++++++++++++++++++++++++++-
 doc/ref/srfi-modules.texi      |   6 +
 module/Makefile.am             |   1 +
 module/srfi/srfi-214.scm       | 735 +++++++++++++++++++++++++++++
 test-suite/Makefile.am         |   1 +
 test-suite/tests/srfi-214.test | 437 ++++++++++++++++++
 6 files changed, 1993 insertions(+), 1 deletion(-)
 create mode 100644 module/srfi/srfi-214.scm
 create mode 100644 test-suite/tests/srfi-214.test

diff --git a/doc/ref/api-data.texi b/doc/ref/api-data.texi
index b6c2c4d61..ca1addb5c 100644
--- a/doc/ref/api-data.texi
+++ b/doc/ref/api-data.texi
@@ -26,7 +26,8 @@ complex.
 * Bit Vectors::                 Vectors of bits.
 * Bytevectors::                 Sequences of bytes.
 * Arrays::                      Multidimensional matrices.
-* VLists::                      Vector-like lists.
+* VLists::                      Vector-like lists
+* Flexvectors::                 Mutable vectors with adjustable size
 * Record Overview::             Walking through the maze of record APIs.
 * SRFI-9 Records::              The standard, recommended record API.
 * Records::                     Guile's historical record API.
@@ -8393,6 +8394,817 @@ Return a new vlist whose contents correspond to @var{lst}.
 Return a new list whose contents match those of @var{vlist}.
 @end deffn
 
+@node Flexvectors
+@subsection Flexvectors
+@cindex flexvector
+
+Flexvectors are sometimes better known as a @url{https://en.wikipedia.org/wiki/Dynamic_array,dynamic arrays}. This data
+structure has a wide variety of names in different languages:
+
+@itemize @bullet{}
+
+@item
+JavaScript and Ruby call it an array
+@item
+Python calls it a list
+@item
+Java calls it an ArrayList (and, before that, it was called a Vector)
+
+@end itemize
+
+
+Flexvectors have the same O(1) random-access performance guarantees as
+ordinary vectors. Additionally, appending to the back of a flexvector
+has the same (amortized) performance as setting an existing location in
+the same flexvector.
+
+Functions in this module can be obtained with:
+
+@example
+(use-modules (srfi srfi-214))
+@end example
+
+@subsubsection Constructors
+
+@deffn {Scheme Procedure} make-flexvector size [fill]
+
+Creates and returns a flexvector of size @var{size}. If @var{fill} is
+specified, all of the elements of the vector are initialized to
+@var{fill}. Otherwise, their contents are indeterminate.
+
+
+@example
+(make-flexvector 5 3) @result{} #<flexvector 3 3 3 3 3>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector x ...
+
+Creates and returns a flexvector whose elements are @var{x ...}.
+
+@example
+(flexvector 0 1 2 3 4) @result{} #<flexvector 0 1 2 3 4>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-unfold p f g initial-seed ...
+@deffnx {Scheme Procedure} flexvector-unfold-right p f g initial-seed ...
+
+The fundamental flexvector constructor. @code{flexvector-unfold} is
+modeled on SRFI 1 @code{unfold} instead of SRFI 133
+@code{vector-unfold} because flexvectors are not limited to a
+predetermined length.
+
+@example
+;; List of squares: 1^2 ... 10^2
+(flexvector-unfold (lambda (x) (> x 10)) (lambda (x) (* x x)) (lambda (x) (+ x 1)) 1)
+@result{} #<flexvector 1 4 9 16 25 36 49 64 81 100>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy fv [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy fv [start [end]]
+
+Allocates a new flexvector whose length is @code{(- end start)} and fills
+it with elements from @var{fv}, taking elements from @var{fv} starting
+at index @var{start} and stopping at index @var{end}. @var{start}
+defaults to @var{0} and @var{end} defaults to the value of
+@code{(flexvector-length fv)}.
+
+@example
+(flexvector-copy (flexvector 'a 'b 'c)) @result{} #<flexvector a b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1) @result{} #<flexvector b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1 2) @result{} #<flexvector b>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append fv ...
+
+Returns a newly allocated flexvector that contains all elements in order
+from the subsequent locations in @var{fv ...}.
+
+@example
+(flexvector-append (flexvector 'x) (flexvector 'y))
+@result{} #<flexvector x y>
+
+(flexvector-append (flexvector 'a) (flexvector 'b 'c 'd))
+@result{} #<flexvector a b c d>
+
+(flexvector-append (flexvector 'a (flexvector 'b))
+                   (flexvector (flexvector 'c)))
+@result{} #<flexvector a #<flexvector b> #<flexvector c>>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-concatenate list-of-flexvectors
+
+Equivalent to @code{(apply flexvector-append list-of-flexvectors)}, but
+may be implemented more efficiently.
+
+@example
+(flexvector-concatenate (list (flexvector 'a 'b) (flexvector 'c 'd)))
+@result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-append-subvectors [fv start end] ...
+
+Returns a vector that contains every element of each @var{fv} from
+@var{start} to @var{end} in the specified order. This procedure is a
+generalization of @code{flexvector-append}.
+
+@example
+(flexvector-append-subvectors (flexvector 'a 'b 'c 'd 'e) 0 2
+                              (flexvector 'f 'g 'h 'i 'j) 2 4)
+@result{} #<flexvector a b h i>
+@end example
+@end deffn
+
+@subsubsection Predicates
+
+@deffn {Scheme Procedure} flexvector? x
+
+Disjoint type predicate for flexvectors: this returns @var{#t} if
+@var{x} is a flexvector, and @var{#f} otherwise.
+
+@example
+(flexvector? (flexvector 1 2 3)) @result{} #t
+(flexvector? (vector 1 2 3)) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-empty? fv
+
+Returns @var{#t} if @var{fv} is empty (i.e., its length is @var{0}), and
+@var{#f} if not.
+
+@example
+(flexvector-empty? (flexvector)) @result{} #t
+(flexvector-empty? (flexvector 'a)) @result{} #f
+(flexvector-empty? (flexvector (flexvector))) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector=? elt=? fv ...
+
+Flexvector structural equality predicate, generalized across
+user-specified element equality predicates. Flexvectors @var{a} and
+@var{b} are considered equal by @code{flexvector=?} iff their lengths are
+the same and, for each index @var{i} less than @code{(flexvector-length
+a)}, @code{(elt=? (flexvector-ref a i) (flexvector-ref b i))} is true.
+@var{elt=?} is always applied to two arguments.
+
+
+@example
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b)) @result{} #t
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4)) @result{} #t
+@end example
+@end deffn
+
+@subsubsection Selectors
+
+@deffn {Scheme Procedure} flexvector-ref fv i
+
+Flexvector element dereferencing: returns the value at location @var{i}
+in @var{fv}. Indexing is zero-based. It is an error if @var{i} is
+outside the range [0, @code{(flexvector-length fv)}).
+
+@example
+(flexvector-ref (flexvector 'a 'b 'c 'd) 2) @result{} c
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-front fv
+
+Returns the first element in @var{fv}. It is an error if @var{fv} is
+empty. Alias for @code{(flexvector-ref fv 0)}.
+
+@example
+(flexvector-front (flexvector 'a 'b 'c 'd)) @result{} a
+@end example
+@end deffn
+@deffn {Scheme Procedure} flexvector-back fv
+
+Returns the last element in @var{fv}. It is an error if @var{fv} is
+empty. Alias for @code{(flexvector-ref fv (- (flexvector-length fv)
+1))}.
+
+@example
+(flexvector-back (flexvector 'a 'b 'c 'd)) @result{} d
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-length fv
+
+Returns the length of @var{fv}, which is the number of elements
+contained in @var{fv}.
+
+@end deffn
+
+@subsubsection Mutators
+
+@deffn {Scheme Procedure} flexvector-add! fv i x ...
+
+Inserts the elements @var{x ...} into @var{fv} at the location @var{i},
+preserving their order and shifting all elements after @var{i} backward
+to make room. This increases the length of @var{fv} by the number of
+elements inserted.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}].
+
+@code{flexvector-add!} returns @var{fv} after mutating it.
+
+@example
+(flexvector-add! (flexvector 'a 'b) 1 'c) @result{} #<flexvector a c b>
+(flexvector-add! (flexvector 'a 'b) 2 'c 'd 'e) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-front! fv x ...
+@deffnx {Scheme Procedure} flexvector-add-back! fv x ...
+
+Inserts the elements @var{x ...} into the front or back of @var{fv},
+preserving their order. This increases the length of @var{fv} by the
+number of elements inserted.
+
+@code{flexvector-add-back!} of one element has the same O(1)
+computational complexity as @code{vector-set!}, amortized.
+
+These procedures return @var{fv} after mutating it.
+
+@example
+(flexvector-add-front! (flexvector 'a 'b) 'c) @result{} #<flexvector c a b>
+(flexvector-add-front! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector c d a b>
+
+(flexvector-add-back! (flexvector 'a 'b) 'c) @result{} #<flexvector a b c>
+(flexvector-add-back! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-all! fv i xs
+
+Inserts the elements of the list @code{xs} into @var{fv} at location
+@var{i}. Equivalent to @code{(apply flexvector-add! fv i xs)}. Returns
+@var{fv} after mutating it.
+
+@example
+(flexvector-add-all! (flexvector 'a 'b) 2 '(c d e)) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append! fv1 fv2 ...
+
+Inserts the elements of the flexvectors @var{fv2 ...} at the end of the
+flexvector @var{fv1}, in order. Returns @var{fv1} after mutating it.
+
+@example
+(flexvector-append! (flexvector 'a 'b) (flexvector 'c 'd) (flexvector 'e)) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove! fv i
+
+Removes and returns the element at @var{i} in @var{fv}, then
+shifts all subsequent elements forward, reducing the length of @var{fv}
+by 1.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}).
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-front! fv
+@deffnx {Scheme Procedure} flexvector-remove-back! fv
+Removes and returns the first element from @var{fv}, then shifts
+all other elements forward. @code{flexvector-remove-back!} instead
+removes the last element, without moving any other elements, and has the
+same performance guarantees as @code{flexvector-add-back!}.
+
+It is an error if @var{fv} is empty.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-range! fv start [end]
+
+Removes all elements from @var{fv} between @var{start} and
+@var{end}, shifting all elements after @var{end} forward by @code{(- end
+start)}. If @var{end} is not present, it defaults to
+@code{(flexvector-length fv)}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@code{flexvector-remove-range!} returns @var{fv} after mutating
+it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-clear! fv
+
+Removes all items from @var{fv}, setting its length to 0.
+Returns @var{fv} after mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-set! fv i x
+
+Assigns the value of @var{x} to the location @var{i} in
+@var{fv}. It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}]. If @var{i} is equal to
+@code{(flexvector-length fv)}, @var{x} is appended after the last
+element in @var{fv}; this is equivalent to @code{flexvector-add-back!}.
+
+Returns the previous value at location @var{i} in @var{fv}, or
+an unspecified value if @var{i} is equal to @code{(flexvector-length
+fv)}.
+
+@code{flexvector-set!} has the same O(1) computational
+complexity as @code{vector-set!}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-swap! fv i j
+
+Swaps or exchanges the values of the locations in @var{fv} at
+indexes @var{i} and @var{j}. It is an error if either @var{i} or @var{j}
+is outside the range [0, @code{(flexvector-length fv)}). Returns @var{fv}
+after mutating it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-fill! fv fill [start [end]]
+
+Assigns the value of every location in @var{fv} between
+@var{start}, which defaults to 0 and @var{end}, which defaults to the
+length of @var{fv}, to @var{fill}. Returns @var{fv} after mutating it.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}]. It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-reverse! fv
+
+Destructively reverses @var{fv} in-place. Returns @var{fv} after
+mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy! to at from [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy! to at from [start [end]]
+
+Copies the elements of flexvector @var{from} between @var{start}
+and @var{end} to flexvector @var{to}, starting at @var{at}. The order in
+which elements are copied is unspecified, except that if the source and
+destination overlap, copying takes place as if the source is first
+copied into a temporary vector and then into the destination. This can
+be achieved without allocating storage by making sure to copy in the
+correct direction in such circumstances.
+
+@code{flexvector-reverse-copy!} is the same, but copies elements
+in reverse order.
+
+@var{start} and @var{end} default to 0 and
+@code{(flexvector-length from)} if not present. Both @var{start} and
+@var{end} are clamped to the range [0, @code{(flexvector-length from)}].
+It is an error if @var{end} is less than @var{start}.
+
+Unlike @code{vector-copy!}, @code{flexvector-copy!} may copy
+elements past the end of @var{to}, which will increase the length of
+@var{to}.
+
+@code{flexvector-copy!} shares the performance characteristics
+of @code{vector-copy!}.
+
+Both procedures return @var{to} after mutating it.
+
+@end deffn
+
+@subsubsection Iteration
+
+@deffn {Scheme Procedure} flexvector-fold kons knil fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-fold-right kons knil fv1 fv2 ...
+
+The fundamental flexvector iterator. @var{kons} is iterated over each
+value in all of the vectors, stopping at the end of the shortest;
+@var{kons} is applied as @code{(kons state (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)} where @var{state} is the current state
+value—the current state value begins with @var{knil}, and becomes
+whatever @var{kons} returned on the previous iteration—and @var{i} is
+the current index.
+
+The iteration of @code{flexvector-fold} is strictly
+left-to-right. The iteration of @code{flexvector-fold-right} is strictly
+right-to-left.
+
+@example
+(flexvector-fold (lambda (len str) (max (string-length str) len))
+                 0
+                 (flexvector "baz" "qux" "quux"))
+@result{} 4
+
+(flexvector-fold-right (lambda (tail elt) (cons elt tail))
+                       '()
+                       (flexvector 1 2 3))
+@result{} (1 2 3)
+
+(flexvector-fold (lambda (counter n)
+                   (if (even? n) (+ counter 1) counter))
+                 0
+                 (flexvector 1 2 3 4 5 6 7))
+@result{} 3
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index f fv1 fv2 ...
+
+Constructs a new flexvector of the shortest size of the flexvector
+arguments. Each element at index @var{i} of the new flexvector is mapped
+from the old flexvectors by @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}. The dynamic order of application of
+@var{f} is unspecified.
+
+
+
+
+@code{flexvector-map/index} is a variant that passes @var{i} as
+the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-map (lambda (x) (* x 10)) (flexvector 10 20 30))
+@result{} #<flexvector 100 200 300>
+
+(flexvector-map/index (lambda (i x) (+ x (* i 2))) (flexvector 10 20 30))
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map! f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index! f fv1 fv2 ...
+
+
+Similar to @code{flexvector-map}, but rather than mapping the new
+elements into a new flexvector, the new mapped elements are
+destructively inserted into @var{fv1}. Again, the dynamic order of
+application of @var{f} is unspecified, so it is dangerous for @var{f} to
+apply either @code{flexvector-ref} or @code{flexvector-set!} to @var{fv1}
+in @var{f}.
+
+
+@example
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map! (lambda (x) (* x 10)) fv)
+  fv)
+@result{} #<flexvector 100 200 300>
+
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv)
+  fv)
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-append-map/index f fv1 fv2 ...
+
+Constructs a new flexvector by appending the results of each call to
+@var{f} on the elements of the flexvectors @var{fv1}, @var{fv2}, etc.,
+in order. Each call is of the form @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}. Iteration stops when the end of the
+shortest flexvector argument is reached. The dynamic order of
+application of @var{f} is unspecified.
+
+
+
+
+@var{f} must return a flexvector. It is an error if @var{f}
+returns anything else.
+
+
+
+
+@code{flexvector-append-map/index} is a variant that passes the
+index @var{i} as the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-append-map (lambda (x) (flexvector (* x 10) (* x 100))) (flexvector 10 20 30))
+@result{} #<flexvector 100 1000 200 2000 300 3000>
+
+(flexvector-append-map/index (lambda (i x) (flexvector x i)) (flexvector 10 20 30))
+@result{} #<flexvector 10 0 20 1 30 2>
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index pred? fv
+
+Constructs a new flexvector consisting of only the elements of @var{fv}
+for which @var{pred?} returns a non-@var{#f} value.
+@code{flexvector-filter/index} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+@example
+(flexvector-filter even? (flexvector 1 2 3 4 5 6 7 8))
+@result{} #<flexvector 2 4 6 8>
+
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter! pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index! pred? fv
+
+Similar to @code{flexvector-filter}, but destructively updates @var{fv}
+by removing all elements for which @var{pred?} returns @var{#f}.
+@code{flexvector-filter/index!} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+
+@example
+(let ((fv (flexvector 1 2 3 4 5 6 7 8)))
+  (flexvector-filter! odd? fv)
+  fv)
+@result{} #<flexvector 1 3 5 7>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-for-each f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-for-each/index f fv1 fv2 ...
+
+Simple flexvector iterator: applies @var{f} to the corresponding list of
+parallel elements from @var{fv1 fv2 ...} in the range [0, @code{length}),
+where @code{length} is the length of the smallest flexvector argument
+passed. In contrast with @code{flexvector-map}, @var{f} is reliably
+applied in left-to-right order, starting at index 0, in the flexvectors.
+
+@code{flexvector-for-each/index} is a variant that passes the
+index as the first argument to @var{f} for each element.
+
+Example:
+
+@example
+(flexvector-for-each (lambda (x) (display x) (newline))
+                     f(lexvector "foo" "bar" "baz" "quux" "zot"))
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-count pred? fv1 fv2 ...
+
+Counts the number of parallel elements in the flexvectors that satisfy
+@var{pred?}, which is applied, for each index @var{i} in the range [0,
+@emph{length}) where @emph{length} is the length of the smallest
+flexvector argument, to each parallel element in the flexvectors, in
+order.
+
+
+@example
+(flexvector-count even? (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} 3
+
+(flexvector-count < (flexvector 1 3 6 9) (flexvector 2 4 6 8 10 12))
+@result{} 2
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-cumulate f knil fv
+
+Returns a newly-allocated flexvector @var{new} with the same length as
+@var{fv}. Each element @var{i} of @var{new} is set to the result of
+@code{(f (flexvector-ref new (- i 1)) (flexvector-ref fv i))}, except
+that, for the first call on @var{f}, the first argument is @var{knil}.
+The @var{new} flexvector is returned.
+
+
+@example
+(flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} #<flexvector 3 4 8 9 14 23 25 30 36>
+
+@end example
+@end deffn
+
+@subsubsection Searching
+
+@deffn {Scheme Procedure} flexvector-index pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-index/right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that satisfy @var{pred?}. If no matching element is found by the end of
+the shortest flexvector, @code{#f} is returned.
+
+@var{flexvector-index-right} is similar, but returns the index
+of the @emph{last} elements that satisfy @var{pred?}, and requires all
+flexvector arguments to have the same length.
+
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+@example
+(flexvector-index even? (flexvector 3 1 4 1 5 9))
+@result{} 2
+
+(flexvector-index < (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} 1
+
+(flexvector-index = (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} #f
+
+(flexvector-index-right < (flexvector 3 1 4 1 5) (flexvector 2 7 1 8 2))
+@result{} 3
+
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-skip pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-skip-right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that do @emph{not} satisfy @var{pred?}. If all the values in the
+flexvectors satisfy @var{pred?} until the end of the shortest
+flexvector, this returns @var{#f}.
+
+@code{flexvector-skip-right} is similar, but returns the index of
+the @emph{last} elements that do not satisfy @var{pred?}, and requires
+all flexvector arguments to have the same length.
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+
+@example
+(flexvector-skip number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 2
+
+(flexvector-skip-right number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 4
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-binary-search fv value cmp [start [end]]
+
+Similar to @code{flexvector-index} and @code{flexvector-index-right},
+but, instead of searching left-to-right or right-to-left, this performs
+a binary search. If there is more than one element of @var{fv} that
+matches @var{value} in the sense of @var{cmp},
+@code{flexvector-binary-search} may return the index of any of them.
+
+The search is performed on only the indexes of @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}. Both @var{start} and @var{end} are clamped to the
+range [0, @code{(flexvector-length fv)}]. It is an error if @var{end} is
+less than @var{start}.
+
+@var{cmp} should be a procedure of two arguments that returns
+either a negative integer, which indicates that its first argument is
+less than its second; zero, which indicates that they are equal; or a
+positive integer, which indicates that the first argument is greater
+than the second argument. An example @var{cmp} might be:
+
+
+@example
+(lambda (char1 char2)
+  (cond ((char<? char1 char2) -1)
+        ((char=? char1 char2) 0)
+        (else 1)))
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-any pred? fv1 fv2 ...
+
+Finds the first set of elements in parallel from @var{fv1 fv2
+...} for which @var{pred?} returns a true value. If such a parallel set
+of elements exists, @code{flexvector-any} returns the value that
+@var{pred?} returned for that set of elements. The iteration is strictly
+left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-every pred? fv1 fv2 ...
+
+If, for every index @var{i} between 0 and the length of the
+shortest flexvector argument, the set of elements @code{(flexvector-ref
+fv1 i) (flexvector-ref fv2 i) ...} satisfies @var{pred?},
+@code{flexvector-every} returns the value that @var{pred?} returned for
+the last set of elements, at the last index of the shortest flexvector.
+The iteration is strictly left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-partition pred? fv
+
+Returns two values: a flexvector containing all elements of
+@var{fv} that satisfy @var{pred?}, and a flexvector containing all
+elements of @var{fv} that do not satisfy @var{pred?}. Elements remain in
+their original order.
+
+@end deffn
+
+@subsubsection Conversion
+
+@deffn {Scheme Procedure} flexvector->vector fv [start [end]]
+
+Creates a vector containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} vector->flexvector vec [start [end]]
+
+Creates a flexvector containing the elements in @var{vec}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{vec}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(vector-length vec)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector->list fv [start [end]]
+@deffnx {Scheme Procedure} reverse-flexvector->list fv [start [end]]
+
+Creates a list containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+@code{reverse-flexvector->list} is similar, but creates a list
+with elements in reverse order of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+
+@end deffn
+
+@deffn {Scheme Procedure} list->flexvector proper-list
+
+Creates a flexvector of elements from @var{proper-list}.
+
+@code{reverse-list->flexvector} is similar, but creates a
+flexvector with elements in reverse order of @var{proper-list}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->string fv [start [end]]
+
+Creates a string containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}. It is an error if the elements are not characters.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} string->flexvector string [start [end]]
+
+Creates a flexvector containing the elements in @var{string}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{string}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(string-length string)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->generator fv
+
+Returns a SRFI 158 generator that emits the elements of the
+flexvector @var{fv}, in order. If @var{fv} is mutated before the
+generator is exhausted, the generator's remaining return values are
+undefined.
+
+@end deffn
+
+
 @node Record Overview
 @subsection Record Overview
 
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 8ff42d82a..a93fe1d0e 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -65,6 +65,7 @@ get the relevant SRFI documents from the SRFI home page
 * SRFI-105::                    Curly-infix expressions.
 * SRFI-111::                    Boxes.
 * SRFI-171::                    Transducers
+* SRFI-214::                    Flexvectors
 @end menu
 
 
@@ -6141,6 +6142,11 @@ The generator version of list-reduce.  It reduces over @code{gen} until
 it returns the EOF object
 @end deffn
 
+@node SRFI-214
+@subsection SRFI-214 - Flexvectors
+
+Documentation for SRFI-214, Flexvectors is provided in @xref{Flexvectors}.
+
 @c srfi-modules.texi ends here
 
 @c Local Variables:
diff --git a/module/Makefile.am b/module/Makefile.am
index f6f5a9bb8..799ef7bd6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -323,6 +323,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..a7f3f6d08
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,735 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) Adam Nelson (2020).
+;;; Copyright (C) Vijay Marupudi (2022).
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy of
+;;; this software and associated documentation files (the "Software"), to deal in
+;;; the Software without restriction, including without limitation the rights to
+;;; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+;;; the Software, and to permit persons to whom the Software is furnished to do so,
+;;; subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice (including the next
+;;; paragraph) shall be included in all copies or substantial portions of the
+;;; Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+;;; FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+;;; COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+;;; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; Authorship: This code was largely written by Adam Nelson as a
+;; sample implementation for srfi-214 and adapted for Guile by Vijay
+;; Marupudi.
+
+(define-module (srfi srfi-214))
+
+(use-modules ((scheme base)
+              #:prefix r7:)
+             (scheme case-lambda)
+             (scheme write)
+             (srfi srfi-1)
+             (srfi srfi-9)
+             (srfi srfi-9 gnu)
+             (srfi srfi-11)
+             (rnrs io ports))
+
+
+(export ; Constructors
+        make-flexvector flexvector
+        flexvector-unfold flexvector-unfold-right
+        flexvector-copy flexvector-reverse-copy
+        flexvector-append flexvector-concatenate flexvector-append-subvectors
+        <flexvector>
+
+        ; 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)
+
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#<flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display ">" port)
+                                (begin
+                                  (format port " ~a" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ">" port)
+                                        (begin
+                                          (format port " ~a" (flexvector-ref obj i))
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (r7:vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (r7:vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (r7:vector-copy! v (+ i xvlen) v i len)
+    (r7:vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (r7:vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (r7:vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (r7:vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (r7:vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (r7:vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (r7:map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (r7:vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (r7:vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (r7:vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (r7:map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (r7:map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (r7:map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (r7:map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply r7:string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (r7:vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 16fa2e952..a62ffcf6c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,6 +162,7 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
             tests/srfi-171.test                 \
+	    tests/srfi-214.test                 \
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-214.test b/test-suite/tests/srfi-214.test
new file mode 100644
index 000000000..dacec8fa8
--- /dev/null
+++ b/test-suite/tests/srfi-214.test
@@ -0,0 +1,437 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;;    Copyright (C) 2020 Adam Nelson.
+;;;    Copyright (C) 2022 Vijay Marupudi.
+;;;
+;;; This code is based on the file tests.scm in the reference
+;;; implementation of SRFI-214, provided under the following license:
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining
+;;; a copy of this software and associated documentation files (the
+;;; "Software"), to deal in the Software without restriction, including
+;;; without limitation the rights to use, copy, modify, merge, publish,
+;;; distribute, sublicense, and/or sell copies of the Software, and to
+;;; permit persons to whom the Software is furnished to do so, subject to
+;;; the following conditions:
+;;;
+;;; The above copyright notice and this permission notice shall be
+;;; included in all copies or substantial portions of the Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;;; SOFTWARE.
+
+(define-module (test-suite test-srfi-214)
+  #:use-module (srfi srfi-214)
+  #:use-module (test-suite lib)
+  #:use-module (rnrs io ports))
+
+(with-test-prefix "SRFI-214"
+
+  (pass-if "flexvector?"
+    (equal? #t (flexvector? (flexvector))))
+  (pass-if "flexvector-length"
+    (equal? 3 (flexvector-length (make-flexvector 3 #f))))
+  (pass-if "flexvector"
+    (equal? 3 (flexvector-length (flexvector 1 2 3))))
+
+  (let ((fv (flexvector 'a 'b 'c)))
+    (pass-if "flexvector-ref"
+      (equal? 'b (flexvector-ref fv 1)))
+    (pass-if "flexvector-front"
+      (equal? 'a (flexvector-front fv)))
+    (pass-if "flexvector-back"
+      (equal? 'c (flexvector-back fv)))
+    (pass-if "flexvector-set! return"
+      (equal? 'b (flexvector-set! fv 1 'd)))
+    (pass-if "flexvector-set! mutate"
+      (equal? 'd (flexvector-ref fv 1)))
+    (pass-if "flexvector-add-back! return"
+      (equal? fv (flexvector-add-back! fv 'e)))
+    (pass-if "flexvector-add-back! mutate"
+      (equal? '(4 . e)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv (- (flexvector-length fv) 1)))))
+    (pass-if "flexvector-remove! return"
+      (equal? 'd (flexvector-remove! fv 1)))
+    (pass-if "flexvector-remove! mutate"
+      (equal? '(3 . c)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv 1))))
+    (pass-if "flexvector-clear! return"
+      (equal? fv (flexvector-clear! fv)))
+    (pass-if "flexvector-clear! mutate"
+      (equal? 0 (flexvector-length fv)))
+    (pass-if "flexvector-empty?"
+      (equal? #t (flexvector-empty? fv))))
+
+  (pass-if "flexvector=? same symbols"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b))))
+  (pass-if "flexvector=? different symbols"
+    (equal? #f
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a))))
+  (pass-if "flexvector=? different lengths"
+    (equal? #f
+            (flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? same numbers"
+    (equal? #t
+            (flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? 0 arguments"
+    (equal? #t
+            (flexvector=? eq?)))
+  (pass-if "flexvector=? 1 argument"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a))))
+
+  (pass-if "make-flexvector"
+    (equal? #(a a a) (flexvector->vector (make-flexvector 3 'a))))
+
+  (pass-if "flexvector-unfold"
+    (equal?
+     #(1 4 9 16 25 36 49 64 81 100)
+     (flexvector->vector
+      (flexvector-unfold (lambda (x) (> x 10))
+                         (lambda (x) (* x x))
+                         (lambda (x) (+ x 1))
+                         1))))
+  (pass-if "flexvector-unfold-right"
+    (equal?
+     #(100 81 64 49 36 25 16 9 4 1)
+     (flexvector->vector
+      (flexvector-unfold-right (lambda (x) (> x 10))
+                               (lambda (x) (* x x))
+                               (lambda (x) (+ x 1))
+                               1))))
+
+
+  (pass-if "string->flexvector"
+    (equal? #(#\a #\b #\c)
+            (flexvector->vector (string->flexvector "abc"))))
+  (pass-if "flexvector->string"
+    (equal? "abc" (flexvector->string (flexvector #\a #\b #\c))))
+
+  (define genlist '(a b c))
+  (define (mock-generator)
+    (if (pair? genlist)
+        (let ((value (car genlist)))
+          (set! genlist (cdr genlist))
+          value)
+        (eof-object)))
+
+  (pass-if "generator->flexvector"
+    (equal? #(a b c)
+            (flexvector->vector (generator->flexvector mock-generator))))
+  (pass-if "flexvector->generator"
+    (equal? '(a b c #t)
+            (let* ((gen (flexvector->generator (flexvector 'a 'b 'c)))
+                   (one (gen))
+                   (two (gen))
+                   (three (gen))
+                   (four (eof-object? (gen))))
+              (list one two three four))))
+
+                                        ; Nondestructive operations on one vector
+  (let ((fv (flexvector 10 20 30)))
+    (pass-if "flexvector->vector"
+      (equal? #(10 20 30) (flexvector->vector fv)))
+    (pass-if "flexvector->list"
+      (equal? '(10 20 30) (flexvector->list fv)))
+    (pass-if "reverse-flexvector->list"
+      (equal? '(30 20 10) (reverse-flexvector->list fv)))
+    (pass-if "flexvector-copy"
+      (equal? #t
+              (let ((copy (flexvector-copy fv)))
+                (and (= (flexvector-length fv) (flexvector-length copy))
+                     (not (eq? fv copy))))))
+    (pass-if "flexvector-reverse-copy"
+      (equal? #(30 20 10)
+              (flexvector->vector (flexvector-reverse-copy fv))))
+    (pass-if "flexvector-copy start"
+      (equal? #(20 30)
+              (flexvector->vector (flexvector-copy fv 1))))
+    (pass-if "flexvector-copy start end"
+      (equal? #(20)
+              (flexvector->vector (flexvector-copy fv 1 2))))
+    (pass-if "flexvector-for-each"
+      (equal? '(30 20 10)
+              (let ((res '()))
+                (flexvector-for-each (lambda (x) (set! res (cons x res))) fv)
+                res)))
+    (pass-if "flexvector-for-each/index"
+      (equal? '(34 22 10)
+              (let ((res '()))
+                (flexvector-for-each/index
+                 (lambda (i x) (set! res (cons (+ x (* i 2)) res)))
+                 fv)
+                res)))
+    (pass-if "flexvector-map"
+      (equal? #(100 200 300)
+              (flexvector->vector (flexvector-map (lambda (x) (* x 10)) fv))))
+    (pass-if "flexvector-map/index"
+      (equal? #(10 22 34)
+              (flexvector->vector (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv))))
+    (pass-if "flexvector-append-map"
+      (equal? #(10 100 20 200 30 300)
+              (flexvector->vector
+               (flexvector-append-map (lambda (x) (flexvector x (* x 10))) fv))))
+    (pass-if "flexvector-append-map/index"
+      (equal? #(0 10 10 1 20 22 2 30 34)
+              (flexvector->vector
+               (flexvector-append-map/index
+                (lambda (i x) (flexvector i x (+ x (* i 2))))
+                fv))))
+    (pass-if "flexvector-filter"
+      (equal? #(10)
+              (flexvector->vector (flexvector-filter (lambda (x) (< x 15)) fv))))
+    (pass-if "flexvector-filter/index"
+      (equal? #(10 30)
+              (flexvector->vector (flexvector-filter/index (lambda (i x) (not (= i 1))) fv))))
+    (pass-if "flexvector-fold"
+      (equal? '(30 20 10)
+              (flexvector-fold (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-fold-right"
+      (equal? '(10 20 30)
+              (flexvector-fold-right (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-count"
+      (equal? 2
+              (flexvector-count (lambda (x) (< x 25)) fv)))
+    (pass-if "flexvector-cumulate"
+      (equal? #(3 4 8 9 14 23 25 30 36)
+              (flexvector->vector
+               (flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6)))))
+    (pass-if "flexvector-any"
+      (equal? '(#t . #f)
+              (cons (flexvector-any (lambda (x) (= x 20)) fv)
+                    (flexvector-any (lambda (x) (= x 21)) fv))))
+    (pass-if "flexvector-every"
+      (equal? '(#t . #f)
+              (cons (flexvector-every (lambda (x) (< x 40)) fv)
+                    (flexvector-every (lambda (x) (< x 30)) fv))))
+    (pass-if "flexvector-index"
+      (equal? 1
+              (flexvector-index (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-index-right"
+      (equal? 2
+              (flexvector-index-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-skip"
+      (equal? 1
+              (flexvector-skip (lambda (x) (< x 20)) fv)))
+    (pass-if "flexvector-skip-right"
+      (equal? 0
+              (flexvector-skip-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-partition"
+      (equal? '(#(10 20) #(30))
+              (call-with-values
+                  (lambda () (flexvector-partition (lambda (x) (< x 25)) fv))
+                (lambda vs ((@ (scheme base) map) flexvector->vector vs))))))
+
+  (let ((fv (flexvector #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j))
+        (cmp (lambda (char1 char2)
+               (cond ((char<? char1 char2) -1)
+                     ((char=? char1 char2) 0)
+                     (else 1)))))
+    (pass-if "flexvector-binary-search"
+      (equal? 3
+              (flexvector-binary-search fv #\d cmp)))
+    (pass-if "flexvector-binary-search first"
+      (equal? 0
+              (flexvector-binary-search fv #\a cmp)))
+    (pass-if "flexvector-binary-search last"
+      (equal? 9
+              (flexvector-binary-search fv #\j cmp)))
+    (pass-if "flexvector-binary-search not found"
+      (equal? #f
+              (flexvector-binary-search fv #\k cmp)))
+
+    (pass-if "flexvector-binary-search in range"
+      (equal? 5
+              (flexvector-binary-search fv #\f cmp 2 6)))
+    (pass-if "flexvector-binary-search out of range"
+      (equal? #f
+              (flexvector-binary-search fv #\f cmp 1 5))))
+
+                                        ; Nondestructive operations on multiple vectors
+  (pass-if "flexvector-append"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-append (flexvector 10 20)
+                                (flexvector)
+                                (flexvector 30 40)
+                                (flexvector 50 60)))))
+  (pass-if "flexvector-concatenate"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-concatenate
+              (list (flexvector 10 20)
+                    (flexvector)
+                    (flexvector 30 40)
+                    (flexvector 50 60))))))
+  (pass-if "flexvector-append-subvectors"
+    (equal? #(a b h i)
+            (flexvector->vector
+             (flexvector-append-subvectors
+              (flexvector 'a 'b 'c 'd 'e) 0 2
+              (flexvector 'f 'g 'h 'i 'j) 2 4))))
+
+
+                                        ; Destructive operations on one vector
+  (define-syntax mutate-as
+    (syntax-rules ()
+      ((_ name vec expr)
+       (let ((name (vector->flexvector vec)))
+         expr
+         (flexvector->vector name)))))
+
+  (pass-if "flexvector-add! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! start"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! start multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! middle"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo baz) (flexvector-add! x 1 'bar))))
+  (pass-if "flexvector-add! middle multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo quux) (flexvector-add! x 1 'bar 'baz 'qux))))
+  (pass-if "flexvector-add! end"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz))))
+  (pass-if "flexvector-add! end multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-add-all!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo qux) (flexvector-add-all! x 1 '(bar baz)))))
+
+  (pass-if "flexvector-add-front! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-front! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-front!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add-front! x 'foo 'bar 'baz))))
+
+  (pass-if "flexvector-add-back! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-back! x 'foo))))
+  (pass-if "flexvector-add-back! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-back! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-back!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz))))
+  (pass-if "flexvector-add-back! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-append!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux)))))
+  (pass-if "flexvector-append! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux) (flexvector 'quux)))))
+
+  (pass-if "flexvector-remove!"
+    (equal? '#(foo baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove! x 1))))
+  (pass-if "flexvector-remove! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove! x 0))))
+
+  (pass-if "flexvector-remove-front!"
+    (equal? '#(bar baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-front! x))))
+  (pass-if "flexvector-remove-front! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-front! x))))
+
+  (pass-if "flexvector-remove-back!"
+    (equal? '#(foo bar)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-back! x))))
+  (pass-if "flexvector-remove-back! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-back! x))))
+
+  (pass-if "flexvector-remove-range!"
+    (equal? '#(a e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 4))))
+  (pass-if "flexvector-remove-range! empty range"
+    (equal? '#(a b c d e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 1))))
+  (pass-if "flexvector-remove-range! overflow left"
+    (equal? '#(e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x -1 4))))
+  (pass-if "flexvector-remove-range! overflow right"
+    (equal? '#(a b)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 2 10))))
+
+  (pass-if "flexvector-map!"
+    (equal? '#(100 200 300)
+            (mutate-as fv '#(10 20 30) (flexvector-map! (lambda (x) (* x 10)) fv))))
+  (pass-if "flexvector-map/index!"
+    (equal? '#(10 22 34)
+            (mutate-as fv '#(10 20 30) (flexvector-map/index! (lambda (i x) (+ x (* i 2))) fv))))
+  (pass-if "flexvector-filter!"
+    (equal? '#(10)
+            (mutate-as fv '#(10 20 30) (flexvector-filter! (lambda (x) (< x 15)) fv))))
+  (pass-if "flexvector-filter/index!"
+    (equal? '#(10 30)
+            (mutate-as fv '#(10 20 30) (flexvector-filter/index! (lambda (i x) (not (= i 1))) fv))))
+
+  (pass-if "flexvector-swap!"
+    (equal? #(10 30 20)
+            (mutate-as fv '#(10 20 30) (flexvector-swap! fv 1 2))))
+  (pass-if "flexvector-reverse!"
+    (equal? #(30 20 10)
+            (mutate-as fv '#(10 20 30) (flexvector-reverse! fv))))
+
+  (pass-if "flexvector-copy!"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-copy! bounded"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-copy! overflow"
+    (equal? #(1 2 30 40 50)
+            (mutate-as fv '#(1 2 3) (flexvector-copy! fv 2 (flexvector 30 40 50)))))
+  (pass-if "flexvector-reverse-copy!"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-reverse-copy! bounded"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-reverse-copy! overflow"
+    (equal? #(1 2 50 40 30)
+            (mutate-as fv '#(1 2 3) (flexvector-reverse-copy! fv 2 (flexvector 30 40 50)))))
+
+  (pass-if "flexvector-fill!"
+    (equal? '#(foo foo foo)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'foo))))
+  (pass-if "flexvector-fill! start"
+    (equal? '#(1 2 bar bar bar)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'bar 2))))
+  (pass-if "flexvector-fill! start end"
+    (equal? '#(1 2 baz baz 5)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'baz 2 4))))
+  (pass-if "flexvector-fill! clamped"
+    (equal? '#(qux qux qux)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'qux -1 10)))))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 15:34           ` Vijay Marupudi
@ 2022-01-20 16:53             ` Maxime Devos
  2022-01-20 17:57               ` Vijay Marupudi
  0 siblings, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-01-20 16:53 UTC (permalink / raw)
  To: Vijay Marupudi, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1938 bytes --]

Vijay Marupudi schreef op do 20-01-2022 om 10:34 [-0500]:
> My latest patch now has documentation, mostly derived from the SRFI-
> 214
> documentation. Who would have figured that conversion to texinfo
> would be the
> most time consuming part of this patch?
> 
> I would like advice on how to attribute the documentation to Adam
> Nelson.

Here are two examples in the wild (slib):

> 6.18.11 provide and require
> ---------------------------
> 
> Aubrey Jaffer, mostly to support his portable Scheme library SLIB,
> implemented a provide/require mechanism for many Scheme
> implementations.
> Library files in SLIB _provide_ a feature, and when user programs
> _require_ that feature, the library file is loaded in.
> 

(GOOPS):

> 8 GOOPS
> *******
>
> GOOPS is the object oriented extension to Guile.  Its implementation
> is
> derived from STk-3.99.3 by Erick Gallesio and version 1.3 of Gregor
> Kiczales’ ‘Tiny-Clos’.  It is very close in spirit to CLOS, the
> Common
> Lisp Object System, but is adapted for the Scheme language.
> 
> [...]
> 8.1 Copyright Notice
> ====================
> 
> The material in this chapter is partly derived from the STk Reference
> Manual written by Erick Gallesio, whose copyright notice is as
> follows.
> 
>    Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
> Permission to use, copy, modify, distribute,and license this software
> and its documentation for any purpose is hereby granted, provided
> that
> existing copyright notices are retained in all copies and that this
> notice is included verbatim in any distributions.  No written
> agreement,
> license, or royalty fee is required for any of the authorized uses.
> This software is provided “AS IS” without express or implied
> warranty.
> 
>    The material has been adapted for use in Guile, with the author’s
> permission.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 16:53             ` Maxime Devos
@ 2022-01-20 17:57               ` Vijay Marupudi
  2022-01-20 18:15                 ` Maxime Devos
  2022-10-12 12:22                 ` Ludovic Courtès
  0 siblings, 2 replies; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-20 17:57 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

[-- Attachment #1: Type: text/plain, Size: 242 bytes --]

> Here are two examples in the wild (slib):

Thanks, the patch, which is attached, now attributes credit
appropriately.

Thank you very much for your help Maxime. I believe there is nothing
else pending and that the patch is ready?

~ Vijay


[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 77056 bytes --]

From 42206dec4d5e9ae51665c6e98ef07715b89b12fe Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Tue, 18 Jan 2022 20:52:08 -0500
Subject: [PATCH] Added srfi-214: flexvectors

Included code, documentation, and tests
---
 doc/ref/api-data.texi          | 842 ++++++++++++++++++++++++++++++++-
 doc/ref/srfi-modules.texi      |   6 +
 module/Makefile.am             |   1 +
 module/srfi/srfi-214.scm       | 735 ++++++++++++++++++++++++++++
 test-suite/Makefile.am         |   1 +
 test-suite/tests/srfi-214.test | 437 +++++++++++++++++
 6 files changed, 2021 insertions(+), 1 deletion(-)
 create mode 100644 module/srfi/srfi-214.scm
 create mode 100644 test-suite/tests/srfi-214.test

diff --git a/doc/ref/api-data.texi b/doc/ref/api-data.texi
index b6c2c4d61..1ba7b57a9 100644
--- a/doc/ref/api-data.texi
+++ b/doc/ref/api-data.texi
@@ -26,7 +26,8 @@ complex.
 * Bit Vectors::                 Vectors of bits.
 * Bytevectors::                 Sequences of bytes.
 * Arrays::                      Multidimensional matrices.
-* VLists::                      Vector-like lists.
+* VLists::                      Vector-like lists
+* Flexvectors::                 Mutable vectors with adjustable size
 * Record Overview::             Walking through the maze of record APIs.
 * SRFI-9 Records::              The standard, recommended record API.
 * Records::                     Guile's historical record API.
@@ -8393,6 +8394,845 @@ Return a new vlist whose contents correspond to @var{lst}.
 Return a new list whose contents match those of @var{vlist}.
 @end deffn
 
+@node Flexvectors
+@subsection Flexvectors
+@cindex flexvector
+
+Flexvectors are sometimes better known as a @url{https://en.wikipedia.org/wiki/Dynamic_array,dynamic arrays}. This data
+structure has a wide variety of names in different languages:
+
+@itemize @bullet{}
+
+@item
+JavaScript and Ruby call it an array
+@item
+Python calls it a list
+@item
+Java calls it an ArrayList (and, before that, it was called a Vector)
+
+@end itemize
+
+
+Flexvectors have the same O(1) random-access performance guarantees as
+ordinary vectors. Additionally, appending to the back of a flexvector
+has the same (amortized) performance as setting an existing location in
+the same flexvector.
+
+Functions in this module can be obtained with:
+
+@example
+(use-modules (srfi srfi-214))
+@end example
+
+The material in this section was derived from the
+@url{https://srfi.schemers.org/srfi-214/srfi-214.html,SRFI-214} proposal
+written by Adam Nelson, whose copyright notice is as follows.
+
+@quotation
+(C) Adam Nelson 2020-2021.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+@end quotation
+
+@subsubsection Constructors
+
+@deffn {Scheme Procedure} make-flexvector size [fill]
+
+Creates and returns a flexvector of size @var{size}. If @var{fill} is
+specified, all of the elements of the vector are initialized to
+@var{fill}. Otherwise, their contents are indeterminate.
+
+
+@example
+(make-flexvector 5 3) @result{} #<flexvector 3 3 3 3 3>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector x ...
+
+Creates and returns a flexvector whose elements are @var{x ...}.
+
+@example
+(flexvector 0 1 2 3 4) @result{} #<flexvector 0 1 2 3 4>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-unfold p f g initial-seed ...
+@deffnx {Scheme Procedure} flexvector-unfold-right p f g initial-seed ...
+
+The fundamental flexvector constructor. @code{flexvector-unfold} is
+modeled on SRFI 1 @code{unfold} instead of SRFI 133
+@code{vector-unfold} because flexvectors are not limited to a
+predetermined length.
+
+@example
+;; List of squares: 1^2 ... 10^2
+(flexvector-unfold (lambda (x) (> x 10)) (lambda (x) (* x x)) (lambda (x) (+ x 1)) 1)
+@result{} #<flexvector 1 4 9 16 25 36 49 64 81 100>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy fv [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy fv [start [end]]
+
+Allocates a new flexvector whose length is @code{(- end start)} and fills
+it with elements from @var{fv}, taking elements from @var{fv} starting
+at index @var{start} and stopping at index @var{end}. @var{start}
+defaults to @var{0} and @var{end} defaults to the value of
+@code{(flexvector-length fv)}.
+
+@example
+(flexvector-copy (flexvector 'a 'b 'c)) @result{} #<flexvector a b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1) @result{} #<flexvector b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1 2) @result{} #<flexvector b>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append fv ...
+
+Returns a newly allocated flexvector that contains all elements in order
+from the subsequent locations in @var{fv ...}.
+
+@example
+(flexvector-append (flexvector 'x) (flexvector 'y))
+@result{} #<flexvector x y>
+
+(flexvector-append (flexvector 'a) (flexvector 'b 'c 'd))
+@result{} #<flexvector a b c d>
+
+(flexvector-append (flexvector 'a (flexvector 'b))
+                   (flexvector (flexvector 'c)))
+@result{} #<flexvector a #<flexvector b> #<flexvector c>>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-concatenate list-of-flexvectors
+
+Equivalent to @code{(apply flexvector-append list-of-flexvectors)}, but
+may be implemented more efficiently.
+
+@example
+(flexvector-concatenate (list (flexvector 'a 'b) (flexvector 'c 'd)))
+@result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-append-subvectors [fv start end] ...
+
+Returns a vector that contains every element of each @var{fv} from
+@var{start} to @var{end} in the specified order. This procedure is a
+generalization of @code{flexvector-append}.
+
+@example
+(flexvector-append-subvectors (flexvector 'a 'b 'c 'd 'e) 0 2
+                              (flexvector 'f 'g 'h 'i 'j) 2 4)
+@result{} #<flexvector a b h i>
+@end example
+@end deffn
+
+@subsubsection Predicates
+
+@deffn {Scheme Procedure} flexvector? x
+
+Disjoint type predicate for flexvectors: this returns @var{#t} if
+@var{x} is a flexvector, and @var{#f} otherwise.
+
+@example
+(flexvector? (flexvector 1 2 3)) @result{} #t
+(flexvector? (vector 1 2 3)) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-empty? fv
+
+Returns @var{#t} if @var{fv} is empty (i.e., its length is @var{0}), and
+@var{#f} if not.
+
+@example
+(flexvector-empty? (flexvector)) @result{} #t
+(flexvector-empty? (flexvector 'a)) @result{} #f
+(flexvector-empty? (flexvector (flexvector))) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector=? elt=? fv ...
+
+Flexvector structural equality predicate, generalized across
+user-specified element equality predicates. Flexvectors @var{a} and
+@var{b} are considered equal by @code{flexvector=?} iff their lengths are
+the same and, for each index @var{i} less than @code{(flexvector-length
+a)}, @code{(elt=? (flexvector-ref a i) (flexvector-ref b i))} is true.
+@var{elt=?} is always applied to two arguments.
+
+
+@example
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b)) @result{} #t
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4)) @result{} #t
+@end example
+@end deffn
+
+@subsubsection Selectors
+
+@deffn {Scheme Procedure} flexvector-ref fv i
+
+Flexvector element dereferencing: returns the value at location @var{i}
+in @var{fv}. Indexing is zero-based. It is an error if @var{i} is
+outside the range [0, @code{(flexvector-length fv)}).
+
+@example
+(flexvector-ref (flexvector 'a 'b 'c 'd) 2) @result{} c
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-front fv
+
+Returns the first element in @var{fv}. It is an error if @var{fv} is
+empty. Alias for @code{(flexvector-ref fv 0)}.
+
+@example
+(flexvector-front (flexvector 'a 'b 'c 'd)) @result{} a
+@end example
+@end deffn
+@deffn {Scheme Procedure} flexvector-back fv
+
+Returns the last element in @var{fv}. It is an error if @var{fv} is
+empty. Alias for @code{(flexvector-ref fv (- (flexvector-length fv)
+1))}.
+
+@example
+(flexvector-back (flexvector 'a 'b 'c 'd)) @result{} d
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-length fv
+
+Returns the length of @var{fv}, which is the number of elements
+contained in @var{fv}.
+
+@end deffn
+
+@subsubsection Mutators
+
+@deffn {Scheme Procedure} flexvector-add! fv i x ...
+
+Inserts the elements @var{x ...} into @var{fv} at the location @var{i},
+preserving their order and shifting all elements after @var{i} backward
+to make room. This increases the length of @var{fv} by the number of
+elements inserted.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}].
+
+@code{flexvector-add!} returns @var{fv} after mutating it.
+
+@example
+(flexvector-add! (flexvector 'a 'b) 1 'c) @result{} #<flexvector a c b>
+(flexvector-add! (flexvector 'a 'b) 2 'c 'd 'e) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-front! fv x ...
+@deffnx {Scheme Procedure} flexvector-add-back! fv x ...
+
+Inserts the elements @var{x ...} into the front or back of @var{fv},
+preserving their order. This increases the length of @var{fv} by the
+number of elements inserted.
+
+@code{flexvector-add-back!} of one element has the same O(1)
+computational complexity as @code{vector-set!}, amortized.
+
+These procedures return @var{fv} after mutating it.
+
+@example
+(flexvector-add-front! (flexvector 'a 'b) 'c) @result{} #<flexvector c a b>
+(flexvector-add-front! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector c d a b>
+
+(flexvector-add-back! (flexvector 'a 'b) 'c) @result{} #<flexvector a b c>
+(flexvector-add-back! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-all! fv i xs
+
+Inserts the elements of the list @code{xs} into @var{fv} at location
+@var{i}. Equivalent to @code{(apply flexvector-add! fv i xs)}. Returns
+@var{fv} after mutating it.
+
+@example
+(flexvector-add-all! (flexvector 'a 'b) 2 '(c d e)) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append! fv1 fv2 ...
+
+Inserts the elements of the flexvectors @var{fv2 ...} at the end of the
+flexvector @var{fv1}, in order. Returns @var{fv1} after mutating it.
+
+@example
+(flexvector-append! (flexvector 'a 'b) (flexvector 'c 'd) (flexvector 'e)) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove! fv i
+
+Removes and returns the element at @var{i} in @var{fv}, then
+shifts all subsequent elements forward, reducing the length of @var{fv}
+by 1.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}).
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-front! fv
+@deffnx {Scheme Procedure} flexvector-remove-back! fv
+Removes and returns the first element from @var{fv}, then shifts
+all other elements forward. @code{flexvector-remove-back!} instead
+removes the last element, without moving any other elements, and has the
+same performance guarantees as @code{flexvector-add-back!}.
+
+It is an error if @var{fv} is empty.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-range! fv start [end]
+
+Removes all elements from @var{fv} between @var{start} and
+@var{end}, shifting all elements after @var{end} forward by @code{(- end
+start)}. If @var{end} is not present, it defaults to
+@code{(flexvector-length fv)}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@code{flexvector-remove-range!} returns @var{fv} after mutating
+it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-clear! fv
+
+Removes all items from @var{fv}, setting its length to 0.
+Returns @var{fv} after mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-set! fv i x
+
+Assigns the value of @var{x} to the location @var{i} in
+@var{fv}. It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}]. If @var{i} is equal to
+@code{(flexvector-length fv)}, @var{x} is appended after the last
+element in @var{fv}; this is equivalent to @code{flexvector-add-back!}.
+
+Returns the previous value at location @var{i} in @var{fv}, or
+an unspecified value if @var{i} is equal to @code{(flexvector-length
+fv)}.
+
+@code{flexvector-set!} has the same O(1) computational
+complexity as @code{vector-set!}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-swap! fv i j
+
+Swaps or exchanges the values of the locations in @var{fv} at
+indexes @var{i} and @var{j}. It is an error if either @var{i} or @var{j}
+is outside the range [0, @code{(flexvector-length fv)}). Returns @var{fv}
+after mutating it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-fill! fv fill [start [end]]
+
+Assigns the value of every location in @var{fv} between
+@var{start}, which defaults to 0 and @var{end}, which defaults to the
+length of @var{fv}, to @var{fill}. Returns @var{fv} after mutating it.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}]. It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-reverse! fv
+
+Destructively reverses @var{fv} in-place. Returns @var{fv} after
+mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy! to at from [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy! to at from [start [end]]
+
+Copies the elements of flexvector @var{from} between @var{start}
+and @var{end} to flexvector @var{to}, starting at @var{at}. The order in
+which elements are copied is unspecified, except that if the source and
+destination overlap, copying takes place as if the source is first
+copied into a temporary vector and then into the destination. This can
+be achieved without allocating storage by making sure to copy in the
+correct direction in such circumstances.
+
+@code{flexvector-reverse-copy!} is the same, but copies elements
+in reverse order.
+
+@var{start} and @var{end} default to 0 and
+@code{(flexvector-length from)} if not present. Both @var{start} and
+@var{end} are clamped to the range [0, @code{(flexvector-length from)}].
+It is an error if @var{end} is less than @var{start}.
+
+Unlike @code{vector-copy!}, @code{flexvector-copy!} may copy
+elements past the end of @var{to}, which will increase the length of
+@var{to}.
+
+@code{flexvector-copy!} shares the performance characteristics
+of @code{vector-copy!}.
+
+Both procedures return @var{to} after mutating it.
+
+@end deffn
+
+@subsubsection Iteration
+
+@deffn {Scheme Procedure} flexvector-fold kons knil fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-fold-right kons knil fv1 fv2 ...
+
+The fundamental flexvector iterator. @var{kons} is iterated over each
+value in all of the vectors, stopping at the end of the shortest;
+@var{kons} is applied as @code{(kons state (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)} where @var{state} is the current state
+value—the current state value begins with @var{knil}, and becomes
+whatever @var{kons} returned on the previous iteration—and @var{i} is
+the current index.
+
+The iteration of @code{flexvector-fold} is strictly
+left-to-right. The iteration of @code{flexvector-fold-right} is strictly
+right-to-left.
+
+@example
+(flexvector-fold (lambda (len str) (max (string-length str) len))
+                 0
+                 (flexvector "baz" "qux" "quux"))
+@result{} 4
+
+(flexvector-fold-right (lambda (tail elt) (cons elt tail))
+                       '()
+                       (flexvector 1 2 3))
+@result{} (1 2 3)
+
+(flexvector-fold (lambda (counter n)
+                   (if (even? n) (+ counter 1) counter))
+                 0
+                 (flexvector 1 2 3 4 5 6 7))
+@result{} 3
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index f fv1 fv2 ...
+
+Constructs a new flexvector of the shortest size of the flexvector
+arguments. Each element at index @var{i} of the new flexvector is mapped
+from the old flexvectors by @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}. The dynamic order of application of
+@var{f} is unspecified.
+
+
+
+
+@code{flexvector-map/index} is a variant that passes @var{i} as
+the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-map (lambda (x) (* x 10)) (flexvector 10 20 30))
+@result{} #<flexvector 100 200 300>
+
+(flexvector-map/index (lambda (i x) (+ x (* i 2))) (flexvector 10 20 30))
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map! f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index! f fv1 fv2 ...
+
+
+Similar to @code{flexvector-map}, but rather than mapping the new
+elements into a new flexvector, the new mapped elements are
+destructively inserted into @var{fv1}. Again, the dynamic order of
+application of @var{f} is unspecified, so it is dangerous for @var{f} to
+apply either @code{flexvector-ref} or @code{flexvector-set!} to @var{fv1}
+in @var{f}.
+
+
+@example
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map! (lambda (x) (* x 10)) fv)
+  fv)
+@result{} #<flexvector 100 200 300>
+
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv)
+  fv)
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-append-map/index f fv1 fv2 ...
+
+Constructs a new flexvector by appending the results of each call to
+@var{f} on the elements of the flexvectors @var{fv1}, @var{fv2}, etc.,
+in order. Each call is of the form @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}. Iteration stops when the end of the
+shortest flexvector argument is reached. The dynamic order of
+application of @var{f} is unspecified.
+
+
+
+
+@var{f} must return a flexvector. It is an error if @var{f}
+returns anything else.
+
+
+
+
+@code{flexvector-append-map/index} is a variant that passes the
+index @var{i} as the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-append-map (lambda (x) (flexvector (* x 10) (* x 100))) (flexvector 10 20 30))
+@result{} #<flexvector 100 1000 200 2000 300 3000>
+
+(flexvector-append-map/index (lambda (i x) (flexvector x i)) (flexvector 10 20 30))
+@result{} #<flexvector 10 0 20 1 30 2>
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index pred? fv
+
+Constructs a new flexvector consisting of only the elements of @var{fv}
+for which @var{pred?} returns a non-@var{#f} value.
+@code{flexvector-filter/index} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+@example
+(flexvector-filter even? (flexvector 1 2 3 4 5 6 7 8))
+@result{} #<flexvector 2 4 6 8>
+
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter! pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index! pred? fv
+
+Similar to @code{flexvector-filter}, but destructively updates @var{fv}
+by removing all elements for which @var{pred?} returns @var{#f}.
+@code{flexvector-filter/index!} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+
+@example
+(let ((fv (flexvector 1 2 3 4 5 6 7 8)))
+  (flexvector-filter! odd? fv)
+  fv)
+@result{} #<flexvector 1 3 5 7>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-for-each f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-for-each/index f fv1 fv2 ...
+
+Simple flexvector iterator: applies @var{f} to the corresponding list of
+parallel elements from @var{fv1 fv2 ...} in the range [0, @code{length}),
+where @code{length} is the length of the smallest flexvector argument
+passed. In contrast with @code{flexvector-map}, @var{f} is reliably
+applied in left-to-right order, starting at index 0, in the flexvectors.
+
+@code{flexvector-for-each/index} is a variant that passes the
+index as the first argument to @var{f} for each element.
+
+Example:
+
+@example
+(flexvector-for-each (lambda (x) (display x) (newline))
+                     f(lexvector "foo" "bar" "baz" "quux" "zot"))
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-count pred? fv1 fv2 ...
+
+Counts the number of parallel elements in the flexvectors that satisfy
+@var{pred?}, which is applied, for each index @var{i} in the range [0,
+@emph{length}) where @emph{length} is the length of the smallest
+flexvector argument, to each parallel element in the flexvectors, in
+order.
+
+
+@example
+(flexvector-count even? (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} 3
+
+(flexvector-count < (flexvector 1 3 6 9) (flexvector 2 4 6 8 10 12))
+@result{} 2
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-cumulate f knil fv
+
+Returns a newly-allocated flexvector @var{new} with the same length as
+@var{fv}. Each element @var{i} of @var{new} is set to the result of
+@code{(f (flexvector-ref new (- i 1)) (flexvector-ref fv i))}, except
+that, for the first call on @var{f}, the first argument is @var{knil}.
+The @var{new} flexvector is returned.
+
+
+@example
+(flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} #<flexvector 3 4 8 9 14 23 25 30 36>
+
+@end example
+@end deffn
+
+@subsubsection Searching
+
+@deffn {Scheme Procedure} flexvector-index pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-index/right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that satisfy @var{pred?}. If no matching element is found by the end of
+the shortest flexvector, @code{#f} is returned.
+
+@var{flexvector-index-right} is similar, but returns the index
+of the @emph{last} elements that satisfy @var{pred?}, and requires all
+flexvector arguments to have the same length.
+
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+@example
+(flexvector-index even? (flexvector 3 1 4 1 5 9))
+@result{} 2
+
+(flexvector-index < (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} 1
+
+(flexvector-index = (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} #f
+
+(flexvector-index-right < (flexvector 3 1 4 1 5) (flexvector 2 7 1 8 2))
+@result{} 3
+
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-skip pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-skip-right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that do @emph{not} satisfy @var{pred?}. If all the values in the
+flexvectors satisfy @var{pred?} until the end of the shortest
+flexvector, this returns @var{#f}.
+
+@code{flexvector-skip-right} is similar, but returns the index of
+the @emph{last} elements that do not satisfy @var{pred?}, and requires
+all flexvector arguments to have the same length.
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+
+@example
+(flexvector-skip number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 2
+
+(flexvector-skip-right number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 4
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-binary-search fv value cmp [start [end]]
+
+Similar to @code{flexvector-index} and @code{flexvector-index-right},
+but, instead of searching left-to-right or right-to-left, this performs
+a binary search. If there is more than one element of @var{fv} that
+matches @var{value} in the sense of @var{cmp},
+@code{flexvector-binary-search} may return the index of any of them.
+
+The search is performed on only the indexes of @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}. Both @var{start} and @var{end} are clamped to the
+range [0, @code{(flexvector-length fv)}]. It is an error if @var{end} is
+less than @var{start}.
+
+@var{cmp} should be a procedure of two arguments that returns
+either a negative integer, which indicates that its first argument is
+less than its second; zero, which indicates that they are equal; or a
+positive integer, which indicates that the first argument is greater
+than the second argument. An example @var{cmp} might be:
+
+
+@example
+(lambda (char1 char2)
+  (cond ((char<? char1 char2) -1)
+        ((char=? char1 char2) 0)
+        (else 1)))
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-any pred? fv1 fv2 ...
+
+Finds the first set of elements in parallel from @var{fv1 fv2
+...} for which @var{pred?} returns a true value. If such a parallel set
+of elements exists, @code{flexvector-any} returns the value that
+@var{pred?} returned for that set of elements. The iteration is strictly
+left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-every pred? fv1 fv2 ...
+
+If, for every index @var{i} between 0 and the length of the
+shortest flexvector argument, the set of elements @code{(flexvector-ref
+fv1 i) (flexvector-ref fv2 i) ...} satisfies @var{pred?},
+@code{flexvector-every} returns the value that @var{pred?} returned for
+the last set of elements, at the last index of the shortest flexvector.
+The iteration is strictly left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-partition pred? fv
+
+Returns two values: a flexvector containing all elements of
+@var{fv} that satisfy @var{pred?}, and a flexvector containing all
+elements of @var{fv} that do not satisfy @var{pred?}. Elements remain in
+their original order.
+
+@end deffn
+
+@subsubsection Conversion
+
+@deffn {Scheme Procedure} flexvector->vector fv [start [end]]
+
+Creates a vector containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} vector->flexvector vec [start [end]]
+
+Creates a flexvector containing the elements in @var{vec}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{vec}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(vector-length vec)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector->list fv [start [end]]
+@deffnx {Scheme Procedure} reverse-flexvector->list fv [start [end]]
+
+Creates a list containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+@code{reverse-flexvector->list} is similar, but creates a list
+with elements in reverse order of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+
+@end deffn
+
+@deffn {Scheme Procedure} list->flexvector proper-list
+
+Creates a flexvector of elements from @var{proper-list}.
+
+@code{reverse-list->flexvector} is similar, but creates a
+flexvector with elements in reverse order of @var{proper-list}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->string fv [start [end]]
+
+Creates a string containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}. It is an error if the elements are not characters.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} string->flexvector string [start [end]]
+
+Creates a flexvector containing the elements in @var{string}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{string}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(string-length string)}). It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->generator fv
+
+Returns a SRFI 158 generator that emits the elements of the
+flexvector @var{fv}, in order. If @var{fv} is mutated before the
+generator is exhausted, the generator's remaining return values are
+undefined.
+
+@end deffn
+
+
 @node Record Overview
 @subsection Record Overview
 
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 8ff42d82a..a93fe1d0e 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -65,6 +65,7 @@ get the relevant SRFI documents from the SRFI home page
 * SRFI-105::                    Curly-infix expressions.
 * SRFI-111::                    Boxes.
 * SRFI-171::                    Transducers
+* SRFI-214::                    Flexvectors
 @end menu
 
 
@@ -6141,6 +6142,11 @@ The generator version of list-reduce.  It reduces over @code{gen} until
 it returns the EOF object
 @end deffn
 
+@node SRFI-214
+@subsection SRFI-214 - Flexvectors
+
+Documentation for SRFI-214, Flexvectors is provided in @xref{Flexvectors}.
+
 @c srfi-modules.texi ends here
 
 @c Local Variables:
diff --git a/module/Makefile.am b/module/Makefile.am
index f6f5a9bb8..799ef7bd6 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -323,6 +323,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..c9d8c9cd3
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,735 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) Adam Nelson (2020).
+;;; Copyright (C) Vijay Marupudi (2022).
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy of
+;;; this software and associated documentation files (the "Software"), to deal in
+;;; the Software without restriction, including without limitation the rights to
+;;; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+;;; the Software, and to permit persons to whom the Software is furnished to do so,
+;;; subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice (including the next
+;;; paragraph) shall be included in all copies or substantial portions of the
+;;; Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+;;; FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+;;; COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+;;; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; Authorship: This code was largely written by Adam Nelson as a
+;; sample implementation for srfi-214 and adapted for Guile by Vijay
+;; Marupudi.
+
+(define-module (srfi srfi-214))
+
+(use-modules ((scheme base)
+              #:prefix r7:)
+             (scheme case-lambda)
+             (scheme write)
+             (srfi srfi-1)
+             (srfi srfi-9)
+             (srfi srfi-9 gnu)
+             (srfi srfi-11)
+             (rnrs io ports))
+
+
+(export ; Constructors
+        make-flexvector flexvector
+        flexvector-unfold flexvector-unfold-right
+        flexvector-copy flexvector-reverse-copy
+        flexvector-append flexvector-concatenate flexvector-append-subvectors
+        <flexvector>
+
+        ; 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)
+
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#<flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display ">" port)
+                                (begin
+                                  (format port " ~s" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ">" port)
+                                        (begin
+                                          (write (flexvector-ref obj i) port)
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (r7:vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (r7:vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (r7:vector-copy! v (+ i xvlen) v i len)
+    (r7:vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (r7:vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (r7:vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (r7:vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (r7:vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (r7:vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (r7:map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (r7:vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (r7:vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (r7:vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (r7:map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (r7:map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (r7:map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (r7:map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (r7:map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (r7:map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (r7:map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply r7:string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (r7:vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 16fa2e952..a62ffcf6c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,6 +162,7 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
             tests/srfi-171.test                 \
+	    tests/srfi-214.test                 \
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-214.test b/test-suite/tests/srfi-214.test
new file mode 100644
index 000000000..dacec8fa8
--- /dev/null
+++ b/test-suite/tests/srfi-214.test
@@ -0,0 +1,437 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;;    Copyright (C) 2020 Adam Nelson.
+;;;    Copyright (C) 2022 Vijay Marupudi.
+;;;
+;;; This code is based on the file tests.scm in the reference
+;;; implementation of SRFI-214, provided under the following license:
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining
+;;; a copy of this software and associated documentation files (the
+;;; "Software"), to deal in the Software without restriction, including
+;;; without limitation the rights to use, copy, modify, merge, publish,
+;;; distribute, sublicense, and/or sell copies of the Software, and to
+;;; permit persons to whom the Software is furnished to do so, subject to
+;;; the following conditions:
+;;;
+;;; The above copyright notice and this permission notice shall be
+;;; included in all copies or substantial portions of the Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;;; SOFTWARE.
+
+(define-module (test-suite test-srfi-214)
+  #:use-module (srfi srfi-214)
+  #:use-module (test-suite lib)
+  #:use-module (rnrs io ports))
+
+(with-test-prefix "SRFI-214"
+
+  (pass-if "flexvector?"
+    (equal? #t (flexvector? (flexvector))))
+  (pass-if "flexvector-length"
+    (equal? 3 (flexvector-length (make-flexvector 3 #f))))
+  (pass-if "flexvector"
+    (equal? 3 (flexvector-length (flexvector 1 2 3))))
+
+  (let ((fv (flexvector 'a 'b 'c)))
+    (pass-if "flexvector-ref"
+      (equal? 'b (flexvector-ref fv 1)))
+    (pass-if "flexvector-front"
+      (equal? 'a (flexvector-front fv)))
+    (pass-if "flexvector-back"
+      (equal? 'c (flexvector-back fv)))
+    (pass-if "flexvector-set! return"
+      (equal? 'b (flexvector-set! fv 1 'd)))
+    (pass-if "flexvector-set! mutate"
+      (equal? 'd (flexvector-ref fv 1)))
+    (pass-if "flexvector-add-back! return"
+      (equal? fv (flexvector-add-back! fv 'e)))
+    (pass-if "flexvector-add-back! mutate"
+      (equal? '(4 . e)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv (- (flexvector-length fv) 1)))))
+    (pass-if "flexvector-remove! return"
+      (equal? 'd (flexvector-remove! fv 1)))
+    (pass-if "flexvector-remove! mutate"
+      (equal? '(3 . c)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv 1))))
+    (pass-if "flexvector-clear! return"
+      (equal? fv (flexvector-clear! fv)))
+    (pass-if "flexvector-clear! mutate"
+      (equal? 0 (flexvector-length fv)))
+    (pass-if "flexvector-empty?"
+      (equal? #t (flexvector-empty? fv))))
+
+  (pass-if "flexvector=? same symbols"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b))))
+  (pass-if "flexvector=? different symbols"
+    (equal? #f
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a))))
+  (pass-if "flexvector=? different lengths"
+    (equal? #f
+            (flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? same numbers"
+    (equal? #t
+            (flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? 0 arguments"
+    (equal? #t
+            (flexvector=? eq?)))
+  (pass-if "flexvector=? 1 argument"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a))))
+
+  (pass-if "make-flexvector"
+    (equal? #(a a a) (flexvector->vector (make-flexvector 3 'a))))
+
+  (pass-if "flexvector-unfold"
+    (equal?
+     #(1 4 9 16 25 36 49 64 81 100)
+     (flexvector->vector
+      (flexvector-unfold (lambda (x) (> x 10))
+                         (lambda (x) (* x x))
+                         (lambda (x) (+ x 1))
+                         1))))
+  (pass-if "flexvector-unfold-right"
+    (equal?
+     #(100 81 64 49 36 25 16 9 4 1)
+     (flexvector->vector
+      (flexvector-unfold-right (lambda (x) (> x 10))
+                               (lambda (x) (* x x))
+                               (lambda (x) (+ x 1))
+                               1))))
+
+
+  (pass-if "string->flexvector"
+    (equal? #(#\a #\b #\c)
+            (flexvector->vector (string->flexvector "abc"))))
+  (pass-if "flexvector->string"
+    (equal? "abc" (flexvector->string (flexvector #\a #\b #\c))))
+
+  (define genlist '(a b c))
+  (define (mock-generator)
+    (if (pair? genlist)
+        (let ((value (car genlist)))
+          (set! genlist (cdr genlist))
+          value)
+        (eof-object)))
+
+  (pass-if "generator->flexvector"
+    (equal? #(a b c)
+            (flexvector->vector (generator->flexvector mock-generator))))
+  (pass-if "flexvector->generator"
+    (equal? '(a b c #t)
+            (let* ((gen (flexvector->generator (flexvector 'a 'b 'c)))
+                   (one (gen))
+                   (two (gen))
+                   (three (gen))
+                   (four (eof-object? (gen))))
+              (list one two three four))))
+
+                                        ; Nondestructive operations on one vector
+  (let ((fv (flexvector 10 20 30)))
+    (pass-if "flexvector->vector"
+      (equal? #(10 20 30) (flexvector->vector fv)))
+    (pass-if "flexvector->list"
+      (equal? '(10 20 30) (flexvector->list fv)))
+    (pass-if "reverse-flexvector->list"
+      (equal? '(30 20 10) (reverse-flexvector->list fv)))
+    (pass-if "flexvector-copy"
+      (equal? #t
+              (let ((copy (flexvector-copy fv)))
+                (and (= (flexvector-length fv) (flexvector-length copy))
+                     (not (eq? fv copy))))))
+    (pass-if "flexvector-reverse-copy"
+      (equal? #(30 20 10)
+              (flexvector->vector (flexvector-reverse-copy fv))))
+    (pass-if "flexvector-copy start"
+      (equal? #(20 30)
+              (flexvector->vector (flexvector-copy fv 1))))
+    (pass-if "flexvector-copy start end"
+      (equal? #(20)
+              (flexvector->vector (flexvector-copy fv 1 2))))
+    (pass-if "flexvector-for-each"
+      (equal? '(30 20 10)
+              (let ((res '()))
+                (flexvector-for-each (lambda (x) (set! res (cons x res))) fv)
+                res)))
+    (pass-if "flexvector-for-each/index"
+      (equal? '(34 22 10)
+              (let ((res '()))
+                (flexvector-for-each/index
+                 (lambda (i x) (set! res (cons (+ x (* i 2)) res)))
+                 fv)
+                res)))
+    (pass-if "flexvector-map"
+      (equal? #(100 200 300)
+              (flexvector->vector (flexvector-map (lambda (x) (* x 10)) fv))))
+    (pass-if "flexvector-map/index"
+      (equal? #(10 22 34)
+              (flexvector->vector (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv))))
+    (pass-if "flexvector-append-map"
+      (equal? #(10 100 20 200 30 300)
+              (flexvector->vector
+               (flexvector-append-map (lambda (x) (flexvector x (* x 10))) fv))))
+    (pass-if "flexvector-append-map/index"
+      (equal? #(0 10 10 1 20 22 2 30 34)
+              (flexvector->vector
+               (flexvector-append-map/index
+                (lambda (i x) (flexvector i x (+ x (* i 2))))
+                fv))))
+    (pass-if "flexvector-filter"
+      (equal? #(10)
+              (flexvector->vector (flexvector-filter (lambda (x) (< x 15)) fv))))
+    (pass-if "flexvector-filter/index"
+      (equal? #(10 30)
+              (flexvector->vector (flexvector-filter/index (lambda (i x) (not (= i 1))) fv))))
+    (pass-if "flexvector-fold"
+      (equal? '(30 20 10)
+              (flexvector-fold (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-fold-right"
+      (equal? '(10 20 30)
+              (flexvector-fold-right (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-count"
+      (equal? 2
+              (flexvector-count (lambda (x) (< x 25)) fv)))
+    (pass-if "flexvector-cumulate"
+      (equal? #(3 4 8 9 14 23 25 30 36)
+              (flexvector->vector
+               (flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6)))))
+    (pass-if "flexvector-any"
+      (equal? '(#t . #f)
+              (cons (flexvector-any (lambda (x) (= x 20)) fv)
+                    (flexvector-any (lambda (x) (= x 21)) fv))))
+    (pass-if "flexvector-every"
+      (equal? '(#t . #f)
+              (cons (flexvector-every (lambda (x) (< x 40)) fv)
+                    (flexvector-every (lambda (x) (< x 30)) fv))))
+    (pass-if "flexvector-index"
+      (equal? 1
+              (flexvector-index (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-index-right"
+      (equal? 2
+              (flexvector-index-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-skip"
+      (equal? 1
+              (flexvector-skip (lambda (x) (< x 20)) fv)))
+    (pass-if "flexvector-skip-right"
+      (equal? 0
+              (flexvector-skip-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-partition"
+      (equal? '(#(10 20) #(30))
+              (call-with-values
+                  (lambda () (flexvector-partition (lambda (x) (< x 25)) fv))
+                (lambda vs ((@ (scheme base) map) flexvector->vector vs))))))
+
+  (let ((fv (flexvector #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j))
+        (cmp (lambda (char1 char2)
+               (cond ((char<? char1 char2) -1)
+                     ((char=? char1 char2) 0)
+                     (else 1)))))
+    (pass-if "flexvector-binary-search"
+      (equal? 3
+              (flexvector-binary-search fv #\d cmp)))
+    (pass-if "flexvector-binary-search first"
+      (equal? 0
+              (flexvector-binary-search fv #\a cmp)))
+    (pass-if "flexvector-binary-search last"
+      (equal? 9
+              (flexvector-binary-search fv #\j cmp)))
+    (pass-if "flexvector-binary-search not found"
+      (equal? #f
+              (flexvector-binary-search fv #\k cmp)))
+
+    (pass-if "flexvector-binary-search in range"
+      (equal? 5
+              (flexvector-binary-search fv #\f cmp 2 6)))
+    (pass-if "flexvector-binary-search out of range"
+      (equal? #f
+              (flexvector-binary-search fv #\f cmp 1 5))))
+
+                                        ; Nondestructive operations on multiple vectors
+  (pass-if "flexvector-append"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-append (flexvector 10 20)
+                                (flexvector)
+                                (flexvector 30 40)
+                                (flexvector 50 60)))))
+  (pass-if "flexvector-concatenate"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-concatenate
+              (list (flexvector 10 20)
+                    (flexvector)
+                    (flexvector 30 40)
+                    (flexvector 50 60))))))
+  (pass-if "flexvector-append-subvectors"
+    (equal? #(a b h i)
+            (flexvector->vector
+             (flexvector-append-subvectors
+              (flexvector 'a 'b 'c 'd 'e) 0 2
+              (flexvector 'f 'g 'h 'i 'j) 2 4))))
+
+
+                                        ; Destructive operations on one vector
+  (define-syntax mutate-as
+    (syntax-rules ()
+      ((_ name vec expr)
+       (let ((name (vector->flexvector vec)))
+         expr
+         (flexvector->vector name)))))
+
+  (pass-if "flexvector-add! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! start"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! start multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! middle"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo baz) (flexvector-add! x 1 'bar))))
+  (pass-if "flexvector-add! middle multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo quux) (flexvector-add! x 1 'bar 'baz 'qux))))
+  (pass-if "flexvector-add! end"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz))))
+  (pass-if "flexvector-add! end multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-add-all!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo qux) (flexvector-add-all! x 1 '(bar baz)))))
+
+  (pass-if "flexvector-add-front! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-front! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-front!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add-front! x 'foo 'bar 'baz))))
+
+  (pass-if "flexvector-add-back! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-back! x 'foo))))
+  (pass-if "flexvector-add-back! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-back! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-back!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz))))
+  (pass-if "flexvector-add-back! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-append!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux)))))
+  (pass-if "flexvector-append! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux) (flexvector 'quux)))))
+
+  (pass-if "flexvector-remove!"
+    (equal? '#(foo baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove! x 1))))
+  (pass-if "flexvector-remove! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove! x 0))))
+
+  (pass-if "flexvector-remove-front!"
+    (equal? '#(bar baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-front! x))))
+  (pass-if "flexvector-remove-front! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-front! x))))
+
+  (pass-if "flexvector-remove-back!"
+    (equal? '#(foo bar)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-back! x))))
+  (pass-if "flexvector-remove-back! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-back! x))))
+
+  (pass-if "flexvector-remove-range!"
+    (equal? '#(a e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 4))))
+  (pass-if "flexvector-remove-range! empty range"
+    (equal? '#(a b c d e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 1))))
+  (pass-if "flexvector-remove-range! overflow left"
+    (equal? '#(e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x -1 4))))
+  (pass-if "flexvector-remove-range! overflow right"
+    (equal? '#(a b)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 2 10))))
+
+  (pass-if "flexvector-map!"
+    (equal? '#(100 200 300)
+            (mutate-as fv '#(10 20 30) (flexvector-map! (lambda (x) (* x 10)) fv))))
+  (pass-if "flexvector-map/index!"
+    (equal? '#(10 22 34)
+            (mutate-as fv '#(10 20 30) (flexvector-map/index! (lambda (i x) (+ x (* i 2))) fv))))
+  (pass-if "flexvector-filter!"
+    (equal? '#(10)
+            (mutate-as fv '#(10 20 30) (flexvector-filter! (lambda (x) (< x 15)) fv))))
+  (pass-if "flexvector-filter/index!"
+    (equal? '#(10 30)
+            (mutate-as fv '#(10 20 30) (flexvector-filter/index! (lambda (i x) (not (= i 1))) fv))))
+
+  (pass-if "flexvector-swap!"
+    (equal? #(10 30 20)
+            (mutate-as fv '#(10 20 30) (flexvector-swap! fv 1 2))))
+  (pass-if "flexvector-reverse!"
+    (equal? #(30 20 10)
+            (mutate-as fv '#(10 20 30) (flexvector-reverse! fv))))
+
+  (pass-if "flexvector-copy!"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-copy! bounded"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-copy! overflow"
+    (equal? #(1 2 30 40 50)
+            (mutate-as fv '#(1 2 3) (flexvector-copy! fv 2 (flexvector 30 40 50)))))
+  (pass-if "flexvector-reverse-copy!"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-reverse-copy! bounded"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-reverse-copy! overflow"
+    (equal? #(1 2 50 40 30)
+            (mutate-as fv '#(1 2 3) (flexvector-reverse-copy! fv 2 (flexvector 30 40 50)))))
+
+  (pass-if "flexvector-fill!"
+    (equal? '#(foo foo foo)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'foo))))
+  (pass-if "flexvector-fill! start"
+    (equal? '#(1 2 bar bar bar)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'bar 2))))
+  (pass-if "flexvector-fill! start end"
+    (equal? '#(1 2 baz baz 5)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'baz 2 4))))
+  (pass-if "flexvector-fill! clamped"
+    (equal? '#(qux qux qux)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'qux -1 10)))))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 17:57               ` Vijay Marupudi
@ 2022-01-20 18:15                 ` Maxime Devos
  2022-01-20 20:38                   ` Vijay Marupudi
  2022-10-12 12:22                 ` Ludovic Courtès
  1 sibling, 1 reply; 14+ messages in thread
From: Maxime Devos @ 2022-01-20 18:15 UTC (permalink / raw)
  To: Vijay Marupudi, guile-devel

[-- Attachment #1: Type: text/plain, Size: 732 bytes --]

Vijay Marupudi schreef op do 20-01-2022 om 12:57 [-0500]:
> > Here are two examples in the wild (slib):
> 
> Thanks, the patch, which is attached, now attributes credit
> appropriately.
> 
> Thank you very much for your help Maxime. I believe there is nothing
> else pending and that the patch is ready?

I haven't really looked closely at the documentation or code,
but the structure of the patch seems fine now, except perhaps:

> "Software"), to deal in the Software without restriction, including

Unicode has been a thing now since quite a while, so writing “Software”
with curly quotes instead of "straight quotes" is possible now.  Or
perhaps Texinfo takes care of that by itself.

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 18:15                 ` Maxime Devos
@ 2022-01-20 20:38                   ` Vijay Marupudi
  2022-10-07 19:58                     ` Vijay Marupudi
  0 siblings, 1 reply; 14+ messages in thread
From: Vijay Marupudi @ 2022-01-20 20:38 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

> I haven't really looked closely at the documentation or code,
> but the structure of the patch seems fine now

That's good to hear, awaiting code review then!

> , except perhaps:
>
>> "Software"), to deal in the Software without restriction, including
>
> Unicode has been a thing now since quite a while, so writing “Software”
> with curly quotes instead of "straight quotes" is possible now.  Or
> perhaps Texinfo takes care of that by itself.

I copied the original text of the license in the srfi, I don't want to
modify it just for typographical reasons, but the maintainers are
welcome to do that if they wish!

~ Vijay



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 20:38                   ` Vijay Marupudi
@ 2022-10-07 19:58                     ` Vijay Marupudi
  0 siblings, 0 replies; 14+ messages in thread
From: Vijay Marupudi @ 2022-10-07 19:58 UTC (permalink / raw)
  To: Maxime Devos, guile-devel

Hello guile-devel,

Looking for a review and merge of this patch if possible!

~ Vijay



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-01-20 17:57               ` Vijay Marupudi
  2022-01-20 18:15                 ` Maxime Devos
@ 2022-10-12 12:22                 ` Ludovic Courtès
  2022-11-13 20:27                   ` Vijay Marupudi
  1 sibling, 1 reply; 14+ messages in thread
From: Ludovic Courtès @ 2022-10-12 12:22 UTC (permalink / raw)
  To: guile-devel; +Cc: guile-devel

Hi Vijay,

Sorry for the looong delay!

Overall the patches look great to me.  Below are comments and
suggestions, mostly cosmetic.

Vijay Marupudi <vijay@vijaymarupudi.com> skribis:

> From 42206dec4d5e9ae51665c6e98ef07715b89b12fe Mon Sep 17 00:00:00 2001
> From: Vijay Marupudi <vijay@vijaymarupudi.com>
> Date: Tue, 18 Jan 2022 20:52:08 -0500
> Subject: [PATCH] Added srfi-214: flexvectors
>
> Included code, documentation, and tests

Please use the ChangeLog style for commit messages (see ‘git log’ for
examples); as a welcome gift, we can do it for you though.  :-)


[...]

> +@node Flexvectors
> +@subsection Flexvectors
> +@cindex flexvector

General comments:

  • please leave two spaces after end-of-sentence periods (a convention
    eases navigation with Emacs);

  • use @dfn to decorate a term the first time it’s introduced, @code
    for identifiers, etc.;

  • limit lines to ~80 columns.

> +Flexvectors are sometimes better known as a @url{https://en.wikipedia.org/wiki/Dynamic_array,dynamic arrays}. This data
> +structure has a wide variety of names in different languages:

Maybe add a first sentence before this one, like: “The @code{(srfi
srfi-214)} module implements @dfn{flexvectors}, a data structure for
mutable vectors with adjustable size.”

> +@itemize @bullet{}

You can drop @bullet{}.

> +@item
> +JavaScript and Ruby call it an array
> +@item
> +Python calls it a list
> +@item
> +Java calls it an ArrayList (and, before that, it was called a Vector)

Add a semicolon at the end of the first two lines, a period for the last
one.  @code{ArrayList}.


[...]

> +++ b/module/srfi/srfi-214.scm
> @@ -0,0 +1,735 @@
> +;;; -*- mode: scheme; coding: utf-8; -*-
> +;;;
> +;;; Copyright (C) Adam Nelson (2020).
> +;;; Copyright (C) Vijay Marupudi (2022).

Nitpick: should be:

  Copyright (C) 2022 …

> +(define-module (srfi srfi-214))
> +
> +(use-modules ((scheme base)
> +              #:prefix r7:)
> +             (scheme case-lambda)
> +             (scheme write)
> +             (srfi srfi-1)
> +             (srfi srfi-9)
> +             (srfi srfi-9 gnu)
> +             (srfi srfi-11)
> +             (rnrs io ports))
> +
> +
> +(export ; Constructors

Please use a single ‘define-module’ clause with #:use-module and
#:export lines (this is equivalent but that’s what we conventionally
use and it makes the interface clearer upfront).

Avoid using R6RS and R7RS modules as they pull in a whole lot of stuff.
For example, maybe you can use (ice-9 binary-ports) instead of (rnrs io
ports); maybe you don’t need (scheme …) at all because Guile most likely
has equivalent things built in.

> +        make-flexvector flexvector
> +        flexvector-unfold flexvector-unfold-right
> +        flexvector-copy flexvector-reverse-copy
> +        flexvector-append flexvector-concatenate flexvector-append-subvectors
> +        <flexvector>

Don’t export <flexvector> as it would expose implementation details (the
record interface).

> +(define (flexvector . xs)

In general we try to add docstrings for all public top-level
procedures.  Bonus points if you can do that.  :-)

The rest looks great to me!

Could you send an updated patch?

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Added srfi-214: flexvectors
  2022-10-12 12:22                 ` Ludovic Courtès
@ 2022-11-13 20:27                   ` Vijay Marupudi
  0 siblings, 0 replies; 14+ messages in thread
From: Vijay Marupudi @ 2022-11-13 20:27 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 2047 bytes --]

Hello,

I've made all the suggested edits. Sorry about the delay, universities
get quite busy in the middle of the semester.

> Please use the ChangeLog style for commit messages (see ‘git log’ for
> examples); as a welcome gift, we can do it for you though.  :-)

I've tried to do this, please verify this!
>
>   • please leave two spaces after end-of-sentence periods (a convention
>     eases navigation with Emacs);
>
>   • use @dfn to decorate a term the first time it’s introduced, @code
>     for identifiers, etc.;
>
>   • limit lines to ~80 columns.

Changed.


> Maybe add a first sentence before this one, like: “The @code{(srfi
> srfi-214)} module implements @dfn{flexvectors}, a data structure for
> mutable vectors with adjustable size.”

Added.

> You can drop @bullet{}.

Removed.

> Add a semicolon at the end of the first two lines, a period for the last
> one.  @code{ArrayList}.

Added.

> Nitpick: should be:
>
>   Copyright (C) 2022 …
>

Changed.

> Please use a single ‘define-module’ clause with #:use-module and
> #:export lines (this is equivalent but that’s what we conventionally
> use and it makes the interface clearer upfront).
>
> Avoid using R6RS and R7RS modules as they pull in a whole lot of stuff.
> For example, maybe you can use (ice-9 binary-ports) instead of (rnrs io
> ports); maybe you don’t need (scheme …) at all because Guile most likely
> has equivalent things built in.

Changed both to fit the convention.

> Don’t export <flexvector> as it would expose implementation details (the
> record interface).

I removed that export.

> In general we try to add docstrings for all public top-level
> procedures.  Bonus points if you can do that.  :-)

Ah, this would take way too long for me, so I'll leave this up to
another contributor in the future. Would be a great first contribution!

> The rest looks great to me!
>
> Could you send an updated patch?

I've attached the updated patch.

~ Vijay


[-- Attachment #2: 0001-Added-srfi-214-flexvectors.patch --]
[-- Type: text/x-patch, Size: 78025 bytes --]

From 0b1b46123a62c2c65dd58805592d4da3325eccf5 Mon Sep 17 00:00:00 2001
From: Vijay Marupudi <vijay@vijaymarupudi.com>
Date: Sun, 13 Nov 2022 15:23:02 -0500
Subject: [PATCH] Added srfi-214: flexvectors

* am/bootstrap.am: Added srfi/srfi-214.scm to list to scheme files to compile.
* doc/ref/api-data.texi: Added documentation for flexvectors.
* doc/ref/srfi-modules.texi: Inserted a link to the documentation for flexvectors.
* module/srfi/srfi-214.scm: Code for srfi-214.scm, adapted from the sample implementation.
* test-suite/Makefile.am: Added srfi-214.test to the list of tests to run.
* test-suite/tests/srfi-214.test: Adapted the srfi-214 sample tests to the Guile test suite.

Signed-off-by: Vijay Marupudi <vijay@vijaymarupudi.com>
---
 am/bootstrap.am                |   1 +
 doc/ref/api-data.texi          | 854 ++++++++++++++++++++++++++++++++-
 doc/ref/srfi-modules.texi      |   6 +
 module/srfi/srfi-214.scm       | 740 ++++++++++++++++++++++++++++
 test-suite/Makefile.am         |   1 +
 test-suite/tests/srfi-214.test | 437 +++++++++++++++++
 6 files changed, 2038 insertions(+), 1 deletion(-)
 create mode 100644 module/srfi/srfi-214.scm
 create mode 100644 test-suite/tests/srfi-214.test

diff --git a/am/bootstrap.am b/am/bootstrap.am
index 0257d53dc..374674ea9 100644
--- a/am/bootstrap.am
+++ b/am/bootstrap.am
@@ -344,6 +344,7 @@ SOURCES =					\
   srfi/srfi-171.scm                             \
   srfi/srfi-171/gnu.scm                         \
   srfi/srfi-171/meta.scm                        \
+  srfi/srfi-214.scm                             \
 						\
   statprof.scm					\
 						\
diff --git a/doc/ref/api-data.texi b/doc/ref/api-data.texi
index 8658b9785..bddcc4a2b 100644
--- a/doc/ref/api-data.texi
+++ b/doc/ref/api-data.texi
@@ -26,7 +26,8 @@ complex.
 * Bit Vectors::                 Vectors of bits.
 * Bytevectors::                 Sequences of bytes.
 * Arrays::                      Multidimensional matrices.
-* VLists::                      Vector-like lists.
+* VLists::                      Vector-like lists
+* Flexvectors::                 Mutable vectors with adjustable size
 * Record Overview::             Walking through the maze of record APIs.
 * SRFI-9 Records::              The standard, recommended record API.
 * Records::                     Guile's historical record API.
@@ -8314,6 +8315,857 @@ Return a new vlist whose contents correspond to @var{lst}.
 Return a new list whose contents match those of @var{vlist}.
 @end deffn
 
+@node Flexvectors
+@subsection Flexvectors
+@cindex flexvector
+
+The @code{(srfi srfi-214)} module implements @dfn{flexvectors}, a data
+structure for mutable vectors with adjustable size.  Flexvectors are
+sometimes better known as a
+@url{https://en.wikipedia.org/wiki/Dynamic_array,dynamic arrays}.  This
+data structure has a wide variety of names in different languages:
+
+@itemize
+
+@item
+JavaScript and Ruby call it an array;
+@item
+Python calls it a list;
+@item
+Java calls it an @code{ArrayList} (and, before that, it was called a Vector).
+
+@end itemize
+
+
+Flexvectors have the same O(1) random-access performance guarantees as
+ordinary vectors.  Additionally, appending to the back of a flexvector
+has the same (amortized) performance as setting an existing location in
+the same flexvector.
+
+Functions in this module can be obtained with:
+
+@example
+(use-modules (srfi srfi-214))
+@end example
+
+The material in this section was derived from the
+@url{https://srfi.schemers.org/srfi-214/srfi-214.html,SRFI-214} proposal
+written by Adam Nelson, whose copyright notice is as follows.
+
+@quotation
+(C) Adam Nelson 2020-2021.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+@end quotation
+
+@subsubsection Constructors
+
+@deffn {Scheme Procedure} make-flexvector size [fill]
+
+Creates and returns a flexvector of size @var{size}.  If @var{fill} is
+specified, all of the elements of the vector are initialized to
+@var{fill}.  Otherwise, their contents are indeterminate.
+
+
+@example
+(make-flexvector 5 3) @result{} #<flexvector 3 3 3 3 3>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector x ...
+
+Creates and returns a flexvector whose elements are @var{x ...}.
+
+@example
+(flexvector 0 1 2 3 4) @result{} #<flexvector 0 1 2 3 4>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-unfold p f g initial-seed ...
+@deffnx {Scheme Procedure} flexvector-unfold-right p f g initial-seed ...
+
+The fundamental flexvector constructor.  @code{flexvector-unfold} is
+modeled on SRFI 1 @code{unfold} instead of SRFI 133
+@code{vector-unfold} because flexvectors are not limited to a
+predetermined length.
+
+@example
+;; List of squares: 1^2 ... 10^2
+(flexvector-unfold
+  (lambda (x) (> x 10))
+  (lambda (x) (* x x))
+  (lambda (x) (+ x 1))
+  1)
+@result{} #<flexvector 1 4 9 16 25 36 49 64 81 100>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy fv [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy fv [start [end]]
+
+Allocates a new flexvector whose length is @code{(- end start)} and fills
+it with elements from @var{fv}, taking elements from @var{fv} starting
+at index @var{start} and stopping at index @var{end}.  @var{start}
+defaults to @var{0} and @var{end} defaults to the value of
+@code{(flexvector-length fv)}.
+
+@example
+(flexvector-copy (flexvector 'a 'b 'c)) @result{} #<flexvector a b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1) @result{} #<flexvector b c>
+(flexvector-copy (flexvector 'a 'b 'c) 1 2) @result{} #<flexvector b>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append fv ...
+
+Returns a newly allocated flexvector that contains all elements in order
+from the subsequent locations in @var{fv ...}.
+
+@example
+(flexvector-append (flexvector 'x) (flexvector 'y))
+@result{} #<flexvector x y>
+
+(flexvector-append (flexvector 'a) (flexvector 'b 'c 'd))
+@result{} #<flexvector a b c d>
+
+(flexvector-append (flexvector 'a (flexvector 'b))
+                   (flexvector (flexvector 'c)))
+@result{} #<flexvector a #<flexvector b> #<flexvector c>>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-concatenate list-of-flexvectors
+
+Equivalent to @code{(apply flexvector-append list-of-flexvectors)}, but
+may be implemented more efficiently.
+
+@example
+(flexvector-concatenate (list (flexvector 'a 'b) (flexvector 'c 'd)))
+@result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-append-subvectors [fv start end] ...
+
+Returns a vector that contains every element of each @var{fv} from
+@var{start} to @var{end} in the specified order.  This procedure is a
+generalization of @code{flexvector-append}.
+
+@example
+(flexvector-append-subvectors (flexvector 'a 'b 'c 'd 'e) 0 2
+                              (flexvector 'f 'g 'h 'i 'j) 2 4)
+@result{} #<flexvector a b h i>
+@end example
+@end deffn
+
+@subsubsection Predicates
+
+@deffn {Scheme Procedure} flexvector? x
+
+Disjoint type predicate for flexvectors: this returns @var{#t} if
+@var{x} is a flexvector, and @var{#f} otherwise.
+
+@example
+(flexvector? (flexvector 1 2 3)) @result{} #t
+(flexvector? (vector 1 2 3)) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-empty? fv
+
+Returns @var{#t} if @var{fv} is empty (i.e., its length is @var{0}), and
+@var{#f} if not.
+
+@example
+(flexvector-empty? (flexvector)) @result{} #t
+(flexvector-empty? (flexvector 'a)) @result{} #f
+(flexvector-empty? (flexvector (flexvector))) @result{} #f
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector=? elt=? fv ...
+
+Flexvector structural equality predicate, generalized across
+user-specified element equality predicates.  Flexvectors @var{a} and
+@var{b} are considered equal by @code{flexvector=?} iff their lengths are
+the same and, for each index @var{i} less than @code{(flexvector-length
+a)}, @code{(elt=? (flexvector-ref a i) (flexvector-ref b i))} is true.
+@var{elt=?} is always applied to two arguments.
+
+
+@example
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b)) @result{} #t
+(flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4)) @result{} #f
+(flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4)) @result{} #t
+@end example
+@end deffn
+
+@subsubsection Selectors
+
+@deffn {Scheme Procedure} flexvector-ref fv i
+
+Flexvector element dereferencing: returns the value at location @var{i}
+in @var{fv}.  Indexing is zero-based.  It is an error if @var{i} is
+outside the range [0, @code{(flexvector-length fv)}).
+
+@example
+(flexvector-ref (flexvector 'a 'b 'c 'd) 2) @result{} c
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-front fv
+
+Returns the first element in @var{fv}.  It is an error if @var{fv} is
+empty.  Alias for @code{(flexvector-ref fv 0)}.
+
+@example
+(flexvector-front (flexvector 'a 'b 'c 'd)) @result{} a
+@end example
+@end deffn
+@deffn {Scheme Procedure} flexvector-back fv
+
+Returns the last element in @var{fv}.  It is an error if @var{fv} is
+empty.  Alias for @code{(flexvector-ref fv (- (flexvector-length fv)
+1))}.
+
+@example
+(flexvector-back (flexvector 'a 'b 'c 'd)) @result{} d
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-length fv
+
+Returns the length of @var{fv}, which is the number of elements
+contained in @var{fv}.
+
+@end deffn
+
+@subsubsection Mutators
+
+@deffn {Scheme Procedure} flexvector-add! fv i x ...
+
+Inserts the elements @var{x ...} into @var{fv} at the location @var{i},
+preserving their order and shifting all elements after @var{i} backward
+to make room.  This increases the length of @var{fv} by the number of
+elements inserted.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}].
+
+@code{flexvector-add!} returns @var{fv} after mutating it.
+
+@example
+(flexvector-add! (flexvector 'a 'b) 1 'c) @result{} #<flexvector a c b>
+(flexvector-add! (flexvector 'a 'b) 2 'c 'd 'e) @result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-front! fv x ...
+@deffnx {Scheme Procedure} flexvector-add-back! fv x ...
+
+Inserts the elements @var{x ...} into the front or back of @var{fv},
+preserving their order.  This increases the length of @var{fv} by the
+number of elements inserted.
+
+@code{flexvector-add-back!} of one element has the same O(1)
+computational complexity as @code{vector-set!}, amortized.
+
+These procedures return @var{fv} after mutating it.
+
+@example
+(flexvector-add-front! (flexvector 'a 'b) 'c) @result{} #<flexvector c a b>
+(flexvector-add-front! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector c d a b>
+
+(flexvector-add-back! (flexvector 'a 'b) 'c) @result{} #<flexvector a b c>
+(flexvector-add-back! (flexvector 'a 'b) 'c 'd) @result{} #<flexvector a b c d>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-add-all! fv i xs
+
+Inserts the elements of the list @code{xs} into @var{fv} at location
+@var{i}.  Equivalent to @code{(apply flexvector-add! fv i xs)}.  Returns
+@var{fv} after mutating it.
+
+@example
+(flexvector-add-all! (flexvector 'a 'b) 2 '(c d e))
+@result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append! fv1 fv2 ...
+
+Inserts the elements of the flexvectors @var{fv2 ...} at the end of the
+flexvector @var{fv1}, in order.  Returns @var{fv1} after mutating it.
+
+@example
+(flexvector-append! (flexvector 'a 'b)
+                    (flexvector 'c 'd)
+                    (flexvector 'e))
+@result{} #<flexvector a b c d e>
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove! fv i
+
+Removes and returns the element at @var{i} in @var{fv}, then
+shifts all subsequent elements forward, reducing the length of @var{fv}
+by 1.
+
+It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}).
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-front! fv
+@deffnx {Scheme Procedure} flexvector-remove-back! fv
+Removes and returns the first element from @var{fv}, then shifts
+all other elements forward.  @code{flexvector-remove-back!} instead
+removes the last element, without moving any other elements, and has the
+same performance guarantees as @code{flexvector-add-back!}.
+
+It is an error if @var{fv} is empty.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-remove-range! fv start [end]
+
+Removes all elements from @var{fv} between @var{start} and
+@var{end}, shifting all elements after @var{end} forward by @code{(- end
+start)}.  If @var{end} is not present, it defaults to
+@code{(flexvector-length fv)}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}).  It is an error if @var{end} is less than
+@var{start}.
+
+@code{flexvector-remove-range!} returns @var{fv} after mutating
+it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-clear! fv
+
+Removes all items from @var{fv}, setting its length to 0.
+Returns @var{fv} after mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-set! fv i x
+
+Assigns the value of @var{x} to the location @var{i} in
+@var{fv}.  It is an error if @var{i} is outside the range [0,
+@code{(flexvector-length fv)}].  If @var{i} is equal to
+@code{(flexvector-length fv)}, @var{x} is appended after the last
+element in @var{fv}; this is equivalent to @code{flexvector-add-back!}.
+
+Returns the previous value at location @var{i} in @var{fv}, or
+an unspecified value if @var{i} is equal to @code{(flexvector-length
+fv)}.
+
+@code{flexvector-set!} has the same O(1) computational
+complexity as @code{vector-set!}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-swap! fv i j
+
+Swaps or exchanges the values of the locations in @var{fv} at
+indexes @var{i} and @var{j}.  It is an error if either @var{i} or @var{j}
+is outside the range [0, @code{(flexvector-length fv)}).  Returns @var{fv}
+after mutating it.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-fill! fv fill [start [end]]
+
+Assigns the value of every location in @var{fv} between
+@var{start}, which defaults to 0 and @var{end}, which defaults to the
+length of @var{fv}, to @var{fill}.  Returns @var{fv} after mutating it.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}].  It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-reverse! fv
+
+Destructively reverses @var{fv} in-place.  Returns @var{fv} after
+mutating it.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-copy! to at from [start [end]]
+@deffnx {Scheme Procedure} flexvector-reverse-copy! to at from [start [end]]
+
+Copies the elements of flexvector @var{from} between @var{start}
+and @var{end} to flexvector @var{to}, starting at @var{at}.  The order in
+which elements are copied is unspecified, except that if the source and
+destination overlap, copying takes place as if the source is first
+copied into a temporary vector and then into the destination.  This can
+be achieved without allocating storage by making sure to copy in the
+correct direction in such circumstances.
+
+@code{flexvector-reverse-copy!} is the same, but copies elements
+in reverse order.
+
+@var{start} and @var{end} default to 0 and
+@code{(flexvector-length from)} if not present.  Both @var{start} and
+@var{end} are clamped to the range [0, @code{(flexvector-length from)}].
+It is an error if @var{end} is less than @var{start}.
+
+Unlike @code{vector-copy!}, @code{flexvector-copy!} may copy
+elements past the end of @var{to}, which will increase the length of
+@var{to}.
+
+@code{flexvector-copy!} shares the performance characteristics
+of @code{vector-copy!}.
+
+Both procedures return @var{to} after mutating it.
+
+@end deffn
+
+@subsubsection Iteration
+
+@deffn {Scheme Procedure} flexvector-fold kons knil fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-fold-right kons knil fv1 fv2 ...
+
+The fundamental flexvector iterator.  @var{kons} is iterated over each
+value in all of the vectors, stopping at the end of the shortest;
+@var{kons} is applied as @code{(kons state (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)} where @var{state} is the current state
+value—the current state value begins with @var{knil}, and becomes
+whatever @var{kons} returned on the previous iteration—and @var{i} is
+the current index.
+
+The iteration of @code{flexvector-fold} is strictly
+left-to-right.  The iteration of @code{flexvector-fold-right} is strictly
+right-to-left.
+
+@example
+(flexvector-fold (lambda (len str) (max (string-length str) len))
+                 0
+                 (flexvector "baz" "qux" "quux"))
+@result{} 4
+
+(flexvector-fold-right (lambda (tail elt) (cons elt tail))
+                       '()
+                       (flexvector 1 2 3))
+@result{} (1 2 3)
+
+(flexvector-fold (lambda (counter n)
+                   (if (even? n) (+ counter 1) counter))
+                 0
+                 (flexvector 1 2 3 4 5 6 7))
+@result{} 3
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index f fv1 fv2 ...
+
+Constructs a new flexvector of the shortest size of the flexvector
+arguments.  Each element at index @var{i} of the new flexvector is mapped
+from the old flexvectors by @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}.  The dynamic order of application of
+@var{f} is unspecified.
+
+
+
+
+@code{flexvector-map/index} is a variant that passes @var{i} as
+the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-map (lambda (x) (* x 10)) (flexvector 10 20 30))
+@result{} #<flexvector 100 200 300>
+
+(flexvector-map/index (lambda (i x) (+ x (* i 2))) (flexvector 10 20 30))
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-map! f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-map/index! f fv1 fv2 ...
+
+
+Similar to @code{flexvector-map}, but rather than mapping the new
+elements into a new flexvector, the new mapped elements are
+destructively inserted into @var{fv1}.  Again, the dynamic order of
+application of @var{f} is unspecified, so it is dangerous for @var{f} to
+apply either @code{flexvector-ref} or @code{flexvector-set!} to @var{fv1}
+in @var{f}.
+
+
+@example
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map! (lambda (x) (* x 10)) fv)
+  fv)
+@result{} #<flexvector 100 200 300>
+
+(let ((fv (flexvector 10 20 30)))
+  (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv)
+  fv)
+@result{} #<flexvector 10 22 34>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-append-map f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-append-map/index f fv1 fv2 ...
+
+Constructs a new flexvector by appending the results of each call to
+@var{f} on the elements of the flexvectors @var{fv1}, @var{fv2}, etc.,
+in order.  Each call is of the form @code{(f (flexvector-ref fv1 i)
+(flexvector-ref fv2 i) ...)}.  Iteration stops when the end of the
+shortest flexvector argument is reached.  The dynamic order of
+application of @var{f} is unspecified.
+
+
+
+
+@var{f} must return a flexvector.  It is an error if @var{f}
+returns anything else.
+
+
+
+
+@code{flexvector-append-map/index} is a variant that passes the
+index @var{i} as the first argument to @var{f} for each element.
+
+
+@example
+(flexvector-append-map (lambda (x) (flexvector (* x 10) (* x 100)))
+                       (flexvector 10 20 30))
+@result{} #<flexvector 100 1000 200 2000 300 3000>
+
+(flexvector-append-map/index (lambda (i x) (flexvector x i)) (flexvector 10 20 30))
+@result{} #<flexvector 10 0 20 1 30 2>
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index pred? fv
+
+Constructs a new flexvector consisting of only the elements of @var{fv}
+for which @var{pred?} returns a non-@var{#f} value.
+@code{flexvector-filter/index} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+@example
+(flexvector-filter even? (flexvector 1 2 3 4 5 6 7 8))
+@result{} #<flexvector 2 4 6 8>
+
+@end example
+
+@end deffn
+@deffn {Scheme Procedure} flexvector-filter! pred? fv
+@deffnx {Scheme Procedure} flexvector-filter/index! pred? fv
+
+Similar to @code{flexvector-filter}, but destructively updates @var{fv}
+by removing all elements for which @var{pred?} returns @var{#f}.
+@code{flexvector-filter/index!} passes the index of each element as the
+first argument to @var{pred?}, and the element itself as the second
+argument.
+
+
+@example
+(let ((fv (flexvector 1 2 3 4 5 6 7 8)))
+  (flexvector-filter! odd? fv)
+  fv)
+@result{} #<flexvector 1 3 5 7>
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-for-each f fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-for-each/index f fv1 fv2 ...
+
+Simple flexvector iterator: applies @var{f} to the corresponding list of
+parallel elements from @var{fv1 fv2 ...} in the range [0, @code{length}),
+where @code{length} is the length of the smallest flexvector argument
+passed.  In contrast with @code{flexvector-map}, @var{f} is reliably
+applied in left-to-right order, starting at index 0, in the flexvectors.
+
+@code{flexvector-for-each/index} is a variant that passes the
+index as the first argument to @var{f} for each element.
+
+Example:
+
+@example
+(flexvector-for-each (lambda (x) (display x) (newline))
+                     (flexvector "foo" "bar" "baz" "quux" "zot"))
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-count pred? fv1 fv2 ...
+
+Counts the number of parallel elements in the flexvectors that satisfy
+@var{pred?}, which is applied, for each index @var{i} in the range [0,
+@emph{length}) where @emph{length} is the length of the smallest
+flexvector argument, to each parallel element in the flexvectors, in
+order.
+
+
+@example
+(flexvector-count even? (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} 3
+
+(flexvector-count < (flexvector 1 3 6 9) (flexvector 2 4 6 8 10 12))
+@result{} 2
+
+@end example
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-cumulate f knil fv
+
+Returns a newly-allocated flexvector @var{new} with the same length as
+@var{fv}.  Each element @var{i} of @var{new} is set to the result of
+@code{(f (flexvector-ref new (- i 1)) (flexvector-ref fv i))}, except
+that, for the first call on @var{f}, the first argument is @var{knil}.
+The @var{new} flexvector is returned.
+
+
+@example
+(flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6))
+@result{} #<flexvector 3 4 8 9 14 23 25 30 36>
+
+@end example
+@end deffn
+
+@subsubsection Searching
+
+@deffn {Scheme Procedure} flexvector-index pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-index/right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that satisfy @var{pred?}.  If no matching element is found by the end of
+the shortest flexvector, @code{#f} is returned.
+
+@var{flexvector-index-right} is similar, but returns the index
+of the @emph{last} elements that satisfy @var{pred?}, and requires all
+flexvector arguments to have the same length.
+
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+@example
+(flexvector-index even? (flexvector 3 1 4 1 5 9))
+@result{} 2
+
+(flexvector-index < (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} 1
+
+(flexvector-index = (flexvector 3 1 4 1 5 9 2 5 6) (flexvector 2 7 1 8 2))
+@result{} #f
+
+(flexvector-index-right < (flexvector 3 1 4 1 5) (flexvector 2 7 1 8 2))
+@result{} 3
+
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-skip pred? fv1 fv2 ...
+@deffnx {Scheme Procedure} flexvector-skip-right pred? fv1 fv2 ...
+
+Finds and returns the index of the first elements in @var{fv1 fv2 ...}
+that do @emph{not} satisfy @var{pred?}.  If all the values in the
+flexvectors satisfy @var{pred?} until the end of the shortest
+flexvector, this returns @var{#f}.
+
+@code{flexvector-skip-right} is similar, but returns the index of
+the @emph{last} elements that do not satisfy @var{pred?}, and requires
+all flexvector arguments to have the same length.
+
+Given @emph{n} arguments @var{fv1 fv2...}, @var{pred?} should be
+a function that takes @emph{n} arguments and returns a single value,
+interpreted as a boolean.
+
+
+@example
+(flexvector-skip number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 2
+
+(flexvector-skip-right number? (flexvector 1 2 'a 'b 3 4 'c 'd))
+@result{} 4
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-binary-search fv value cmp [start [end]]
+
+Similar to @code{flexvector-index} and @code{flexvector-index-right},
+but, instead of searching left-to-right or right-to-left, this performs
+a binary search.  If there is more than one element of @var{fv} that
+matches @var{value} in the sense of @var{cmp},
+@code{flexvector-binary-search} may return the index of any of them.
+
+The search is performed on only the indexes of @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.  Both @var{start} and @var{end} are clamped to the
+range [0, @code{(flexvector-length fv)}].  It is an error if @var{end} is
+less than @var{start}.
+
+@var{cmp} should be a procedure of two arguments that returns
+either a negative integer, which indicates that its first argument is
+less than its second; zero, which indicates that they are equal; or a
+positive integer, which indicates that the first argument is greater
+than the second argument.  An example @var{cmp} might be:
+
+
+@example
+(lambda (char1 char2)
+  (cond ((char<? char1 char2) -1)
+        ((char=? char1 char2) 0)
+        (else 1)))
+@end example
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector-any pred? fv1 fv2 ...
+
+Finds the first set of elements in parallel from @var{fv1 fv2
+...} for which @var{pred?} returns a true value.  If such a parallel set
+of elements exists, @code{flexvector-any} returns the value that
+@var{pred?} returned for that set of elements.  The iteration is strictly
+left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-every pred? fv1 fv2 ...
+
+If, for every index @var{i} between 0 and the length of the
+shortest flexvector argument, the set of elements @code{(flexvector-ref
+fv1 i) (flexvector-ref fv2 i) ...} satisfies @var{pred?},
+@code{flexvector-every} returns the value that @var{pred?} returned for
+the last set of elements, at the last index of the shortest flexvector.
+The iteration is strictly left-to-right.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector-partition pred? fv
+
+Returns two values: a flexvector containing all elements of
+@var{fv} that satisfy @var{pred?}, and a flexvector containing all
+elements of @var{fv} that do not satisfy @var{pred?}.  Elements remain in
+their original order.
+
+@end deffn
+
+@subsubsection Conversion
+
+@deffn {Scheme Procedure} flexvector->vector fv [start [end]]
+
+Creates a vector containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}).  It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} vector->flexvector vec [start [end]]
+
+Creates a flexvector containing the elements in @var{vec}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{vec}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(vector-length vec)}).  It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+
+@deffn {Scheme Procedure} flexvector->list fv [start [end]]
+@deffnx {Scheme Procedure} reverse-flexvector->list fv [start [end]]
+
+Creates a list containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.
+
+@code{reverse-flexvector->list} is similar, but creates a list
+with elements in reverse order of @var{fv}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}).  It is an error if @var{end} is less than
+@var{start}.
+
+
+@end deffn
+
+@deffn {Scheme Procedure} list->flexvector proper-list
+
+Creates a flexvector of elements from @var{proper-list}.
+
+@code{reverse-list->flexvector} is similar, but creates a
+flexvector with elements in reverse order of @var{proper-list}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->string fv [start [end]]
+
+Creates a string containing the elements in @var{fv} between
+@var{start}, which defaults to 0, and @var{end}, which defaults to the
+length of @var{fv}.  It is an error if the elements are not characters.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(flexvector-length fv)}).  It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} string->flexvector string [start [end]]
+
+Creates a flexvector containing the elements in @var{string}
+between @var{start}, which defaults to 0, and @var{end}, which defaults
+to the length of @var{string}.
+
+Both @var{start} and @var{end} are clamped to the range [0,
+@code{(string-length string)}).  It is an error if @var{end} is less than
+@var{start}.
+
+@end deffn
+
+@deffn {Scheme Procedure} flexvector->generator fv
+
+Returns a SRFI 158 generator that emits the elements of the
+flexvector @var{fv}, in order.  If @var{fv} is mutated before the
+generator is exhausted, the generator's remaining return values are
+undefined.
+
+@end deffn
+
+
 @node Record Overview
 @subsection Record Overview
 
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index bce5b4eac..c2671b747 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -65,6 +65,7 @@ get the relevant SRFI documents from the SRFI home page
 * SRFI-105::                    Curly-infix expressions.
 * SRFI-111::                    Boxes.
 * SRFI-171::                    Transducers
+* SRFI-214::                    Flexvectors
 @end menu
 
 
@@ -6148,6 +6149,11 @@ The generator version of list-reduce.  It reduces over @code{gen} until
 it returns the EOF object
 @end deffn
 
+@node SRFI-214
+@subsection SRFI-214 - Flexvectors
+
+Documentation for SRFI-214, Flexvectors is provided in @xref{Flexvectors}.
+
 @c srfi-modules.texi ends here
 
 @c Local Variables:
diff --git a/module/srfi/srfi-214.scm b/module/srfi/srfi-214.scm
new file mode 100644
index 000000000..60432f5bb
--- /dev/null
+++ b/module/srfi/srfi-214.scm
@@ -0,0 +1,740 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;; Copyright (C) 2020 Adam Nelson.
+;;; Copyright (C) 2022 Vijay Marupudi.
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy of
+;;; this software and associated documentation files (the "Software"), to deal in
+;;; the Software without restriction, including without limitation the rights to
+;;; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+;;; the Software, and to permit persons to whom the Software is furnished to do so,
+;;; subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice (including the next
+;;; paragraph) shall be included in all copies or substantial portions of the
+;;; Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+;;; FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+;;; COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+;;; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+;; Authorship: This code was largely written by Adam Nelson as a
+;; sample implementation for srfi-214 and adapted for Guile by Vijay
+;; Marupudi.
+
+(define-module (srfi srfi-214)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-9 gnu)
+  #:use-module (srfi srfi-11)
+  #:use-module (ice-9 binary-ports))
+
+
+(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)
+
+(define string->vector
+  (case-lambda
+    ((str) (list->vector (string->list str)))
+    ((str start) (string->vector (substring str start)))
+    ((str start end) (string->vector (substring str start end)))))
+
+(define vector->string
+  (case-lambda*
+    ((v) (list->string (vector->list v)))
+    ((v start #:optional (end (vector-length v)))
+     (vector->string (vector-copy v start end)))))
+
+(define-syntax assume
+  (syntax-rules ()
+    ((assume expression message ...)
+     (or expression
+         (error "invalid assumption" (quote expression) (list message ...))))
+    ((assume . _)
+     (syntax-error "invalid assume syntax"))))
+
+(define-record-type <flexvector>
+  (%make-flexvector fv-vector fv-length)
+  flexvector?
+  (fv-vector vec set-vec!)
+  (fv-length flexvector-length set-flexvector-length!))
+
+(set-record-type-printer! <flexvector>
+                          (lambda (obj port)
+                            (display "#<flexvector" port)
+                            (if (= (flexvector-length obj) 0)
+                                (display ">" port)
+                                (begin
+                                  (format port " ~s" (flexvector-ref obj 0))
+                                  (let loop ((i 1)
+                                             (len (flexvector-length obj)))
+                                    (if (= len i)
+                                        (display ">" port)
+                                        (begin
+                                          (write (flexvector-ref obj i) port)
+                                          (loop (+ i 1)
+                                                len))))))))
+
+(define (cap fv)
+  (vector-length (vec fv)))
+
+(define (grow! fv)
+  (define old-vec (vec fv))
+  (define new-vec (make-vector (quotient (* (vector-length old-vec) 3) 2)))
+  (vector-copy! new-vec 0 old-vec)
+  (set-vec! fv new-vec)
+  new-vec)
+
+(define make-flexvector
+  (case-lambda
+    ((size)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4)) size))
+    ((size fill)
+      (assume (>= size 0))
+      (%make-flexvector (make-vector (max size 4) fill) size))))
+
+(define (flexvector . xs)
+  (if (null? xs)
+    (%make-flexvector (make-vector 4) 0)
+    (list->flexvector xs)))
+
+(define (flexvector-ref fv index)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (vector-ref (vec fv) index))
+
+(define (flexvector-set! fv index x)
+  (assume (flexvector? fv))
+  (assume (integer? index))
+  (assume (< -1 index (flexvector-length fv)))
+  (let ((last-value (vector-ref (vec fv) index)))
+    (vector-set! (vec fv) index x)
+    last-value))
+
+(define flexvector-add!
+  (case-lambda
+    ((fv i x)
+      (assume (flexvector? fv))
+      (assume (integer? i))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (assume (<= 0 i len))
+        (vector-copy! v (+ i 1) v i len)
+        (vector-set! v i x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv i . xs)
+      (flexvector-add-all! fv i xs))))
+
+(define flexvector-add-back!
+  (case-lambda
+    ((fv x)
+      (assume (flexvector? fv))
+      (let* ((len (flexvector-length fv))
+             (v (if (< len (cap fv)) (vec fv) (grow! fv))))
+        (vector-set! v len x)
+        (set-flexvector-length! fv (+ len 1))
+        fv))
+    ((fv x . xs)
+      (flexvector-add-back! fv x)
+      (apply flexvector-add-back! fv xs))))
+
+(define (flexvector-add-all! fv i xs)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (list? xs))
+  (let* ((len (flexvector-length fv))
+         (xv (list->vector xs))
+         (xvlen (vector-length xv))
+         (v (let lp ((v (vec fv)))
+              (if (< (+ len xvlen) (vector-length v)) v (lp (grow! fv))))))
+    (assume (<= 0 i len))
+    (vector-copy! v (+ i xvlen) v i len)
+    (vector-copy! v i xv 0 xvlen)
+    (set-flexvector-length! fv (+ len xvlen))
+    fv))
+
+(define (flexvector-remove! fv i)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (<= 0 i (- (flexvector-length fv) 1)))
+  (let ((removed (flexvector-ref fv i)))
+    (flexvector-remove-range! fv i (+ i 1))
+    removed))
+
+(define (flexvector-remove-range! fv start end)
+  (assume (flexvector? fv))
+  (let ((len (flexvector-length fv)))
+    (when (< start 0) (set! start 0))
+    (when (>= end len) (set! end len))
+    (assume (<= start end))
+    (vector-copy! (vec fv) start (vec fv) end)
+    (let ((new-len (- len (- end start))))
+      (vector-fill! (vec fv) #f new-len len)
+      (set-flexvector-length! fv new-len)))
+  fv)
+
+(define (flexvector-clear! fv)
+  (assume (flexvector? fv))
+  (set-vec! fv (make-vector 4))
+  (set-flexvector-length! fv 0)
+  fv)
+
+(define vector->flexvector
+  (case-lambda
+    ((vec)
+      (assume (vector? vec))
+      (vector->flexvector vec 0 (vector-length vec)))
+    ((vec start)
+      (assume (vector? vec))
+      (vector->flexvector vec start (vector-length vec)))
+    ((vec start end)
+      (assume (vector? vec))
+      (assume (<= 0 start end (vector-length vec)))
+      (let ((len (- end start)))
+        (cond
+          ((< len 4)
+            (let ((new-vec (make-vector 4)))
+              (vector-copy! new-vec 0 vec start end)
+              (%make-flexvector new-vec len)))
+          (else
+            (%make-flexvector (vector-copy vec start end) len)))))))
+
+(define flexvector->vector
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (flexvector->vector fv 0 (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector->vector fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector-copy (vec fv) start end))))
+
+(define (list->flexvector xs)
+  (let* ((vec (list->vector xs))
+         (len (vector-length vec)))
+    (cond
+      ((< len 4)
+        (let ((new-vec (make-vector 4)))
+          (vector-copy! new-vec 0 vec)
+          (%make-flexvector new-vec len)))
+      (else
+        (%make-flexvector vec len)))))
+
+(define flexvector-filter/index!
+  (case-lambda
+    ((pred? fv)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((pred? i (vector-ref v i))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))
+    ((pred? fv . fvs)
+      (assume (flexvector? fv))
+      (let ((v (vec fv)) (len (flexvector-length fv)))
+        (let lp ((i 0) (j 0))
+          (cond
+            ((>= i len)
+              (set-flexvector-length! fv j)
+              fv)
+            ((apply pred?
+                    i
+                    (vector-ref v i)
+                    (map (lambda (fv) (flexvector-ref fv i)) fvs))
+              (unless (= i j) (vector-set! v j (vector-ref v i)))
+              (lp (+ i 1) (+ j 1)))
+            (else
+              (lp (+ i 1) j))))))))
+
+(define flexvector-copy
+  (case-lambda
+    ((fv)
+      (assume (flexvector? fv))
+      (%make-flexvector (vector-copy (vec fv))
+                        (flexvector-length fv)))
+    ((fv start)
+      (assume (flexvector? fv))
+      (flexvector-copy fv start (flexvector-length fv)))
+    ((fv start end)
+      (assume (flexvector? fv))
+      (assume (<= 0 start end (flexvector-length fv)))
+      (vector->flexvector (vector-copy (vec fv) start end)))))
+
+(define flexvector-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (assume (flexvector? to))
+      (assume (<= 0 at (flexvector-length to)))
+      (assume (<= 0 start end (flexvector-length from)))
+      (let* ((vf (vec from))
+             (lt (+ (flexvector-length to) (- end start)))
+             (vt (let lp ((v (vec to)))
+                   (if (< lt (vector-length v)) v (lp (grow! to))))))
+        (vector-copy! vt at vf start end)
+        (set-flexvector-length! to
+          (max (flexvector-length to) (+ at (- end start))))))))
+
+(define flexvector-unfold
+  (case-lambda
+    ((p f g seed)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seed seed (g seed))) ((p seed) fv)
+        (flexvector-add-back! fv (f seed))))
+    ((p f g . seeds)
+      (define fv (flexvector))
+      (assume (procedure? p))
+      (assume (procedure? f))
+      (assume (procedure? g))
+      (do ((seeds seeds (let-values ((seeds (apply g seeds))) seeds)))
+          ((apply p seeds) fv)
+        (flexvector-add-back! fv (apply f seeds))))))
+
+(define (flexvector-unfold-right . args)
+  (define fv (apply flexvector-unfold args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-fill!
+  (case-lambda
+    ((fv fill)
+      (flexvector-fill! fv fill 0 (flexvector-length fv)))
+    ((fv fill start)
+      (flexvector-fill! fv fill start (flexvector-length fv)))
+    ((fv fill start end)
+      (let ((actual-end (min end (flexvector-length fv))))
+        (do ((i (max 0 start) (+ i 1)))
+            ((>= i actual-end))
+          (flexvector-set! fv i fill))))))
+
+(define (flexvector-reverse-copy . args)
+  (define fv (apply flexvector-copy args))
+  (flexvector-reverse! fv)
+  fv)
+
+(define flexvector-reverse-copy!
+  (case-lambda
+    ((to at from)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from 0 (flexvector-length from)))
+    ((to at from start)
+      (assume (flexvector? from))
+      (flexvector-reverse-copy! to at from start (flexvector-length from)))
+    ((to at from start end)
+      (flexvector-copy! to at from start end)
+      (flexvector-reverse! to at (+ at (- end start))))))
+
+(define (flexvector-append! fv . fvs)
+  (assume (flexvector? fv))
+  (assume (every flexvector? fvs))
+  (for-each
+    (lambda (fv2) (flexvector-copy! fv (flexvector-length fv) fv2))
+    fvs)
+  fv)
+
+(define (flexvector-front fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv 0))
+
+(define (flexvector-back fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-ref fv (- (flexvector-length fv) 1)))
+
+(define flexvector-add-front!
+  (case-lambda
+    ((fv x) (flexvector-add! fv 0 x))
+    ((fv . xs) (apply flexvector-add! fv 0 xs))))
+
+(define (flexvector-remove-front! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv 0))
+
+(define (flexvector-remove-back! fv)
+  (assume (flexvector? fv))
+  (assume (not (flexvector-empty? fv)))
+  (flexvector-remove! fv (- (flexvector-length fv) 1)))
+
+(define (flexvector=? eq . o)
+  (cond
+    ((null? o) #t)
+    ((null? (cdr o)) #t)
+    (else
+      (and (let* ((fv1 (car o))
+                  (fv2 (cadr o))
+                  (len (flexvector-length fv1)))
+             (and (= len (flexvector-length fv2))
+                  (let lp ((i 0))
+                    (or (>= i len)
+                        (and (eq (flexvector-ref fv1 i) (flexvector-ref fv2 i))
+                             (lp (+ i 1)))))))
+           (apply flexvector=? eq (cdr o))))))
+
+(define (flexvector-fold kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i 0) (acc knil))
+          (if (>= i len) acc (lp (+ i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i 0) (acc knil))
+          (if (>= i len)
+              acc
+              (lp (+ i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define (flexvector-fold-right kons knil fv1 . o)
+  (assume (procedure? kons))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (if (null? o)
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i) acc (lp (- i 1) (kons acc (flexvector-ref fv1 i)))))
+        (let lp ((i (- len 1)) (acc knil))
+          (if (negative? i)
+              acc
+              (lp (- i 1)
+                  (apply kons acc (flexvector-ref fv1 i)
+                         (map (lambda (fv) (flexvector-ref fv i)) o))))))))
+
+(define flexvector-for-each/index
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (let ((len (flexvector-length fv)))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (proc i (flexvector-ref fv i)))))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (let ((len (apply min (map flexvector-length fvs))))
+        (do ((i 0 (+ i 1))) ((= i len))
+          (apply proc i (map (lambda (fv) (flexvector-ref fv i)) fvs)))))))
+
+(define flexvector-for-each
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-for-each/index (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-for-each/index (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define flexvector-map/index!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (flexvector-for-each/index
+        (lambda (i x) (flexvector-set! fv i (proc i x)))
+        fv)
+      fv)
+    ((proc fv . fvs)
+      (assume (procedure? proc))
+      (assume (flexvector? fv))
+      (apply flexvector-for-each/index
+        (lambda (i . xs) (flexvector-set! fv i (apply proc i xs)))
+        fv
+        fvs)
+      fv)))
+
+(define flexvector-map!
+  (case-lambda
+    ((proc fv)
+      (assume (procedure? proc))
+      (flexvector-map/index! (lambda (i x) (proc x)) fv))
+    ((proc . fvs)
+      (assume (procedure? proc))
+      (apply flexvector-map/index! (lambda (i . xs) (apply proc xs)) fvs))))
+
+(define (flexvector-map/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-map proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-map! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-append-map/index proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map/index proc fv fvs))
+  out)
+
+(define (flexvector-append-map proc fv . fvs)
+  (define out (flexvector))
+  (flexvector-for-each
+    (lambda (x) (flexvector-append! out x))
+    (apply flexvector-map proc fv fvs))
+  out)
+
+(define flexvector-filter!
+  (case-lambda
+    ((pred? fv)
+      (assume (procedure? pred?))
+      (assume (flexvector? fv))
+      (flexvector-filter/index! (lambda (i x) (pred? x)) fv))
+    ((pred? . fvs)
+      (assume (procedure? pred?))
+      (apply flexvector-filter/index! (lambda (i . xs) (apply pred? xs)) fvs))))
+
+(define (flexvector-filter/index proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter/index! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-filter proc fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-filter! proc (flexvector-copy fv) fvs))
+
+(define (flexvector-index pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i 0))
+      (and (< i len)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (+ i 1)))))))
+
+(define (flexvector-index-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (let ((len (flexvector-length fv1)))
+    (let lp ((i (- len 1)))
+      (and (>= i 0)
+           (if (apply pred?
+                      (flexvector-ref fv1 i)
+                      (map (lambda (fv) (flexvector-ref fv i)) o))
+               i
+               (lp (- i 1)))))))
+
+(define (complement f)
+  (lambda args (not (apply f args))))
+
+(define (flexvector-skip pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index (complement pred?) fv1 o))
+
+(define (flexvector-skip-right pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-index-right (complement pred?) fv1 o))
+
+(define flexvector-binary-search
+  (case-lambda
+    ((fv value cmp)
+      (flexvector-binary-search fv value cmp 0 (flexvector-length fv)))
+    ((fv value cmp start)
+      (flexvector-binary-search fv value cmp start (flexvector-length fv)))
+    ((fv value cmp start end)
+      (assume (flexvector? fv))
+      (assume (procedure? cmp))
+      (assume (integer? start))
+      (assume (integer? end))
+      (assume (<= start end))
+      (let lp ((lo (max start 0))
+               (hi (- (min end (flexvector-length fv)) 1)))
+        (and (<= lo hi)
+             (let* ((mid (quotient (+ lo hi) 2))
+                    (x (flexvector-ref fv mid))
+                    (y (cmp value x)))
+               (cond
+                 ((< y 0) (lp lo (- mid 1)))
+                 ((> y 0) (lp (+ mid 1) hi))
+                 (else mid))))))))
+
+(define (flexvector-any pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (map flexvector-length o))))
+    (let lp ((i 0))
+      (and (< i len)
+           (or (apply pred?
+                      (flexvector-ref fv i)
+                      (map (lambda (v) (flexvector-ref v i)) o))
+               (lp (+ i 1)))))))
+
+(define (flexvector-every pred? fv . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((len (apply min (flexvector-length fv) (map flexvector-length o))))
+    (or (zero? len)
+      (let lp ((i 0))
+        (let ((x (apply pred?
+                        (flexvector-ref fv i)
+                        (map (lambda (v) (flexvector-ref v i)) o))))
+          (if (= i (- len 1))
+              x
+              (and x (lp (+ i 1)))))))))
+
+(define (flexvector-swap! fv i j)
+  (assume (flexvector? fv))
+  (assume (integer? i))
+  (assume (integer? j))
+  (let ((tmp (flexvector-ref fv i)))
+    (flexvector-set! fv i (flexvector-ref fv j))
+    (flexvector-set! fv j tmp)))
+
+(define (flexvector-reverse! fv . o)
+  (assume (flexvector? fv))
+  (let lp ((left (if (pair? o) (car o) 0))
+           (right (- (if (and (pair? o) (pair? (cdr o)))
+                         (cadr o)
+                         (flexvector-length fv))
+                     1)))
+    (cond
+      ((>= left right) (if #f #f))
+      (else
+        (flexvector-swap! fv left right)
+        (lp (+ left 1) (- right 1))))))
+
+(define (flexvector-append fv . fvs)
+  (assume (flexvector? fv))
+  (apply flexvector-append! (flexvector-copy fv) fvs))
+
+(define (flexvector-concatenate ls)
+  (apply flexvector-append ls))
+
+(define (flexvector-append-subvectors . o)
+  (let lp ((ls o) (vecs '()))
+    (if (null? ls)
+        (flexvector-concatenate (reverse vecs))
+        (lp (cdr (cddr ls))
+            (cons (flexvector-copy (car ls) (cadr ls) (car (cddr ls))) vecs)))))
+
+(define (flexvector-empty? fv)
+  (assume (flexvector? fv))
+  (zero? (flexvector-length fv)))
+
+(define (flexvector-count pred? fv1 . o)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv1))
+  (apply flexvector-fold
+         (lambda (count . x) (+ count (if (apply pred? x) 1 0)))
+         0
+         fv1 o))
+
+(define (flexvector-cumulate f knil fv)
+  (assume (procedure? f))
+  (assume (flexvector? fv))
+  (let* ((len (flexvector-length fv))
+         (res (make-vector len)))
+    (let lp ((i 0) (acc knil))
+      (if (>= i len)
+          (vector->flexvector res)
+          (let ((acc (f acc (flexvector-ref fv i))))
+            (vector-set! res i acc)
+            (lp (+ i 1) acc))))))
+
+(define (flexvector-partition pred? fv)
+  (assume (procedure? pred?))
+  (assume (flexvector? fv))
+  (let ((left (flexvector)) (right (flexvector)))
+    (flexvector-for-each
+      (lambda (x) (flexvector-add-back! (if (pred? x) left right) x))
+      fv)
+    (values left right)))
+
+(define (flexvector->list fv)
+  (assume (flexvector? fv))
+  (flexvector-fold-right (lambda (x y) (cons y x)) '() fv))
+
+(define (reverse-flexvector->list fv . o)
+  (assume (flexvector? fv))
+  (flexvector->list (apply flexvector-reverse-copy fv o)))
+
+(define (reverse-list->flexvector ls)
+  (assume (list? ls))
+  (let ((fv (list->flexvector ls)))
+    (flexvector-reverse! fv)
+    fv))
+
+(define (string->flexvector s . o)
+  (assume (string? s))
+  (vector->flexvector (apply string->vector s o)))
+
+(define (flexvector->string fv . o)
+  (assume (flexvector? fv))
+  (vector->string (apply flexvector->vector fv o)))
+
+(define (generator->flexvector g)
+  (assume (procedure? g))
+  (flexvector-unfold eof-object? (lambda (x) x) (lambda (_) (g)) (g)))
+
+(define (flexvector->generator fv)
+  (assume (flexvector? fv))
+  (let ((i 0))
+    (lambda ()
+      (if (< i (flexvector-length fv))
+        (let ((element (flexvector-ref fv i)))
+          (set! i (+ i 1))
+          element)
+        (eof-object)))))
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 16fa2e952..a62ffcf6c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,6 +162,7 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
             tests/srfi-171.test                 \
+	    tests/srfi-214.test                 \
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-214.test b/test-suite/tests/srfi-214.test
new file mode 100644
index 000000000..dacec8fa8
--- /dev/null
+++ b/test-suite/tests/srfi-214.test
@@ -0,0 +1,437 @@
+;;; -*- mode: scheme; coding: utf-8; -*-
+;;;
+;;;    Copyright (C) 2020 Adam Nelson.
+;;;    Copyright (C) 2022 Vijay Marupudi.
+;;;
+;;; This code is based on the file tests.scm in the reference
+;;; implementation of SRFI-214, provided under the following license:
+;;;
+;;; Permission is hereby granted, free of charge, to any person obtaining
+;;; a copy of this software and associated documentation files (the
+;;; "Software"), to deal in the Software without restriction, including
+;;; without limitation the rights to use, copy, modify, merge, publish,
+;;; distribute, sublicense, and/or sell copies of the Software, and to
+;;; permit persons to whom the Software is furnished to do so, subject to
+;;; the following conditions:
+;;;
+;;; The above copyright notice and this permission notice shall be
+;;; included in all copies or substantial portions of the Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+;;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+;;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+;;; SOFTWARE.
+
+(define-module (test-suite test-srfi-214)
+  #:use-module (srfi srfi-214)
+  #:use-module (test-suite lib)
+  #:use-module (rnrs io ports))
+
+(with-test-prefix "SRFI-214"
+
+  (pass-if "flexvector?"
+    (equal? #t (flexvector? (flexvector))))
+  (pass-if "flexvector-length"
+    (equal? 3 (flexvector-length (make-flexvector 3 #f))))
+  (pass-if "flexvector"
+    (equal? 3 (flexvector-length (flexvector 1 2 3))))
+
+  (let ((fv (flexvector 'a 'b 'c)))
+    (pass-if "flexvector-ref"
+      (equal? 'b (flexvector-ref fv 1)))
+    (pass-if "flexvector-front"
+      (equal? 'a (flexvector-front fv)))
+    (pass-if "flexvector-back"
+      (equal? 'c (flexvector-back fv)))
+    (pass-if "flexvector-set! return"
+      (equal? 'b (flexvector-set! fv 1 'd)))
+    (pass-if "flexvector-set! mutate"
+      (equal? 'd (flexvector-ref fv 1)))
+    (pass-if "flexvector-add-back! return"
+      (equal? fv (flexvector-add-back! fv 'e)))
+    (pass-if "flexvector-add-back! mutate"
+      (equal? '(4 . e)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv (- (flexvector-length fv) 1)))))
+    (pass-if "flexvector-remove! return"
+      (equal? 'd (flexvector-remove! fv 1)))
+    (pass-if "flexvector-remove! mutate"
+      (equal? '(3 . c)
+              (cons (flexvector-length fv)
+                    (flexvector-ref fv 1))))
+    (pass-if "flexvector-clear! return"
+      (equal? fv (flexvector-clear! fv)))
+    (pass-if "flexvector-clear! mutate"
+      (equal? 0 (flexvector-length fv)))
+    (pass-if "flexvector-empty?"
+      (equal? #t (flexvector-empty? fv))))
+
+  (pass-if "flexvector=? same symbols"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'a 'b))))
+  (pass-if "flexvector=? different symbols"
+    (equal? #f
+            (flexvector=? eq? (flexvector 'a 'b) (flexvector 'b 'a))))
+  (pass-if "flexvector=? different lengths"
+    (equal? #f
+            (flexvector=? = (flexvector 1 2 3 4 5) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? same numbers"
+    (equal? #t
+            (flexvector=? = (flexvector 1 2 3 4) (flexvector 1 2 3 4))))
+  (pass-if "flexvector=? 0 arguments"
+    (equal? #t
+            (flexvector=? eq?)))
+  (pass-if "flexvector=? 1 argument"
+    (equal? #t
+            (flexvector=? eq? (flexvector 'a))))
+
+  (pass-if "make-flexvector"
+    (equal? #(a a a) (flexvector->vector (make-flexvector 3 'a))))
+
+  (pass-if "flexvector-unfold"
+    (equal?
+     #(1 4 9 16 25 36 49 64 81 100)
+     (flexvector->vector
+      (flexvector-unfold (lambda (x) (> x 10))
+                         (lambda (x) (* x x))
+                         (lambda (x) (+ x 1))
+                         1))))
+  (pass-if "flexvector-unfold-right"
+    (equal?
+     #(100 81 64 49 36 25 16 9 4 1)
+     (flexvector->vector
+      (flexvector-unfold-right (lambda (x) (> x 10))
+                               (lambda (x) (* x x))
+                               (lambda (x) (+ x 1))
+                               1))))
+
+
+  (pass-if "string->flexvector"
+    (equal? #(#\a #\b #\c)
+            (flexvector->vector (string->flexvector "abc"))))
+  (pass-if "flexvector->string"
+    (equal? "abc" (flexvector->string (flexvector #\a #\b #\c))))
+
+  (define genlist '(a b c))
+  (define (mock-generator)
+    (if (pair? genlist)
+        (let ((value (car genlist)))
+          (set! genlist (cdr genlist))
+          value)
+        (eof-object)))
+
+  (pass-if "generator->flexvector"
+    (equal? #(a b c)
+            (flexvector->vector (generator->flexvector mock-generator))))
+  (pass-if "flexvector->generator"
+    (equal? '(a b c #t)
+            (let* ((gen (flexvector->generator (flexvector 'a 'b 'c)))
+                   (one (gen))
+                   (two (gen))
+                   (three (gen))
+                   (four (eof-object? (gen))))
+              (list one two three four))))
+
+                                        ; Nondestructive operations on one vector
+  (let ((fv (flexvector 10 20 30)))
+    (pass-if "flexvector->vector"
+      (equal? #(10 20 30) (flexvector->vector fv)))
+    (pass-if "flexvector->list"
+      (equal? '(10 20 30) (flexvector->list fv)))
+    (pass-if "reverse-flexvector->list"
+      (equal? '(30 20 10) (reverse-flexvector->list fv)))
+    (pass-if "flexvector-copy"
+      (equal? #t
+              (let ((copy (flexvector-copy fv)))
+                (and (= (flexvector-length fv) (flexvector-length copy))
+                     (not (eq? fv copy))))))
+    (pass-if "flexvector-reverse-copy"
+      (equal? #(30 20 10)
+              (flexvector->vector (flexvector-reverse-copy fv))))
+    (pass-if "flexvector-copy start"
+      (equal? #(20 30)
+              (flexvector->vector (flexvector-copy fv 1))))
+    (pass-if "flexvector-copy start end"
+      (equal? #(20)
+              (flexvector->vector (flexvector-copy fv 1 2))))
+    (pass-if "flexvector-for-each"
+      (equal? '(30 20 10)
+              (let ((res '()))
+                (flexvector-for-each (lambda (x) (set! res (cons x res))) fv)
+                res)))
+    (pass-if "flexvector-for-each/index"
+      (equal? '(34 22 10)
+              (let ((res '()))
+                (flexvector-for-each/index
+                 (lambda (i x) (set! res (cons (+ x (* i 2)) res)))
+                 fv)
+                res)))
+    (pass-if "flexvector-map"
+      (equal? #(100 200 300)
+              (flexvector->vector (flexvector-map (lambda (x) (* x 10)) fv))))
+    (pass-if "flexvector-map/index"
+      (equal? #(10 22 34)
+              (flexvector->vector (flexvector-map/index (lambda (i x) (+ x (* i 2))) fv))))
+    (pass-if "flexvector-append-map"
+      (equal? #(10 100 20 200 30 300)
+              (flexvector->vector
+               (flexvector-append-map (lambda (x) (flexvector x (* x 10))) fv))))
+    (pass-if "flexvector-append-map/index"
+      (equal? #(0 10 10 1 20 22 2 30 34)
+              (flexvector->vector
+               (flexvector-append-map/index
+                (lambda (i x) (flexvector i x (+ x (* i 2))))
+                fv))))
+    (pass-if "flexvector-filter"
+      (equal? #(10)
+              (flexvector->vector (flexvector-filter (lambda (x) (< x 15)) fv))))
+    (pass-if "flexvector-filter/index"
+      (equal? #(10 30)
+              (flexvector->vector (flexvector-filter/index (lambda (i x) (not (= i 1))) fv))))
+    (pass-if "flexvector-fold"
+      (equal? '(30 20 10)
+              (flexvector-fold (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-fold-right"
+      (equal? '(10 20 30)
+              (flexvector-fold-right (lambda (x y) (cons y x)) '() fv)))
+    (pass-if "flexvector-count"
+      (equal? 2
+              (flexvector-count (lambda (x) (< x 25)) fv)))
+    (pass-if "flexvector-cumulate"
+      (equal? #(3 4 8 9 14 23 25 30 36)
+              (flexvector->vector
+               (flexvector-cumulate + 0 (flexvector 3 1 4 1 5 9 2 5 6)))))
+    (pass-if "flexvector-any"
+      (equal? '(#t . #f)
+              (cons (flexvector-any (lambda (x) (= x 20)) fv)
+                    (flexvector-any (lambda (x) (= x 21)) fv))))
+    (pass-if "flexvector-every"
+      (equal? '(#t . #f)
+              (cons (flexvector-every (lambda (x) (< x 40)) fv)
+                    (flexvector-every (lambda (x) (< x 30)) fv))))
+    (pass-if "flexvector-index"
+      (equal? 1
+              (flexvector-index (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-index-right"
+      (equal? 2
+              (flexvector-index-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-skip"
+      (equal? 1
+              (flexvector-skip (lambda (x) (< x 20)) fv)))
+    (pass-if "flexvector-skip-right"
+      (equal? 0
+              (flexvector-skip-right (lambda (x) (> x 10)) fv)))
+    (pass-if "flexvector-partition"
+      (equal? '(#(10 20) #(30))
+              (call-with-values
+                  (lambda () (flexvector-partition (lambda (x) (< x 25)) fv))
+                (lambda vs ((@ (scheme base) map) flexvector->vector vs))))))
+
+  (let ((fv (flexvector #\a #\b #\c #\d #\e #\f #\g #\h #\i #\j))
+        (cmp (lambda (char1 char2)
+               (cond ((char<? char1 char2) -1)
+                     ((char=? char1 char2) 0)
+                     (else 1)))))
+    (pass-if "flexvector-binary-search"
+      (equal? 3
+              (flexvector-binary-search fv #\d cmp)))
+    (pass-if "flexvector-binary-search first"
+      (equal? 0
+              (flexvector-binary-search fv #\a cmp)))
+    (pass-if "flexvector-binary-search last"
+      (equal? 9
+              (flexvector-binary-search fv #\j cmp)))
+    (pass-if "flexvector-binary-search not found"
+      (equal? #f
+              (flexvector-binary-search fv #\k cmp)))
+
+    (pass-if "flexvector-binary-search in range"
+      (equal? 5
+              (flexvector-binary-search fv #\f cmp 2 6)))
+    (pass-if "flexvector-binary-search out of range"
+      (equal? #f
+              (flexvector-binary-search fv #\f cmp 1 5))))
+
+                                        ; Nondestructive operations on multiple vectors
+  (pass-if "flexvector-append"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-append (flexvector 10 20)
+                                (flexvector)
+                                (flexvector 30 40)
+                                (flexvector 50 60)))))
+  (pass-if "flexvector-concatenate"
+    (equal? #(10 20 30 40 50 60)
+            (flexvector->vector
+             (flexvector-concatenate
+              (list (flexvector 10 20)
+                    (flexvector)
+                    (flexvector 30 40)
+                    (flexvector 50 60))))))
+  (pass-if "flexvector-append-subvectors"
+    (equal? #(a b h i)
+            (flexvector->vector
+             (flexvector-append-subvectors
+              (flexvector 'a 'b 'c 'd 'e) 0 2
+              (flexvector 'f 'g 'h 'i 'j) 2 4))))
+
+
+                                        ; Destructive operations on one vector
+  (define-syntax mutate-as
+    (syntax-rules ()
+      ((_ name vec expr)
+       (let ((name (vector->flexvector vec)))
+         expr
+         (flexvector->vector name)))))
+
+  (pass-if "flexvector-add! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! start"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add! x 0 'foo))))
+  (pass-if "flexvector-add! start multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add! x 0 'foo 'bar 'baz))))
+  (pass-if "flexvector-add! middle"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo baz) (flexvector-add! x 1 'bar))))
+  (pass-if "flexvector-add! middle multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo quux) (flexvector-add! x 1 'bar 'baz 'qux))))
+  (pass-if "flexvector-add! end"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz))))
+  (pass-if "flexvector-add! end multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add! x 2 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-add-all!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo qux) (flexvector-add-all! x 1 '(bar baz)))))
+
+  (pass-if "flexvector-add-front! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-front! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-front!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(bar baz) (flexvector-add-front! x 'foo))))
+  (pass-if "flexvector-add-front! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(qux quux) (flexvector-add-front! x 'foo 'bar 'baz))))
+
+  (pass-if "flexvector-add-back! empty"
+    (equal? '#(foo)
+            (mutate-as x '#() (flexvector-add-back! x 'foo))))
+  (pass-if "flexvector-add-back! empty multiple"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#() (flexvector-add-back! x 'foo 'bar 'baz))))
+  (pass-if "flexvector-add-back!"
+    (equal? '#(foo bar baz)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz))))
+  (pass-if "flexvector-add-back! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-add-back! x 'baz 'qux 'quux))))
+
+  (pass-if "flexvector-append!"
+    (equal? '#(foo bar baz qux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux)))))
+  (pass-if "flexvector-append! multiple"
+    (equal? '#(foo bar baz qux quux)
+            (mutate-as x '#(foo bar) (flexvector-append! x (flexvector 'baz 'qux) (flexvector 'quux)))))
+
+  (pass-if "flexvector-remove!"
+    (equal? '#(foo baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove! x 1))))
+  (pass-if "flexvector-remove! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove! x 0))))
+
+  (pass-if "flexvector-remove-front!"
+    (equal? '#(bar baz)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-front! x))))
+  (pass-if "flexvector-remove-front! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-front! x))))
+
+  (pass-if "flexvector-remove-back!"
+    (equal? '#(foo bar)
+            (mutate-as x '#(foo bar baz) (flexvector-remove-back! x))))
+  (pass-if "flexvector-remove-back! only"
+    (equal? '#()
+            (mutate-as x '#(foo) (flexvector-remove-back! x))))
+
+  (pass-if "flexvector-remove-range!"
+    (equal? '#(a e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 4))))
+  (pass-if "flexvector-remove-range! empty range"
+    (equal? '#(a b c d e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 1 1))))
+  (pass-if "flexvector-remove-range! overflow left"
+    (equal? '#(e f)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x -1 4))))
+  (pass-if "flexvector-remove-range! overflow right"
+    (equal? '#(a b)
+            (mutate-as x '#(a b c d e f) (flexvector-remove-range! x 2 10))))
+
+  (pass-if "flexvector-map!"
+    (equal? '#(100 200 300)
+            (mutate-as fv '#(10 20 30) (flexvector-map! (lambda (x) (* x 10)) fv))))
+  (pass-if "flexvector-map/index!"
+    (equal? '#(10 22 34)
+            (mutate-as fv '#(10 20 30) (flexvector-map/index! (lambda (i x) (+ x (* i 2))) fv))))
+  (pass-if "flexvector-filter!"
+    (equal? '#(10)
+            (mutate-as fv '#(10 20 30) (flexvector-filter! (lambda (x) (< x 15)) fv))))
+  (pass-if "flexvector-filter/index!"
+    (equal? '#(10 30)
+            (mutate-as fv '#(10 20 30) (flexvector-filter/index! (lambda (i x) (not (= i 1))) fv))))
+
+  (pass-if "flexvector-swap!"
+    (equal? #(10 30 20)
+            (mutate-as fv '#(10 20 30) (flexvector-swap! fv 1 2))))
+  (pass-if "flexvector-reverse!"
+    (equal? #(30 20 10)
+            (mutate-as fv '#(10 20 30) (flexvector-reverse! fv))))
+
+  (pass-if "flexvector-copy!"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-copy! bounded"
+    (equal? #(1 20 30 40 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-copy! overflow"
+    (equal? #(1 2 30 40 50)
+            (mutate-as fv '#(1 2 3) (flexvector-copy! fv 2 (flexvector 30 40 50)))))
+  (pass-if "flexvector-reverse-copy!"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 20 30 40)))))
+  (pass-if "flexvector-reverse-copy! bounded"
+    (equal? #(1 40 30 20 5)
+            (mutate-as fv '#(1 2 3 4 5) (flexvector-reverse-copy! fv 1 (flexvector 10 20 30 40 50) 1 4))))
+  (pass-if "flexvector-reverse-copy! overflow"
+    (equal? #(1 2 50 40 30)
+            (mutate-as fv '#(1 2 3) (flexvector-reverse-copy! fv 2 (flexvector 30 40 50)))))
+
+  (pass-if "flexvector-fill!"
+    (equal? '#(foo foo foo)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'foo))))
+  (pass-if "flexvector-fill! start"
+    (equal? '#(1 2 bar bar bar)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'bar 2))))
+  (pass-if "flexvector-fill! start end"
+    (equal? '#(1 2 baz baz 5)
+            (mutate-as x '#(1 2 3 4 5) (flexvector-fill! x 'baz 2 4))))
+  (pass-if "flexvector-fill! clamped"
+    (equal? '#(qux qux qux)
+            (mutate-as x '#(1 2 3) (flexvector-fill! x 'qux -1 10)))))
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-11-13 20:27 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-19  2:34 [PATCH] Added srfi-214: flexvectors Vijay Marupudi
2022-01-19  9:00 ` Maxime Devos
2022-01-19 13:55   ` Vijay Marupudi
     [not found]   ` <87wnivzvd4.fsf@vijaymarupudi.com>
2022-01-19 15:04     ` Maxime Devos
2022-01-19 15:44       ` Vijay Marupudi
2022-01-19 16:04         ` Maxime Devos
2022-01-20 15:34           ` Vijay Marupudi
2022-01-20 16:53             ` Maxime Devos
2022-01-20 17:57               ` Vijay Marupudi
2022-01-20 18:15                 ` Maxime Devos
2022-01-20 20:38                   ` Vijay Marupudi
2022-10-07 19:58                     ` Vijay Marupudi
2022-10-12 12:22                 ` Ludovic Courtès
2022-11-13 20:27                   ` Vijay Marupudi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).