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