Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / libguile / srfi-4.c
... / ...
CommitLineData
1/* srfi-4.c --- Uniform numeric vector datatypes.
2 *
3 * Copyright (C) 2001, 2004, 2006 Free Software Foundation, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <string.h>
25#include <errno.h>
26#include <stdio.h>
27
28#include "libguile/_scm.h"
29#include "libguile/__scm.h"
30#include "libguile/srfi-4.h"
31#include "libguile/error.h"
32#include "libguile/read.h"
33#include "libguile/ports.h"
34#include "libguile/chars.h"
35#include "libguile/vectors.h"
36#include "libguile/unif.h"
37#include "libguile/strings.h"
38#include "libguile/strports.h"
39#include "libguile/dynwind.h"
40#include "libguile/deprecation.h"
41
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45
46#ifdef HAVE_IO_H
47#include <io.h>
48#endif
49
50/* Smob type code for uniform numeric vectors. */
51int scm_tc16_uvec = 0;
52
53#define SCM_IS_UVEC(obj) SCM_SMOB_PREDICATE (scm_tc16_uvec, (obj))
54
55/* Accessor macros for the three components of a uniform numeric
56 vector:
57 - The type tag (one of the symbolic constants below).
58 - The vector's length (counted in elements).
59 - The address of the data area (holding the elements of the
60 vector). */
61#define SCM_UVEC_TYPE(u) (SCM_CELL_WORD_1(u))
62#define SCM_UVEC_LENGTH(u) ((size_t)SCM_CELL_WORD_2(u))
63#define SCM_UVEC_BASE(u) ((void *)SCM_CELL_WORD_3(u))
64
65
66/* Symbolic constants encoding the various types of uniform
67 numeric vectors. */
68#define SCM_UVEC_U8 0
69#define SCM_UVEC_S8 1
70#define SCM_UVEC_U16 2
71#define SCM_UVEC_S16 3
72#define SCM_UVEC_U32 4
73#define SCM_UVEC_S32 5
74#define SCM_UVEC_U64 6
75#define SCM_UVEC_S64 7
76#define SCM_UVEC_F32 8
77#define SCM_UVEC_F64 9
78#define SCM_UVEC_C32 10
79#define SCM_UVEC_C64 11
80
81
82/* This array maps type tags to the size of the elements. */
83static const int uvec_sizes[12] = {
84 1, 1,
85 2, 2,
86 4, 4,
87#if SCM_HAVE_T_INT64
88 8, 8,
89#else
90 sizeof (SCM), sizeof (SCM),
91#endif
92 sizeof(float), sizeof(double),
93 2*sizeof(float), 2*sizeof(double)
94};
95
96static const char *uvec_tags[12] = {
97 "u8", "s8",
98 "u16", "s16",
99 "u32", "s32",
100 "u64", "s64",
101 "f32", "f64",
102 "c32", "c64",
103};
104
105static const char *uvec_names[12] = {
106 "u8vector", "s8vector",
107 "u16vector", "s16vector",
108 "u32vector", "s32vector",
109 "u64vector", "s64vector",
110 "f32vector", "f64vector",
111 "c32vector", "c64vector"
112};
113
114/* ================================================================ */
115/* SMOB procedures. */
116/* ================================================================ */
117
118
119/* Smob print hook for uniform vectors. */
120static int
121uvec_print (SCM uvec, SCM port, scm_print_state *pstate)
122{
123 union {
124 scm_t_uint8 *u8;
125 scm_t_int8 *s8;
126 scm_t_uint16 *u16;
127 scm_t_int16 *s16;
128 scm_t_uint32 *u32;
129 scm_t_int32 *s32;
130#if SCM_HAVE_T_INT64
131 scm_t_uint64 *u64;
132 scm_t_int64 *s64;
133#endif
134 float *f32;
135 double *f64;
136 SCM *fake_64;
137 } np;
138
139 size_t i = 0;
140 const size_t uvlen = SCM_UVEC_LENGTH (uvec);
141 void *uptr = SCM_UVEC_BASE (uvec);
142
143 switch (SCM_UVEC_TYPE (uvec))
144 {
145 case SCM_UVEC_U8: np.u8 = (scm_t_uint8 *) uptr; break;
146 case SCM_UVEC_S8: np.s8 = (scm_t_int8 *) uptr; break;
147 case SCM_UVEC_U16: np.u16 = (scm_t_uint16 *) uptr; break;
148 case SCM_UVEC_S16: np.s16 = (scm_t_int16 *) uptr; break;
149 case SCM_UVEC_U32: np.u32 = (scm_t_uint32 *) uptr; break;
150 case SCM_UVEC_S32: np.s32 = (scm_t_int32 *) uptr; break;
151#if SCM_HAVE_T_INT64
152 case SCM_UVEC_U64: np.u64 = (scm_t_uint64 *) uptr; break;
153 case SCM_UVEC_S64: np.s64 = (scm_t_int64 *) uptr; break;
154#else
155 case SCM_UVEC_U64:
156 case SCM_UVEC_S64: np.fake_64 = (SCM *) uptr; break;
157#endif
158 case SCM_UVEC_F32: np.f32 = (float *) uptr; break;
159 case SCM_UVEC_F64: np.f64 = (double *) uptr; break;
160 case SCM_UVEC_C32: np.f32 = (float *) uptr; break;
161 case SCM_UVEC_C64: np.f64 = (double *) uptr; break;
162 default:
163 abort (); /* Sanity check. */
164 break;
165 }
166
167 scm_putc ('#', port);
168 scm_puts (uvec_tags [SCM_UVEC_TYPE (uvec)], port);
169 scm_putc ('(', port);
170
171 while (i < uvlen)
172 {
173 if (i != 0) scm_puts (" ", port);
174 switch (SCM_UVEC_TYPE (uvec))
175 {
176 case SCM_UVEC_U8: scm_uintprint (*np.u8, 10, port); np.u8++; break;
177 case SCM_UVEC_S8: scm_intprint (*np.s8, 10, port); np.s8++; break;
178 case SCM_UVEC_U16: scm_uintprint (*np.u16, 10, port); np.u16++; break;
179 case SCM_UVEC_S16: scm_intprint (*np.s16, 10, port); np.s16++; break;
180 case SCM_UVEC_U32: scm_uintprint (*np.u32, 10, port); np.u32++; break;
181 case SCM_UVEC_S32: scm_intprint (*np.s32, 10, port); np.s32++; break;
182#if SCM_HAVE_T_INT64
183 case SCM_UVEC_U64: scm_uintprint (*np.u64, 10, port); np.u64++; break;
184 case SCM_UVEC_S64: scm_intprint (*np.s64, 10, port); np.s64++; break;
185#else
186 case SCM_UVEC_U64:
187 case SCM_UVEC_S64: scm_iprin1 (*np.fake_64, port, pstate);
188 np.fake_64++; break;
189#endif
190 case SCM_UVEC_F32: scm_i_print_double (*np.f32, port); np.f32++; break;
191 case SCM_UVEC_F64: scm_i_print_double (*np.f64, port); np.f64++; break;
192 case SCM_UVEC_C32:
193 scm_i_print_complex (np.f32[0], np.f32[1], port);
194 np.f32 += 2;
195 break;
196 case SCM_UVEC_C64:
197 scm_i_print_complex (np.f64[0], np.f64[1], port);
198 np.f64 += 2;
199 break;
200 default:
201 abort (); /* Sanity check. */
202 break;
203 }
204 i++;
205 }
206 scm_remember_upto_here_1 (uvec);
207 scm_puts (")", port);
208 return 1;
209}
210
211const char *
212scm_i_uniform_vector_tag (SCM uvec)
213{
214 return uvec_tags[SCM_UVEC_TYPE (uvec)];
215}
216
217static SCM
218uvec_equalp (SCM a, SCM b)
219{
220 SCM result = SCM_BOOL_T;
221 if (SCM_UVEC_TYPE (a) != SCM_UVEC_TYPE (b))
222 result = SCM_BOOL_F;
223 else if (SCM_UVEC_LENGTH (a) != SCM_UVEC_LENGTH (b))
224 result = SCM_BOOL_F;
225#if SCM_HAVE_T_INT64 == 0
226 else if (SCM_UVEC_TYPE (a) == SCM_UVEC_U64
227 || SCM_UVEC_TYPE (a) == SCM_UVEC_S64)
228 {
229 SCM *aptr = (SCM *)SCM_UVEC_BASE (a), *bptr = (SCM *)SCM_UVEC_BASE (b);
230 size_t len = SCM_UVEC_LENGTH (a), i;
231 for (i = 0; i < len; i++)
232 if (scm_is_false (scm_num_eq_p (*aptr++, *bptr++)))
233 {
234 result = SCM_BOOL_F;
235 break;
236 }
237 }
238#endif
239 else if (memcmp (SCM_UVEC_BASE (a), SCM_UVEC_BASE (b),
240 SCM_UVEC_LENGTH (a) * uvec_sizes[SCM_UVEC_TYPE(a)]) != 0)
241 result = SCM_BOOL_F;
242
243 scm_remember_upto_here_2 (a, b);
244 return result;
245}
246
247
248/* ================================================================ */
249/* Utility procedures. */
250/* ================================================================ */
251
252static SCM_C_INLINE_KEYWORD int
253is_uvec (int type, SCM obj)
254{
255 if (SCM_IS_UVEC (obj))
256 return SCM_UVEC_TYPE (obj) == type;
257 if (SCM_I_ARRAYP (obj) && SCM_I_ARRAY_NDIM (obj) == 1)
258 {
259 SCM v = SCM_I_ARRAY_V (obj);
260 return SCM_IS_UVEC (v) && SCM_UVEC_TYPE (v) == type;
261 }
262 return 0;
263}
264
265static SCM_C_INLINE_KEYWORD SCM
266uvec_p (int type, SCM obj)
267{
268 return scm_from_bool (is_uvec (type, obj));
269}
270
271static SCM_C_INLINE_KEYWORD void
272uvec_assert (int type, SCM obj)
273{
274 if (!is_uvec (type, obj))
275 scm_wrong_type_arg_msg (NULL, 0, obj, uvec_names[type]);
276}
277
278static SCM
279take_uvec (int type, void *base, size_t len)
280{
281 SCM_RETURN_NEWSMOB3 (scm_tc16_uvec, type, len, (scm_t_bits) base);
282}
283
284/* Create a new, uninitialized uniform numeric vector of type TYPE
285 with space for LEN elements. */
286static SCM
287alloc_uvec (int type, size_t len)
288{
289 void *base;
290 if (len > SCM_I_SIZE_MAX / uvec_sizes[type])
291 scm_out_of_range (NULL, scm_from_size_t (len));
292 base = scm_gc_malloc (len * uvec_sizes[type], uvec_names[type]);
293#if SCM_HAVE_T_INT64 == 0
294 if (type == SCM_UVEC_U64 || type == SCM_UVEC_S64)
295 {
296 SCM *ptr = (SCM *)base;
297 size_t i;
298 for (i = 0; i < len; i++)
299 *ptr++ = SCM_UNSPECIFIED;
300 }
301#endif
302 return take_uvec (type, base, len);
303}
304
305/* GCC doesn't seem to want to optimize unused switch clauses away,
306 so we use a big 'if' in the next two functions.
307*/
308
309static SCM_C_INLINE_KEYWORD SCM
310uvec_fast_ref (int type, const void *base, size_t c_idx)
311{
312 if (type == SCM_UVEC_U8)
313 return scm_from_uint8 (((scm_t_uint8*)base)[c_idx]);
314 else if (type == SCM_UVEC_S8)
315 return scm_from_int8 (((scm_t_int8*)base)[c_idx]);
316 else if (type == SCM_UVEC_U16)
317 return scm_from_uint16 (((scm_t_uint16*)base)[c_idx]);
318 else if (type == SCM_UVEC_S16)
319 return scm_from_int16 (((scm_t_int16*)base)[c_idx]);
320 else if (type == SCM_UVEC_U32)
321 return scm_from_uint32 (((scm_t_uint32*)base)[c_idx]);
322 else if (type == SCM_UVEC_S32)
323 return scm_from_int32 (((scm_t_int32*)base)[c_idx]);
324#if SCM_HAVE_T_INT64
325 else if (type == SCM_UVEC_U64)
326 return scm_from_uint64 (((scm_t_uint64*)base)[c_idx]);
327 else if (type == SCM_UVEC_S64)
328 return scm_from_int64 (((scm_t_int64*)base)[c_idx]);
329#else
330 else if (type == SCM_UVEC_U64)
331 return ((SCM *)base)[c_idx];
332 else if (type == SCM_UVEC_S64)
333 return ((SCM *)base)[c_idx];
334#endif
335 else if (type == SCM_UVEC_F32)
336 return scm_from_double (((float*)base)[c_idx]);
337 else if (type == SCM_UVEC_F64)
338 return scm_from_double (((double*)base)[c_idx]);
339 else if (type == SCM_UVEC_C32)
340 return scm_c_make_rectangular (((float*)base)[2*c_idx],
341 ((float*)base)[2*c_idx+1]);
342 else if (type == SCM_UVEC_C64)
343 return scm_c_make_rectangular (((double*)base)[2*c_idx],
344 ((double*)base)[2*c_idx+1]);
345 else
346 return SCM_BOOL_F;
347}
348
349#if SCM_HAVE_T_INT64 == 0
350static SCM scm_uint64_min, scm_uint64_max;
351static SCM scm_int64_min, scm_int64_max;
352
353static void
354assert_exact_integer_range (SCM val, SCM min, SCM max)
355{
356 if (!scm_is_integer (val)
357 || scm_is_false (scm_exact_p (val)))
358 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
359 if (scm_is_true (scm_less_p (val, min))
360 || scm_is_true (scm_gr_p (val, max)))
361 scm_out_of_range (NULL, val);
362}
363#endif
364
365static SCM_C_INLINE_KEYWORD void
366uvec_fast_set_x (int type, void *base, size_t c_idx, SCM val)
367{
368 if (type == SCM_UVEC_U8)
369 (((scm_t_uint8*)base)[c_idx]) = scm_to_uint8 (val);
370 else if (type == SCM_UVEC_S8)
371 (((scm_t_int8*)base)[c_idx]) = scm_to_int8 (val);
372 else if (type == SCM_UVEC_U16)
373 (((scm_t_uint16*)base)[c_idx]) = scm_to_uint16 (val);
374 else if (type == SCM_UVEC_S16)
375 (((scm_t_int16*)base)[c_idx]) = scm_to_int16 (val);
376 else if (type == SCM_UVEC_U32)
377 (((scm_t_uint32*)base)[c_idx]) = scm_to_uint32 (val);
378 else if (type == SCM_UVEC_S32)
379 (((scm_t_int32*)base)[c_idx]) = scm_to_int32 (val);
380#if SCM_HAVE_T_INT64
381 else if (type == SCM_UVEC_U64)
382 (((scm_t_uint64*)base)[c_idx]) = scm_to_uint64 (val);
383 else if (type == SCM_UVEC_S64)
384 (((scm_t_int64*)base)[c_idx]) = scm_to_int64 (val);
385#else
386 else if (type == SCM_UVEC_U64)
387 {
388 assert_exact_integer_range (val, scm_uint64_min, scm_uint64_max);
389 ((SCM *)base)[c_idx] = val;
390 }
391 else if (type == SCM_UVEC_S64)
392 {
393 assert_exact_integer_range (val, scm_int64_min, scm_int64_max);
394 ((SCM *)base)[c_idx] = val;
395 }
396#endif
397 else if (type == SCM_UVEC_F32)
398 (((float*)base)[c_idx]) = scm_to_double (val);
399 else if (type == SCM_UVEC_F64)
400 (((double*)base)[c_idx]) = scm_to_double (val);
401 else if (type == SCM_UVEC_C32)
402 {
403 (((float*)base)[2*c_idx]) = scm_c_real_part (val);
404 (((float*)base)[2*c_idx+1]) = scm_c_imag_part (val);
405 }
406 else if (type == SCM_UVEC_C64)
407 {
408 (((double*)base)[2*c_idx]) = scm_c_real_part (val);
409 (((double*)base)[2*c_idx+1]) = scm_c_imag_part (val);
410 }
411}
412
413static SCM_C_INLINE_KEYWORD SCM
414make_uvec (int type, SCM len, SCM fill)
415{
416 size_t c_len = scm_to_size_t (len);
417 SCM uvec = alloc_uvec (type, c_len);
418 if (!SCM_UNBNDP (fill))
419 {
420 size_t idx;
421 void *base = SCM_UVEC_BASE (uvec);
422 for (idx = 0; idx < c_len; idx++)
423 uvec_fast_set_x (type, base, idx, fill);
424 }
425 return uvec;
426}
427
428static SCM_C_INLINE_KEYWORD void *
429uvec_writable_elements (int type, SCM uvec, scm_t_array_handle *handle,
430 size_t *lenp, ssize_t *incp)
431{
432 if (type >= 0)
433 {
434 SCM v = uvec;
435 if (SCM_I_ARRAYP (v))
436 v = SCM_I_ARRAY_V (v);
437 uvec_assert (type, v);
438 }
439
440 return scm_uniform_vector_writable_elements (uvec, handle, lenp, incp);
441}
442
443static SCM_C_INLINE_KEYWORD const void *
444uvec_elements (int type, SCM uvec, scm_t_array_handle *handle,
445 size_t *lenp, ssize_t *incp)
446{
447 return uvec_writable_elements (type, uvec, handle, lenp, incp);
448}
449
450static int
451uvec_type (scm_t_array_handle *h)
452{
453 SCM v = h->array;
454 if (SCM_I_ARRAYP (v))
455 v = SCM_I_ARRAY_V (v);
456 return SCM_UVEC_TYPE (v);
457}
458
459static SCM
460uvec_to_list (int type, SCM uvec)
461{
462 scm_t_array_handle handle;
463 size_t len;
464 ssize_t i, inc;
465 const void *elts;
466 SCM res = SCM_EOL;
467
468 elts = uvec_elements (type, uvec, &handle, &len, &inc);
469 for (i = len*inc; i > 0;)
470 {
471 i -= inc;
472 res = scm_cons (scm_array_handle_ref (&handle, i), res);
473 }
474 scm_array_handle_release (&handle);
475 return res;
476}
477
478static SCM_C_INLINE_KEYWORD SCM
479uvec_length (int type, SCM uvec)
480{
481 scm_t_array_handle handle;
482 size_t len;
483 ssize_t inc;
484 uvec_elements (type, uvec, &handle, &len, &inc);
485 scm_array_handle_release (&handle);
486 return scm_from_size_t (len);
487}
488
489static SCM_C_INLINE_KEYWORD SCM
490uvec_ref (int type, SCM uvec, SCM idx)
491{
492 scm_t_array_handle handle;
493 size_t i, len;
494 ssize_t inc;
495 const void *elts;
496 SCM res;
497
498 elts = uvec_elements (type, uvec, &handle, &len, &inc);
499 if (type < 0)
500 type = uvec_type (&handle);
501 i = scm_to_unsigned_integer (idx, 0, len-1);
502 res = uvec_fast_ref (type, elts, i*inc);
503 scm_array_handle_release (&handle);
504 return res;
505}
506
507static SCM_C_INLINE_KEYWORD SCM
508uvec_set_x (int type, SCM uvec, SCM idx, SCM val)
509{
510 scm_t_array_handle handle;
511 size_t i, len;
512 ssize_t inc;
513 void *elts;
514
515 elts = uvec_writable_elements (type, uvec, &handle, &len, &inc);
516 if (type < 0)
517 type = uvec_type (&handle);
518 i = scm_to_unsigned_integer (idx, 0, len-1);
519 uvec_fast_set_x (type, elts, i*inc, val);
520 scm_array_handle_release (&handle);
521 return SCM_UNSPECIFIED;
522}
523
524static SCM_C_INLINE_KEYWORD SCM
525list_to_uvec (int type, SCM list)
526{
527 SCM uvec;
528 void *base;
529 long idx;
530 long len = scm_ilength (list);
531 if (len < 0)
532 scm_wrong_type_arg_msg (NULL, 0, list, "proper list");
533
534 uvec = alloc_uvec (type, len);
535 base = SCM_UVEC_BASE (uvec);
536 idx = 0;
537 while (scm_is_pair (list) && idx < len)
538 {
539 uvec_fast_set_x (type, base, idx, SCM_CAR (list));
540 list = SCM_CDR (list);
541 idx++;
542 }
543 return uvec;
544}
545
546static SCM
547coerce_to_uvec (int type, SCM obj)
548{
549 if (is_uvec (type, obj))
550 return obj;
551 else if (scm_is_pair (obj))
552 return list_to_uvec (type, obj);
553 else if (scm_is_generalized_vector (obj))
554 {
555 scm_t_array_handle handle;
556 size_t len = scm_c_generalized_vector_length (obj), i;
557 SCM uvec = alloc_uvec (type, len);
558 scm_array_get_handle (uvec, &handle);
559 for (i = 0; i < len; i++)
560 scm_array_handle_set (&handle, i,
561 scm_c_generalized_vector_ref (obj, i));
562 scm_array_handle_release (&handle);
563 return uvec;
564 }
565 else
566 scm_wrong_type_arg_msg (NULL, 0, obj, "list or generalized vector");
567}
568
569SCM_SYMBOL (scm_sym_a, "a");
570SCM_SYMBOL (scm_sym_b, "b");
571
572SCM
573scm_i_generalized_vector_type (SCM v)
574{
575 if (scm_is_vector (v))
576 return SCM_BOOL_T;
577 else if (scm_is_string (v))
578 return scm_sym_a;
579 else if (scm_is_bitvector (v))
580 return scm_sym_b;
581 else if (scm_is_uniform_vector (v))
582 return scm_from_locale_symbol (uvec_tags[SCM_UVEC_TYPE(v)]);
583 else
584 return SCM_BOOL_F;
585}
586
587int
588scm_is_uniform_vector (SCM obj)
589{
590 if (SCM_IS_UVEC (obj))
591 return 1;
592 if (SCM_I_ARRAYP (obj) && SCM_I_ARRAY_NDIM (obj) == 1)
593 {
594 SCM v = SCM_I_ARRAY_V (obj);
595 return SCM_IS_UVEC (v);
596 }
597 return 0;
598}
599
600size_t
601scm_c_uniform_vector_length (SCM uvec)
602{
603 /* scm_generalized_vector_get_handle will ultimately call us to get
604 the length of uniform vectors, so we can't use uvec_elements for
605 naked vectors.
606 */
607
608 if (SCM_IS_UVEC (uvec))
609 return SCM_UVEC_LENGTH (uvec);
610 else
611 {
612 scm_t_array_handle handle;
613 size_t len;
614 ssize_t inc;
615 uvec_elements (-1, uvec, &handle, &len, &inc);
616 scm_array_handle_release (&handle);
617 return len;
618 }
619}
620
621SCM_DEFINE (scm_uniform_vector_p, "uniform-vector?", 1, 0, 0,
622 (SCM obj),
623 "Return @code{#t} if @var{obj} is a uniform vector.")
624#define FUNC_NAME s_scm_uniform_vector_p
625{
626 return scm_from_bool (scm_is_uniform_vector (obj));
627}
628#undef FUNC_NAME
629
630SCM
631scm_c_uniform_vector_ref (SCM v, size_t idx)
632{
633 scm_t_array_handle handle;
634 size_t len;
635 ssize_t inc;
636 SCM res;
637
638 uvec_elements (-1, v, &handle, &len, &inc);
639 if (idx >= len)
640 scm_out_of_range (NULL, scm_from_size_t (idx));
641 res = scm_array_handle_ref (&handle, idx*inc);
642 scm_array_handle_release (&handle);
643 return res;
644}
645
646SCM_DEFINE (scm_uniform_vector_ref, "uniform-vector-ref", 2, 0, 0,
647 (SCM v, SCM idx),
648 "Return the element at index @var{idx} of the\n"
649 "homogenous numeric vector @var{v}.")
650#define FUNC_NAME s_scm_uniform_vector_ref
651{
652#if SCM_ENABLE_DEPRECATED
653 /* Support old argument convention.
654 */
655 if (scm_is_pair (idx))
656 {
657 scm_c_issue_deprecation_warning
658 ("Using a list as the index to uniform-vector-ref is deprecated.");
659 if (!scm_is_null (SCM_CDR (idx)))
660 scm_wrong_num_args (NULL);
661 idx = SCM_CAR (idx);
662 }
663#endif
664
665 return scm_c_uniform_vector_ref (v, scm_to_size_t (idx));
666}
667#undef FUNC_NAME
668
669void
670scm_c_uniform_vector_set_x (SCM v, size_t idx, SCM val)
671{
672 scm_t_array_handle handle;
673 size_t len;
674 ssize_t inc;
675
676 uvec_writable_elements (-1, v, &handle, &len, &inc);
677 if (idx >= len)
678 scm_out_of_range (NULL, scm_from_size_t (idx));
679 scm_array_handle_set (&handle, idx*inc, val);
680 scm_array_handle_release (&handle);
681}
682
683SCM_DEFINE (scm_uniform_vector_set_x, "uniform-vector-set!", 3, 0, 0,
684 (SCM v, SCM idx, SCM val),
685 "Set the element at index @var{idx} of the\n"
686 "homogenous numeric vector @var{v} to @var{val}.")
687#define FUNC_NAME s_scm_uniform_vector_set_x
688{
689#if SCM_ENABLE_DEPRECATED
690 /* Support old argument convention.
691 */
692 if (scm_is_pair (idx))
693 {
694 scm_c_issue_deprecation_warning
695 ("Using a list as the index to uniform-vector-set! is deprecated.");
696 if (!scm_is_null (SCM_CDR (idx)))
697 scm_wrong_num_args (NULL);
698 idx = SCM_CAR (idx);
699 }
700#endif
701
702 scm_c_uniform_vector_set_x (v, scm_to_size_t (idx), val);
703 return SCM_UNSPECIFIED;
704}
705#undef FUNC_NAME
706
707SCM_DEFINE (scm_uniform_vector_to_list, "uniform-vector->list", 1, 0, 0,
708 (SCM uvec),
709 "Convert the uniform numeric vector @var{uvec} to a list.")
710#define FUNC_NAME s_scm_uniform_vector_to_list
711{
712 return uvec_to_list (-1, uvec);
713}
714#undef FUNC_NAME
715
716size_t
717scm_array_handle_uniform_element_size (scm_t_array_handle *h)
718{
719 SCM vec = h->array;
720 if (SCM_I_ARRAYP (vec))
721 vec = SCM_I_ARRAY_V (vec);
722 if (scm_is_uniform_vector (vec))
723 return uvec_sizes[SCM_UVEC_TYPE(vec)];
724 scm_wrong_type_arg_msg (NULL, 0, h->array, "uniform array");
725}
726
727#if SCM_ENABLE_DEPRECATED
728
729/* return the size of an element in a uniform array or 0 if type not
730 found. */
731size_t
732scm_uniform_element_size (SCM obj)
733{
734 scm_c_issue_deprecation_warning
735 ("scm_uniform_element_size is deprecated. "
736 "Use scm_array_handle_uniform_element_size instead.");
737
738 if (SCM_IS_UVEC (obj))
739 return uvec_sizes[SCM_UVEC_TYPE(obj)];
740 else
741 return 0;
742}
743
744#endif
745
746const void *
747scm_array_handle_uniform_elements (scm_t_array_handle *h)
748{
749 return scm_array_handle_uniform_writable_elements (h);
750}
751
752void *
753scm_array_handle_uniform_writable_elements (scm_t_array_handle *h)
754{
755 SCM vec = h->array;
756 if (SCM_I_ARRAYP (vec))
757 vec = SCM_I_ARRAY_V (vec);
758 if (SCM_IS_UVEC (vec))
759 {
760 size_t size = uvec_sizes[SCM_UVEC_TYPE(vec)];
761 char *elts = SCM_UVEC_BASE (vec);
762 return (void *) (elts + size*h->base);
763 }
764 scm_wrong_type_arg_msg (NULL, 0, h->array, "uniform array");
765}
766
767const void *
768scm_uniform_vector_elements (SCM uvec,
769 scm_t_array_handle *h,
770 size_t *lenp, ssize_t *incp)
771{
772 return scm_uniform_vector_writable_elements (uvec, h, lenp, incp);
773}
774
775void *
776scm_uniform_vector_writable_elements (SCM uvec,
777 scm_t_array_handle *h,
778 size_t *lenp, ssize_t *incp)
779{
780 scm_generalized_vector_get_handle (uvec, h);
781 if (lenp)
782 {
783 scm_t_array_dim *dim = scm_array_handle_dims (h);
784 *lenp = dim->ubnd - dim->lbnd + 1;
785 *incp = dim->inc;
786 }
787 return scm_array_handle_uniform_writable_elements (h);
788}
789
790SCM_DEFINE (scm_uniform_vector_length, "uniform-vector-length", 1, 0, 0,
791 (SCM v),
792 "Return the number of elements in the uniform vector @var{v}.")
793#define FUNC_NAME s_scm_uniform_vector_length
794{
795 return uvec_length (-1, v);
796}
797#undef FUNC_NAME
798
799SCM_DEFINE (scm_uniform_vector_read_x, "uniform-vector-read!", 1, 3, 0,
800 (SCM uvec, SCM port_or_fd, SCM start, SCM end),
801 "Fill the elements of @var{uvec} by reading\n"
802 "raw bytes from @var{port-or-fdes}, using host byte order.\n\n"
803 "The optional arguments @var{start} (inclusive) and @var{end}\n"
804 "(exclusive) allow a specified region to be read,\n"
805 "leaving the remainder of the vector unchanged.\n\n"
806 "When @var{port-or-fdes} is a port, all specified elements\n"
807 "of @var{uvec} are attempted to be read, potentially blocking\n"
808 "while waiting formore input or end-of-file.\n"
809 "When @var{port-or-fd} is an integer, a single call to\n"
810 "read(2) is made.\n\n"
811 "An error is signalled when the last element has only\n"
812 "been partially filled before reaching end-of-file or in\n"
813 "the single call to read(2).\n\n"
814 "@code{uniform-vector-read!} returns the number of elements\n"
815 "read.\n\n"
816 "@var{port-or-fdes} may be omitted, in which case it defaults\n"
817 "to the value returned by @code{(current-input-port)}.")
818#define FUNC_NAME s_scm_uniform_vector_read_x
819{
820 scm_t_array_handle handle;
821 size_t vlen, sz, ans;
822 ssize_t inc;
823 size_t cstart, cend;
824 size_t remaining, off;
825 char *base;
826
827 if (SCM_UNBNDP (port_or_fd))
828 port_or_fd = scm_current_input_port ();
829 else
830 SCM_ASSERT (scm_is_integer (port_or_fd)
831 || (SCM_OPINPORTP (port_or_fd)),
832 port_or_fd, SCM_ARG2, FUNC_NAME);
833
834 if (!scm_is_uniform_vector (uvec))
835 scm_wrong_type_arg_msg (NULL, 0, uvec, "uniform vector");
836
837 base = scm_uniform_vector_writable_elements (uvec, &handle, &vlen, &inc);
838 sz = scm_array_handle_uniform_element_size (&handle);
839
840 if (inc != 1)
841 {
842 /* XXX - we should of course support non contiguous vectors. */
843 scm_misc_error (NULL, "only contiguous vectors are supported: ~a",
844 scm_list_1 (uvec));
845 }
846
847 cstart = 0;
848 cend = vlen;
849 if (!SCM_UNBNDP (start))
850 {
851 cstart = scm_to_unsigned_integer (start, 0, vlen);
852 if (!SCM_UNBNDP (end))
853 cend = scm_to_unsigned_integer (end, cstart, vlen);
854 }
855
856 remaining = (cend - cstart) * sz;
857 off = cstart * sz;
858
859 if (SCM_NIMP (port_or_fd))
860 {
861 ans = cend - cstart;
862 remaining -= scm_c_read (port_or_fd, base + off, remaining);
863 if (remaining % sz != 0)
864 SCM_MISC_ERROR ("unexpected EOF", SCM_EOL);
865 ans -= remaining / sz;
866 }
867 else /* file descriptor. */
868 {
869 int fd = scm_to_int (port_or_fd);
870 int n;
871
872 SCM_SYSCALL (n = read (fd, base + off, remaining));
873 if (n == -1)
874 SCM_SYSERROR;
875 if (n % sz != 0)
876 SCM_MISC_ERROR ("unexpected EOF", SCM_EOL);
877 ans = n / sz;
878 }
879
880 scm_array_handle_release (&handle);
881
882 return scm_from_size_t (ans);
883}
884#undef FUNC_NAME
885
886SCM_DEFINE (scm_uniform_vector_write, "uniform-vector-write", 1, 3, 0,
887 (SCM uvec, SCM port_or_fd, SCM start, SCM end),
888 "Write the elements of @var{uvec} as raw bytes to\n"
889 "@var{port-or-fdes}, in the host byte order.\n\n"
890 "The optional arguments @var{start} (inclusive)\n"
891 "and @var{end} (exclusive) allow\n"
892 "a specified region to be written.\n\n"
893 "When @var{port-or-fdes} is a port, all specified elements\n"
894 "of @var{uvec} are attempted to be written, potentially blocking\n"
895 "while waiting for more room.\n"
896 "When @var{port-or-fd} is an integer, a single call to\n"
897 "write(2) is made.\n\n"
898 "An error is signalled when the last element has only\n"
899 "been partially written in the single call to write(2).\n\n"
900 "The number of objects actually written is returned.\n"
901 "@var{port-or-fdes} may be\n"
902 "omitted, in which case it defaults to the value returned by\n"
903 "@code{(current-output-port)}.")
904#define FUNC_NAME s_scm_uniform_vector_write
905{
906 scm_t_array_handle handle;
907 size_t vlen, sz, ans;
908 ssize_t inc;
909 size_t cstart, cend;
910 size_t amount, off;
911 const char *base;
912
913 port_or_fd = SCM_COERCE_OUTPORT (port_or_fd);
914
915 if (SCM_UNBNDP (port_or_fd))
916 port_or_fd = scm_current_output_port ();
917 else
918 SCM_ASSERT (scm_is_integer (port_or_fd)
919 || (SCM_OPOUTPORTP (port_or_fd)),
920 port_or_fd, SCM_ARG2, FUNC_NAME);
921
922 base = scm_uniform_vector_elements (uvec, &handle, &vlen, &inc);
923 sz = scm_array_handle_uniform_element_size (&handle);
924
925 if (inc != 1)
926 {
927 /* XXX - we should of course support non contiguous vectors. */
928 scm_misc_error (NULL, "only contiguous vectors are supported: ~a",
929 scm_list_1 (uvec));
930 }
931
932 cstart = 0;
933 cend = vlen;
934 if (!SCM_UNBNDP (start))
935 {
936 cstart = scm_to_unsigned_integer (start, 0, vlen);
937 if (!SCM_UNBNDP (end))
938 cend = scm_to_unsigned_integer (end, cstart, vlen);
939 }
940
941 amount = (cend - cstart) * sz;
942 off = cstart * sz;
943
944 if (SCM_NIMP (port_or_fd))
945 {
946 scm_lfwrite (base + off, amount, port_or_fd);
947 ans = cend - cstart;
948 }
949 else /* file descriptor. */
950 {
951 int fd = scm_to_int (port_or_fd), n;
952 SCM_SYSCALL (n = write (fd, base + off, amount));
953 if (n == -1)
954 SCM_SYSERROR;
955 if (n % sz != 0)
956 SCM_MISC_ERROR ("last element only written partially", SCM_EOL);
957 ans = n / sz;
958 }
959
960 scm_array_handle_release (&handle);
961
962 return scm_from_size_t (ans);
963}
964#undef FUNC_NAME
965
966/* ================================================================ */
967/* Exported procedures. */
968/* ================================================================ */
969
970#define TYPE SCM_UVEC_U8
971#define TAG u8
972#define CTYPE scm_t_uint8
973#include "libguile/srfi-4.i.c"
974
975#define TYPE SCM_UVEC_S8
976#define TAG s8
977#define CTYPE scm_t_int8
978#include "libguile/srfi-4.i.c"
979
980#define TYPE SCM_UVEC_U16
981#define TAG u16
982#define CTYPE scm_t_uint16
983#include "libguile/srfi-4.i.c"
984
985#define TYPE SCM_UVEC_S16
986#define TAG s16
987#define CTYPE scm_t_int16
988#include "libguile/srfi-4.i.c"
989
990#define TYPE SCM_UVEC_U32
991#define TAG u32
992#define CTYPE scm_t_uint32
993#include "libguile/srfi-4.i.c"
994
995#define TYPE SCM_UVEC_S32
996#define TAG s32
997#define CTYPE scm_t_int32
998#include "libguile/srfi-4.i.c"
999
1000#define TYPE SCM_UVEC_U64
1001#define TAG u64
1002#if SCM_HAVE_T_UINT64
1003#define CTYPE scm_t_uint64
1004#endif
1005#include "libguile/srfi-4.i.c"
1006
1007#define TYPE SCM_UVEC_S64
1008#define TAG s64
1009#if SCM_HAVE_T_INT64
1010#define CTYPE scm_t_int64
1011#endif
1012#include "libguile/srfi-4.i.c"
1013
1014#define TYPE SCM_UVEC_F32
1015#define TAG f32
1016#define CTYPE float
1017#include "libguile/srfi-4.i.c"
1018
1019#define TYPE SCM_UVEC_F64
1020#define TAG f64
1021#define CTYPE double
1022#include "libguile/srfi-4.i.c"
1023
1024#define TYPE SCM_UVEC_C32
1025#define TAG c32
1026#define CTYPE float
1027#include "libguile/srfi-4.i.c"
1028
1029#define TYPE SCM_UVEC_C64
1030#define TAG c64
1031#define CTYPE double
1032#include "libguile/srfi-4.i.c"
1033
1034static scm_i_t_array_ref uvec_reffers[12] = {
1035 u8ref, s8ref,
1036 u16ref, s16ref,
1037 u32ref, s32ref,
1038 u64ref, s64ref,
1039 f32ref, f64ref,
1040 c32ref, c64ref
1041};
1042
1043static scm_i_t_array_set uvec_setters[12] = {
1044 u8set, s8set,
1045 u16set, s16set,
1046 u32set, s32set,
1047 u64set, s64set,
1048 f32set, f64set,
1049 c32set, c64set
1050};
1051
1052scm_i_t_array_ref
1053scm_i_uniform_vector_ref_proc (SCM uvec)
1054{
1055 return uvec_reffers[SCM_UVEC_TYPE(uvec)];
1056}
1057
1058scm_i_t_array_set
1059scm_i_uniform_vector_set_proc (SCM uvec)
1060{
1061 return uvec_setters[SCM_UVEC_TYPE(uvec)];
1062}
1063
1064void
1065scm_init_srfi_4 (void)
1066{
1067 scm_tc16_uvec = scm_make_smob_type ("uvec", 0);
1068 scm_set_smob_equalp (scm_tc16_uvec, uvec_equalp);
1069 scm_set_smob_print (scm_tc16_uvec, uvec_print);
1070
1071#if SCM_HAVE_T_INT64 == 0
1072 scm_uint64_min =
1073 scm_permanent_object (scm_from_int (0));
1074 scm_uint64_max =
1075 scm_permanent_object (scm_c_read_string ("18446744073709551615"));
1076 scm_int64_min =
1077 scm_permanent_object (scm_c_read_string ("-9223372036854775808"));
1078 scm_int64_max =
1079 scm_permanent_object (scm_c_read_string ("9223372036854775807"));
1080#endif
1081
1082#include "libguile/srfi-4.x"
1083
1084}
1085
1086/* End of srfi-4.c. */