Merge branch 'master' into boehm-demers-weiser-gc
[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
f8579182
MV
247
248/* ================================================================ */
249/* Utility procedures. */
250/* ================================================================ */
251
b0c0a310 252static SCM_C_INLINE_KEYWORD int
f8579182
MV
253is_uvec (int type, SCM obj)
254{
4330ee25
MV
255 if (SCM_IS_UVEC (obj))
256 return SCM_UVEC_TYPE (obj) == type;
04b87de5 257 if (SCM_I_ARRAYP (obj) && SCM_I_ARRAY_NDIM (obj) == 1)
4330ee25 258 {
04b87de5 259 SCM v = SCM_I_ARRAY_V (obj);
4330ee25
MV
260 return SCM_IS_UVEC (v) && SCM_UVEC_TYPE (v) == type;
261 }
262 return 0;
f8579182
MV
263}
264
b0c0a310 265static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
266uvec_p (int type, SCM obj)
267{
268 return scm_from_bool (is_uvec (type, obj));
269}
270
b0c0a310 271static SCM_C_INLINE_KEYWORD void
f8579182
MV
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
faa00365 278static SCM
ab7acbb7 279take_uvec (int type, void *base, size_t len)
faa00365
MV
280{
281 SCM_RETURN_NEWSMOB3 (scm_tc16_uvec, type, len, (scm_t_bits) base);
282}
283
69d2000d 284/* Create a new, uninitialized uniform numeric vector of type TYPE
f8579182
MV
285 with space for LEN elements. */
286static SCM
faa00365 287alloc_uvec (int type, size_t len)
f8579182 288{
811eb6d0
MV
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]);
00c17d45
MV
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
faa00365 302 return take_uvec (type, base, len);
f8579182
MV
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
b0c0a310 309static SCM_C_INLINE_KEYWORD SCM
4330ee25 310uvec_fast_ref (int type, const void *base, size_t c_idx)
f8579182
MV
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]);
00c17d45
MV
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];
f8579182
MV
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]);
cbdc8379
MV
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]);
28d4aef1
MV
345 else
346 return SCM_BOOL_F;
f8579182
MV
347}
348
00c17d45
MV
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
b0c0a310 365static SCM_C_INLINE_KEYWORD void
f8579182
MV
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);
00c17d45
MV
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 }
f8579182
MV
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);
cbdc8379
MV
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 }
f8579182
MV
411}
412
b0c0a310 413static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
414make_uvec (int type, SCM len, SCM fill)
415{
811eb6d0 416 size_t c_len = scm_to_size_t (len);
f8579182
MV
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
b0c0a310 428static SCM_C_INLINE_KEYWORD void *
4330ee25
MV
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;
04b87de5
MV
435 if (SCM_I_ARRAYP (v))
436 v = SCM_I_ARRAY_V (v);
4330ee25
MV
437 uvec_assert (type, v);
438 }
439
440 return scm_uniform_vector_writable_elements (uvec, handle, lenp, incp);
441}
442
b0c0a310 443static SCM_C_INLINE_KEYWORD const void *
4330ee25
MV
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
5e320e59
MV
450static int
451uvec_type (scm_t_array_handle *h)
452{
453 SCM v = h->array;
04b87de5
MV
454 if (SCM_I_ARRAYP (v))
455 v = SCM_I_ARRAY_V (v);
5e320e59
MV
456 return SCM_UVEC_TYPE (v);
457}
458
4330ee25
MV
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;
4ea4bc4c 472 res = scm_cons (scm_array_handle_ref (&handle, i), res);
4330ee25
MV
473 }
474 scm_array_handle_release (&handle);
475 return res;
476}
477
b0c0a310 478static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
479uvec_length (int type, SCM uvec)
480{
4330ee25
MV
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);
f8579182
MV
487}
488
b0c0a310 489static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
490uvec_ref (int type, SCM uvec, SCM idx)
491{
4330ee25
MV
492 scm_t_array_handle handle;
493 size_t i, len;
494 ssize_t inc;
495 const void *elts;
f8579182
MV
496 SCM res;
497
4330ee25 498 elts = uvec_elements (type, uvec, &handle, &len, &inc);
5e320e59
MV
499 if (type < 0)
500 type = uvec_type (&handle);
4330ee25
MV
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);
f8579182
MV
504 return res;
505}
506
b0c0a310 507static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
508uvec_set_x (int type, SCM uvec, SCM idx, SCM val)
509{
4330ee25
MV
510 scm_t_array_handle handle;
511 size_t i, len;
512 ssize_t inc;
513 void *elts;
f8579182 514
4330ee25 515 elts = uvec_writable_elements (type, uvec, &handle, &len, &inc);
5e320e59
MV
516 if (type < 0)
517 type = uvec_type (&handle);
4330ee25
MV
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);
f8579182
MV
521 return SCM_UNSPECIFIED;
522}
523
b0c0a310 524static SCM_C_INLINE_KEYWORD SCM
f8579182
MV
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
90d4368c
MV
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);
811eb6d0 553 else if (scm_is_generalized_vector (obj))
90d4368c 554 {
4e8ad323 555 scm_t_array_handle handle;
811eb6d0
MV
556 size_t len = scm_c_generalized_vector_length (obj), i;
557 SCM uvec = alloc_uvec (type, len);
4e8ad323 558 scm_array_get_handle (uvec, &handle);
811eb6d0 559 for (i = 0; i < len; i++)
4e8ad323
MV
560 scm_array_handle_set (&handle, i,
561 scm_c_generalized_vector_ref (obj, i));
562 scm_array_handle_release (&handle);
90d4368c
MV
563 return uvec;
564 }
565 else
811eb6d0 566 scm_wrong_type_arg_msg (NULL, 0, obj, "list or generalized vector");
90d4368c
MV
567}
568
f301dbf3
MV
569SCM_SYMBOL (scm_sym_a, "a");
570SCM_SYMBOL (scm_sym_b, "b");
f8579182 571
e0e49670 572SCM
f301dbf3 573scm_i_generalized_vector_type (SCM v)
e0e49670 574{
811eb6d0 575 if (scm_is_vector (v))
f301dbf3 576 return SCM_BOOL_T;
811eb6d0 577 else if (scm_is_string (v))
f301dbf3 578 return scm_sym_a;
811eb6d0 579 else if (scm_is_bitvector (v))
f301dbf3 580 return scm_sym_b;
811eb6d0 581 else if (scm_is_uniform_vector (v))
f301dbf3 582 return scm_from_locale_symbol (uvec_tags[SCM_UVEC_TYPE(v)]);
811eb6d0
MV
583 else
584 return SCM_BOOL_F;
e0e49670
MV
585}
586
587int
588scm_is_uniform_vector (SCM obj)
589{
4330ee25
MV
590 if (SCM_IS_UVEC (obj))
591 return 1;
04b87de5 592 if (SCM_I_ARRAYP (obj) && SCM_I_ARRAY_NDIM (obj) == 1)
4330ee25 593 {
04b87de5 594 SCM v = SCM_I_ARRAY_V (obj);
4330ee25
MV
595 return SCM_IS_UVEC (v);
596 }
597 return 0;
e0e49670
MV
598}
599
600size_t
4330ee25 601scm_c_uniform_vector_length (SCM uvec)
e0e49670 602{
4330ee25
MV
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);
e0e49670 610 else
4330ee25
MV
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 }
e0e49670
MV
619}
620
e0e49670
MV
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
4330ee25
MV
630SCM
631scm_c_uniform_vector_ref (SCM v, size_t idx)
632{
633 scm_t_array_handle handle;
4330ee25
MV
634 size_t len;
635 ssize_t inc;
636 SCM res;
637
4e8ad323 638 uvec_elements (-1, v, &handle, &len, &inc);
4330ee25
MV
639 if (idx >= len)
640 scm_out_of_range (NULL, scm_from_size_t (idx));
4e8ad323 641 res = scm_array_handle_ref (&handle, idx*inc);
4330ee25
MV
642 scm_array_handle_release (&handle);
643 return res;
644}
645
e0e49670
MV
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{
4330ee25 652#if SCM_ENABLE_DEPRECATED
e0e49670
MV
653 /* Support old argument convention.
654 */
655 if (scm_is_pair (idx))
656 {
4330ee25
MV
657 scm_c_issue_deprecation_warning
658 ("Using a list as the index to uniform-vector-ref is deprecated.");
e0e49670
MV
659 if (!scm_is_null (SCM_CDR (idx)))
660 scm_wrong_num_args (NULL);
661 idx = SCM_CAR (idx);
662 }
4330ee25 663#endif
e0e49670 664
4330ee25 665 return scm_c_uniform_vector_ref (v, scm_to_size_t (idx));
e0e49670
MV
666}
667#undef FUNC_NAME
668
4330ee25
MV
669void
670scm_c_uniform_vector_set_x (SCM v, size_t idx, SCM val)
811eb6d0 671{
4330ee25 672 scm_t_array_handle handle;
4330ee25
MV
673 size_t len;
674 ssize_t inc;
675
4e8ad323 676 uvec_writable_elements (-1, v, &handle, &len, &inc);
4330ee25
MV
677 if (idx >= len)
678 scm_out_of_range (NULL, scm_from_size_t (idx));
4e8ad323 679 scm_array_handle_set (&handle, idx*inc, val);
4330ee25 680 scm_array_handle_release (&handle);
811eb6d0
MV
681}
682
e0e49670
MV
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{
4330ee25 689#if SCM_ENABLE_DEPRECATED
e0e49670
MV
690 /* Support old argument convention.
691 */
692 if (scm_is_pair (idx))
693 {
4330ee25
MV
694 scm_c_issue_deprecation_warning
695 ("Using a list as the index to uniform-vector-set! is deprecated.");
e0e49670
MV
696 if (!scm_is_null (SCM_CDR (idx)))
697 scm_wrong_num_args (NULL);
698 idx = SCM_CAR (idx);
699 }
4330ee25 700#endif
e0e49670 701
4330ee25
MV
702 scm_c_uniform_vector_set_x (v, scm_to_size_t (idx), val);
703 return SCM_UNSPECIFIED;
e0e49670
MV
704}
705#undef FUNC_NAME
706
707SCM_DEFINE (scm_uniform_vector_to_list, "uniform-vector->list", 1, 0, 0,
708 (SCM uvec),
69d2000d 709 "Convert the uniform numeric vector @var{uvec} to a list.")
811eb6d0 710#define FUNC_NAME s_scm_uniform_vector_to_list
e0e49670 711{
4330ee25 712 return uvec_to_list (-1, uvec);
e0e49670
MV
713}
714#undef FUNC_NAME
715
6e708ef2 716size_t
fea99690 717scm_array_handle_uniform_element_size (scm_t_array_handle *h)
e0e49670 718{
fea99690 719 SCM vec = h->array;
04b87de5
MV
720 if (SCM_I_ARRAYP (vec))
721 vec = SCM_I_ARRAY_V (vec);
fea99690
MV
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");
e0e49670 725}
7c2ef9a8
MV
726
727#if SCM_ENABLE_DEPRECATED
fea99690 728
6e708ef2
MV
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)
e0e49670 733{
7c2ef9a8
MV
734 scm_c_issue_deprecation_warning
735 ("scm_uniform_element_size is deprecated. "
736 "Use scm_array_handle_uniform_element_size instead.");
737
4330ee25 738 if (SCM_IS_UVEC (obj))
fea99690 739 return uvec_sizes[SCM_UVEC_TYPE(obj)];
6e708ef2
MV
740 else
741 return 0;
e0e49670
MV
742}
743
7c2ef9a8
MV
744#endif
745
6e708ef2
MV
746const void *
747scm_array_handle_uniform_elements (scm_t_array_handle *h)
d44ff083 748{
6e708ef2 749 return scm_array_handle_uniform_writable_elements (h);
d44ff083
MV
750}
751
b590aceb 752void *
6e708ef2 753scm_array_handle_uniform_writable_elements (scm_t_array_handle *h)
b590aceb 754{
6e708ef2 755 SCM vec = h->array;
04b87de5
MV
756 if (SCM_I_ARRAYP (vec))
757 vec = SCM_I_ARRAY_V (vec);
4330ee25 758 if (SCM_IS_UVEC (vec))
6e708ef2
MV
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");
b590aceb
MV
765}
766
6e708ef2
MV
767const void *
768scm_uniform_vector_elements (SCM uvec,
769 scm_t_array_handle *h,
770 size_t *lenp, ssize_t *incp)
b590aceb 771{
6e708ef2 772 return scm_uniform_vector_writable_elements (uvec, h, lenp, incp);
b590aceb
MV
773}
774
6e708ef2
MV
775void *
776scm_uniform_vector_writable_elements (SCM uvec,
777 scm_t_array_handle *h,
778 size_t *lenp, ssize_t *incp)
e0e49670 779{
fea99690 780 scm_generalized_vector_get_handle (uvec, h);
6e708ef2
MV
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);
e0e49670
MV
788}
789
790SCM_DEFINE (scm_uniform_vector_length, "uniform-vector-length", 1, 0, 0,
791 (SCM v),
811eb6d0 792 "Return the number of elements in the uniform vector @var{v}.")
e0e49670
MV
793#define FUNC_NAME s_scm_uniform_vector_length
794{
4330ee25 795 return uvec_length (-1, v);
e0e49670
MV
796}
797#undef FUNC_NAME
798
69730f92
MV
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"
6e708ef2
MV
814 "@code{uniform-vector-read!} returns the number of elements\n"
815 "read.\n\n"
69730f92
MV
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{
6e708ef2 820 scm_t_array_handle handle;
69730f92 821 size_t vlen, sz, ans;
6e708ef2 822 ssize_t inc;
69730f92
MV
823 size_t cstart, cend;
824 size_t remaining, off;
2b829bbb 825 char *base;
69730f92
MV
826
827 if (SCM_UNBNDP (port_or_fd))
9de87eea 828 port_or_fd = scm_current_input_port ();
69730f92
MV
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
6e708ef2
MV
834 if (!scm_is_uniform_vector (uvec))
835 scm_wrong_type_arg_msg (NULL, 0, uvec, "uniform vector");
69730f92 836
6e708ef2 837 base = scm_uniform_vector_writable_elements (uvec, &handle, &vlen, &inc);
fea99690 838 sz = scm_array_handle_uniform_element_size (&handle);
6e708ef2
MV
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 }
69730f92
MV
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 {
69730f92 861 ans = cend - cstart;
b5cb4464
NJ
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;
69730f92
MV
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
fea99690
MV
880 scm_array_handle_release (&handle);
881
69730f92
MV
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{
6e708ef2 906 scm_t_array_handle handle;
69730f92 907 size_t vlen, sz, ans;
6e708ef2 908 ssize_t inc;
69730f92
MV
909 size_t cstart, cend;
910 size_t amount, off;
2b829bbb 911 const char *base;
69730f92
MV
912
913 port_or_fd = SCM_COERCE_OUTPORT (port_or_fd);
914
915 if (SCM_UNBNDP (port_or_fd))
9de87eea 916 port_or_fd = scm_current_output_port ();
69730f92
MV
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
6e708ef2 922 base = scm_uniform_vector_elements (uvec, &handle, &vlen, &inc);
fea99690 923 sz = scm_array_handle_uniform_element_size (&handle);
6e708ef2
MV
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 }
69730f92
MV
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
fea99690
MV
960 scm_array_handle_release (&handle);
961
69730f92
MV
962 return scm_from_size_t (ans);
963}
964#undef FUNC_NAME
965
f8579182
MV
966/* ================================================================ */
967/* Exported procedures. */
968/* ================================================================ */
969
e0e49670
MV
970#define TYPE SCM_UVEC_U8
971#define TAG u8
972#define CTYPE scm_t_uint8
f8579182
MV
973#include "libguile/srfi-4.i.c"
974
e0e49670
MV
975#define TYPE SCM_UVEC_S8
976#define TAG s8
977#define CTYPE scm_t_int8
f8579182
MV
978#include "libguile/srfi-4.i.c"
979
e0e49670
MV
980#define TYPE SCM_UVEC_U16
981#define TAG u16
982#define CTYPE scm_t_uint16
f8579182
MV
983#include "libguile/srfi-4.i.c"
984
e0e49670
MV
985#define TYPE SCM_UVEC_S16
986#define TAG s16
987#define CTYPE scm_t_int16
f8579182
MV
988#include "libguile/srfi-4.i.c"
989
e0e49670
MV
990#define TYPE SCM_UVEC_U32
991#define TAG u32
992#define CTYPE scm_t_uint32
f8579182
MV
993#include "libguile/srfi-4.i.c"
994
e0e49670
MV
995#define TYPE SCM_UVEC_S32
996#define TAG s32
997#define CTYPE scm_t_int32
f8579182
MV
998#include "libguile/srfi-4.i.c"
999
e0e49670
MV
1000#define TYPE SCM_UVEC_U64
1001#define TAG u64
00c17d45 1002#if SCM_HAVE_T_UINT64
e0e49670 1003#define CTYPE scm_t_uint64
00c17d45 1004#endif
f8579182
MV
1005#include "libguile/srfi-4.i.c"
1006
e0e49670
MV
1007#define TYPE SCM_UVEC_S64
1008#define TAG s64
00c17d45 1009#if SCM_HAVE_T_INT64
e0e49670 1010#define CTYPE scm_t_int64
00c17d45 1011#endif
f8579182
MV
1012#include "libguile/srfi-4.i.c"
1013
e0e49670
MV
1014#define TYPE SCM_UVEC_F32
1015#define TAG f32
1016#define CTYPE float
f8579182
MV
1017#include "libguile/srfi-4.i.c"
1018
e0e49670
MV
1019#define TYPE SCM_UVEC_F64
1020#define TAG f64
1021#define CTYPE double
f8579182
MV
1022#include "libguile/srfi-4.i.c"
1023
cbdc8379
MV
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
4ea4bc4c
MV
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
f8579182
MV
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);
f8579182 1069 scm_set_smob_print (scm_tc16_uvec, uvec_print);
f301dbf3 1070
00c17d45
MV
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
f8579182 1082#include "libguile/srfi-4.x"
cbdc8379 1083
f8579182
MV
1084}
1085
1086/* End of srfi-4.c. */