Commit | Line | Data |
---|---|---|
c4af9d8c AW |
1 | ;;; figl |
2 | ;;; Copyright (C) 2013 Andy Wingo <wingo@pobox.com> | |
3 | ;;; | |
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. | |
8 | ;;; | |
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. | |
13 | ;;; | |
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/>. | |
17 | ||
18 | ;;; Commentary: | |
19 | ;; | |
20 | ;; Packed binary structures. | |
21 | ;; | |
22 | ;;; Code: | |
23 | ||
24 | (define-module (figl contrib packed-struct) | |
25 | #:use-module (ice-9 futures) | |
26 | #:use-module (rnrs bytevectors) | |
27 | #:export ( | |
28 | define-packed-struct | |
3c2e9972 | 29 | packed-struct-size |
c4af9d8c AW |
30 | pack pack* unpack unpack* |
31 | ||
32 | make-packed-array | |
33 | packed-array-length | |
34 | ||
35 | pack-each pack-each/serial | |
36 | unpack-each unpack-each/serial | |
37 | repack-each repack-each/serial | |
38 | )) | |
39 | ||
40 | (define-syntax define-packed-struct | |
41 | (lambda (stx) | |
42 | (define (stx-map-fold proc lst seed) | |
43 | (let lp ((lst lst) (out '()) (seed seed)) | |
44 | (syntax-case lst () | |
45 | (() (values (reverse out) seed)) | |
46 | ((elt . lst) | |
47 | (call-with-values (lambda () (proc #'elt seed)) | |
48 | (lambda (elt seed) | |
49 | (lp #'lst (cons elt out) seed))))))) | |
50 | ||
51 | (define (compute-layout types) | |
52 | (stx-map-fold | |
53 | (lambda (type offset) | |
54 | (define (return size ref set) | |
55 | (values #`(#,offset #,ref #,set) | |
56 | (+ offset size))) | |
57 | (case (syntax->datum type) | |
58 | ((float) (return 4 | |
59 | #'bytevector-ieee-single-native-ref | |
60 | #'bytevector-ieee-single-native-set!)) | |
61 | ((double) (return 8 | |
62 | #'bytevector-ieee-double-native-ref | |
63 | #'bytevector-ieee-double-native-set!)) | |
64 | ((int8) (return 1 | |
65 | #'bytevector-s8-ref | |
66 | #'bytevector-s8-set!)) | |
67 | ((uint8) (return 1 | |
68 | #'bytevector-u8-ref | |
69 | #'bytevector-u8-set!)) | |
70 | ((int16) (return 2 | |
71 | #'bytevector-s16-native-ref | |
72 | #'bytevector-s16-native-set!)) | |
73 | ((uint16) (return 2 | |
74 | #'bytevector-u16-native-ref | |
75 | #'bytevector-u16-native-set!)) | |
76 | ((int32) (return 4 | |
77 | #'bytevector-s32-native-ref | |
78 | #'bytevector-s32-native-set!)) | |
79 | ((uint32) (return 4 | |
80 | #'bytevector-u32-native-ref | |
81 | #'bytevector-u32-native-set!)) | |
82 | ((int64) (return 8 | |
83 | #'bytevector-s64-native-ref | |
84 | #'bytevector-s64-native-set!)) | |
85 | ((uint64) (return 8 | |
86 | #'bytevector-u64-native-ref | |
87 | #'bytevector-u64-native-set!)) | |
88 | (else (error "unrecognized type" (syntax->datum type))))) | |
89 | types | |
90 | 0)) | |
91 | ||
92 | (syntax-case stx () | |
93 | ((define-packed-struct name | |
94 | (field-name field-type) | |
95 | ...) | |
96 | (call-with-values (lambda () (compute-layout #'(field-type ...))) | |
97 | (lambda (accessors byte-size) | |
98 | (with-syntax ((((field-offset field-ref field-set) ...) accessors) | |
99 | (byte-size byte-size)) | |
100 | #`(define-inlinable (name method field) | |
101 | (case method | |
102 | ((size) byte-size) | |
103 | ((unpacker) | |
104 | (lambda (bv offset k) | |
105 | (k (field-ref bv (+ offset field-offset)) | |
106 | ...))) | |
107 | ((packer) | |
108 | (lambda (bv offset field-name ...) | |
109 | (field-set bv (+ offset field-offset) field-name) | |
110 | ...)) | |
111 | ((getter) | |
112 | (case field | |
113 | ((field-name) | |
114 | (lambda (bv offset) | |
115 | (field-ref bv (+ offset field-offset)))) | |
116 | ... | |
117 | (else (error "unknown field" field)))) | |
118 | ((setter) | |
119 | (case field | |
120 | ((field-name) | |
121 | (lambda (bv offset val) | |
122 | (field-set bv (+ offset field-offset) val))) | |
123 | ... | |
124 | (else (error "unknown field" field))))))))))))) | |
125 | ||
126 | (define-syntax-rule (packed-struct-size type) | |
127 | (type 'size #f)) | |
128 | ||
129 | (define-syntax-rule (packed-struct-getter type field) | |
130 | (type 'getter 'field)) | |
131 | ||
132 | (define-syntax-rule (packed-struct-setter type field) | |
133 | (type 'setter 'field)) | |
134 | ||
135 | (define-syntax-rule (packed-struct-unpacker type) | |
136 | (type 'unpacker #f)) | |
137 | ||
138 | (define-syntax-rule (packed-struct-packer type) | |
139 | (type 'packer #f)) | |
140 | ||
141 | (define-syntax-rule (unpack* bv offset type k) | |
142 | ((packed-struct-unpacker type) bv offset k)) | |
143 | ||
144 | (define-syntax-rule (unpack bv n type k) | |
145 | (unpack* bv (* n (packed-struct-size type)) type k)) | |
146 | ||
147 | (define-syntax-rule (pack* bv offset type v ...) | |
148 | ((packed-struct-packer type) bv offset v ...)) | |
149 | ||
150 | (define-syntax-rule (pack bv n type v ...) | |
151 | (pack* bv (* n (packed-struct-size type)) type v ...)) | |
152 | ||
153 | (define-syntax-rule (make-packed-array type len) | |
154 | (make-bytevector (* (packed-struct-size type) len) 0)) | |
155 | ||
156 | (define-syntax-rule (packed-array-length bv type) | |
157 | (/ (bytevector-length bv) (packed-struct-size type))) | |
158 | ||
159 | (define* (parallel-iota n proc #:optional (nprocs (current-processor-count))) | |
160 | (let lp ((start 0) (end n) (nprocs nprocs)) | |
161 | (cond | |
162 | ((= start end)) | |
163 | ((= nprocs 1) | |
164 | (let lp ((n start)) | |
165 | (when (< n end) | |
166 | (proc n) | |
167 | (lp (1+ n))))) | |
168 | (else | |
169 | (let* ((pivot (+ start (ceiling/ (- end start) nprocs))) | |
170 | (left (future (lp start pivot 1)))) | |
171 | (lp pivot end (1- nprocs)) | |
172 | (touch left)))))) | |
173 | ||
174 | (define-syntax-rule (pack-each* bv type proc nprocs) | |
175 | (parallel-iota (packed-array-length bv type) | |
176 | (lambda (n) | |
177 | (call-with-values (lambda () (proc n)) | |
178 | (lambda args | |
179 | (apply (packed-struct-packer type) | |
180 | bv | |
181 | (* n (packed-struct-size type)) | |
182 | args)))) | |
183 | nprocs)) | |
184 | ||
185 | (define-syntax-rule (pack-each bv type proc) | |
186 | (pack-each* bv type proc (current-processor-count))) | |
187 | ||
188 | (define-syntax-rule (pack-each/serial bv type proc) | |
189 | (pack-each* bv type proc 1)) | |
190 | ||
191 | (define-syntax-rule (unpack-each* bv type proc nprocs) | |
192 | (parallel-iota (packed-array-length bv type) | |
193 | (lambda (n) | |
194 | ((packed-struct-unpacker type) | |
195 | bv | |
196 | (* n (packed-struct-size type)) | |
197 | (lambda args | |
198 | (apply proc n args)))) | |
199 | nprocs)) | |
200 | ||
201 | (define-syntax-rule (unpack-each bv type proc) | |
202 | (unpack-each* bv type proc (current-processor-count))) | |
203 | ||
204 | (define-syntax-rule (unpack-each/serial bv type proc) | |
205 | (unpack-each* bv type proc 1)) | |
206 | ||
207 | (define-syntax-rule (repack-each* bv type proc nprocs) | |
208 | (pack-each* bv type | |
209 | (lambda (n) | |
210 | ((packed-struct-unpacker type) | |
211 | bv | |
212 | (* n (packed-struct-size type)) | |
213 | (lambda args | |
214 | (apply proc n args)))) | |
215 | nprocs)) | |
216 | ||
217 | (define-syntax-rule (repack-each bv type proc) | |
218 | (repack-each* bv type proc (current-processor-count))) | |
219 | ||
220 | (define-syntax-rule (repack-each/serial bv type proc) | |
221 | (repack-each* bv type proc 1)) |