export packed-struct-size
[clinton/guile-figl.git] / figl / contrib / packed-struct.scm
CommitLineData
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))