(scm_array_handle_ref, scm_array_handle_set): Changed
[bpt/guile.git] / libguile / unif.c
1 /* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18
19 /*
20 This file has code for arrays in lots of variants (double, integer,
21 unsigned etc. ). It suffers from hugely repetitive code because
22 there is similar (but different) code for every variant included. (urg.)
23
24 --hwn
25 */
26 \f
27
28 #if HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35
36 #include "libguile/_scm.h"
37 #include "libguile/__scm.h"
38 #include "libguile/eq.h"
39 #include "libguile/chars.h"
40 #include "libguile/eval.h"
41 #include "libguile/fports.h"
42 #include "libguile/smob.h"
43 #include "libguile/feature.h"
44 #include "libguile/root.h"
45 #include "libguile/strings.h"
46 #include "libguile/srfi-13.h"
47 #include "libguile/srfi-4.h"
48 #include "libguile/vectors.h"
49 #include "libguile/list.h"
50 #include "libguile/deprecation.h"
51 #include "libguile/dynwind.h"
52
53 #include "libguile/validate.h"
54 #include "libguile/unif.h"
55 #include "libguile/ramap.h"
56 #include "libguile/print.h"
57 #include "libguile/read.h"
58
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62
63 #ifdef HAVE_IO_H
64 #include <io.h>
65 #endif
66
67 \f
68 /* The set of uniform scm_vector types is:
69 * Vector of: Called: Replaced by:
70 * unsigned char string
71 * char byvect s8 or u8, depending on signedness of 'char'
72 * boolean bvect
73 * signed long ivect s32
74 * unsigned long uvect u32
75 * float fvect f32
76 * double dvect d32
77 * complex double cvect c64
78 * short svect s16
79 * long long llvect s64
80 */
81
82 scm_t_bits scm_tc16_array;
83 scm_t_bits scm_tc16_enclosed_array;
84
85 typedef SCM creator_proc (SCM len, SCM fill);
86
87 struct {
88 char *type_name;
89 SCM type;
90 creator_proc *creator;
91 } type_creator_table[] = {
92 { "a", SCM_UNSPECIFIED, scm_make_string },
93 { "b", SCM_UNSPECIFIED, scm_make_bitvector },
94 { "u8", SCM_UNSPECIFIED, scm_make_u8vector },
95 { "s8", SCM_UNSPECIFIED, scm_make_s8vector },
96 { "u16", SCM_UNSPECIFIED, scm_make_u16vector },
97 { "s16", SCM_UNSPECIFIED, scm_make_s16vector },
98 { "u32", SCM_UNSPECIFIED, scm_make_u32vector },
99 { "s32", SCM_UNSPECIFIED, scm_make_s32vector },
100 { "u64", SCM_UNSPECIFIED, scm_make_u64vector },
101 { "s64", SCM_UNSPECIFIED, scm_make_s64vector },
102 { "f32", SCM_UNSPECIFIED, scm_make_f32vector },
103 { "f64", SCM_UNSPECIFIED, scm_make_f64vector },
104 { "c32", SCM_UNSPECIFIED, scm_make_c32vector },
105 { "c64", SCM_UNSPECIFIED, scm_make_c64vector },
106 { NULL }
107 };
108
109 static void
110 init_type_creator_table ()
111 {
112 int i;
113 for (i = 0; type_creator_table[i].type_name; i++)
114 {
115 SCM sym = scm_from_locale_symbol (type_creator_table[i].type_name);
116 type_creator_table[i].type = scm_permanent_object (sym);
117 }
118 }
119
120 static creator_proc *
121 type_to_creator (SCM type)
122 {
123 int i;
124
125 if (scm_is_eq (type, SCM_BOOL_T))
126 return scm_make_vector;
127 for (i = 0; type_creator_table[i].type_name; i++)
128 if (scm_is_eq (type, type_creator_table[i].type))
129 return type_creator_table[i].creator;
130
131 scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (type));
132 }
133
134 static SCM
135 make_typed_vector (SCM type, size_t len)
136 {
137 creator_proc *creator = type_to_creator (type);
138 return creator (scm_from_size_t (len), SCM_UNDEFINED);
139 }
140
141 #if SCM_ENABLE_DEPRECATED
142
143 SCM_SYMBOL (scm_sym_s, "s");
144 SCM_SYMBOL (scm_sym_l, "l");
145
146 static SCM
147 prototype_to_type (SCM proto)
148 {
149 const char *type_name;
150
151 if (scm_is_eq (proto, SCM_BOOL_T))
152 type_name = "b";
153 else if (scm_is_eq (proto, SCM_MAKE_CHAR ('a')))
154 type_name = "a";
155 else if (scm_is_eq (proto, SCM_MAKE_CHAR (0)))
156 type_name = "s8";
157 else if (scm_is_eq (proto, scm_sym_s))
158 type_name = "s16";
159 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (1))))
160 type_name = "u32";
161 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (-1))))
162 type_name = "s32";
163 else if (scm_is_eq (proto, scm_sym_l))
164 type_name = "s64";
165 else if (scm_is_true (scm_eqv_p (proto, scm_from_double (1.0))))
166 type_name = "f32";
167 else if (scm_is_true (scm_eqv_p (proto, scm_divide (scm_from_int (1),
168 scm_from_int (3)))))
169 type_name = "f64";
170 else if (scm_is_true (scm_eqv_p (proto, scm_c_make_rectangular (0, 1))))
171 type_name = "c64";
172 else if (scm_is_null (proto))
173 type_name = NULL;
174 else
175 type_name = NULL;
176
177 if (type_name)
178 return scm_from_locale_symbol (type_name);
179 else
180 return SCM_BOOL_T;
181 }
182
183 static SCM
184 scm_i_get_old_prototype (SCM uvec)
185 {
186 if (scm_is_bitvector (uvec))
187 return SCM_BOOL_T;
188 else if (scm_is_string (uvec))
189 return SCM_MAKE_CHAR ('a');
190 else if (scm_is_true (scm_s8vector_p (uvec)))
191 return SCM_MAKE_CHAR ('\0');
192 else if (scm_is_true (scm_s16vector_p (uvec)))
193 return scm_sym_s;
194 else if (scm_is_true (scm_u32vector_p (uvec)))
195 return scm_from_int (1);
196 else if (scm_is_true (scm_s32vector_p (uvec)))
197 return scm_from_int (-1);
198 else if (scm_is_true (scm_s64vector_p (uvec)))
199 return scm_sym_l;
200 else if (scm_is_true (scm_f32vector_p (uvec)))
201 return scm_from_double (1.0);
202 else if (scm_is_true (scm_f64vector_p (uvec)))
203 return scm_divide (scm_from_int (1), scm_from_int (3));
204 else if (scm_is_true (scm_c64vector_p (uvec)))
205 return scm_c_make_rectangular (0, 1);
206 else if (scm_is_vector (uvec))
207 return SCM_EOL;
208 else
209 scm_misc_error (NULL, "~a has no prototype", scm_list_1 (uvec));
210 }
211
212 SCM
213 scm_make_uve (long k, SCM prot)
214 #define FUNC_NAME "scm_make_uve"
215 {
216 scm_c_issue_deprecation_warning
217 ("`scm_make_uve' is deprecated, see the manual for alternatives.");
218
219 return make_typed_vector (prototype_to_type (prot), k);
220 }
221 #undef FUNC_NAME
222
223 #endif
224
225 int
226 scm_is_array (SCM obj)
227 {
228 return (SCM_ENCLOSED_ARRAYP (obj)
229 || SCM_ARRAYP (obj)
230 || scm_is_generalized_vector (obj));
231 }
232
233 int
234 scm_is_typed_array (SCM obj, SCM type)
235 {
236 if (SCM_ENCLOSED_ARRAYP (obj))
237 {
238 /* Enclosed arrays are arrays but are not of any type.
239 */
240 return 0;
241 }
242
243 /* Get storage vector.
244 */
245 if (SCM_ARRAYP (obj))
246 obj = SCM_ARRAY_V (obj);
247
248 /* It must be a generalized vector (which includes vectors, strings, etc).
249 */
250 if (!scm_is_generalized_vector (obj))
251 return 0;
252
253 return scm_is_eq (type, scm_i_generalized_vector_type (obj));
254 }
255
256 void
257 scm_array_get_handle (SCM array, scm_t_array_handle *h)
258 {
259 h->array = array;
260 if (SCM_ARRAYP (array) || SCM_ENCLOSED_ARRAYP (array))
261 {
262 h->dims = SCM_ARRAY_DIMS (array);
263 h->base = SCM_ARRAY_BASE (array);
264 }
265 else if (scm_is_generalized_vector (array))
266 {
267 h->dim0.lbnd = 0;
268 h->dim0.ubnd = scm_c_generalized_vector_length (array) - 1;
269 h->dim0.inc = 1;
270 h->dims = &h->dim0;
271 h->base = 0;
272 }
273 else
274 scm_wrong_type_arg_msg (NULL, 0, array, "array");
275 }
276
277 void
278 scm_array_handle_release (scm_t_array_handle *h)
279 {
280 /* Nothing to do here until arrays need to be reserved for real.
281 */
282 }
283
284 size_t
285 scm_array_handle_rank (scm_t_array_handle *h)
286 {
287 if (SCM_ARRAYP (h->array) || SCM_ENCLOSED_ARRAYP (h->array))
288 return SCM_ARRAY_NDIM (h->array);
289 else
290 return 1;
291 }
292
293 scm_t_array_dim *
294 scm_array_handle_dims (scm_t_array_handle *h)
295 {
296 return h->dims;
297 }
298
299 SCM
300 scm_array_handle_ref (scm_t_array_handle *h, ssize_t pos)
301 {
302 pos += h->base;
303 if (SCM_ARRAYP (h->array))
304 return scm_i_cvref (SCM_ARRAY_V (h->array), pos, 0);
305 if (SCM_ENCLOSED_ARRAYP (h->array))
306 return scm_i_cvref (SCM_ARRAY_V (h->array), pos, 1);
307 return scm_c_generalized_vector_ref (h->array, pos);
308 }
309
310 void
311 scm_array_handle_set (scm_t_array_handle *h, ssize_t pos, SCM val)
312 {
313 pos += h->base;
314 if (SCM_ARRAYP (h->array))
315 scm_c_generalized_vector_set_x (SCM_ARRAY_V (h->array), pos, val);
316 if (SCM_ENCLOSED_ARRAYP (h->array))
317 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-enclosed array");
318 scm_c_generalized_vector_set_x (h->array, pos, val);
319 }
320
321 const SCM *
322 scm_array_handle_elements (scm_t_array_handle *h)
323 {
324 SCM vec = h->array;
325 if (SCM_ARRAYP (vec))
326 vec = SCM_ARRAY_V (vec);
327 if (SCM_I_IS_VECTOR (vec))
328 return SCM_I_VECTOR_ELTS (vec) + h->base;
329 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
330 }
331
332 SCM *
333 scm_array_handle_writable_elements (scm_t_array_handle *h)
334 {
335 SCM vec = h->array;
336 if (SCM_ARRAYP (vec))
337 vec = SCM_ARRAY_V (vec);
338 if (SCM_I_IS_VECTOR (vec))
339 return SCM_I_VECTOR_WELTS (vec) + h->base;
340 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
341 }
342
343 void
344 scm_generalized_vector_get_handle (SCM vec, scm_t_array_handle *h)
345 {
346 scm_array_get_handle (vec, h);
347 if (scm_array_handle_rank (h) != 1)
348 scm_wrong_type_arg_msg (NULL, 0, vec, "vector");
349 }
350
351 const SCM *
352 scm_vector_elements (SCM vec, scm_t_array_handle *h,
353 size_t *lenp, ssize_t *incp)
354 {
355 scm_generalized_vector_get_handle (vec, h);
356 if (lenp)
357 {
358 scm_t_array_dim *dim = scm_array_handle_dims (h);
359 *lenp = dim->ubnd - dim->lbnd + 1;
360 *incp = dim->inc;
361 }
362 return scm_array_handle_elements (h);
363 }
364
365 SCM *
366 scm_vector_writable_elements (SCM vec, scm_t_array_handle *h,
367 size_t *lenp, ssize_t *incp)
368 {
369 scm_generalized_vector_get_handle (vec, h);
370 if (lenp)
371 {
372 scm_t_array_dim *dim = scm_array_handle_dims (h);
373 *lenp = dim->ubnd - dim->lbnd + 1;
374 *incp = dim->inc;
375 }
376 return scm_array_handle_writable_elements (h);
377 }
378
379 #if SCM_ENABLE_DEPRECATED
380
381 SCM_DEFINE (scm_array_p, "array?", 1, 1, 0,
382 (SCM obj, SCM prot),
383 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
384 "not.")
385 #define FUNC_NAME s_scm_array_p
386 {
387 if (!SCM_UNBNDP (prot))
388 {
389 scm_c_issue_deprecation_warning
390 ("Using prototypes with `array?' is deprecated."
391 " Use `typed-array?' instead.");
392
393 return scm_typed_array_p (obj, prototype_to_type (prot));
394 }
395 else
396 return scm_from_bool (scm_is_array (obj));
397 }
398 #undef FUNC_NAME
399
400 #else /* !SCM_ENABLE_DEPRECATED */
401
402 /* We keep the old 2-argument C prototype for a while although the old
403 PROT argument is always ignored now. C code should probably use
404 scm_is_array or scm_is_typed_array anyway.
405 */
406
407 static SCM scm_i_array_p (SCM obj);
408
409 SCM_DEFINE (scm_i_array_p, "array?", 1, 0, 0,
410 (SCM obj),
411 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
412 "not.")
413 #define FUNC_NAME s_scm_i_array_p
414 {
415 return scm_from_bool (scm_is_array (obj));
416 }
417 #undef FUNC_NAME
418
419 SCM
420 scm_array_p (SCM obj, SCM prot)
421 {
422 return scm_from_bool (scm_is_array (obj));
423 }
424
425 #endif /* !SCM_ENABLE_DEPRECATED */
426
427
428 SCM_DEFINE (scm_typed_array_p, "typed-array?", 2, 0, 0,
429 (SCM obj, SCM type),
430 "Return @code{#t} if the @var{obj} is an array of type\n"
431 "@var{type}, and @code{#f} if not.")
432 #define FUNC_NAME s_scm_typed_array_p
433 {
434 return scm_from_bool (scm_is_typed_array (obj, type));
435 }
436 #undef FUNC_NAME
437
438
439 SCM_DEFINE (scm_array_rank, "array-rank", 1, 0, 0,
440 (SCM array),
441 "Return the number of dimensions of the array @var{array.}\n")
442 #define FUNC_NAME s_scm_array_rank
443 {
444 if (scm_is_generalized_vector (array))
445 return scm_from_int (1);
446
447 if (SCM_ARRAYP (array) || SCM_ENCLOSED_ARRAYP (array))
448 return scm_from_size_t (SCM_ARRAY_NDIM (array));
449
450 scm_wrong_type_arg_msg (NULL, 0, array, "array");
451 }
452 #undef FUNC_NAME
453
454
455 SCM_DEFINE (scm_array_dimensions, "array-dimensions", 1, 0, 0,
456 (SCM ra),
457 "@code{array-dimensions} is similar to @code{array-shape} but replaces\n"
458 "elements with a @code{0} minimum with one greater than the maximum. So:\n"
459 "@lisp\n"
460 "(array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) 5)\n"
461 "@end lisp")
462 #define FUNC_NAME s_scm_array_dimensions
463 {
464 if (scm_is_generalized_vector (ra))
465 return scm_list_1 (scm_generalized_vector_length (ra));
466
467 if (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra))
468 {
469 SCM res = SCM_EOL;
470 size_t k;
471 scm_t_array_dim *s;
472
473 k = SCM_ARRAY_NDIM (ra);
474 s = SCM_ARRAY_DIMS (ra);
475 while (k--)
476 res = scm_cons (s[k].lbnd
477 ? scm_cons2 (scm_from_long (s[k].lbnd),
478 scm_from_long (s[k].ubnd),
479 SCM_EOL)
480 : scm_from_long (1 + s[k].ubnd),
481 res);
482 return res;
483 }
484
485 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
486 }
487 #undef FUNC_NAME
488
489
490 SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
491 (SCM ra),
492 "Return the root vector of a shared array.")
493 #define FUNC_NAME s_scm_shared_array_root
494 {
495 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
496 SCM_ARG1, FUNC_NAME);
497 return SCM_ARRAY_V (ra);
498 }
499 #undef FUNC_NAME
500
501
502 SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
503 (SCM ra),
504 "Return the root vector index of the first element in the array.")
505 #define FUNC_NAME s_scm_shared_array_offset
506 {
507 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
508 SCM_ARG1, FUNC_NAME);
509 return scm_from_int (SCM_ARRAY_BASE (ra));
510 }
511 #undef FUNC_NAME
512
513
514 SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
515 (SCM ra),
516 "For each dimension, return the distance between elements in the root vector.")
517 #define FUNC_NAME s_scm_shared_array_increments
518 {
519 SCM res = SCM_EOL;
520 size_t k;
521 scm_t_array_dim *s;
522
523 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
524 SCM_ARG1, FUNC_NAME);
525 k = SCM_ARRAY_NDIM (ra);
526 s = SCM_ARRAY_DIMS (ra);
527 while (k--)
528 res = scm_cons (scm_from_long (s[k].inc), res);
529 return res;
530 }
531 #undef FUNC_NAME
532
533
534 static char s_bad_ind[] = "Bad scm_array index";
535
536
537 long
538 scm_aind (SCM ra, SCM args, const char *what)
539 {
540 SCM ind;
541 register long j;
542 register unsigned long pos = SCM_ARRAY_BASE (ra);
543 register unsigned long k = SCM_ARRAY_NDIM (ra);
544 scm_t_array_dim *s = SCM_ARRAY_DIMS (ra);
545
546 if (scm_is_integer (args))
547 {
548 if (k != 1)
549 scm_error_num_args_subr (what);
550 return pos + (scm_to_long (args) - s->lbnd) * (s->inc);
551 }
552 while (k && scm_is_pair (args))
553 {
554 ind = SCM_CAR (args);
555 args = SCM_CDR (args);
556 if (!scm_is_integer (ind))
557 scm_misc_error (what, s_bad_ind, SCM_EOL);
558 j = scm_to_long (ind);
559 if (j < s->lbnd || j > s->ubnd)
560 scm_out_of_range (what, ind);
561 pos += (j - s->lbnd) * (s->inc);
562 k--;
563 s++;
564 }
565 if (k != 0 || !scm_is_null (args))
566 scm_error_num_args_subr (what);
567
568 return pos;
569 }
570
571
572 static SCM
573 scm_i_make_ra (int ndim, scm_t_bits tag)
574 {
575 SCM ra;
576 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + tag,
577 scm_gc_malloc ((sizeof (scm_t_array) +
578 ndim * sizeof (scm_t_array_dim)),
579 "array"));
580 SCM_ARRAY_V (ra) = SCM_BOOL_F;
581 return ra;
582 }
583
584 SCM
585 scm_make_ra (int ndim)
586 {
587 return scm_i_make_ra (ndim, scm_tc16_array);
588 }
589
590
591 static char s_bad_spec[] = "Bad scm_array dimension";
592
593
594 /* Increments will still need to be set. */
595
596 SCM
597 scm_shap2ra (SCM args, const char *what)
598 {
599 scm_t_array_dim *s;
600 SCM ra, spec, sp;
601 int ndim = scm_ilength (args);
602 if (ndim < 0)
603 scm_misc_error (what, s_bad_spec, SCM_EOL);
604
605 ra = scm_make_ra (ndim);
606 SCM_ARRAY_BASE (ra) = 0;
607 s = SCM_ARRAY_DIMS (ra);
608 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
609 {
610 spec = SCM_CAR (args);
611 if (scm_is_integer (spec))
612 {
613 if (scm_to_long (spec) < 0)
614 scm_misc_error (what, s_bad_spec, SCM_EOL);
615 s->lbnd = 0;
616 s->ubnd = scm_to_long (spec) - 1;
617 s->inc = 1;
618 }
619 else
620 {
621 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
622 scm_misc_error (what, s_bad_spec, SCM_EOL);
623 s->lbnd = scm_to_long (SCM_CAR (spec));
624 sp = SCM_CDR (spec);
625 if (!scm_is_pair (sp)
626 || !scm_is_integer (SCM_CAR (sp))
627 || !scm_is_null (SCM_CDR (sp)))
628 scm_misc_error (what, s_bad_spec, SCM_EOL);
629 s->ubnd = scm_to_long (SCM_CAR (sp));
630 s->inc = 1;
631 }
632 }
633 return ra;
634 }
635
636 SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
637 (SCM type, SCM fill, SCM bounds),
638 "Create and return an array of type @var{type}.")
639 #define FUNC_NAME s_scm_make_typed_array
640 {
641 size_t k, rlen = 1;
642 scm_t_array_dim *s;
643 creator_proc *creator;
644 SCM ra;
645
646 creator = type_to_creator (type);
647 ra = scm_shap2ra (bounds, FUNC_NAME);
648 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
649 s = SCM_ARRAY_DIMS (ra);
650 k = SCM_ARRAY_NDIM (ra);
651
652 while (k--)
653 {
654 s[k].inc = rlen;
655 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd);
656 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
657 }
658
659 if (scm_is_eq (fill, SCM_UNSPECIFIED))
660 fill = SCM_UNDEFINED;
661
662 SCM_ARRAY_V (ra) = creator (scm_from_size_t (rlen), fill);
663
664 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
665 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
666 return SCM_ARRAY_V (ra);
667 return ra;
668 }
669 #undef FUNC_NAME
670
671 SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
672 (SCM fill, SCM bounds),
673 "Create and return an array.")
674 #define FUNC_NAME s_scm_make_array
675 {
676 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
677 }
678 #undef FUNC_NAME
679
680 #if SCM_ENABLE_DEPRECATED
681
682 SCM_DEFINE (scm_dimensions_to_uniform_array, "dimensions->uniform-array", 2, 1, 0,
683 (SCM dims, SCM prot, SCM fill),
684 "@deffnx {Scheme Procedure} make-uniform-vector length prototype [fill]\n"
685 "Create and return a uniform array or vector of type\n"
686 "corresponding to @var{prototype} with dimensions @var{dims} or\n"
687 "length @var{length}. If @var{fill} is supplied, it's used to\n"
688 "fill the array, otherwise @var{prototype} is used.")
689 #define FUNC_NAME s_scm_dimensions_to_uniform_array
690 {
691 scm_c_issue_deprecation_warning
692 ("`dimensions->uniform-array' is deprecated. "
693 "Use `make-typed-array' instead.");
694
695 if (scm_is_integer (dims))
696 dims = scm_list_1 (dims);
697 return scm_make_typed_array (prototype_to_type (prot), fill, dims);
698 }
699 #undef FUNC_NAME
700
701 #endif
702
703 void
704 scm_ra_set_contp (SCM ra)
705 {
706 /* XXX - correct? one-dimensional arrays are always 'contiguous',
707 is that right?
708 */
709 size_t k = SCM_ARRAY_NDIM (ra);
710 if (k)
711 {
712 long inc = SCM_ARRAY_DIMS (ra)[k - 1].inc;
713 while (k--)
714 {
715 if (inc != SCM_ARRAY_DIMS (ra)[k].inc)
716 {
717 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
718 return;
719 }
720 inc *= (SCM_ARRAY_DIMS (ra)[k].ubnd
721 - SCM_ARRAY_DIMS (ra)[k].lbnd + 1);
722 }
723 }
724 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
725 }
726
727
728 SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
729 (SCM oldra, SCM mapfunc, SCM dims),
730 "@code{make-shared-array} can be used to create shared subarrays of other\n"
731 "arrays. The @var{mapper} is a function that translates coordinates in\n"
732 "the new array into coordinates in the old array. A @var{mapper} must be\n"
733 "linear, and its range must stay within the bounds of the old array, but\n"
734 "it can be otherwise arbitrary. A simple example:\n"
735 "@lisp\n"
736 "(define fred (make-array #f 8 8))\n"
737 "(define freds-diagonal\n"
738 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
739 "(array-set! freds-diagonal 'foo 3)\n"
740 "(array-ref fred 3 3) @result{} foo\n"
741 "(define freds-center\n"
742 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
743 "(array-ref freds-center 0 0) @result{} foo\n"
744 "@end lisp")
745 #define FUNC_NAME s_scm_make_shared_array
746 {
747 SCM ra;
748 SCM inds, indptr;
749 SCM imap;
750 size_t k, i;
751 long old_min, new_min, old_max, new_max;
752 scm_t_array_dim *s;
753
754 SCM_VALIDATE_REST_ARGUMENT (dims);
755 SCM_VALIDATE_ARRAY (1, oldra);
756 SCM_VALIDATE_PROC (2, mapfunc);
757 ra = scm_shap2ra (dims, FUNC_NAME);
758 if (SCM_ARRAYP (oldra))
759 {
760 SCM_ARRAY_V (ra) = SCM_ARRAY_V (oldra);
761 old_min = old_max = SCM_ARRAY_BASE (oldra);
762 s = SCM_ARRAY_DIMS (oldra);
763 k = SCM_ARRAY_NDIM (oldra);
764 while (k--)
765 {
766 if (s[k].inc > 0)
767 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
768 else
769 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
770 }
771 }
772 else
773 {
774 SCM_ARRAY_V (ra) = oldra;
775 old_min = 0;
776 old_max = scm_c_generalized_vector_length (oldra) - 1;
777 }
778 inds = SCM_EOL;
779 s = SCM_ARRAY_DIMS (ra);
780 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
781 {
782 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
783 if (s[k].ubnd < s[k].lbnd)
784 {
785 if (1 == SCM_ARRAY_NDIM (ra))
786 ra = make_typed_vector (scm_array_type (ra), 0);
787 else
788 SCM_ARRAY_V (ra) = make_typed_vector (scm_array_type (ra), 0);
789 return ra;
790 }
791 }
792 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
793 if (SCM_ARRAYP (oldra))
794 i = (size_t) scm_aind (oldra, imap, FUNC_NAME);
795 else
796 {
797 if (!scm_is_integer (imap))
798 {
799 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
800 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
801 imap = SCM_CAR (imap);
802 }
803 i = scm_to_size_t (imap);
804 }
805 SCM_ARRAY_BASE (ra) = new_min = new_max = i;
806 indptr = inds;
807 k = SCM_ARRAY_NDIM (ra);
808 while (k--)
809 {
810 if (s[k].ubnd > s[k].lbnd)
811 {
812 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
813 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
814 if (SCM_ARRAYP (oldra))
815
816 s[k].inc = scm_aind (oldra, imap, FUNC_NAME) - i;
817 else
818 {
819 if (!scm_is_integer (imap))
820 {
821 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
822 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
823 imap = SCM_CAR (imap);
824 }
825 s[k].inc = scm_to_long (imap) - i;
826 }
827 i += s[k].inc;
828 if (s[k].inc > 0)
829 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
830 else
831 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
832 }
833 else
834 s[k].inc = new_max - new_min + 1; /* contiguous by default */
835 indptr = SCM_CDR (indptr);
836 }
837 if (old_min > new_min || old_max < new_max)
838 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
839 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
840 {
841 SCM v = SCM_ARRAY_V (ra);
842 size_t length = scm_c_generalized_vector_length (v);
843 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
844 return v;
845 if (s->ubnd < s->lbnd)
846 return make_typed_vector (scm_array_type (ra), 0);
847 }
848 scm_ra_set_contp (ra);
849 return ra;
850 }
851 #undef FUNC_NAME
852
853
854 /* args are RA . DIMS */
855 SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
856 (SCM ra, SCM args),
857 "Return an array sharing contents with @var{array}, but with\n"
858 "dimensions arranged in a different order. There must be one\n"
859 "@var{dim} argument for each dimension of @var{array}.\n"
860 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
861 "and the rank of the array to be returned. Each integer in that\n"
862 "range must appear at least once in the argument list.\n"
863 "\n"
864 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
865 "dimensions in the array to be returned, their positions in the\n"
866 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
867 "may have the same value, in which case the returned array will\n"
868 "have smaller rank than @var{array}.\n"
869 "\n"
870 "@lisp\n"
871 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
872 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
873 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
874 " #2((a 4) (b 5) (c 6))\n"
875 "@end lisp")
876 #define FUNC_NAME s_scm_transpose_array
877 {
878 SCM res, vargs;
879 scm_t_array_dim *s, *r;
880 int ndim, i, k;
881
882 SCM_VALIDATE_REST_ARGUMENT (args);
883 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
884
885 if (scm_is_generalized_vector (ra))
886 {
887 /* Make sure that we are called with a single zero as
888 arguments.
889 */
890 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
891 SCM_WRONG_NUM_ARGS ();
892 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
893 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
894 return ra;
895 }
896
897 if (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra))
898 {
899 vargs = scm_vector (args);
900 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_ARRAY_NDIM (ra))
901 SCM_WRONG_NUM_ARGS ();
902 ndim = 0;
903 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
904 {
905 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
906 0, SCM_ARRAY_NDIM(ra));
907 if (ndim < i)
908 ndim = i;
909 }
910 ndim++;
911 res = scm_make_ra (ndim);
912 SCM_ARRAY_V (res) = SCM_ARRAY_V (ra);
913 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra);
914 for (k = ndim; k--;)
915 {
916 SCM_ARRAY_DIMS (res)[k].lbnd = 0;
917 SCM_ARRAY_DIMS (res)[k].ubnd = -1;
918 }
919 for (k = SCM_ARRAY_NDIM (ra); k--;)
920 {
921 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
922 s = &(SCM_ARRAY_DIMS (ra)[k]);
923 r = &(SCM_ARRAY_DIMS (res)[i]);
924 if (r->ubnd < r->lbnd)
925 {
926 r->lbnd = s->lbnd;
927 r->ubnd = s->ubnd;
928 r->inc = s->inc;
929 ndim--;
930 }
931 else
932 {
933 if (r->ubnd > s->ubnd)
934 r->ubnd = s->ubnd;
935 if (r->lbnd < s->lbnd)
936 {
937 SCM_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
938 r->lbnd = s->lbnd;
939 }
940 r->inc += s->inc;
941 }
942 }
943 if (ndim > 0)
944 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
945 scm_ra_set_contp (res);
946 return res;
947 }
948
949 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
950 }
951 #undef FUNC_NAME
952
953 /* args are RA . AXES */
954 SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
955 (SCM ra, SCM axes),
956 "@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than\n"
957 "the rank of @var{array}. @var{enclose-array} returns an array\n"
958 "resembling an array of shared arrays. The dimensions of each shared\n"
959 "array are the same as the @var{dim}th dimensions of the original array,\n"
960 "the dimensions of the outer array are the same as those of the original\n"
961 "array that did not match a @var{dim}.\n\n"
962 "An enclosed array is not a general Scheme array. Its elements may not\n"
963 "be set using @code{array-set!}. Two references to the same element of\n"
964 "an enclosed array will be @code{equal?} but will not in general be\n"
965 "@code{eq?}. The value returned by @var{array-prototype} when given an\n"
966 "enclosed array is unspecified.\n\n"
967 "examples:\n"
968 "@lisp\n"
969 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{}\n"
970 " #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>\n\n"
971 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{}\n"
972 " #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>\n"
973 "@end lisp")
974 #define FUNC_NAME s_scm_enclose_array
975 {
976 SCM axv, res, ra_inr;
977 const char *c_axv;
978 scm_t_array_dim vdim, *s = &vdim;
979 int ndim, j, k, ninr, noutr;
980
981 SCM_VALIDATE_REST_ARGUMENT (axes);
982 if (scm_is_null (axes))
983 axes = scm_cons ((SCM_ARRAYP (ra) ? scm_from_size_t (SCM_ARRAY_NDIM (ra) - 1) : SCM_INUM0), SCM_EOL);
984 ninr = scm_ilength (axes);
985 if (ninr < 0)
986 SCM_WRONG_NUM_ARGS ();
987 ra_inr = scm_make_ra (ninr);
988
989 if (scm_is_generalized_vector (ra))
990 {
991 s->lbnd = 0;
992 s->ubnd = scm_c_generalized_vector_length (ra) - 1;
993 s->inc = 1;
994 SCM_ARRAY_V (ra_inr) = ra;
995 SCM_ARRAY_BASE (ra_inr) = 0;
996 ndim = 1;
997 }
998 else if (SCM_ARRAYP (ra))
999 {
1000 s = SCM_ARRAY_DIMS (ra);
1001 SCM_ARRAY_V (ra_inr) = SCM_ARRAY_V (ra);
1002 SCM_ARRAY_BASE (ra_inr) = SCM_ARRAY_BASE (ra);
1003 ndim = SCM_ARRAY_NDIM (ra);
1004 }
1005 else
1006 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1007
1008 noutr = ndim - ninr;
1009 if (noutr < 0)
1010 SCM_WRONG_NUM_ARGS ();
1011 axv = scm_make_string (scm_from_int (ndim), SCM_MAKE_CHAR (0));
1012 res = scm_i_make_ra (noutr, scm_tc16_enclosed_array);
1013 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra_inr);
1014 SCM_ARRAY_V (res) = ra_inr;
1015 for (k = 0; k < ninr; k++, axes = SCM_CDR (axes))
1016 {
1017 if (!scm_is_integer (SCM_CAR (axes)))
1018 SCM_MISC_ERROR ("bad axis", SCM_EOL);
1019 j = scm_to_int (SCM_CAR (axes));
1020 SCM_ARRAY_DIMS (ra_inr)[k].lbnd = s[j].lbnd;
1021 SCM_ARRAY_DIMS (ra_inr)[k].ubnd = s[j].ubnd;
1022 SCM_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
1023 scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
1024 }
1025 c_axv = scm_i_string_chars (axv);
1026 for (j = 0, k = 0; k < noutr; k++, j++)
1027 {
1028 while (c_axv[j])
1029 j++;
1030 SCM_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
1031 SCM_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
1032 SCM_ARRAY_DIMS (res)[k].inc = s[j].inc;
1033 }
1034 scm_remember_upto_here_1 (axv);
1035 scm_ra_set_contp (ra_inr);
1036 scm_ra_set_contp (res);
1037 return res;
1038 }
1039 #undef FUNC_NAME
1040
1041
1042
1043 SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
1044 (SCM v, SCM args),
1045 "Return @code{#t} if its arguments would be acceptable to\n"
1046 "@code{array-ref}.")
1047 #define FUNC_NAME s_scm_array_in_bounds_p
1048 {
1049 SCM res = SCM_BOOL_T;
1050
1051 SCM_VALIDATE_REST_ARGUMENT (args);
1052
1053 if (scm_is_generalized_vector (v))
1054 {
1055 long ind;
1056
1057 if (!scm_is_pair (args))
1058 SCM_WRONG_NUM_ARGS ();
1059 ind = scm_to_long (SCM_CAR (args));
1060 args = SCM_CDR (args);
1061 res = scm_from_bool (ind >= 0
1062 && ind < scm_c_generalized_vector_length (v));
1063 }
1064 else if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
1065 {
1066 size_t k = SCM_ARRAY_NDIM (v);
1067 scm_t_array_dim *s = SCM_ARRAY_DIMS (v);
1068
1069 while (k > 0)
1070 {
1071 long ind;
1072
1073 if (!scm_is_pair (args))
1074 SCM_WRONG_NUM_ARGS ();
1075 ind = scm_to_long (SCM_CAR (args));
1076 args = SCM_CDR (args);
1077 k -= 1;
1078
1079 if (ind < s->lbnd || ind > s->ubnd)
1080 {
1081 res = SCM_BOOL_F;
1082 /* We do not stop the checking after finding a violation
1083 since we want to validate the type-correctness and
1084 number of arguments in any case.
1085 */
1086 }
1087 }
1088 }
1089 else
1090 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1091
1092 if (!scm_is_null (args))
1093 SCM_WRONG_NUM_ARGS ();
1094
1095 return res;
1096 }
1097 #undef FUNC_NAME
1098
1099 SCM
1100 scm_i_cvref (SCM v, size_t pos, int enclosed)
1101 {
1102 if (enclosed)
1103 {
1104 int k = SCM_ARRAY_NDIM (v);
1105 SCM res = scm_make_ra (k);
1106 SCM_ARRAY_V (res) = SCM_ARRAY_V (v);
1107 SCM_ARRAY_BASE (res) = pos;
1108 while (k--)
1109 {
1110 SCM_ARRAY_DIMS (res)[k].ubnd = SCM_ARRAY_DIMS (v)[k].ubnd;
1111 SCM_ARRAY_DIMS (res)[k].lbnd = SCM_ARRAY_DIMS (v)[k].lbnd;
1112 SCM_ARRAY_DIMS (res)[k].inc = SCM_ARRAY_DIMS (v)[k].inc;
1113 }
1114 return res;
1115 }
1116 else
1117 return scm_c_generalized_vector_ref (v, pos);
1118 }
1119
1120 SCM
1121 scm_cvref (SCM v, unsigned long pos, SCM last)
1122 {
1123 return scm_i_cvref (v, pos, 0);
1124 }
1125
1126 SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1127 (SCM v, SCM args),
1128 "Return the element at the @code{(index1, index2)} element in\n"
1129 "@var{array}.")
1130 #define FUNC_NAME s_scm_array_ref
1131 {
1132 long pos;
1133 int enclosed = 0;
1134
1135 if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
1136 {
1137 enclosed = SCM_ENCLOSED_ARRAYP (v);
1138 pos = scm_aind (v, args, FUNC_NAME);
1139 v = SCM_ARRAY_V (v);
1140 }
1141 else
1142 {
1143 size_t length;
1144 if (SCM_NIMP (args))
1145 {
1146 SCM_ASSERT (scm_is_pair (args), args, SCM_ARG2, FUNC_NAME);
1147 pos = scm_to_long (SCM_CAR (args));
1148 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
1149 }
1150 else
1151 pos = scm_to_long (args);
1152 length = scm_c_generalized_vector_length (v);
1153 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
1154 }
1155
1156 return scm_i_cvref (v, pos, enclosed);
1157
1158 wna:
1159 scm_wrong_num_args (NULL);
1160 outrng:
1161 scm_out_of_range (NULL, scm_from_long (pos));
1162 }
1163 #undef FUNC_NAME
1164
1165
1166 SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1167 (SCM v, SCM obj, SCM args),
1168 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
1169 "@var{new-value}. The value returned by array-set! is unspecified.")
1170 #define FUNC_NAME s_scm_array_set_x
1171 {
1172 long pos = 0;
1173
1174 if (SCM_ARRAYP (v))
1175 {
1176 pos = scm_aind (v, args, FUNC_NAME);
1177 v = SCM_ARRAY_V (v);
1178 }
1179 else if (SCM_ENCLOSED_ARRAYP (v))
1180 scm_wrong_type_arg_msg (NULL, 0, v, "non-enclosed array");
1181 else if (scm_is_generalized_vector (v))
1182 {
1183 size_t length;
1184 if (scm_is_pair (args))
1185 {
1186 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
1187 pos = scm_to_long (SCM_CAR (args));
1188 }
1189 else
1190 pos = scm_to_long (args);
1191 length = scm_c_generalized_vector_length (v);
1192 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
1193 }
1194 else
1195 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1196
1197 scm_c_generalized_vector_set_x (v, pos, obj);
1198 return SCM_UNSPECIFIED;
1199
1200 outrng:
1201 scm_out_of_range (NULL, scm_from_long (pos));
1202 wna:
1203 scm_wrong_num_args (NULL);
1204 }
1205 #undef FUNC_NAME
1206
1207 /* attempts to unroll an array into a one-dimensional array.
1208 returns the unrolled array or #f if it can't be done. */
1209 /* if strict is not SCM_UNDEFINED, return #f if returned array
1210 wouldn't have contiguous elements. */
1211 SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1212 (SCM ra, SCM strict),
1213 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
1214 "without changing their order (last subscript changing fastest), then\n"
1215 "@code{array-contents} returns that shared array, otherwise it returns\n"
1216 "@code{#f}. All arrays made by @var{make-array} and\n"
1217 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
1218 "@var{make-shared-array} may not be.\n\n"
1219 "If the optional argument @var{strict} is provided, a shared array will\n"
1220 "be returned only if its elements are stored internally contiguous in\n"
1221 "memory.")
1222 #define FUNC_NAME s_scm_array_contents
1223 {
1224 SCM sra;
1225
1226 if (scm_is_generalized_vector (ra))
1227 return ra;
1228
1229 if (SCM_ARRAYP (ra))
1230 {
1231 size_t k, ndim = SCM_ARRAY_NDIM (ra), len = 1;
1232 if (!SCM_ARRAYP (ra) || !SCM_ARRAY_CONTP (ra))
1233 return SCM_BOOL_F;
1234 for (k = 0; k < ndim; k++)
1235 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1236 if (!SCM_UNBNDP (strict))
1237 {
1238 if (ndim && (1 != SCM_ARRAY_DIMS (ra)[ndim - 1].inc))
1239 return SCM_BOOL_F;
1240 if (scm_is_bitvector (SCM_ARRAY_V (ra)))
1241 {
1242 if (len != scm_c_bitvector_length (SCM_ARRAY_V (ra)) ||
1243 SCM_ARRAY_BASE (ra) % SCM_LONG_BIT ||
1244 len % SCM_LONG_BIT)
1245 return SCM_BOOL_F;
1246 }
1247 }
1248
1249 {
1250 SCM v = SCM_ARRAY_V (ra);
1251 size_t length = scm_c_generalized_vector_length (v);
1252 if ((len == length) && 0 == SCM_ARRAY_BASE (ra) && SCM_ARRAY_DIMS (ra)->inc)
1253 return v;
1254 }
1255
1256 sra = scm_make_ra (1);
1257 SCM_ARRAY_DIMS (sra)->lbnd = 0;
1258 SCM_ARRAY_DIMS (sra)->ubnd = len - 1;
1259 SCM_ARRAY_V (sra) = SCM_ARRAY_V (ra);
1260 SCM_ARRAY_BASE (sra) = SCM_ARRAY_BASE (ra);
1261 SCM_ARRAY_DIMS (sra)->inc = (ndim ? SCM_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
1262 return sra;
1263 }
1264 else if (SCM_ENCLOSED_ARRAYP (ra))
1265 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
1266 else
1267 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1268 }
1269 #undef FUNC_NAME
1270
1271
1272 SCM
1273 scm_ra2contig (SCM ra, int copy)
1274 {
1275 SCM ret;
1276 long inc = 1;
1277 size_t k, len = 1;
1278 for (k = SCM_ARRAY_NDIM (ra); k--;)
1279 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1280 k = SCM_ARRAY_NDIM (ra);
1281 if (SCM_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_ARRAY_DIMS (ra)[k - 1].inc)))
1282 {
1283 if (!scm_is_bitvector (SCM_ARRAY_V (ra)))
1284 return ra;
1285 if ((len == scm_c_bitvector_length (SCM_ARRAY_V (ra)) &&
1286 0 == SCM_ARRAY_BASE (ra) % SCM_LONG_BIT &&
1287 0 == len % SCM_LONG_BIT))
1288 return ra;
1289 }
1290 ret = scm_make_ra (k);
1291 SCM_ARRAY_BASE (ret) = 0;
1292 while (k--)
1293 {
1294 SCM_ARRAY_DIMS (ret)[k].lbnd = SCM_ARRAY_DIMS (ra)[k].lbnd;
1295 SCM_ARRAY_DIMS (ret)[k].ubnd = SCM_ARRAY_DIMS (ra)[k].ubnd;
1296 SCM_ARRAY_DIMS (ret)[k].inc = inc;
1297 inc *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1298 }
1299 SCM_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
1300 if (copy)
1301 scm_array_copy_x (ra, ret);
1302 return ret;
1303 }
1304
1305
1306
1307 SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
1308 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1309 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1310 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
1311 "binary objects from @var{port-or-fdes}.\n"
1312 "If an end of file is encountered,\n"
1313 "the objects up to that point are put into @var{ura}\n"
1314 "(starting at the beginning) and the remainder of the array is\n"
1315 "unchanged.\n\n"
1316 "The optional arguments @var{start} and @var{end} allow\n"
1317 "a specified region of a vector (or linearized array) to be read,\n"
1318 "leaving the remainder of the vector unchanged.\n\n"
1319 "@code{uniform-array-read!} returns the number of objects read.\n"
1320 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1321 "returned by @code{(current-input-port)}.")
1322 #define FUNC_NAME s_scm_uniform_array_read_x
1323 {
1324 if (SCM_UNBNDP (port_or_fd))
1325 port_or_fd = scm_cur_inp;
1326
1327 if (scm_is_uniform_vector (ura))
1328 {
1329 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
1330 }
1331 else if (SCM_ARRAYP (ura))
1332 {
1333 size_t base, vlen, cstart, cend;
1334 SCM cra, ans;
1335
1336 cra = scm_ra2contig (ura, 0);
1337 base = SCM_ARRAY_BASE (cra);
1338 vlen = SCM_ARRAY_DIMS (cra)->inc *
1339 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
1340
1341 cstart = 0;
1342 cend = vlen;
1343 if (!SCM_UNBNDP (start))
1344 {
1345 cstart = scm_to_unsigned_integer (start, 0, vlen);
1346 if (!SCM_UNBNDP (end))
1347 cend = scm_to_unsigned_integer (end, cstart, vlen);
1348 }
1349
1350 ans = scm_uniform_vector_read_x (SCM_ARRAY_V (cra), port_or_fd,
1351 scm_from_size_t (base + cstart),
1352 scm_from_size_t (base + cend));
1353
1354 if (!scm_is_eq (cra, ura))
1355 scm_array_copy_x (cra, ura);
1356 return ans;
1357 }
1358 else if (SCM_ENCLOSED_ARRAYP (ura))
1359 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1360 else
1361 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1362 }
1363 #undef FUNC_NAME
1364
1365 SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
1366 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1367 "Writes all elements of @var{ura} as binary objects to\n"
1368 "@var{port-or-fdes}.\n\n"
1369 "The optional arguments @var{start}\n"
1370 "and @var{end} allow\n"
1371 "a specified region of a vector (or linearized array) to be written.\n\n"
1372 "The number of objects actually written is returned.\n"
1373 "@var{port-or-fdes} may be\n"
1374 "omitted, in which case it defaults to the value returned by\n"
1375 "@code{(current-output-port)}.")
1376 #define FUNC_NAME s_scm_uniform_array_write
1377 {
1378 if (SCM_UNBNDP (port_or_fd))
1379 port_or_fd = scm_cur_outp;
1380
1381 if (scm_is_uniform_vector (ura))
1382 {
1383 return scm_uniform_vector_write (ura, port_or_fd, start, end);
1384 }
1385 else if (SCM_ARRAYP (ura))
1386 {
1387 size_t base, vlen, cstart, cend;
1388 SCM cra, ans;
1389
1390 cra = scm_ra2contig (ura, 1);
1391 base = SCM_ARRAY_BASE (cra);
1392 vlen = SCM_ARRAY_DIMS (cra)->inc *
1393 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
1394
1395 cstart = 0;
1396 cend = vlen;
1397 if (!SCM_UNBNDP (start))
1398 {
1399 cstart = scm_to_unsigned_integer (start, 0, vlen);
1400 if (!SCM_UNBNDP (end))
1401 cend = scm_to_unsigned_integer (end, cstart, vlen);
1402 }
1403
1404 ans = scm_uniform_vector_write (SCM_ARRAY_V (cra), port_or_fd,
1405 scm_from_size_t (base + cstart),
1406 scm_from_size_t (base + cend));
1407
1408 return ans;
1409 }
1410 else if (SCM_ENCLOSED_ARRAYP (ura))
1411 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1412 else
1413 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1414 }
1415 #undef FUNC_NAME
1416
1417
1418 /** Bit vectors */
1419
1420 static scm_t_bits scm_tc16_bitvector;
1421
1422 #define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1423 #define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1424 #define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1425
1426 static size_t
1427 bitvector_free (SCM vec)
1428 {
1429 scm_gc_free (BITVECTOR_BITS (vec),
1430 sizeof (scm_t_uint32) * ((BITVECTOR_LENGTH (vec)+31)/32),
1431 "bitvector");
1432 return 0;
1433 }
1434
1435 static int
1436 bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1437 {
1438 size_t bit_len = BITVECTOR_LENGTH (vec);
1439 size_t word_len = (bit_len+31)/32;
1440 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1441 size_t i, j;
1442
1443 scm_puts ("#*", port);
1444 for (i = 0; i < word_len; i++, bit_len -= 32)
1445 {
1446 scm_t_uint32 mask = 1;
1447 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1448 scm_putc ((bits[i] & mask)? '1' : '0', port);
1449 }
1450
1451 return 1;
1452 }
1453
1454 static SCM
1455 bitvector_equalp (SCM vec1, SCM vec2)
1456 {
1457 size_t bit_len = BITVECTOR_LENGTH (vec1);
1458 size_t word_len = (bit_len + 31) / 32;
1459 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1460 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1461 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1462
1463 /* compare lengths */
1464 if (BITVECTOR_LENGTH (vec2) != bit_len)
1465 return SCM_BOOL_F;
1466 /* avoid underflow in word_len-1 below. */
1467 if (bit_len == 0)
1468 return SCM_BOOL_T;
1469 /* compare full words */
1470 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1471 return SCM_BOOL_F;
1472 /* compare partial last words */
1473 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1474 return SCM_BOOL_F;
1475 return SCM_BOOL_T;
1476 }
1477
1478 int
1479 scm_is_bitvector (SCM vec)
1480 {
1481 return IS_BITVECTOR (vec);
1482 }
1483
1484 SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1485 (SCM obj),
1486 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1487 "return @code{#f}.")
1488 #define FUNC_NAME s_scm_bitvector_p
1489 {
1490 return scm_from_bool (scm_is_bitvector (obj));
1491 }
1492 #undef FUNC_NAME
1493
1494 SCM
1495 scm_c_make_bitvector (size_t len, SCM fill)
1496 {
1497 size_t word_len = (len + 31) / 32;
1498 scm_t_uint32 *bits;
1499 SCM res;
1500
1501 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1502 "bitvector");
1503 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1504
1505 if (!SCM_UNBNDP (fill))
1506 scm_bitvector_fill_x (res, fill);
1507
1508 return res;
1509 }
1510
1511 SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1512 (SCM len, SCM fill),
1513 "Create a new bitvector of length @var{len} and\n"
1514 "optionally initialize all elements to @var{fill}.")
1515 #define FUNC_NAME s_scm_make_bitvector
1516 {
1517 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1518 }
1519 #undef FUNC_NAME
1520
1521 SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1522 (SCM bits),
1523 "Create a new bitvector with the arguments as elements.")
1524 #define FUNC_NAME s_scm_bitvector
1525 {
1526 return scm_list_to_bitvector (bits);
1527 }
1528 #undef FUNC_NAME
1529
1530 size_t
1531 scm_c_bitvector_length (SCM vec)
1532 {
1533 scm_assert_smob_type (scm_tc16_bitvector, vec);
1534 return BITVECTOR_LENGTH (vec);
1535 }
1536
1537 SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1538 (SCM vec),
1539 "Return the length of the bitvector @var{vec}.")
1540 #define FUNC_NAME s_scm_bitvector_length
1541 {
1542 return scm_from_size_t (scm_c_bitvector_length (vec));
1543 }
1544 #undef FUNC_NAME
1545
1546 const scm_t_uint32 *
1547 scm_array_handle_bit_elements (scm_t_array_handle *h)
1548 {
1549 return scm_array_handle_bit_writable_elements (h);
1550 }
1551
1552 scm_t_uint32 *
1553 scm_array_handle_bit_writable_elements (scm_t_array_handle *h)
1554 {
1555 SCM vec = h->array;
1556 if (SCM_ARRAYP (vec))
1557 vec = SCM_ARRAY_V (vec);
1558 if (IS_BITVECTOR (vec))
1559 return BITVECTOR_BITS (vec) + h->base/32;
1560 scm_wrong_type_arg_msg (NULL, 0, h->array, "bit array");
1561 }
1562
1563 size_t
1564 scm_array_handle_bit_elements_offset (scm_t_array_handle *h)
1565 {
1566 return h->base % 32;
1567 }
1568
1569 const scm_t_uint32 *
1570 scm_bitvector_elements (SCM vec,
1571 scm_t_array_handle *h,
1572 size_t *offp,
1573 size_t *lenp,
1574 ssize_t *incp)
1575 {
1576 return scm_bitvector_writable_elements (vec, h, offp, lenp, incp);
1577 }
1578
1579
1580 scm_t_uint32 *
1581 scm_bitvector_writable_elements (SCM vec,
1582 scm_t_array_handle *h,
1583 size_t *offp,
1584 size_t *lenp,
1585 ssize_t *incp)
1586 {
1587 scm_generalized_vector_get_handle (vec, h);
1588 if (offp)
1589 {
1590 scm_t_array_dim *dim = scm_array_handle_dims (h);
1591 *offp = scm_array_handle_bit_elements_offset (h);
1592 *lenp = dim->ubnd - dim->lbnd + 1;
1593 *incp = dim->inc;
1594 }
1595 return scm_array_handle_bit_writable_elements (h);
1596 }
1597
1598 SCM
1599 scm_c_bitvector_ref (SCM vec, size_t idx)
1600 {
1601 scm_t_array_handle handle;
1602 const scm_t_uint32 *bits;
1603
1604 if (IS_BITVECTOR (vec))
1605 {
1606 if (idx >= BITVECTOR_LENGTH (vec))
1607 scm_out_of_range (NULL, scm_from_size_t (idx));
1608 bits = BITVECTOR_BITS(vec);
1609 return scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1610 }
1611 else
1612 {
1613 SCM res;
1614 size_t len, off;
1615 ssize_t inc;
1616
1617 bits = scm_bitvector_elements (vec, &handle, &off, &len, &inc);
1618 if (idx >= len)
1619 scm_out_of_range (NULL, scm_from_size_t (idx));
1620 idx = idx*inc + off;
1621 res = scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1622 scm_array_handle_release (&handle);
1623 return res;
1624 }
1625 }
1626
1627 SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1628 (SCM vec, SCM idx),
1629 "Return the element at index @var{idx} of the bitvector\n"
1630 "@var{vec}.")
1631 #define FUNC_NAME s_scm_bitvector_ref
1632 {
1633 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1634 }
1635 #undef FUNC_NAME
1636
1637 void
1638 scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1639 {
1640 scm_t_array_handle handle;
1641 scm_t_uint32 *bits, mask;
1642
1643 if (IS_BITVECTOR (vec))
1644 {
1645 if (idx >= BITVECTOR_LENGTH (vec))
1646 scm_out_of_range (NULL, scm_from_size_t (idx));
1647 bits = BITVECTOR_BITS(vec);
1648 }
1649 else
1650 {
1651 size_t len, off;
1652 ssize_t inc;
1653
1654 bits = scm_bitvector_writable_elements (vec, &handle, &off, &len, &inc);
1655 if (idx >= len)
1656 scm_out_of_range (NULL, scm_from_size_t (idx));
1657 idx = idx*inc + off;
1658 }
1659
1660 mask = 1L << (idx%32);
1661 if (scm_is_true (val))
1662 bits[idx/32] |= mask;
1663 else
1664 bits[idx/32] &= ~mask;
1665
1666 if (!IS_BITVECTOR (vec))
1667 scm_array_handle_release (&handle);
1668 }
1669
1670 SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1671 (SCM vec, SCM idx, SCM val),
1672 "Set the element at index @var{idx} of the bitvector\n"
1673 "@var{vec} when @var{val} is true, else clear it.")
1674 #define FUNC_NAME s_scm_bitvector_set_x
1675 {
1676 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1677 return SCM_UNSPECIFIED;
1678 }
1679 #undef FUNC_NAME
1680
1681 SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1682 (SCM vec, SCM val),
1683 "Set all elements of the bitvector\n"
1684 "@var{vec} when @var{val} is true, else clear them.")
1685 #define FUNC_NAME s_scm_bitvector_fill_x
1686 {
1687 scm_t_array_handle handle;
1688 size_t off, len;
1689 ssize_t inc;
1690 scm_t_uint32 *bits;
1691
1692 bits = scm_bitvector_writable_elements (vec, &handle,
1693 &off, &len, &inc);
1694
1695 if (off == 0 && inc == 1 && len > 0)
1696 {
1697 /* the usual case
1698 */
1699 size_t word_len = (len + 31) / 32;
1700 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1701
1702 if (scm_is_true (val))
1703 {
1704 memset (bits, 0xFF, sizeof(scm_t_uint32)*(word_len-1));
1705 bits[word_len-1] |= last_mask;
1706 }
1707 else
1708 {
1709 memset (bits, 0x00, sizeof(scm_t_uint32)*(word_len-1));
1710 bits[word_len-1] &= ~last_mask;
1711 }
1712 }
1713 else
1714 {
1715 size_t i;
1716 for (i = 0; i < len; i++)
1717 scm_array_handle_set (&handle, i, val);
1718 }
1719
1720 scm_array_handle_release (&handle);
1721
1722 return SCM_UNSPECIFIED;
1723 }
1724 #undef FUNC_NAME
1725
1726 SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1727 (SCM list),
1728 "Return a new bitvector initialized with the elements\n"
1729 "of @var{list}.")
1730 #define FUNC_NAME s_scm_list_to_bitvector
1731 {
1732 size_t bit_len = scm_to_size_t (scm_length (list));
1733 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1734 size_t word_len = (bit_len+31)/32;
1735 scm_t_array_handle handle;
1736 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec, &handle,
1737 NULL, NULL, NULL);
1738 size_t i, j;
1739
1740 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1741 {
1742 scm_t_uint32 mask = 1;
1743 bits[i] = 0;
1744 for (j = 0; j < 32 && j < bit_len;
1745 j++, mask <<= 1, list = SCM_CDR (list))
1746 if (scm_is_true (SCM_CAR (list)))
1747 bits[i] |= mask;
1748 }
1749
1750 scm_array_handle_release (&handle);
1751
1752 return vec;
1753 }
1754 #undef FUNC_NAME
1755
1756 SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1757 (SCM vec),
1758 "Return a new list initialized with the elements\n"
1759 "of the bitvector @var{vec}.")
1760 #define FUNC_NAME s_scm_bitvector_to_list
1761 {
1762 scm_t_array_handle handle;
1763 size_t off, len;
1764 ssize_t inc;
1765 scm_t_uint32 *bits;
1766 SCM res = SCM_EOL;
1767
1768 bits = scm_bitvector_writable_elements (vec, &handle,
1769 &off, &len, &inc);
1770
1771 if (off == 0 && inc == 1)
1772 {
1773 /* the usual case
1774 */
1775 size_t word_len = (len + 31) / 32;
1776 size_t i, j;
1777
1778 for (i = 0; i < word_len; i++, len -= 32)
1779 {
1780 scm_t_uint32 mask = 1;
1781 for (j = 0; j < 32 && j < len; j++, mask <<= 1)
1782 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1783 }
1784 }
1785 else
1786 {
1787 size_t i;
1788 for (i = 0; i < len; i++)
1789 res = scm_cons (scm_array_handle_ref (&handle, i), res);
1790 }
1791
1792 scm_array_handle_release (&handle);
1793
1794 return scm_reverse_x (res, SCM_EOL);
1795 }
1796 #undef FUNC_NAME
1797
1798 /* From mmix-arith.w by Knuth.
1799
1800 Here's a fun way to count the number of bits in a tetrabyte.
1801
1802 [This classical trick is called the ``Gillies--Miller method for
1803 sideways addition'' in {\sl The Preparation of Programs for an
1804 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1805 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1806 the tricks used here were suggested by Balbir Singh, Peter
1807 Rossmanith, and Stefan Schwoon.]
1808 */
1809
1810 static size_t
1811 count_ones (scm_t_uint32 x)
1812 {
1813 x=x-((x>>1)&0x55555555);
1814 x=(x&0x33333333)+((x>>2)&0x33333333);
1815 x=(x+(x>>4))&0x0f0f0f0f;
1816 x=x+(x>>8);
1817 return (x+(x>>16)) & 0xff;
1818 }
1819
1820 SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
1821 (SCM b, SCM bitvector),
1822 "Return the number of occurrences of the boolean @var{b} in\n"
1823 "@var{bitvector}.")
1824 #define FUNC_NAME s_scm_bit_count
1825 {
1826 scm_t_array_handle handle;
1827 size_t off, len;
1828 ssize_t inc;
1829 scm_t_uint32 *bits;
1830 int bit = scm_to_bool (b);
1831 size_t count = 0;
1832
1833 bits = scm_bitvector_writable_elements (bitvector, &handle,
1834 &off, &len, &inc);
1835
1836 if (off == 0 && inc == 1 && len > 0)
1837 {
1838 /* the usual case
1839 */
1840 size_t word_len = (len + 31) / 32;
1841 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1842 size_t i;
1843
1844 for (i = 0; i < word_len-1; i++)
1845 count += count_ones (bits[i]);
1846 count += count_ones (bits[i] & last_mask);
1847 }
1848 else
1849 {
1850 size_t i;
1851 for (i = 0; i < len; i++)
1852 if (scm_is_true (scm_array_handle_ref (&handle, i)))
1853 count++;
1854 }
1855
1856 scm_array_handle_release (&handle);
1857
1858 return scm_from_size_t (bit? count : len-count);
1859 }
1860 #undef FUNC_NAME
1861
1862 /* returns 32 for x == 0.
1863 */
1864 static size_t
1865 find_first_one (scm_t_uint32 x)
1866 {
1867 size_t pos = 0;
1868 /* do a binary search in x. */
1869 if ((x & 0xFFFF) == 0)
1870 x >>= 16, pos += 16;
1871 if ((x & 0xFF) == 0)
1872 x >>= 8, pos += 8;
1873 if ((x & 0xF) == 0)
1874 x >>= 4, pos += 4;
1875 if ((x & 0x3) == 0)
1876 x >>= 2, pos += 2;
1877 if ((x & 0x1) == 0)
1878 pos += 1;
1879 return pos;
1880 }
1881
1882 SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1883 (SCM item, SCM v, SCM k),
1884 "Return the index of the first occurrance of @var{item} in bit\n"
1885 "vector @var{v}, starting from @var{k}. If there is no\n"
1886 "@var{item} entry between @var{k} and the end of\n"
1887 "@var{bitvector}, then return @code{#f}. For example,\n"
1888 "\n"
1889 "@example\n"
1890 "(bit-position #t #*000101 0) @result{} 3\n"
1891 "(bit-position #f #*0001111 3) @result{} #f\n"
1892 "@end example")
1893 #define FUNC_NAME s_scm_bit_position
1894 {
1895 scm_t_array_handle handle;
1896 size_t off, len, first_bit;
1897 ssize_t inc;
1898 const scm_t_uint32 *bits;
1899 int bit = scm_to_bool (item);
1900 SCM res = SCM_BOOL_F;
1901
1902 bits = scm_bitvector_elements (v, &handle, &off, &len, &inc);
1903 first_bit = scm_to_unsigned_integer (k, 0, len);
1904
1905 if (off == 0 && inc == 1 && len > 0)
1906 {
1907 size_t i, word_len = (len + 31) / 32;
1908 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1909 size_t first_word = first_bit / 32;
1910 scm_t_uint32 first_mask =
1911 ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1912 scm_t_uint32 w;
1913
1914 for (i = first_word; i < word_len; i++)
1915 {
1916 w = (bit? bits[i] : ~bits[i]);
1917 if (i == first_word)
1918 w &= first_mask;
1919 if (i == word_len-1)
1920 w &= last_mask;
1921 if (w)
1922 {
1923 res = scm_from_size_t (32*i + find_first_one (w));
1924 break;
1925 }
1926 }
1927 }
1928 else
1929 {
1930 size_t i;
1931 for (i = first_bit; i < len; i++)
1932 {
1933 SCM elt = scm_array_handle_ref (&handle, i);
1934 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
1935 {
1936 res = scm_from_size_t (i);
1937 break;
1938 }
1939 }
1940 }
1941
1942 scm_array_handle_release (&handle);
1943
1944 return res;
1945 }
1946 #undef FUNC_NAME
1947
1948 SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
1949 (SCM v, SCM kv, SCM obj),
1950 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1951 "selecting the entries to change. The return value is\n"
1952 "unspecified.\n"
1953 "\n"
1954 "If @var{kv} is a bit vector, then those entries where it has\n"
1955 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1956 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1957 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1958 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1959 "\n"
1960 "@example\n"
1961 "(define bv #*01000010)\n"
1962 "(bit-set*! bv #*10010001 #t)\n"
1963 "bv\n"
1964 "@result{} #*11010011\n"
1965 "@end example\n"
1966 "\n"
1967 "If @var{kv} is a u32vector, then its elements are\n"
1968 "indices into @var{v} which are set to @var{obj}.\n"
1969 "\n"
1970 "@example\n"
1971 "(define bv #*01000010)\n"
1972 "(bit-set*! bv #u32(5 2 7) #t)\n"
1973 "bv\n"
1974 "@result{} #*01100111\n"
1975 "@end example")
1976 #define FUNC_NAME s_scm_bit_set_star_x
1977 {
1978 scm_t_array_handle v_handle;
1979 size_t v_off, v_len;
1980 ssize_t v_inc;
1981 scm_t_uint32 *v_bits;
1982 int bit;
1983
1984 /* Validate that OBJ is a boolean so this is done even if we don't
1985 need BIT.
1986 */
1987 bit = scm_to_bool (obj);
1988
1989 v_bits = scm_bitvector_writable_elements (v, &v_handle,
1990 &v_off, &v_len, &v_inc);
1991
1992 if (scm_is_bitvector (kv))
1993 {
1994 scm_t_array_handle kv_handle;
1995 size_t kv_off, kv_len;
1996 ssize_t kv_inc;
1997 const scm_t_uint32 *kv_bits;
1998
1999 kv_bits = scm_bitvector_elements (v, &kv_handle,
2000 &kv_off, &kv_len, &kv_inc);
2001
2002 if (v_len != kv_len)
2003 scm_misc_error (NULL,
2004 "bit vectors must have equal length",
2005 SCM_EOL);
2006
2007 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2008 {
2009 size_t word_len = (kv_len + 31) / 32;
2010 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2011 size_t i;
2012
2013 if (bit == 0)
2014 {
2015 for (i = 0; i < word_len-1; i++)
2016 v_bits[i] &= ~kv_bits[i];
2017 v_bits[i] &= ~(kv_bits[i] & last_mask);
2018 }
2019 else
2020 {
2021 for (i = 0; i < word_len-1; i++)
2022 v_bits[i] |= kv_bits[i];
2023 v_bits[i] |= kv_bits[i] & last_mask;
2024 }
2025 }
2026 else
2027 {
2028 size_t i;
2029 for (i = 0; i < kv_len; i++)
2030 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2031 scm_array_handle_set (&v_handle, i, obj);
2032 }
2033
2034 scm_array_handle_release (&kv_handle);
2035
2036 }
2037 else if (scm_is_true (scm_u32vector_p (kv)))
2038 {
2039 scm_t_array_handle kv_handle;
2040 size_t i, kv_len;
2041 ssize_t kv_inc;
2042 const scm_t_uint32 *kv_elts;
2043
2044 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2045 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2046 scm_array_handle_set (&v_handle, (size_t) *kv_elts, obj);
2047
2048 scm_array_handle_release (&kv_handle);
2049 }
2050 else
2051 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2052
2053 scm_array_handle_release (&v_handle);
2054
2055 return SCM_UNSPECIFIED;
2056 }
2057 #undef FUNC_NAME
2058
2059
2060 SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
2061 (SCM v, SCM kv, SCM obj),
2062 "Return a count of how many entries in bit vector @var{v} are\n"
2063 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
2064 "consider.\n"
2065 "\n"
2066 "If @var{kv} is a bit vector, then those entries where it has\n"
2067 "@code{#t} are the ones in @var{v} which are considered.\n"
2068 "@var{kv} and @var{v} must be the same length.\n"
2069 "\n"
2070 "If @var{kv} is a u32vector, then it contains\n"
2071 "the indexes in @var{v} to consider.\n"
2072 "\n"
2073 "For example,\n"
2074 "\n"
2075 "@example\n"
2076 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
2077 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
2078 "@end example")
2079 #define FUNC_NAME s_scm_bit_count_star
2080 {
2081 scm_t_array_handle v_handle;
2082 size_t v_off, v_len;
2083 ssize_t v_inc;
2084 const scm_t_uint32 *v_bits;
2085 size_t count = 0;
2086 int bit;
2087
2088 /* Validate that OBJ is a boolean so this is done even if we don't
2089 need BIT.
2090 */
2091 bit = scm_to_bool (obj);
2092
2093 v_bits = scm_bitvector_elements (v, &v_handle,
2094 &v_off, &v_len, &v_inc);
2095
2096 if (scm_is_bitvector (kv))
2097 {
2098 scm_t_array_handle kv_handle;
2099 size_t kv_off, kv_len;
2100 ssize_t kv_inc;
2101 const scm_t_uint32 *kv_bits;
2102
2103 kv_bits = scm_bitvector_elements (v, &kv_handle,
2104 &kv_off, &kv_len, &kv_inc);
2105
2106 if (v_len != kv_len)
2107 scm_misc_error (NULL,
2108 "bit vectors must have equal length",
2109 SCM_EOL);
2110
2111 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2112 {
2113 size_t i, word_len = (kv_len + 31) / 32;
2114 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2115 scm_t_uint32 xor_mask = bit? 0 : ((scm_t_uint32)-1);
2116
2117 for (i = 0; i < word_len-1; i++)
2118 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i]);
2119 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i] & last_mask);
2120 }
2121 else
2122 {
2123 size_t i;
2124 for (i = 0; i < kv_len; i++)
2125 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2126 {
2127 SCM elt = scm_array_handle_ref (&v_handle, i);
2128 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2129 count++;
2130 }
2131 }
2132
2133 scm_array_handle_release (&kv_handle);
2134
2135 }
2136 else if (scm_is_true (scm_u32vector_p (kv)))
2137 {
2138 scm_t_array_handle kv_handle;
2139 size_t i, kv_len;
2140 ssize_t kv_inc;
2141 const scm_t_uint32 *kv_elts;
2142
2143 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2144 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2145 {
2146 SCM elt = scm_array_handle_ref (&v_handle, *kv_elts);
2147 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2148 count++;
2149 }
2150
2151 scm_array_handle_release (&kv_handle);
2152 }
2153 else
2154 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2155
2156 scm_array_handle_release (&v_handle);
2157
2158 return scm_from_size_t (count);
2159 }
2160 #undef FUNC_NAME
2161
2162 SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
2163 (SCM v),
2164 "Modify the bit vector @var{v} by replacing each element with\n"
2165 "its negation.")
2166 #define FUNC_NAME s_scm_bit_invert_x
2167 {
2168 scm_t_array_handle handle;
2169 size_t off, len;
2170 ssize_t inc;
2171 scm_t_uint32 *bits;
2172
2173 bits = scm_bitvector_writable_elements (v, &handle, &off, &len, &inc);
2174
2175 if (off == 0 && inc == 1 && len > 0)
2176 {
2177 size_t word_len = (len + 31) / 32;
2178 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
2179 size_t i;
2180
2181 for (i = 0; i < word_len-1; i++)
2182 bits[i] = ~bits[i];
2183 bits[i] = bits[i] ^ last_mask;
2184 }
2185 else
2186 {
2187 size_t i;
2188 for (i = 0; i < len; i++)
2189 scm_array_handle_set (&handle, i,
2190 scm_not (scm_array_handle_ref (&handle, i)));
2191 }
2192
2193 scm_array_handle_release (&handle);
2194
2195 return SCM_UNSPECIFIED;
2196 }
2197 #undef FUNC_NAME
2198
2199
2200 SCM
2201 scm_istr2bve (SCM str)
2202 {
2203 scm_t_array_handle handle;
2204 size_t len = scm_i_string_length (str);
2205 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
2206 SCM res = vec;
2207
2208 scm_t_uint32 mask;
2209 size_t k, j;
2210 const char *c_str;
2211 scm_t_uint32 *data;
2212
2213 data = scm_bitvector_writable_elements (vec, &handle, NULL, NULL, NULL);
2214 c_str = scm_i_string_chars (str);
2215
2216 for (k = 0; k < (len + 31) / 32; k++)
2217 {
2218 data[k] = 0L;
2219 j = len - k * 32;
2220 if (j > 32)
2221 j = 32;
2222 for (mask = 1L; j--; mask <<= 1)
2223 switch (*c_str++)
2224 {
2225 case '0':
2226 break;
2227 case '1':
2228 data[k] |= mask;
2229 break;
2230 default:
2231 res = SCM_BOOL_F;
2232 goto exit;
2233 }
2234 }
2235
2236 exit:
2237 scm_array_handle_release (&handle);
2238 scm_remember_upto_here_1 (str);
2239 return res;
2240 }
2241
2242
2243
2244 static SCM
2245 ra2l (SCM ra, unsigned long base, unsigned long k)
2246 {
2247 SCM res = SCM_EOL;
2248 long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2249 size_t i;
2250 int enclosed = SCM_ENCLOSED_ARRAYP (ra);
2251
2252 if (SCM_ARRAY_DIMS (ra)[k].ubnd < SCM_ARRAY_DIMS (ra)[k].lbnd)
2253 return SCM_EOL;
2254 i = base + (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd) * inc;
2255 if (k < SCM_ARRAY_NDIM (ra) - 1)
2256 {
2257 do
2258 {
2259 i -= inc;
2260 res = scm_cons (ra2l (ra, i, k + 1), res);
2261 }
2262 while (i != base);
2263 }
2264 else
2265 do
2266 {
2267 i -= inc;
2268 res = scm_cons (scm_i_cvref (SCM_ARRAY_V (ra), i, enclosed),
2269 res);
2270 }
2271 while (i != base);
2272 return res;
2273 }
2274
2275
2276 SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
2277 (SCM v),
2278 "Return a list consisting of all the elements, in order, of\n"
2279 "@var{array}.")
2280 #define FUNC_NAME s_scm_array_to_list
2281 {
2282 if (scm_is_generalized_vector (v))
2283 return scm_generalized_vector_to_list (v);
2284 else if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
2285 return ra2l (v, SCM_ARRAY_BASE (v), 0);
2286
2287 scm_wrong_type_arg_msg (NULL, 0, v, "array");
2288 }
2289 #undef FUNC_NAME
2290
2291
2292 static int l2ra(SCM lst, SCM ra, unsigned long base, unsigned long k);
2293
2294 SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2295 (SCM type, SCM ndim, SCM lst),
2296 "Return an array of the type @var{type}\n"
2297 "with elements the same as those of @var{lst}.\n"
2298 "\n"
2299 "The argument @var{ndim} determines the number of dimensions\n"
2300 "of the array. It is either an exact integer, giving the\n"
2301 "number directly, or a list of exact integers, whose length\n"
2302 "specifies the number of dimensions and each element is the\n"
2303 "lower index bound of its dimension.")
2304 #define FUNC_NAME s_scm_list_to_typed_array
2305 {
2306 SCM shape, row;
2307 SCM ra;
2308 unsigned long k;
2309
2310 shape = SCM_EOL;
2311 row = lst;
2312 if (scm_is_integer (ndim))
2313 {
2314 size_t k = scm_to_size_t (ndim);
2315 while (k-- > 0)
2316 {
2317 shape = scm_cons (scm_length (row), shape);
2318 if (k > 0)
2319 row = scm_car (row);
2320 }
2321 }
2322 else
2323 {
2324 while (1)
2325 {
2326 shape = scm_cons (scm_list_2 (scm_car (ndim),
2327 scm_sum (scm_sum (scm_car (ndim),
2328 scm_length (row)),
2329 scm_from_int (-1))),
2330 shape);
2331 ndim = scm_cdr (ndim);
2332 if (scm_is_pair (ndim))
2333 row = scm_car (row);
2334 else
2335 break;
2336 }
2337 }
2338
2339 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
2340 scm_reverse_x (shape, SCM_EOL));
2341
2342 if (scm_is_null (shape))
2343 {
2344 SCM_ASRTGO (1 == scm_ilength (lst), badlst);
2345 scm_array_set_x (ra, SCM_CAR (lst), SCM_EOL);
2346 return ra;
2347 }
2348 if (!SCM_ARRAYP (ra))
2349 {
2350 size_t length = scm_c_generalized_vector_length (ra);
2351 for (k = 0; k < length; k++, lst = SCM_CDR (lst))
2352 scm_c_generalized_vector_set_x (ra, k, SCM_CAR (lst));
2353 return ra;
2354 }
2355 if (l2ra (lst, ra, SCM_ARRAY_BASE (ra), 0))
2356 return ra;
2357 else
2358 badlst:SCM_MISC_ERROR ("Bad scm_array contents list: ~S",
2359 scm_list_1 (lst));
2360 }
2361 #undef FUNC_NAME
2362
2363 SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
2364 (SCM ndim, SCM lst),
2365 "Return an array with elements the same as those of @var{lst}.")
2366 #define FUNC_NAME s_scm_list_to_array
2367 {
2368 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
2369 }
2370 #undef FUNC_NAME
2371
2372 static int
2373 l2ra (SCM lst, SCM ra, unsigned long base, unsigned long k)
2374 {
2375 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2376 register long n = (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd);
2377 int ok = 1;
2378 if (n <= 0)
2379 return (scm_is_null (lst));
2380 if (k < SCM_ARRAY_NDIM (ra) - 1)
2381 {
2382 while (n--)
2383 {
2384 if (!scm_is_pair (lst))
2385 return 0;
2386 ok = ok && l2ra (SCM_CAR (lst), ra, base, k + 1);
2387 base += inc;
2388 lst = SCM_CDR (lst);
2389 }
2390 if (!scm_is_null (lst))
2391 return 0;
2392 }
2393 else
2394 {
2395 while (n--)
2396 {
2397 if (!scm_is_pair (lst))
2398 return 0;
2399 scm_array_set_x (SCM_ARRAY_V (ra), SCM_CAR (lst), scm_from_ulong (base));
2400 base += inc;
2401 lst = SCM_CDR (lst);
2402 }
2403 if (!scm_is_null (lst))
2404 return 0;
2405 }
2406 return ok;
2407 }
2408
2409 #if SCM_ENABLE_DEPRECATED
2410
2411 SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
2412 (SCM ndim, SCM prot, SCM lst),
2413 "Return a uniform array of the type indicated by prototype\n"
2414 "@var{prot} with elements the same as those of @var{lst}.\n"
2415 "Elements must be of the appropriate type, no coercions are\n"
2416 "done.\n"
2417 "\n"
2418 "The argument @var{ndim} determines the number of dimensions\n"
2419 "of the array. It is either an exact integer, giving the\n"
2420 "number directly, or a list of exact integers, whose length\n"
2421 "specifies the number of dimensions and each element is the\n"
2422 "lower index bound of its dimension.")
2423 #define FUNC_NAME s_scm_list_to_uniform_array
2424 {
2425 return scm_list_to_typed_array (prototype_to_type (prot), ndim, lst);
2426 }
2427 #undef FUNC_NAME
2428
2429 #endif
2430
2431 /* Print dimension DIM of ARRAY.
2432 */
2433
2434 static int
2435 scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
2436 SCM port, scm_print_state *pstate)
2437 {
2438 scm_t_array_dim *dim_spec = SCM_ARRAY_DIMS (array) + dim;
2439 long idx;
2440
2441 scm_putc ('(', port);
2442
2443 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2444 {
2445 if (dim < SCM_ARRAY_NDIM(array)-1)
2446 scm_i_print_array_dimension (array, dim+1, base, enclosed,
2447 port, pstate);
2448 else
2449 scm_iprin1 (scm_i_cvref (SCM_ARRAY_V (array), base, enclosed),
2450 port, pstate);
2451 if (idx < dim_spec->ubnd)
2452 scm_putc (' ', port);
2453 base += dim_spec->inc;
2454 }
2455
2456 scm_putc (')', port);
2457 return 1;
2458 }
2459
2460 /* Print an array. (Only for strict arrays, not for generalized vectors.)
2461 */
2462
2463 static int
2464 scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2465 {
2466 long ndim = SCM_ARRAY_NDIM (array);
2467 scm_t_array_dim *dim_specs = SCM_ARRAY_DIMS (array);
2468 SCM v = SCM_ARRAY_V (array);
2469 unsigned long base = SCM_ARRAY_BASE (array);
2470 long i;
2471
2472 scm_putc ('#', port);
2473 if (ndim != 1 || dim_specs[0].lbnd != 0)
2474 scm_intprint (ndim, 10, port);
2475 if (scm_is_uniform_vector (v))
2476 scm_puts (scm_i_uniform_vector_tag (v), port);
2477 else if (scm_is_bitvector (v))
2478 scm_puts ("b", port);
2479 else if (scm_is_string (v))
2480 scm_puts ("a", port);
2481 else if (!scm_is_vector (v))
2482 scm_puts ("?", port);
2483
2484 for (i = 0; i < ndim; i++)
2485 if (dim_specs[i].lbnd != 0)
2486 {
2487 for (i = 0; i < ndim; i++)
2488 {
2489 scm_putc ('@', port);
2490 scm_uintprint (dim_specs[i].lbnd, 10, port);
2491 }
2492 break;
2493 }
2494
2495 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
2496 }
2497
2498 static int
2499 scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
2500 {
2501 size_t base;
2502
2503 scm_putc ('#', port);
2504 base = SCM_ARRAY_BASE (array);
2505 scm_puts ("<enclosed-array ", port);
2506 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
2507 scm_putc ('>', port);
2508 return 1;
2509 }
2510
2511 /* Read an array. This function can also read vectors and uniform
2512 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2513 handled here.
2514
2515 C is the first character read after the '#'.
2516 */
2517
2518 static SCM
2519 tag_to_type (const char *tag, SCM port)
2520 {
2521 #if SCM_ENABLE_DEPRECATED
2522 {
2523 /* Recognize the old syntax.
2524 */
2525 const char *instead;
2526 switch (tag[0])
2527 {
2528 case 'u':
2529 instead = "u32";
2530 break;
2531 case 'e':
2532 instead = "s32";
2533 break;
2534 case 's':
2535 instead = "f32";
2536 break;
2537 case 'i':
2538 instead = "f64";
2539 break;
2540 case 'y':
2541 instead = "s8";
2542 break;
2543 case 'h':
2544 instead = "s16";
2545 break;
2546 case 'l':
2547 instead = "s64";
2548 break;
2549 case 'c':
2550 instead = "c64";
2551 break;
2552 default:
2553 instead = NULL;
2554 break;
2555 }
2556
2557 if (instead && tag[1] == '\0')
2558 {
2559 scm_c_issue_deprecation_warning_fmt
2560 ("The tag '%c' is deprecated for uniform vectors. "
2561 "Use '%s' instead.", tag[0], instead);
2562 return scm_from_locale_symbol (instead);
2563 }
2564 }
2565 #endif
2566
2567 return scm_from_locale_symbol (tag);
2568 }
2569
2570 SCM
2571 scm_i_read_array (SCM port, int c)
2572 {
2573 size_t rank;
2574 int got_rank;
2575 char tag[80];
2576 int tag_len;
2577
2578 SCM lower_bounds, elements;
2579
2580 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2581 the array code can not deal with zero-length dimensions yet, and
2582 we want to allow zero-length vectors, of course.
2583 */
2584 if (c == '(')
2585 {
2586 scm_ungetc (c, port);
2587 return scm_vector (scm_read (port));
2588 }
2589
2590 /* Disambiguate between '#f' and uniform floating point vectors.
2591 */
2592 if (c == 'f')
2593 {
2594 c = scm_getc (port);
2595 if (c != '3' && c != '6')
2596 {
2597 if (c != EOF)
2598 scm_ungetc (c, port);
2599 return SCM_BOOL_F;
2600 }
2601 rank = 1;
2602 got_rank = 1;
2603 tag[0] = 'f';
2604 tag_len = 1;
2605 goto continue_reading_tag;
2606 }
2607
2608 /* Read rank. We disallow arrays of rank zero since they do not
2609 seem to work reliably yet. */
2610 rank = 0;
2611 got_rank = 0;
2612 while ('0' <= c && c <= '9')
2613 {
2614 rank = 10*rank + c-'0';
2615 got_rank = 1;
2616 c = scm_getc (port);
2617 }
2618 if (!got_rank)
2619 rank = 1;
2620 else if (rank == 0)
2621 scm_i_input_error (NULL, port,
2622 "array rank must be positive", SCM_EOL);
2623
2624 /* Read tag. */
2625 tag_len = 0;
2626 continue_reading_tag:
2627 while (c != EOF && c != '(' && c != '@' && tag_len < 80)
2628 {
2629 tag[tag_len++] = c;
2630 c = scm_getc (port);
2631 }
2632 tag[tag_len] = '\0';
2633
2634 /* Read lower bounds. */
2635 lower_bounds = SCM_EOL;
2636 while (c == '@')
2637 {
2638 /* Yeah, right, we should use some ready-made integer parsing
2639 routine for this...
2640 */
2641
2642 long lbnd = 0;
2643 long sign = 1;
2644
2645 c = scm_getc (port);
2646 if (c == '-')
2647 {
2648 sign = -1;
2649 c = scm_getc (port);
2650 }
2651 while ('0' <= c && c <= '9')
2652 {
2653 lbnd = 10*lbnd + c-'0';
2654 c = scm_getc (port);
2655 }
2656 lower_bounds = scm_cons (scm_from_long (sign*lbnd), lower_bounds);
2657 }
2658
2659 /* Read nested lists of elements.
2660 */
2661 if (c != '(')
2662 scm_i_input_error (NULL, port,
2663 "missing '(' in vector or array literal",
2664 SCM_EOL);
2665 scm_ungetc (c, port);
2666 elements = scm_read (port);
2667
2668 if (scm_is_null (lower_bounds))
2669 lower_bounds = scm_from_size_t (rank);
2670 else if (scm_ilength (lower_bounds) != rank)
2671 scm_i_input_error (NULL, port,
2672 "the number of lower bounds must match the array rank",
2673 SCM_EOL);
2674
2675 /* Construct array. */
2676 return scm_list_to_typed_array (tag_to_type (tag, port),
2677 lower_bounds,
2678 elements);
2679 }
2680
2681 int
2682 scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
2683 {
2684 scm_iprin1 (exp, port, pstate);
2685 return 1;
2686 }
2687
2688 SCM_DEFINE (scm_array_type, "array-type", 1, 0, 0,
2689 (SCM ra),
2690 "")
2691 #define FUNC_NAME s_scm_array_type
2692 {
2693 if (SCM_ARRAYP (ra))
2694 return scm_i_generalized_vector_type (SCM_ARRAY_V (ra));
2695 else if (scm_is_generalized_vector (ra))
2696 return scm_i_generalized_vector_type (ra);
2697 else if (SCM_ENCLOSED_ARRAYP (ra))
2698 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
2699 else
2700 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2701 }
2702 #undef FUNC_NAME
2703
2704 #if SCM_ENABLE_DEPRECATED
2705
2706 SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
2707 (SCM ra),
2708 "Return an object that would produce an array of the same type\n"
2709 "as @var{array}, if used as the @var{prototype} for\n"
2710 "@code{make-uniform-array}.")
2711 #define FUNC_NAME s_scm_array_prototype
2712 {
2713 if (SCM_ARRAYP (ra))
2714 return scm_i_get_old_prototype (SCM_ARRAY_V (ra));
2715 else if (scm_is_generalized_vector (ra))
2716 return scm_i_get_old_prototype (ra);
2717 else if (SCM_ENCLOSED_ARRAYP (ra))
2718 return SCM_UNSPECIFIED;
2719 else
2720 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2721 }
2722 #undef FUNC_NAME
2723
2724 #endif
2725
2726 static SCM
2727 array_mark (SCM ptr)
2728 {
2729 return SCM_ARRAY_V (ptr);
2730 }
2731
2732 static size_t
2733 array_free (SCM ptr)
2734 {
2735 scm_gc_free (SCM_ARRAY_MEM (ptr),
2736 (sizeof (scm_t_array)
2737 + SCM_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2738 "array");
2739 return 0;
2740 }
2741
2742 void
2743 scm_init_unif ()
2744 {
2745 scm_tc16_array = scm_make_smob_type ("array", 0);
2746 scm_set_smob_mark (scm_tc16_array, array_mark);
2747 scm_set_smob_free (scm_tc16_array, array_free);
2748 scm_set_smob_print (scm_tc16_array, scm_i_print_array);
2749 scm_set_smob_equalp (scm_tc16_array, scm_array_equal_p);
2750
2751 scm_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
2752 scm_set_smob_mark (scm_tc16_enclosed_array, array_mark);
2753 scm_set_smob_free (scm_tc16_enclosed_array, array_free);
2754 scm_set_smob_print (scm_tc16_enclosed_array, scm_i_print_enclosed_array);
2755 scm_set_smob_equalp (scm_tc16_enclosed_array, scm_array_equal_p);
2756
2757 scm_add_feature ("array");
2758
2759 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2760 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2761 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2762 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2763
2764 init_type_creator_table ();
2765
2766 #include "libguile/unif.x"
2767
2768 }
2769
2770 /*
2771 Local Variables:
2772 c-file-style: "gnu"
2773 End:
2774 */