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