(module record-vector racket/base ;; 20-nov-2025, start Racket version due to keyword type. ;; 02-jan-2026, start to replace proceures to the macroforms (provide record-vector make-rv record-vector? record-vector-length rv-len record-vector-ref rv-ref record-vector-update! rv-update! record-vector-attr? rv-attr? record-vector-set! rv-set! record-vector-clone rv-clone rv-composev record-vector-like? rv-like? ) (require racket/vector) (define-syntax is-keyq? (syntax-rules () ((_ k) (or (keyword? (quote k)) (symbol? (quote k)))))) (define-syntax maybe-keyq (syntax-rules () ((_ k) (cond ((is-keyq? k) (quote k)) (else (error (format "Attribute must be unquoted keyword or symbol, not |~a|" (quote k)))))))) (define-syntax rv* (syntax-rules () ((_ ix alst vals ke wal) (mcons (reverse (cons `(,(maybe-keyq ke) . ,ix) alst)) (list->vector (reverse (cons wal vals))))) ((_ ix alst vals ke wal k ...) (rv* (add1 ix) (cons `(,(maybe-keyq ke) . ,ix) alst) (cons wal vals) k ...)))) (define-syntax record-vector (syntax-rules () ((_ ke val ...) (rv* 0 '() '() ke val ...)) ((_) (mcons '() #())))) (define-syntax-rule (make-rv some ...) (record-vector some ...)) (define (record-vector? r) (and (mpair? r) (list? (mcar r)) (vector? (mcdr r)))) (define (record-vector-length r) (vector-length (mcdr r))) (define-syntax-rule (rv-len r) (record-vector-length r)) (define-syntax exact-integer-or? (syntax-rules () ((_ n) (and (exact-integer? n) n)))) (define-syntax record-vector-ref (syntax-rules () ((_ r index) (record-vector-ref r index #f)) ((_ r/m (index) default) (let ((r r/m)) (cond ((exact-integer-or? index) => (lambda (ix) (vector-ref (mcdr r) ix))) (else (cond ((assq index (mcar r)) => (lambda (ix) (vector-ref (mcdr r) (cdr ix)))) (else default)))))) ((_ r index default) (record-vector-ref r ((quote index)) default)))) (define-syntax rv-ref (syntax-rules () ((_ r prop) (record-vector-ref r prop)) ((_ r prop1 prop2 ...) (rv-ref (record-vector-ref r prop1) prop2 ...)))) (define-syntax record-vector-update! (syntax-rules () ((_ r/m (index) value) (let ((r r/m)) (cond ((exact-integer-or? index) => (lambda (ix) (vector-set! (mcdr r) ix value) r)) (else (cond ((assq index (mcar r)) => (lambda (i) (vector-set! (mcdr r) (cdr i) value))) (else (set-mcar! r (reverse (cons (cons index (vector-length (mcdr r))) (reverse (mcar r))))) (set-mcdr! r (vector-extend (mcdr r) (add1 (vector-length (mcdr r))) value)))) r)))) ((_ r index value) (record-vector-update! r ((quote index)) value)))) (define-syntax rv-update! (syntax-rules () ((_ r prop val) (record-vector-update! r prop val)) ((_ r/m prop1 prop2 ...) (let ((r r/m)) (rv-update! (record-vector-ref r prop1) prop2 ...) r)))) (define rec (make-rv #:t (make-rv #:s 0 #:tz (make-rv name 'utc rem "Greenwich")) #:k -0.1)) (define-syntax record-vector-attr? (syntax-rules () ((_ r k) (assq (maybe-keyq k) (mcar r))))) (define-syntax-rule (rv-attr? r k) (record-vector-attr? r k)) (define-syntax record-vector-set! (syntax-rules () ((_ r/m (index) value) (let ((r r/m)) (cond ((exact-integer-or? index) => (lambda (ix) (vector-set! (mcdr r) ix value) )) (else (cond ((assq index (mcar r)) => (lambda (cix) (vector-set! (mcdr r) (cdr cix) value))) (else (error (format "NO such attr |~a|" index)))))))) ((_ r index value) (record-vector-set! r ((quote index)) value)))) (define-syntax rv-set! (syntax-rules () ((_ r prop val) (record-vector-set! r prop val)) ((_ r prop1 prop2 ...) (rv-set! (record-vector-ref r prop1) prop2 ...)))) #;(define (record-vector-clone src . r) (define (record-copy rvec) (do ((i 0 (+ i 1)) (newvec (make-vector (vector-length rvec)))) ((= i (vector-length newvec)) newvec) (let ((val (vector-ref rvec i))) (vector-set! newvec i (if (record-vector? val) (record-vector-clone val) val))))) (let ((dst (mcons (mcar src) (record-copy (mcdr src))))) (let loop ((defs r)) (unless (null? defs) (cond ((and (maybe-keyq (car defs)) (pair? (cdr defs))) (record-vector-update! dst (car defs) (cadr defs)) (loop (cddr defs))) (else (error "unmatched keyword in " r))))) dst)) (define (recordv-copy rvec) (do ((i 0 (+ i 1)) (newvec (make-vector (vector-length rvec)))) ((= i (vector-length newvec)) newvec) (let ((val (vector-ref rvec i))) (vector-set! newvec i (if (record-vector? val) (record-vector-clone val) val))))) (define (rv-copy rec) (mcons (mcar rec) (recordv-copy (mcdr rec)))) (define-syntax rv-chain-update (syntax-rules () ((_ r k v) (record-vector-update! r k v)) ((_ r k w next ...) (rv-chain-update (rv-update! r k w) next ...)))) (define-syntax record-vector-clone (syntax-rules () ((_ rec) (rv-copy rec)) ((_ rec kw ...) (let ((r (rv-copy rec))) (rv-chain-update r kw ...))))) (define-syntax-rule (rv-clone r k ...) (record-vector-clone r k ...)) (define (random-of/2 a b) (if (zero? (random 2)) a b)) (define (rv-composev one two [selector random-of/2]) (mcons (mcar one) (for/vector ([i (mcdr one)] [j (mcdr two)]) (selector i j)))) (define (record-vector-like? rv etrv) (define hlp (lambda (props et) (call/cc (lambda (k) (for-each (lambda (e) (unless (assq (car e) props) (k #f))) (mcar et)) #t)))) (cond ((and (null? (mcar rv)) (null? (mcar etrv))) #t) ((or (null? (mcar rv)) (null? (mcar etrv))) #f) (else (or (hlp (mcar rv) etrv) (hlp (mcar etrv) rv))))) (define-syntax-rule (rv-like? left right) (record-vector-like? left right)) ) ;; end of module