2 ;;; Copyright (C) 2013 Andy Wingo <wingo@pobox.com>
4 ;;; Figl is free software: you can redistribute it and/or modify it
5 ;;; under the terms of the GNU Lesser General Public License as
6 ;;; published by the Free Software Foundation, either version 3 of the
7 ;;; License, or (at your option) any later version.
9 ;;; Figl is distributed in the hope that it will be useful, but WITHOUT
10 ;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 ;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12 ;;; Public License for more details.
14 ;;; You should have received a copy of the GNU Lesser General Public
15 ;;; License along with this program. If not, see
16 ;;; <http://www.gnu.org/licenses/>.
20 ;; Packed binary structures.
24 (define-module (figl contrib packed-struct)
25 #:use-module (ice-9 futures)
26 #:use-module (rnrs bytevectors)
29 pack pack* unpack unpack*
34 pack-each pack-each/serial
35 unpack-each unpack-each/serial
36 repack-each repack-each/serial
39 (define-syntax define-packed-struct
41 (define (stx-map-fold proc lst seed)
42 (let lp ((lst lst) (out '()) (seed seed))
44 (() (values (reverse out) seed))
46 (call-with-values (lambda () (proc #'elt seed))
48 (lp #'lst (cons elt out) seed)))))))
50 (define (compute-layout types)
53 (define (return size ref set)
54 (values #`(#,offset #,ref #,set)
56 (case (syntax->datum type)
58 #'bytevector-ieee-single-native-ref
59 #'bytevector-ieee-single-native-set!))
61 #'bytevector-ieee-double-native-ref
62 #'bytevector-ieee-double-native-set!))
65 #'bytevector-s8-set!))
68 #'bytevector-u8-set!))
70 #'bytevector-s16-native-ref
71 #'bytevector-s16-native-set!))
73 #'bytevector-u16-native-ref
74 #'bytevector-u16-native-set!))
76 #'bytevector-s32-native-ref
77 #'bytevector-s32-native-set!))
79 #'bytevector-u32-native-ref
80 #'bytevector-u32-native-set!))
82 #'bytevector-s64-native-ref
83 #'bytevector-s64-native-set!))
85 #'bytevector-u64-native-ref
86 #'bytevector-u64-native-set!))
87 (else (error "unrecognized type" (syntax->datum type)))))
92 ((define-packed-struct name
93 (field-name field-type)
95 (call-with-values (lambda () (compute-layout #'(field-type ...)))
96 (lambda (accessors byte-size)
97 (with-syntax ((((field-offset field-ref field-set) ...) accessors)
98 (byte-size byte-size))
99 #`(define-inlinable (name method field)
103 (lambda (bv offset k)
104 (k (field-ref bv (+ offset field-offset))
107 (lambda (bv offset field-name ...)
108 (field-set bv (+ offset field-offset) field-name)
114 (field-ref bv (+ offset field-offset))))
116 (else (error "unknown field" field))))
120 (lambda (bv offset val)
121 (field-set bv (+ offset field-offset) val)))
123 (else (error "unknown field" field)))))))))))))
125 (define-syntax-rule (packed-struct-size type)
128 (define-syntax-rule (packed-struct-getter type field)
129 (type 'getter 'field))
131 (define-syntax-rule (packed-struct-setter type field)
132 (type 'setter 'field))
134 (define-syntax-rule (packed-struct-unpacker type)
137 (define-syntax-rule (packed-struct-packer type)
140 (define-syntax-rule (unpack* bv offset type k)
141 ((packed-struct-unpacker type) bv offset k))
143 (define-syntax-rule (unpack bv n type k)
144 (unpack* bv (* n (packed-struct-size type)) type k))
146 (define-syntax-rule (pack* bv offset type v ...)
147 ((packed-struct-packer type) bv offset v ...))
149 (define-syntax-rule (pack bv n type v ...)
150 (pack* bv (* n (packed-struct-size type)) type v ...))
152 (define-syntax-rule (make-packed-array type len)
153 (make-bytevector (* (packed-struct-size type) len) 0))
155 (define-syntax-rule (packed-array-length bv type)
156 (/ (bytevector-length bv) (packed-struct-size type)))
158 (define* (parallel-iota n proc #:optional (nprocs (current-processor-count)))
159 (let lp ((start 0) (end n) (nprocs nprocs))
168 (let* ((pivot (+ start (ceiling/ (- end start) nprocs)))
169 (left (future (lp start pivot 1))))
170 (lp pivot end (1- nprocs))
173 (define-syntax-rule (pack-each* bv type proc nprocs)
174 (parallel-iota (packed-array-length bv type)
176 (call-with-values (lambda () (proc n))
178 (apply (packed-struct-packer type)
180 (* n (packed-struct-size type))
184 (define-syntax-rule (pack-each bv type proc)
185 (pack-each* bv type proc (current-processor-count)))
187 (define-syntax-rule (pack-each/serial bv type proc)
188 (pack-each* bv type proc 1))
190 (define-syntax-rule (unpack-each* bv type proc nprocs)
191 (parallel-iota (packed-array-length bv type)
193 ((packed-struct-unpacker type)
195 (* n (packed-struct-size type))
197 (apply proc n args))))
200 (define-syntax-rule (unpack-each bv type proc)
201 (unpack-each* bv type proc (current-processor-count)))
203 (define-syntax-rule (unpack-each/serial bv type proc)
204 (unpack-each* bv type proc 1))
206 (define-syntax-rule (repack-each* bv type proc nprocs)
209 ((packed-struct-unpacker type)
211 (* n (packed-struct-size type))
213 (apply proc n args))))
216 (define-syntax-rule (repack-each bv type proc)
217 (repack-each* bv type proc (current-processor-count)))
219 (define-syntax-rule (repack-each/serial bv type proc)
220 (repack-each* bv type proc 1))