srfi-123.scm (9578B)
1 ;;; generic-ref-set --- Generic accessor and modifier operators. 2 3 ;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com> 4 5 ;; Permission is hereby granted, free of charge, to any person obtaining 6 ;; a copy of this software and associated documentation files (the 7 ;; "Software"), to deal in the Software without restriction, including 8 ;; without limitation the rights to use, copy, modify, merge, publish, 9 ;; distribute, sublicense, and/or sell copies of the Software, and to 10 ;; permit persons to whom the Software is furnished to do so, subject to 11 ;; the following conditions: 12 13 ;; The above copyright notice and this permission notice shall be 14 ;; included in all copies or substantial portions of the Software. 15 16 ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 ;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 ;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 ;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 (define-library (srfi srfi-123) 25 (export ref ref* ~ register-getter-with-setter! $bracket-apply$ set! setter getter-with-setter) 26 (import 27 (scheme base) 28 (scheme case-lambda) 29 30 (rnrs hashtables) 31 (rnrs records inspection) 32 (rnrs records procedural) 33 (rnrs records syntactic) 34 35 (srfi 1) 36 (srfi 4) 37 (srfi 17) 38 (srfi 26) 39 (srfi 31) 40 (srfi 43) 41 (srfi 111) 42 ) 43 (begin 44 45 ;;; Helpers 46 47 (define-syntax push! 48 (syntax-rules () 49 ((_ <list-var> <x>) 50 (set! <list-var> (cons <x> <list-var>))))) 51 52 (define (alist->hashtable alist) 53 (let ((table (make-eqv-hashtable 100))) 54 (for-each (lambda (entry) 55 (hashtable-set! table (car entry) (cdr entry))) 56 alist) 57 table)) 58 59 (define (pair-ref pair key) 60 (cond 61 ((eqv? 'car key) 62 (car pair)) 63 ((eqv? 'cdr key) 64 (cdr pair)) 65 (else 66 (list-ref pair key)))) 67 68 (define (pair-set! pair key value) 69 (cond 70 ((eqv? 'car key) 71 (set-car! pair value)) 72 ((eqv? 'cdr key) 73 (set-cdr! pair value)) 74 (else 75 (list-set! pair key value)))) 76 77 ;;; Record inspection support 78 79 (define (rtd-field-index rtd field) 80 "Find the index of a FIELD in the Record Type Descriptor RTD. 81 82 Raise an error if the field does not exist." 83 (let* ((fields (record-type-field-names rtd)) 84 (field-index (vector-index (cut eq? field <>) fields))) 85 (unless field-index 86 (error "Field does not exist in Record Type Descriptor (wanted field, existing fields):" 87 field-index 88 fields)) 89 field-index)) 90 (define rtd-accessor record-accessor) 91 (define rtd-mutator record-mutator) 92 (define (record-ref record field) 93 (let* ((rtd (record-rtd record)) 94 (field-index (rtd-field-index rtd field)) 95 (accessor (rtd-accessor rtd field-index))) 96 (accessor record))) 97 (define (record-set! record field value) 98 (let* ((rtd (record-rtd record)) 99 (field-index (rtd-field-index rtd field)) 100 (mutator (rtd-mutator rtd field-index))) 101 (mutator record value))) 102 (define record-getter 103 (list (cons record? record-ref))) 104 (define record-setter 105 (list (cons record? record-set!))) 106 (define record-type 107 (list record?)) 108 109 ;;; SRFI-4 support 110 111 ;;; In some implementations, SRFI-4 vectors are also bytevectors. We accomodate 112 ;;; for those implementations by using generic bytevector-ref/set! procedures 113 ;;; which possibly dispatch to an SRFI-4 type's getter/setter, but also 114 ;;; inserting the SRFI-4 getters/setters into the top-level dispatch tables. 115 116 (define srfi-4-getters 117 (list (cons s8vector? s8vector-ref) 118 (cons u8vector? u8vector-ref) 119 (cons s16vector? s16vector-ref) 120 (cons u16vector? u16vector-ref) 121 (cons s32vector? s32vector-ref) 122 (cons u32vector? u32vector-ref) 123 (cons s64vector? s64vector-ref) 124 (cons u64vector? u64vector-ref))) 125 (define srfi-4-setters 126 (list (cons s8vector? s8vector-set!) 127 (cons u8vector? u8vector-set!) 128 (cons s16vector? s16vector-set!) 129 (cons u16vector? u16vector-set!) 130 (cons s32vector? s32vector-set!) 131 (cons u32vector? u32vector-set!) 132 (cons s64vector? s64vector-set!) 133 (cons u64vector? u64vector-set!))) 134 (define srfi-4-types 135 (list s8vector? u8vector? s16vector? u16vector? s32vector? u32vector? 136 s64vector? u64vector?)) 137 (define srfi-4-getters-table (alist->hashtable srfi-4-getters)) 138 (define srfi-4-setters-table (alist->hashtable srfi-4-setters)) 139 (define (bytevector-ref bytevector index) 140 (let* ((type (find (lambda (pred) (pred bytevector)) srfi-4-types)) 141 (getter (if type 142 (ref srfi-4-getters-table type) 143 bytevector-u8-ref))) 144 (getter bytevector index))) 145 (define (bytevector-set! bytevector index value) 146 (let* ((type (find (lambda (pred) (pred bytevector)) srfi-4-types)) 147 (setter (if type 148 (ref srfi-4-setters-table type) 149 bytevector-u8-set!))) 150 (setter bytevector index value))) 151 152 ;;; SRFI-111 boxes support 153 154 (define (box-ref box _field) 155 (unbox box)) 156 (define (box-set! box _field value) 157 (set-box! box value)) 158 (define box-getter (list (cons box? box-ref))) 159 (define box-setter (list (cons box? box-set!))) 160 (define box-type (list box?)) 161 162 ;;; Main 163 164 (define %ref 165 (case-lambda 166 ((object field) 167 (let ((getter (lookup-getter object)) 168 (sparse? (sparse-type? object))) 169 (if sparse? 170 (let* ((not-found (cons #f #f)) 171 (result (getter object field not-found))) 172 (if (eqv? result not-found) 173 (error "Object has no entry for field." object field) 174 result)) 175 (getter object field)))) 176 ((object field default) 177 (let ((getter (lookup-getter object))) 178 (getter object field default))))) 179 180 (define (%ref* object field . fields) 181 (if (null? fields) 182 (%ref object field) 183 (apply %ref* (%ref object field) fields))) 184 185 (define (%set! object field value) 186 (let ((setter (lookup-setter object))) 187 (setter object field value))) 188 189 (define ref 190 (getter-with-setter 191 %ref 192 (lambda (object field value) 193 (%set! object field value)))) 194 195 (define ref* 196 (getter-with-setter 197 %ref* 198 ;; XXX: Originally it used the SRFI-31 rec construct, but it just would not compile! 199 ;; 200 ;; (rec (set!* object field rest0 . rest) 201 ;; (if (null? rest) 202 ;; (%set! object field rest0) 203 ;; (apply set!* (ref object field) rest0 rest))) 204 ;; 205 ;; 206 (let () 207 (define (set!* object field rest0 . rest) 208 (if (null? rest) 209 (%set! object field rest0) 210 (apply set!* (ref object field) rest0 rest))) 211 set!*))) 212 213 (define ~ ref*) 214 215 (define $bracket-apply$ ref*) 216 217 (define (lookup-getter object) 218 (or (hashtable-ref getter-table (type-of object) #f) 219 (error "No generic getter for object's type." object))) 220 221 (define (lookup-setter object) 222 (or (hashtable-ref setter-table (type-of object) #f) 223 (error "No generic setter for object's type." object))) 224 225 (define (sparse-type? object) 226 (memv (type-of object) sparse-types)) 227 228 (define (type-of object) 229 (find (lambda (pred) (pred object)) type-list)) 230 231 (define getter-table 232 (alist->hashtable 233 (append 234 (list (cons bytevector? bytevector-ref) 235 (cons hashtable? hashtable-ref) 236 (cons pair? pair-ref) 237 (cons string? string-ref) 238 (cons vector? vector-ref)) 239 record-getter 240 srfi-4-getters 241 box-getter))) 242 243 (define setter-table 244 (alist->hashtable 245 (append 246 (list (cons bytevector? bytevector-set!) 247 (cons hashtable? hashtable-set!) 248 (cons pair? pair-set!) 249 (cons string? string-set!) 250 (cons vector? vector-set!)) 251 record-setter 252 srfi-4-setters 253 box-setter))) 254 255 (define sparse-types 256 (list hashtable?)) 257 258 (define type-list 259 ;; Although the whole SRFI intrinsically neglects performance, we still use 260 ;; the micro-optimization of ordering this list roughly according to most 261 ;; likely match. 262 (append 263 (list hashtable? vector? pair? bytevector? string?) 264 srfi-4-types 265 box-type 266 ;; The record type must be placed last so specific record types (e.g. box) 267 ;; take precedence. 268 record-type 269 ;; Place those types we don't support really last. 270 (list boolean? char? eof-object? null? number? port? procedure? symbol?))) 271 272 (define (register-getter-with-setter! type getter sparse?) 273 (push! type-list type) 274 (set! (~ getter-table type) getter) 275 (set! (~ setter-table type) (setter getter)) 276 (when sparse? 277 (push! sparse-types type))) 278 )) 279 280 ;;; srfi-123.scm ends here