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