;; persistent collections on the Chez RT. ;; ;; The vector / map / set the emitted programs construct from literals and ;; operate on via the lowered leaf ops (conj/get/nth/count/assoc/...). Loaded by ;; rt.ss after values.ss; jolt=2 / jolt-hash (values.ss) call into the ;; jolt-coll? / jolt-coll=? / jolt-coll-hash hooks defined here (forward refs, ;; resolved at run time — nothing is CALLED during load). ;; ;; The persistent vector is a copy-on-write Scheme vector and the map/set are a ;; bitmap HAMT. They live in Scheme; correctness, not perf, is the gate. ;; ============================================================================ ;; small immutable-vector helpers (manual; avoid stdlib arg-order ambiguity) ;; ============================================================================ (define (vec-copy-range v start end) (let ((out (make-vector (fx- end start)))) (let loop ((i start)) (when (fxvector xs))) (define (make-map-entry k v) (make-pvec (vector k v) #t)) (define (jolt-map-entry? x) (and (pvec? x) (pvec-ent x) #t)) (define (pvec-count p) (vector-length (pvec-v p))) ;; jolt models every number as a double, so vector indices arrive as flonums — ;; coerce an integer-valued index to a Scheme fixnum before bounds math. (define (->idx i) (if (fixnum? i) i (if (flonum? i) (exact (floor i)) i))) (define (pvec-nth-d p i d) (let ((v (pvec-v p)) (i (->idx i))) (if (and (fixnum? i) (fx>=? i 0) (fxidx i))) (cond ((and (fx>=? i 0) (fx? shift max-shift) (fx=? eh h)) (make-hcoll h (list (cons ek ev) (cons k v))) (let ((ei (chunk eh shift)) (ni (chunk h shift))) (if (fx=? ei ni) (make-hnode (fxsll 1 ei) (vector (split-leaf (fx+ shift 5) ek ev h k v))) (let ((eb (fxsll 1 ei)) (nb (fxsll 1 ni))) (if (fx (lambda (m) (jolt-invoke m coll x))) (else (error 'conj "unsupported collection")))) ;; (conj) -> []; (conj nil a b ...) builds a list (conj prepending -> (b a)). (define (jolt-conj . args) (if (null? args) (jolt-vector) (let ((coll (car args)) (xs (cdr args))) (if (jolt-nil? coll) (fold-left jolt-conj1 jolt-empty-list xs) (meta-carry coll (fold-left jolt-conj1 coll xs)))))) ;; A host shim registers a type's get via register-get-arm! (handler: (coll k d) -> ;; value) instead of set!-wrapping jolt-get — disjoint coll types, checked before the ;; base map/set/vec/string cases (cf. register-hash-arm!). (define jolt-get-arms '()) (define (register-get-arm! pred handler) (set! jolt-get-arms (cons (cons pred handler) jolt-get-arms))) (define (jolt-get-base coll k d) (cond ((pmap? coll) (pmap-get coll k d)) ((pset? coll) (if (pset-contains? coll k) k d)) ((pvec? coll) (pvec-nth-d coll k d)) ((string? coll) (let ((i (->idx k))) (if (and (fixnum? i) (fx>=? i 0) (fxidx i))) (cond ((pvec? coll) (let ((v (pvec-v coll))) (if (and (fx>=? i 0) (fx=? i 0) (fx (lambda (m) (jolt-invoke m coll i))) (else (error 'nth "unsupported collection"))))) ((coll i d) (let ((i (->idx i))) (cond ((pvec? coll) (pvec-nth-d coll i d)) ((string? coll) (if (and (fx>=? i 0) (fx (lambda (m) (jolt-invoke m coll i d))) (else d)))))) ;; a count is an exact integer (JVM parity: count returns a long). jolt= is ;; exactness-aware, so this must be exact to match an exact integer literal: ;; (= 2 (count m)) -> 2 vs exact 2 -> true. (define (jolt-count coll) (begin (cond ((pvec? coll) (pvec-count coll)) ((pmap? coll) (pmap-cnt coll)) ((pset? coll) (pset-count coll)) ((string? coll) (string-length coll)) ((jolt-nil? coll) 0) ((empty-list-t? coll) 0) ((cseq? coll) (let loop ((s coll) (n 0)) ; walk (forces a finite seq) (if (jolt-nil? s) n (loop (jolt-seq (seq-more s)) (fx+ n 1))))) ((rec-coll-method coll "count") => (lambda (m) (jolt-invoke m coll))) (else (error 'count "uncountable"))))) (define (jolt-assoc1 coll k v) (cond ((pmap? coll) (pmap-assoc coll k v)) ((pvec? coll) (pvec-assoc coll k v)) ((jolt-nil? coll) (pmap-assoc empty-pmap k v)) ((rec-coll-method coll "assoc") => (lambda (m) (jolt-invoke m coll k v))) (else (error 'assoc "unsupported collection")))) (define (jolt-assoc coll . kvs) (meta-carry coll (let loop ((coll coll) (kvs kvs)) (cond ((null? kvs) coll) ((null? (cdr kvs)) (error 'assoc "assoc expects an even number of key/vals")) (else (loop (jolt-assoc1 coll (car kvs) (cadr kvs)) (cddr kvs))))))) (define (jolt-dissoc coll . ks) (cond ((jolt-nil? coll) jolt-nil) ((pmap? coll) (meta-carry coll (fold-left pmap-dissoc coll ks))) (else (error 'dissoc "unsupported collection")))) (define (jolt-contains? coll k) (cond ((pmap? coll) (pmap-contains? coll k)) ((pset? coll) (pset-contains? coll k)) ((pvec? coll) (let ((k (->idx k))) (and (fixnum? k) (fx>=? k 0) (fx