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