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