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