(scm_bitvector_elements): Made return value "const".
[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 const 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_elements (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_elements 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_elements (SCM vec)
1343 {
1344 scm_frame_unwind_handler_with_scm (scm_bitvector_release_elements, vec,
1345 SCM_F_WIND_EXPLICITLY);
1346 }
1347
1348 scm_t_uint32 *
1349 scm_bitvector_writable_elements (SCM vec)
1350 {
1351 scm_assert_smob_type (scm_tc16_bitvector, vec);
1352 return BITVECTOR_BITS (vec);
1353 }
1354
1355 void
1356 scm_bitvector_release_writable_elements (SCM vec)
1357 {
1358 scm_remember_upto_here_1 (vec);
1359 }
1360
1361 void
1362 scm_frame_bitvector_release_writable_elements (SCM vec)
1363 {
1364 scm_frame_unwind_handler_with_scm
1365 (scm_bitvector_release_writable_elements, vec,
1366 SCM_F_WIND_EXPLICITLY);
1367 }
1368
1369 SCM
1370 scm_c_bitvector_ref (SCM vec, size_t idx)
1371 {
1372 if (idx < scm_c_bitvector_length (vec))
1373 {
1374 const scm_t_uint32 *bits = scm_bitvector_elements (vec);
1375 SCM res = (bits[idx/32] & (1L << (idx%32)))? SCM_BOOL_T : SCM_BOOL_F;
1376 scm_bitvector_release_elements (vec);
1377 return res;
1378 }
1379 else
1380 scm_out_of_range (NULL, scm_from_size_t (idx));
1381 }
1382
1383 SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1384 (SCM vec, SCM idx),
1385 "Return the element at index @var{idx} of the bitvector\n"
1386 "@var{vec}.")
1387 #define FUNC_NAME s_scm_bitvector_ref
1388 {
1389 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1390 }
1391 #undef FUNC_NAME
1392
1393 void
1394 scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1395 {
1396 if (idx < scm_c_bitvector_length (vec))
1397 {
1398 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec);
1399 scm_t_uint32 mask = 1L << (idx%32);
1400 if (scm_is_true (val))
1401 bits[idx/32] |= mask;
1402 else
1403 bits[idx/32] &= ~mask;
1404 scm_bitvector_release_writable_elements (vec);
1405 }
1406 else
1407 scm_out_of_range (NULL, scm_from_size_t (idx));
1408 }
1409
1410 SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1411 (SCM vec, SCM idx, SCM val),
1412 "Set the element at index @var{idx} of the bitvector\n"
1413 "@var{vec} when @var{val} is true, else clear it.")
1414 #define FUNC_NAME s_scm_bitvector_set_x
1415 {
1416 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1417 return SCM_UNSPECIFIED;
1418 }
1419 #undef FUNC_NAME
1420
1421 SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1422 (SCM vec, SCM val),
1423 "Set all elements of the bitvector\n"
1424 "@var{vec} when @var{val} is true, else clear them.")
1425 #define FUNC_NAME s_scm_bitvector_fill_x
1426 {
1427 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec);
1428 size_t bit_len = BITVECTOR_LENGTH (vec);
1429 size_t word_len = (bit_len + 31) / 32;
1430 memset (bits, scm_is_true (val)? -1:0, sizeof (scm_t_uint32) * word_len);
1431 scm_bitvector_release_writable_elements (vec);
1432 return SCM_UNSPECIFIED;
1433 }
1434 #undef FUNC_NAME
1435
1436 SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1437 (SCM list),
1438 "Return a new bitvector initialized with the elements\n"
1439 "of @var{list}.")
1440 #define FUNC_NAME s_scm_list_to_bitvector
1441 {
1442 size_t bit_len = scm_to_size_t (scm_length (list));
1443 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1444 size_t word_len = (bit_len+31)/32;
1445 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec);
1446 size_t i, j;
1447
1448 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1449 {
1450 scm_t_uint32 mask = 1;
1451 bits[i] = 0;
1452 for (j = 0; j < 32 && j < bit_len;
1453 j++, mask <<= 1, list = SCM_CDR (list))
1454 if (scm_is_true (SCM_CAR (list)))
1455 bits[i] |= mask;
1456 }
1457
1458 scm_bitvector_release_writable_elements (vec);
1459 return vec;
1460 }
1461 #undef FUNC_NAME
1462
1463 SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1464 (SCM vec),
1465 "Return a new list initialized with the elements\n"
1466 "of the bitvector @var{vec}.")
1467 #define FUNC_NAME s_scm_bitvector_to_list
1468 {
1469 size_t bit_len = scm_c_bitvector_length (vec);
1470 SCM res = SCM_EOL;
1471 size_t word_len = (bit_len+31)/32;
1472 const scm_t_uint32 *bits = scm_bitvector_elements (vec);
1473 size_t i, j;
1474
1475 for (i = 0; i < word_len; i++, bit_len -= 32)
1476 {
1477 scm_t_uint32 mask = 1;
1478 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1479 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1480 }
1481
1482 scm_bitvector_release_elements (vec);
1483 return scm_reverse_x (res, SCM_EOL);
1484 }
1485 #undef FUNC_NAME
1486
1487 /* From mmix-arith.w by Knuth.
1488
1489 Here's a fun way to count the number of bits in a tetrabyte.
1490
1491 [This classical trick is called the ``Gillies--Miller method for
1492 sideways addition'' in {\sl The Preparation of Programs for an
1493 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1494 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1495 the tricks used here were suggested by Balbir Singh, Peter
1496 Rossmanith, and Stefan Schwoon.]
1497 */
1498
1499 static size_t
1500 count_ones (scm_t_uint32 x)
1501 {
1502 x=x-((x>>1)&0x55555555);
1503 x=(x&0x33333333)+((x>>2)&0x33333333);
1504 x=(x+(x>>4))&0x0f0f0f0f;
1505 x=x+(x>>8);
1506 return (x+(x>>16)) & 0xff;
1507 }
1508
1509 SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
1510 (SCM b, SCM bitvector),
1511 "Return the number of occurrences of the boolean @var{b} in\n"
1512 "@var{bitvector}.")
1513 #define FUNC_NAME s_scm_bit_count
1514 {
1515 size_t bit_len = scm_c_bitvector_length (bitvector);
1516 size_t word_len = (bit_len + 31) / 32;
1517 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1518 const scm_t_uint32 *bits = scm_bitvector_elements (bitvector);
1519
1520 int bit = scm_to_bool (b);
1521 size_t count = 0, i;
1522
1523 if (bit_len == 0)
1524 return 0;
1525
1526 for (i = 0; i < word_len-1; i++)
1527 count += count_ones (bits[i]);
1528 count += count_ones (bits[i] & last_mask);
1529
1530 scm_bitvector_release_elements (bitvector);
1531 return scm_from_size_t (bit? count : bit_len-count);
1532 }
1533 #undef FUNC_NAME
1534
1535 /* returns 32 for x == 0.
1536 */
1537 static size_t
1538 find_first_one (scm_t_uint32 x)
1539 {
1540 size_t pos = 0;
1541 /* do a binary search in x. */
1542 if ((x & 0xFFFF) == 0)
1543 x >>= 16, pos += 16;
1544 if ((x & 0xFF) == 0)
1545 x >>= 8, pos += 8;
1546 if ((x & 0xF) == 0)
1547 x >>= 4, pos += 4;
1548 if ((x & 0x3) == 0)
1549 x >>= 2, pos += 2;
1550 if ((x & 0x1) == 0)
1551 pos += 1;
1552 return pos;
1553 }
1554
1555 SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1556 (SCM item, SCM v, SCM k),
1557 "Return the index of the first occurrance of @var{item} in bit\n"
1558 "vector @var{v}, starting from @var{k}. If there is no\n"
1559 "@var{item} entry between @var{k} and the end of\n"
1560 "@var{bitvector}, then return @code{#f}. For example,\n"
1561 "\n"
1562 "@example\n"
1563 "(bit-position #t #*000101 0) @result{} 3\n"
1564 "(bit-position #f #*0001111 3) @result{} #f\n"
1565 "@end example")
1566 #define FUNC_NAME s_scm_bit_position
1567 {
1568 size_t bit_len = scm_c_bitvector_length (v);
1569 size_t word_len = (bit_len + 31) / 32;
1570 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1571 const scm_t_uint32 *bits = scm_bitvector_elements (v);
1572 size_t first_bit = scm_to_unsigned_integer (k, 0, bit_len);
1573 size_t first_word = first_bit / 32;
1574 scm_t_uint32 first_mask = ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1575 scm_t_uint32 w;
1576
1577 int bit = scm_to_bool (item);
1578 size_t i;
1579 SCM res = SCM_BOOL_F;
1580
1581 if (bit_len == 0)
1582 return 0;
1583
1584 for (i = first_word; i < word_len; i++)
1585 {
1586 w = (bit? bits[i] : ~bits[i]);
1587 if (i == first_word)
1588 w &= first_mask;
1589 if (i == word_len-1)
1590 w &= last_mask;
1591 if (w)
1592 {
1593 res = scm_from_size_t (32*i + find_first_one (w));
1594 break;
1595 }
1596 }
1597
1598 scm_bitvector_release_elements (v);
1599 return res;
1600 }
1601 #undef FUNC_NAME
1602
1603 SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
1604 (SCM v, SCM kv, SCM obj),
1605 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1606 "selecting the entries to change. The return value is\n"
1607 "unspecified.\n"
1608 "\n"
1609 "If @var{kv} is a bit vector, then those entries where it has\n"
1610 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1611 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1612 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1613 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1614 "\n"
1615 "@example\n"
1616 "(define bv #*01000010)\n"
1617 "(bit-set*! bv #*10010001 #t)\n"
1618 "bv\n"
1619 "@result{} #*11010011\n"
1620 "@end example\n"
1621 "\n"
1622 "If @var{kv} is a u32vector, then its elements are\n"
1623 "indices into @var{v} which are set to @var{obj}.\n"
1624 "\n"
1625 "@example\n"
1626 "(define bv #*01000010)\n"
1627 "(bit-set*! bv #u32(5 2 7) #t)\n"
1628 "bv\n"
1629 "@result{} #*01100111\n"
1630 "@end example")
1631 #define FUNC_NAME s_scm_bit_set_star_x
1632 {
1633 if (scm_is_bitvector (kv))
1634 {
1635 size_t bit_len = scm_c_bitvector_length (kv);
1636 size_t word_len = (bit_len + 31) / 32;
1637 scm_t_uint32 *bits1;
1638 const scm_t_uint32 *bits2;
1639 size_t i;
1640 int bit = scm_to_bool (obj);
1641
1642 if (scm_c_bitvector_length (v) != bit_len)
1643 scm_misc_error (NULL,
1644 "bit vectors must have equal length",
1645 SCM_EOL);
1646
1647 bits1 = scm_bitvector_writable_elements (v);
1648 bits2 = scm_bitvector_elements (kv);
1649
1650 if (bit == 0)
1651 for (i = 0; i < word_len; i++)
1652 bits1[i] &= ~bits2[i];
1653 else
1654 for (i = 0; i < word_len; i++)
1655 bits1[i] |= bits2[i];
1656
1657 scm_bitvector_release_elements (kv);
1658 scm_bitvector_release_writable_elements (v);
1659 }
1660 else if (scm_is_true (scm_u32vector_p (kv)))
1661 {
1662 size_t ulen, i;
1663 const scm_t_uint32 *indices;
1664
1665 /* assert that obj is a boolean.
1666 */
1667 scm_to_bool (obj);
1668
1669 scm_frame_begin (0);
1670
1671 ulen = scm_c_uniform_vector_length (kv);
1672 indices = scm_u32vector_elements (kv);
1673 scm_frame_uniform_vector_release_elements (kv);
1674
1675 for (i = 0; i < ulen; i++)
1676 scm_c_bitvector_set_x (v, (size_t)indices[i], obj);
1677
1678 scm_frame_end ();
1679 }
1680 else
1681 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
1682
1683 return SCM_UNSPECIFIED;
1684 }
1685 #undef FUNC_NAME
1686
1687
1688 SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
1689 (SCM v, SCM kv, SCM obj),
1690 "Return a count of how many entries in bit vector @var{v} are\n"
1691 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
1692 "consider.\n"
1693 "\n"
1694 "If @var{kv} is a bit vector, then those entries where it has\n"
1695 "@code{#t} are the ones in @var{v} which are considered.\n"
1696 "@var{kv} and @var{v} must be the same length.\n"
1697 "\n"
1698 "If @var{kv} is a u32vector, then it contains\n"
1699 "the indexes in @var{v} to consider.\n"
1700 "\n"
1701 "For example,\n"
1702 "\n"
1703 "@example\n"
1704 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
1705 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
1706 "@end example")
1707 #define FUNC_NAME s_scm_bit_count_star
1708 {
1709 if (scm_is_bitvector (kv))
1710 {
1711 size_t bit_len = scm_c_bitvector_length (kv);
1712 size_t word_len = (bit_len + 31) / 32;
1713 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1714 scm_t_uint32 xor_mask = scm_to_bool (obj)? 0 : ((scm_t_uint32)-1);
1715 const scm_t_uint32 *bits1, *bits2;
1716 size_t count = 0, i;
1717
1718 if (scm_c_bitvector_length (v) != bit_len)
1719 scm_misc_error (NULL,
1720 "bit vectors must have equal length",
1721 SCM_EOL);
1722
1723 if (bit_len == 0)
1724 return scm_from_size_t (0);
1725
1726 bits1 = scm_bitvector_elements (v);
1727 bits2 = scm_bitvector_elements (kv);
1728
1729 for (i = 0; i < word_len-1; i++)
1730 count += count_ones ((bits1[i]^xor_mask) & bits2[i]);
1731 count += count_ones ((bits1[i]^xor_mask) & bits2[i] & last_mask);
1732
1733 scm_bitvector_release_elements (kv);
1734 scm_bitvector_release_elements (v);
1735
1736 return scm_from_size_t (count);
1737 }
1738 else if (scm_is_true (scm_u32vector_p (kv)))
1739 {
1740 size_t count = 0, ulen, i;
1741 const scm_t_uint32 *indices;
1742 int bit = scm_to_bool (obj);
1743
1744 scm_frame_begin (0);
1745
1746 ulen = scm_c_uniform_vector_length (kv);
1747 indices = scm_u32vector_elements (kv);
1748 scm_frame_uniform_vector_release_elements (kv);
1749
1750 for (i = 0; i < ulen; i++)
1751 if ((scm_is_true (scm_c_bitvector_ref (v, (size_t)indices[i])) != 0)
1752 == (bit != 0))
1753 count++;
1754
1755 scm_frame_end ();
1756
1757 return scm_from_size_t (count);
1758 }
1759 else
1760 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
1761 }
1762 #undef FUNC_NAME
1763
1764
1765 SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
1766 (SCM v),
1767 "Modify the bit vector @var{v} by replacing each element with\n"
1768 "its negation.")
1769 #define FUNC_NAME s_scm_bit_invert_x
1770 {
1771 size_t bit_len = scm_c_bitvector_length (v);
1772 size_t word_len = (bit_len + 31) / 32;
1773 scm_t_uint32 *bits = scm_bitvector_writable_elements (v);
1774 size_t i;
1775
1776 for (i = 0; i < word_len; i++)
1777 bits[i] = ~bits[i];
1778
1779 scm_bitvector_release_writable_elements (v);
1780 return SCM_UNSPECIFIED;
1781 }
1782 #undef FUNC_NAME
1783
1784
1785 SCM
1786 scm_istr2bve (SCM str)
1787 {
1788 size_t len = scm_i_string_length (str);
1789 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
1790 SCM res = vec;
1791
1792 scm_t_uint32 mask;
1793 size_t k, j;
1794 const char *c_str = scm_i_string_chars (str);
1795 scm_t_uint32 *data = scm_bitvector_writable_elements (vec);
1796
1797 for (k = 0; k < (len + 31) / 32; k++)
1798 {
1799 data[k] = 0L;
1800 j = len - k * 32;
1801 if (j > 32)
1802 j = 32;
1803 for (mask = 1L; j--; mask <<= 1)
1804 switch (*c_str++)
1805 {
1806 case '0':
1807 break;
1808 case '1':
1809 data[k] |= mask;
1810 break;
1811 default:
1812 res = SCM_BOOL_F;
1813 goto exit;
1814 }
1815 }
1816
1817 exit:
1818 scm_remember_upto_here_1 (str);
1819 scm_bitvector_release_writable_elements (vec);
1820 return res;
1821 }
1822
1823
1824
1825 static SCM
1826 ra2l (SCM ra, unsigned long base, unsigned long k)
1827 {
1828 SCM res = SCM_EOL;
1829 long inc = SCM_ARRAY_DIMS (ra)[k].inc;
1830 size_t i;
1831 int enclosed = SCM_ENCLOSED_ARRAYP (ra);
1832
1833 if (SCM_ARRAY_DIMS (ra)[k].ubnd < SCM_ARRAY_DIMS (ra)[k].lbnd)
1834 return SCM_EOL;
1835 i = base + (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd) * inc;
1836 if (k < SCM_ARRAY_NDIM (ra) - 1)
1837 {
1838 do
1839 {
1840 i -= inc;
1841 res = scm_cons (ra2l (ra, i, k + 1), res);
1842 }
1843 while (i != base);
1844 }
1845 else
1846 do
1847 {
1848 i -= inc;
1849 res = scm_cons (scm_i_cvref (SCM_ARRAY_V (ra), i, enclosed),
1850 res);
1851 }
1852 while (i != base);
1853 return res;
1854 }
1855
1856
1857 SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
1858 (SCM v),
1859 "Return a list consisting of all the elements, in order, of\n"
1860 "@var{array}.")
1861 #define FUNC_NAME s_scm_array_to_list
1862 {
1863 if (scm_is_generalized_vector (v))
1864 return scm_generalized_vector_to_list (v);
1865 else if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
1866 return ra2l (v, SCM_ARRAY_BASE (v), 0);
1867
1868 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1869 }
1870 #undef FUNC_NAME
1871
1872
1873 static int l2ra(SCM lst, SCM ra, unsigned long base, unsigned long k);
1874
1875 SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
1876 (SCM ndim, SCM prot, SCM lst),
1877 "@deffnx {Scheme Procedure} list->uniform-vector prot lst\n"
1878 "Return a uniform array of the type indicated by prototype\n"
1879 "@var{prot} with elements the same as those of @var{lst}.\n"
1880 "Elements must be of the appropriate type, no coercions are\n"
1881 "done.\n"
1882 "\n"
1883 "The argument @var{ndim} determines the number of dimensions\n"
1884 "of the array. It is either an exact integer, giving the\n"
1885 "number directly, or a list of exact integers, whose length\n"
1886 "specifies the number of dimensions and each element is the\n"
1887 "lower index bound of its dimension.")
1888 #define FUNC_NAME s_scm_list_to_uniform_array
1889 {
1890 SCM shape, row;
1891 SCM ra;
1892 unsigned long k;
1893
1894 shape = SCM_EOL;
1895 row = lst;
1896 if (scm_is_integer (ndim))
1897 {
1898 size_t k = scm_to_size_t (ndim);
1899 while (k-- > 0)
1900 {
1901 shape = scm_cons (scm_length (row), shape);
1902 if (k > 0)
1903 row = scm_car (row);
1904 }
1905 }
1906 else
1907 {
1908 while (1)
1909 {
1910 shape = scm_cons (scm_list_2 (scm_car (ndim),
1911 scm_sum (scm_sum (scm_car (ndim),
1912 scm_length (row)),
1913 scm_from_int (-1))),
1914 shape);
1915 ndim = scm_cdr (ndim);
1916 if (scm_is_pair (ndim))
1917 row = scm_car (row);
1918 else
1919 break;
1920 }
1921 }
1922
1923 ra = scm_dimensions_to_uniform_array (scm_reverse_x (shape, SCM_EOL), prot,
1924 SCM_UNDEFINED);
1925
1926 if (scm_is_null (shape))
1927 {
1928 SCM_ASRTGO (1 == scm_ilength (lst), badlst);
1929 scm_array_set_x (ra, SCM_CAR (lst), SCM_EOL);
1930 return ra;
1931 }
1932 if (!SCM_ARRAYP (ra))
1933 {
1934 size_t length = scm_c_generalized_vector_length (ra);
1935 for (k = 0; k < length; k++, lst = SCM_CDR (lst))
1936 scm_c_generalized_vector_set_x (ra, k, SCM_CAR (lst));
1937 return ra;
1938 }
1939 if (l2ra (lst, ra, SCM_ARRAY_BASE (ra), 0))
1940 return ra;
1941 else
1942 badlst:SCM_MISC_ERROR ("Bad scm_array contents list: ~S",
1943 scm_list_1 (lst));
1944 }
1945 #undef FUNC_NAME
1946
1947 static int
1948 l2ra (SCM lst, SCM ra, unsigned long base, unsigned long k)
1949 {
1950 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
1951 register long n = (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd);
1952 int ok = 1;
1953 if (n <= 0)
1954 return (scm_is_null (lst));
1955 if (k < SCM_ARRAY_NDIM (ra) - 1)
1956 {
1957 while (n--)
1958 {
1959 if (!scm_is_pair (lst))
1960 return 0;
1961 ok = ok && l2ra (SCM_CAR (lst), ra, base, k + 1);
1962 base += inc;
1963 lst = SCM_CDR (lst);
1964 }
1965 if (!scm_is_null (lst))
1966 return 0;
1967 }
1968 else
1969 {
1970 while (n--)
1971 {
1972 if (!scm_is_pair (lst))
1973 return 0;
1974 scm_array_set_x (SCM_ARRAY_V (ra), SCM_CAR (lst), scm_from_ulong (base));
1975 base += inc;
1976 lst = SCM_CDR (lst);
1977 }
1978 if (!scm_is_null (lst))
1979 return 0;
1980 }
1981 return ok;
1982 }
1983
1984
1985 /* Print dimension DIM of ARRAY.
1986 */
1987
1988 static int
1989 scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
1990 SCM port, scm_print_state *pstate)
1991 {
1992 scm_t_array_dim *dim_spec = SCM_ARRAY_DIMS (array) + dim;
1993 long idx;
1994
1995 scm_putc ('(', port);
1996
1997 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
1998 {
1999 if (dim < SCM_ARRAY_NDIM(array)-1)
2000 scm_i_print_array_dimension (array, dim+1, base, enclosed,
2001 port, pstate);
2002 else
2003 scm_iprin1 (scm_i_cvref (SCM_ARRAY_V (array), base, enclosed),
2004 port, pstate);
2005 if (idx < dim_spec->ubnd)
2006 scm_putc (' ', port);
2007 base += dim_spec->inc;
2008 }
2009
2010 scm_putc (')', port);
2011 return 1;
2012 }
2013
2014 /* Print an array. (Only for strict arrays, not for strings, uniform
2015 vectors, vectors and other stuff that can masquerade as an array.)
2016 */
2017
2018 /* The array tag is generally of the form
2019 *
2020 * #<rank><unif><@lower><@lower>...
2021 *
2022 * <rank> is a positive integer in decimal giving the rank of the
2023 * array. It is omitted when the rank is 1 and the array is
2024 * non-shared and has zero-origin. For shared arrays and for a
2025 * non-zero origin, the rank is always printed even when it is 1 to
2026 * dinstinguish them from ordinary vectors.
2027 *
2028 * <unif> is the tag for a uniform (or homogenous) numeric vector,
2029 * like u8, s16, etc, as defined by SRFI-4. It is omitted when the
2030 * array is not uniform.
2031 *
2032 * <@lower> is a 'at' sign followed by a integer in decimal giving the
2033 * lower bound of a dimension. There is one <@lower> for each
2034 * dimension. When all lower bounds are zero, all <@lower> are
2035 * omitted.
2036 *
2037 * Thus,
2038 *
2039 * #(1 2 3) is non-uniform array of rank 1 with lower bound 0 in
2040 * dimension 0. (I.e., a regular vector.)
2041 *
2042 * #@2(1 2 3) is non-uniform array of rank 1 with lower bound 2 in
2043 * dimension 0.
2044 *
2045 * #2((1 2 3) (4 5 6)) is a non-uniform array of rank 2; a 3x3
2046 * matrix with index ranges 0..2 and 0..2.
2047 *
2048 * #u32(0 1 2) is a uniform u8 array of rank 1.
2049 *
2050 * #2u32@2@3((1 2) (2 3)) is a uniform u8 array of rank 2 with index
2051 * ranges 2..3 and 3..4.
2052 */
2053
2054 static int
2055 scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2056 {
2057 long ndim = SCM_ARRAY_NDIM (array);
2058 scm_t_array_dim *dim_specs = SCM_ARRAY_DIMS (array);
2059 SCM v = SCM_ARRAY_V (array);
2060 unsigned long base = SCM_ARRAY_BASE (array);
2061 long i;
2062
2063 scm_putc ('#', port);
2064 if (ndim != 1 || dim_specs[0].lbnd != 0)
2065 scm_intprint (ndim, 10, port);
2066 if (scm_is_uniform_vector (v))
2067 scm_puts (scm_i_uniform_vector_tag (v), port);
2068 else if (scm_is_bitvector (v))
2069 scm_puts ("b", port);
2070 else if (scm_is_string (v))
2071 scm_puts ("a", port);
2072 else if (!scm_is_vector (v))
2073 scm_puts ("?", port);
2074
2075 for (i = 0; i < ndim; i++)
2076 if (dim_specs[i].lbnd != 0)
2077 {
2078 for (i = 0; i < ndim; i++)
2079 {
2080 scm_putc ('@', port);
2081 scm_uintprint (dim_specs[i].lbnd, 10, port);
2082 }
2083 break;
2084 }
2085
2086 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
2087 }
2088
2089 static int
2090 scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
2091 {
2092 size_t base;
2093
2094 scm_putc ('#', port);
2095 base = SCM_ARRAY_BASE (array);
2096 scm_puts ("<enclosed-array ", port);
2097 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
2098 scm_putc ('>', port);
2099 return 1;
2100 }
2101
2102 /* Read an array. This function can also read vectors and uniform
2103 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2104 handled here.
2105
2106 C is the first character read after the '#'.
2107 */
2108
2109 typedef struct {
2110 const char *tag;
2111 SCM *creator_var;
2112 } tag_creator;
2113
2114 static tag_creator tag_creator_table[] = {
2115 { "", &scm_i_proc_make_vector },
2116 { "a", &scm_i_proc_make_string },
2117 { "b", &scm_i_proc_make_bitvector },
2118 { "u8", &scm_i_proc_make_u8vector },
2119 { "s8", &scm_i_proc_make_s8vector },
2120 { "u16", &scm_i_proc_make_u16vector },
2121 { "s16", &scm_i_proc_make_s16vector },
2122 { "u32", &scm_i_proc_make_u32vector },
2123 { "s32", &scm_i_proc_make_s32vector },
2124 { "u64", &scm_i_proc_make_u64vector },
2125 { "s64", &scm_i_proc_make_s64vector },
2126 { "f32", &scm_i_proc_make_f32vector },
2127 { "f64", &scm_i_proc_make_f64vector },
2128 { "c32", &scm_i_proc_make_c32vector },
2129 { "c64", &scm_i_proc_make_c64vector },
2130 { NULL, NULL }
2131 };
2132
2133 static SCM
2134 scm_i_tag_to_creator (const char *tag, SCM port)
2135 {
2136 tag_creator *tp;
2137
2138 for (tp = tag_creator_table; tp->tag; tp++)
2139 if (!strcmp (tp->tag, tag))
2140 return *(tp->creator_var);
2141
2142 #if SCM_ENABLE_DEPRECATED
2143 {
2144 /* Recognize the old syntax, producing the old prototypes.
2145 */
2146 SCM proto = SCM_EOL;
2147 const char *instead;
2148 switch (tag[0])
2149 {
2150 case 'u':
2151 proto = scm_from_int (1);
2152 instead = "u32";
2153 break;
2154 case 'e':
2155 proto = scm_from_int (-1);
2156 instead = "s32";
2157 break;
2158 case 's':
2159 proto = scm_from_double (1.0);
2160 instead = "f32";
2161 break;
2162 case 'i':
2163 proto = scm_divide (scm_from_int (1), scm_from_int (3));
2164 instead = "f64";
2165 break;
2166 case 'y':
2167 proto = SCM_MAKE_CHAR (0);
2168 instead = "s8";
2169 break;
2170 case 'h':
2171 proto = scm_from_locale_symbol ("s");
2172 instead = "s16";
2173 break;
2174 case 'l':
2175 proto = scm_from_locale_symbol ("l");
2176 instead = "s64";
2177 break;
2178 case 'c':
2179 proto = scm_c_make_rectangular (0.0, 1.0);
2180 instead = "c64";
2181 break;
2182 default:
2183 instead = "???";
2184 break;
2185 }
2186 if (!scm_is_eq (proto, SCM_EOL) && tag[1] == '\0')
2187 {
2188 scm_c_issue_deprecation_warning_fmt
2189 ("The tag '%c' is deprecated for uniform vectors. "
2190 "Use '%s' instead.", tag[0], instead);
2191 return proto;
2192 }
2193 }
2194 #endif
2195
2196 scm_i_input_error (NULL, port,
2197 "unrecognized uniform array tag: ~a",
2198 scm_list_1 (scm_from_locale_string (tag)));
2199 return SCM_BOOL_F;
2200 }
2201
2202 SCM
2203 scm_i_read_array (SCM port, int c)
2204 {
2205 size_t rank;
2206 int got_rank;
2207 char tag[80];
2208 int tag_len;
2209
2210 SCM lower_bounds, elements;
2211
2212 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2213 the array code can not deal with zero-length dimensions yet, and
2214 we want to allow zero-length vectors, of course.
2215 */
2216 if (c == '(')
2217 {
2218 scm_ungetc (c, port);
2219 return scm_vector (scm_read (port));
2220 }
2221
2222 /* Disambiguate between '#f' and uniform floating point vectors.
2223 */
2224 if (c == 'f')
2225 {
2226 c = scm_getc (port);
2227 if (c != '3' && c != '6')
2228 {
2229 if (c != EOF)
2230 scm_ungetc (c, port);
2231 return SCM_BOOL_F;
2232 }
2233 rank = 1;
2234 got_rank = 1;
2235 tag[0] = 'f';
2236 tag_len = 1;
2237 goto continue_reading_tag;
2238 }
2239
2240 /* Read rank. We disallow arrays of rank zero since they do not
2241 seem to work reliably yet. */
2242 rank = 0;
2243 got_rank = 0;
2244 while ('0' <= c && c <= '9')
2245 {
2246 rank = 10*rank + c-'0';
2247 got_rank = 1;
2248 c = scm_getc (port);
2249 }
2250 if (!got_rank)
2251 rank = 1;
2252 else if (rank == 0)
2253 scm_i_input_error (NULL, port,
2254 "array rank must be positive", SCM_EOL);
2255
2256 /* Read tag. */
2257 tag_len = 0;
2258 continue_reading_tag:
2259 while (c != EOF && c != '(' && c != '@' && tag_len < 80)
2260 {
2261 tag[tag_len++] = c;
2262 c = scm_getc (port);
2263 }
2264 tag[tag_len] = '\0';
2265
2266 /* Read lower bounds. */
2267 lower_bounds = SCM_EOL;
2268 while (c == '@')
2269 {
2270 /* Yeah, right, we should use some ready-made integer parsing
2271 routine for this...
2272 */
2273
2274 long lbnd = 0;
2275 long sign = 1;
2276
2277 c = scm_getc (port);
2278 if (c == '-')
2279 {
2280 sign = -1;
2281 c = scm_getc (port);
2282 }
2283 while ('0' <= c && c <= '9')
2284 {
2285 lbnd = 10*lbnd + c-'0';
2286 c = scm_getc (port);
2287 }
2288 lower_bounds = scm_cons (scm_from_long (sign*lbnd), lower_bounds);
2289 }
2290
2291 /* Read nested lists of elements.
2292 */
2293 if (c != '(')
2294 scm_i_input_error (NULL, port,
2295 "missing '(' in vector or array literal",
2296 SCM_EOL);
2297 scm_ungetc (c, port);
2298 elements = scm_read (port);
2299
2300 if (scm_is_null (lower_bounds))
2301 lower_bounds = scm_from_size_t (rank);
2302 else if (scm_ilength (lower_bounds) != rank)
2303 scm_i_input_error (NULL, port,
2304 "the number of lower bounds must match the array rank",
2305 SCM_EOL);
2306
2307 /* Construct array. */
2308 return scm_list_to_uniform_array (lower_bounds,
2309 scm_i_tag_to_creator (tag, port),
2310 elements);
2311 }
2312
2313 int
2314 scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
2315 {
2316 scm_iprin1 (exp, port, pstate);
2317 return 1;
2318 }
2319
2320 SCM_DEFINE (scm_array_creator, "array-creator", 1, 0, 0,
2321 (SCM ra),
2322 "Return a procedure that would produce an array of the same type\n"
2323 "as @var{array} if used as the @var{creator} with\n"
2324 "@code{make-array*}.")
2325 #define FUNC_NAME s_scm_array_creator
2326 {
2327 if (SCM_ARRAYP (ra))
2328 return scm_i_generalized_vector_creator (SCM_ARRAY_V (ra));
2329 else if (scm_is_generalized_vector (ra))
2330 return scm_i_generalized_vector_creator (ra);
2331 else if (SCM_ENCLOSED_ARRAYP (ra))
2332 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
2333 else
2334 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2335 }
2336 #undef FUNC_NAME
2337
2338 #if SCM_ENABLE_DEPRECATED
2339
2340 SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
2341 (SCM ra),
2342 "Return an object that would produce an array of the same type\n"
2343 "as @var{array}, if used as the @var{prototype} for\n"
2344 "@code{make-uniform-array}.")
2345 #define FUNC_NAME s_scm_array_prototype
2346 {
2347 if (SCM_ARRAYP (ra))
2348 return scm_i_get_old_prototype (SCM_ARRAY_V (ra));
2349 else if (scm_is_generalized_vector (ra))
2350 return scm_i_get_old_prototype (ra);
2351 else if (SCM_ENCLOSED_ARRAYP (ra))
2352 return SCM_UNSPECIFIED;
2353 else
2354 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2355 }
2356 #undef FUNC_NAME
2357
2358 #endif
2359
2360 static SCM
2361 array_mark (SCM ptr)
2362 {
2363 return SCM_ARRAY_V (ptr);
2364 }
2365
2366
2367 static size_t
2368 array_free (SCM ptr)
2369 {
2370 scm_gc_free (SCM_ARRAY_MEM (ptr),
2371 (sizeof (scm_t_array)
2372 + SCM_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2373 "array");
2374 return 0;
2375 }
2376
2377 void
2378 scm_init_unif ()
2379 {
2380 scm_tc16_array = scm_make_smob_type ("array", 0);
2381 scm_set_smob_mark (scm_tc16_array, array_mark);
2382 scm_set_smob_free (scm_tc16_array, array_free);
2383 scm_set_smob_print (scm_tc16_array, scm_i_print_array);
2384 scm_set_smob_equalp (scm_tc16_array, scm_array_equal_p);
2385
2386 scm_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
2387 scm_set_smob_mark (scm_tc16_enclosed_array, array_mark);
2388 scm_set_smob_free (scm_tc16_enclosed_array, array_free);
2389 scm_set_smob_print (scm_tc16_enclosed_array, scm_i_print_enclosed_array);
2390 scm_set_smob_equalp (scm_tc16_enclosed_array, scm_array_equal_p);
2391
2392 scm_add_feature ("array");
2393
2394 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2395 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2396 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2397 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2398
2399 #include "libguile/unif.x"
2400
2401 scm_i_proc_make_vector = scm_variable_ref (scm_c_lookup ("make-vector"));
2402 scm_i_proc_make_string = scm_variable_ref (scm_c_lookup ("make-string"));
2403 scm_i_proc_make_bitvector =
2404 scm_variable_ref (scm_c_lookup ("make-bitvector"));
2405 }
2406
2407 /*
2408 Local Variables:
2409 c-file-style: "gnu"
2410 End:
2411 */