Removed a lot of now-useless SMOB mark/free functions.
[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 #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_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 = SCM_I_ARRAY_NDIM (v);
1154 scm_t_array_dim *s = SCM_I_ARRAY_DIMS (v);
1155
1156 while (k > 0)
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 k -= 1;
1165
1166 if (ind < s->lbnd || ind > s->ubnd)
1167 {
1168 res = SCM_BOOL_F;
1169 /* We do not stop the checking after finding a violation
1170 since we want to validate the type-correctness and
1171 number of arguments in any case.
1172 */
1173 }
1174 }
1175 }
1176 else if (scm_is_generalized_vector (v))
1177 {
1178 /* Since real arrays have been covered above, all generalized
1179 vectors are guaranteed to be zero-origin here.
1180 */
1181
1182 long ind;
1183
1184 if (!scm_is_pair (args))
1185 SCM_WRONG_NUM_ARGS ();
1186 ind = scm_to_long (SCM_CAR (args));
1187 args = SCM_CDR (args);
1188 res = scm_from_bool (ind >= 0
1189 && ind < scm_c_generalized_vector_length (v));
1190 }
1191 else
1192 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1193
1194 if (!scm_is_null (args))
1195 SCM_WRONG_NUM_ARGS ();
1196
1197 return res;
1198 }
1199 #undef FUNC_NAME
1200
1201 SCM
1202 scm_i_cvref (SCM v, size_t pos, int enclosed)
1203 {
1204 if (enclosed)
1205 {
1206 int k = SCM_I_ARRAY_NDIM (v);
1207 SCM res = scm_i_make_ra (k, 0);
1208 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (v);
1209 SCM_I_ARRAY_BASE (res) = pos;
1210 while (k--)
1211 {
1212 SCM_I_ARRAY_DIMS (res)[k].ubnd = SCM_I_ARRAY_DIMS (v)[k].ubnd;
1213 SCM_I_ARRAY_DIMS (res)[k].lbnd = SCM_I_ARRAY_DIMS (v)[k].lbnd;
1214 SCM_I_ARRAY_DIMS (res)[k].inc = SCM_I_ARRAY_DIMS (v)[k].inc;
1215 }
1216 return res;
1217 }
1218 else
1219 return scm_c_generalized_vector_ref (v, pos);
1220 }
1221
1222 SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1223 (SCM v, SCM args),
1224 "Return the element at the @code{(index1, index2)} element in\n"
1225 "@var{array}.")
1226 #define FUNC_NAME s_scm_array_ref
1227 {
1228 scm_t_array_handle handle;
1229 SCM res;
1230
1231 scm_array_get_handle (v, &handle);
1232 res = scm_array_handle_ref (&handle, scm_array_handle_pos (&handle, args));
1233 scm_array_handle_release (&handle);
1234 return res;
1235 }
1236 #undef FUNC_NAME
1237
1238
1239 SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1240 (SCM v, SCM obj, SCM args),
1241 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
1242 "@var{new-value}. The value returned by array-set! is unspecified.")
1243 #define FUNC_NAME s_scm_array_set_x
1244 {
1245 scm_t_array_handle handle;
1246
1247 scm_array_get_handle (v, &handle);
1248 scm_array_handle_set (&handle, scm_array_handle_pos (&handle, args), obj);
1249 scm_array_handle_release (&handle);
1250 return SCM_UNSPECIFIED;
1251 }
1252 #undef FUNC_NAME
1253
1254 /* attempts to unroll an array into a one-dimensional array.
1255 returns the unrolled array or #f if it can't be done. */
1256 /* if strict is not SCM_UNDEFINED, return #f if returned array
1257 wouldn't have contiguous elements. */
1258 SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1259 (SCM ra, SCM strict),
1260 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
1261 "without changing their order (last subscript changing fastest), then\n"
1262 "@code{array-contents} returns that shared array, otherwise it returns\n"
1263 "@code{#f}. All arrays made by @var{make-array} and\n"
1264 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
1265 "@var{make-shared-array} may not be.\n\n"
1266 "If the optional argument @var{strict} is provided, a shared array will\n"
1267 "be returned only if its elements are stored internally contiguous in\n"
1268 "memory.")
1269 #define FUNC_NAME s_scm_array_contents
1270 {
1271 SCM sra;
1272
1273 if (scm_is_generalized_vector (ra))
1274 return ra;
1275
1276 if (SCM_I_ARRAYP (ra))
1277 {
1278 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
1279 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
1280 return SCM_BOOL_F;
1281 for (k = 0; k < ndim; k++)
1282 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1283 if (!SCM_UNBNDP (strict))
1284 {
1285 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
1286 return SCM_BOOL_F;
1287 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
1288 {
1289 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
1290 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
1291 len % SCM_LONG_BIT)
1292 return SCM_BOOL_F;
1293 }
1294 }
1295
1296 {
1297 SCM v = SCM_I_ARRAY_V (ra);
1298 size_t length = scm_c_generalized_vector_length (v);
1299 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
1300 return v;
1301 }
1302
1303 sra = scm_i_make_ra (1, 0);
1304 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
1305 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
1306 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
1307 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
1308 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
1309 return sra;
1310 }
1311 else if (SCM_I_ENCLOSED_ARRAYP (ra))
1312 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
1313 else
1314 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1315 }
1316 #undef FUNC_NAME
1317
1318
1319 SCM
1320 scm_ra2contig (SCM ra, int copy)
1321 {
1322 SCM ret;
1323 long inc = 1;
1324 size_t k, len = 1;
1325 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
1326 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1327 k = SCM_I_ARRAY_NDIM (ra);
1328 if (SCM_I_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_I_ARRAY_DIMS (ra)[k - 1].inc)))
1329 {
1330 if (!scm_is_bitvector (SCM_I_ARRAY_V (ra)))
1331 return ra;
1332 if ((len == scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) &&
1333 0 == SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT &&
1334 0 == len % SCM_LONG_BIT))
1335 return ra;
1336 }
1337 ret = scm_i_make_ra (k, 0);
1338 SCM_I_ARRAY_BASE (ret) = 0;
1339 while (k--)
1340 {
1341 SCM_I_ARRAY_DIMS (ret)[k].lbnd = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
1342 SCM_I_ARRAY_DIMS (ret)[k].ubnd = SCM_I_ARRAY_DIMS (ra)[k].ubnd;
1343 SCM_I_ARRAY_DIMS (ret)[k].inc = inc;
1344 inc *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1345 }
1346 SCM_I_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
1347 if (copy)
1348 scm_array_copy_x (ra, ret);
1349 return ret;
1350 }
1351
1352
1353
1354 SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
1355 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1356 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1357 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
1358 "binary objects from @var{port-or-fdes}.\n"
1359 "If an end of file is encountered,\n"
1360 "the objects up to that point are put into @var{ura}\n"
1361 "(starting at the beginning) and the remainder of the array is\n"
1362 "unchanged.\n\n"
1363 "The optional arguments @var{start} and @var{end} allow\n"
1364 "a specified region of a vector (or linearized array) to be read,\n"
1365 "leaving the remainder of the vector unchanged.\n\n"
1366 "@code{uniform-array-read!} returns the number of objects read.\n"
1367 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1368 "returned by @code{(current-input-port)}.")
1369 #define FUNC_NAME s_scm_uniform_array_read_x
1370 {
1371 if (SCM_UNBNDP (port_or_fd))
1372 port_or_fd = scm_current_input_port ();
1373
1374 if (scm_is_uniform_vector (ura))
1375 {
1376 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
1377 }
1378 else if (SCM_I_ARRAYP (ura))
1379 {
1380 size_t base, vlen, cstart, cend;
1381 SCM cra, ans;
1382
1383 cra = scm_ra2contig (ura, 0);
1384 base = SCM_I_ARRAY_BASE (cra);
1385 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1386 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1387
1388 cstart = 0;
1389 cend = vlen;
1390 if (!SCM_UNBNDP (start))
1391 {
1392 cstart = scm_to_unsigned_integer (start, 0, vlen);
1393 if (!SCM_UNBNDP (end))
1394 cend = scm_to_unsigned_integer (end, cstart, vlen);
1395 }
1396
1397 ans = scm_uniform_vector_read_x (SCM_I_ARRAY_V (cra), port_or_fd,
1398 scm_from_size_t (base + cstart),
1399 scm_from_size_t (base + cend));
1400
1401 if (!scm_is_eq (cra, ura))
1402 scm_array_copy_x (cra, ura);
1403 return ans;
1404 }
1405 else if (SCM_I_ENCLOSED_ARRAYP (ura))
1406 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1407 else
1408 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1409 }
1410 #undef FUNC_NAME
1411
1412 SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
1413 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1414 "Writes all elements of @var{ura} as binary objects to\n"
1415 "@var{port-or-fdes}.\n\n"
1416 "The optional arguments @var{start}\n"
1417 "and @var{end} allow\n"
1418 "a specified region of a vector (or linearized array) to be written.\n\n"
1419 "The number of objects actually written is returned.\n"
1420 "@var{port-or-fdes} may be\n"
1421 "omitted, in which case it defaults to the value returned by\n"
1422 "@code{(current-output-port)}.")
1423 #define FUNC_NAME s_scm_uniform_array_write
1424 {
1425 if (SCM_UNBNDP (port_or_fd))
1426 port_or_fd = scm_current_output_port ();
1427
1428 if (scm_is_uniform_vector (ura))
1429 {
1430 return scm_uniform_vector_write (ura, port_or_fd, start, end);
1431 }
1432 else if (SCM_I_ARRAYP (ura))
1433 {
1434 size_t base, vlen, cstart, cend;
1435 SCM cra, ans;
1436
1437 cra = scm_ra2contig (ura, 1);
1438 base = SCM_I_ARRAY_BASE (cra);
1439 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1440 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1441
1442 cstart = 0;
1443 cend = vlen;
1444 if (!SCM_UNBNDP (start))
1445 {
1446 cstart = scm_to_unsigned_integer (start, 0, vlen);
1447 if (!SCM_UNBNDP (end))
1448 cend = scm_to_unsigned_integer (end, cstart, vlen);
1449 }
1450
1451 ans = scm_uniform_vector_write (SCM_I_ARRAY_V (cra), port_or_fd,
1452 scm_from_size_t (base + cstart),
1453 scm_from_size_t (base + cend));
1454
1455 return ans;
1456 }
1457 else if (SCM_I_ENCLOSED_ARRAYP (ura))
1458 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1459 else
1460 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1461 }
1462 #undef FUNC_NAME
1463
1464
1465 /** Bit vectors */
1466
1467 static scm_t_bits scm_tc16_bitvector;
1468
1469 #define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1470 #define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1471 #define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1472
1473
1474 static int
1475 bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1476 {
1477 size_t bit_len = BITVECTOR_LENGTH (vec);
1478 size_t word_len = (bit_len+31)/32;
1479 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1480 size_t i, j;
1481
1482 scm_puts ("#*", port);
1483 for (i = 0; i < word_len; i++, bit_len -= 32)
1484 {
1485 scm_t_uint32 mask = 1;
1486 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1487 scm_putc ((bits[i] & mask)? '1' : '0', port);
1488 }
1489
1490 return 1;
1491 }
1492
1493 static SCM
1494 bitvector_equalp (SCM vec1, SCM vec2)
1495 {
1496 size_t bit_len = BITVECTOR_LENGTH (vec1);
1497 size_t word_len = (bit_len + 31) / 32;
1498 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1499 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1500 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1501
1502 /* compare lengths */
1503 if (BITVECTOR_LENGTH (vec2) != bit_len)
1504 return SCM_BOOL_F;
1505 /* avoid underflow in word_len-1 below. */
1506 if (bit_len == 0)
1507 return SCM_BOOL_T;
1508 /* compare full words */
1509 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1510 return SCM_BOOL_F;
1511 /* compare partial last words */
1512 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1513 return SCM_BOOL_F;
1514 return SCM_BOOL_T;
1515 }
1516
1517 int
1518 scm_is_bitvector (SCM vec)
1519 {
1520 return IS_BITVECTOR (vec);
1521 }
1522
1523 SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1524 (SCM obj),
1525 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1526 "return @code{#f}.")
1527 #define FUNC_NAME s_scm_bitvector_p
1528 {
1529 return scm_from_bool (scm_is_bitvector (obj));
1530 }
1531 #undef FUNC_NAME
1532
1533 SCM
1534 scm_c_make_bitvector (size_t len, SCM fill)
1535 {
1536 size_t word_len = (len + 31) / 32;
1537 scm_t_uint32 *bits;
1538 SCM res;
1539
1540 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1541 "bitvector");
1542 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1543
1544 if (!SCM_UNBNDP (fill))
1545 scm_bitvector_fill_x (res, fill);
1546
1547 return res;
1548 }
1549
1550 SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1551 (SCM len, SCM fill),
1552 "Create a new bitvector of length @var{len} and\n"
1553 "optionally initialize all elements to @var{fill}.")
1554 #define FUNC_NAME s_scm_make_bitvector
1555 {
1556 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1557 }
1558 #undef FUNC_NAME
1559
1560 SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1561 (SCM bits),
1562 "Create a new bitvector with the arguments as elements.")
1563 #define FUNC_NAME s_scm_bitvector
1564 {
1565 return scm_list_to_bitvector (bits);
1566 }
1567 #undef FUNC_NAME
1568
1569 size_t
1570 scm_c_bitvector_length (SCM vec)
1571 {
1572 scm_assert_smob_type (scm_tc16_bitvector, vec);
1573 return BITVECTOR_LENGTH (vec);
1574 }
1575
1576 SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1577 (SCM vec),
1578 "Return the length of the bitvector @var{vec}.")
1579 #define FUNC_NAME s_scm_bitvector_length
1580 {
1581 return scm_from_size_t (scm_c_bitvector_length (vec));
1582 }
1583 #undef FUNC_NAME
1584
1585 const scm_t_uint32 *
1586 scm_array_handle_bit_elements (scm_t_array_handle *h)
1587 {
1588 return scm_array_handle_bit_writable_elements (h);
1589 }
1590
1591 scm_t_uint32 *
1592 scm_array_handle_bit_writable_elements (scm_t_array_handle *h)
1593 {
1594 SCM vec = h->array;
1595 if (SCM_I_ARRAYP (vec))
1596 vec = SCM_I_ARRAY_V (vec);
1597 if (IS_BITVECTOR (vec))
1598 return BITVECTOR_BITS (vec) + h->base/32;
1599 scm_wrong_type_arg_msg (NULL, 0, h->array, "bit array");
1600 }
1601
1602 size_t
1603 scm_array_handle_bit_elements_offset (scm_t_array_handle *h)
1604 {
1605 return h->base % 32;
1606 }
1607
1608 const scm_t_uint32 *
1609 scm_bitvector_elements (SCM vec,
1610 scm_t_array_handle *h,
1611 size_t *offp,
1612 size_t *lenp,
1613 ssize_t *incp)
1614 {
1615 return scm_bitvector_writable_elements (vec, h, offp, lenp, incp);
1616 }
1617
1618
1619 scm_t_uint32 *
1620 scm_bitvector_writable_elements (SCM vec,
1621 scm_t_array_handle *h,
1622 size_t *offp,
1623 size_t *lenp,
1624 ssize_t *incp)
1625 {
1626 scm_generalized_vector_get_handle (vec, h);
1627 if (offp)
1628 {
1629 scm_t_array_dim *dim = scm_array_handle_dims (h);
1630 *offp = scm_array_handle_bit_elements_offset (h);
1631 *lenp = dim->ubnd - dim->lbnd + 1;
1632 *incp = dim->inc;
1633 }
1634 return scm_array_handle_bit_writable_elements (h);
1635 }
1636
1637 SCM
1638 scm_c_bitvector_ref (SCM vec, size_t idx)
1639 {
1640 scm_t_array_handle handle;
1641 const scm_t_uint32 *bits;
1642
1643 if (IS_BITVECTOR (vec))
1644 {
1645 if (idx >= BITVECTOR_LENGTH (vec))
1646 scm_out_of_range (NULL, scm_from_size_t (idx));
1647 bits = BITVECTOR_BITS(vec);
1648 return scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1649 }
1650 else
1651 {
1652 SCM res;
1653 size_t len, off;
1654 ssize_t inc;
1655
1656 bits = scm_bitvector_elements (vec, &handle, &off, &len, &inc);
1657 if (idx >= len)
1658 scm_out_of_range (NULL, scm_from_size_t (idx));
1659 idx = idx*inc + off;
1660 res = scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1661 scm_array_handle_release (&handle);
1662 return res;
1663 }
1664 }
1665
1666 SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1667 (SCM vec, SCM idx),
1668 "Return the element at index @var{idx} of the bitvector\n"
1669 "@var{vec}.")
1670 #define FUNC_NAME s_scm_bitvector_ref
1671 {
1672 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1673 }
1674 #undef FUNC_NAME
1675
1676 void
1677 scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1678 {
1679 scm_t_array_handle handle;
1680 scm_t_uint32 *bits, mask;
1681
1682 if (IS_BITVECTOR (vec))
1683 {
1684 if (idx >= BITVECTOR_LENGTH (vec))
1685 scm_out_of_range (NULL, scm_from_size_t (idx));
1686 bits = BITVECTOR_BITS(vec);
1687 }
1688 else
1689 {
1690 size_t len, off;
1691 ssize_t inc;
1692
1693 bits = scm_bitvector_writable_elements (vec, &handle, &off, &len, &inc);
1694 if (idx >= len)
1695 scm_out_of_range (NULL, scm_from_size_t (idx));
1696 idx = idx*inc + off;
1697 }
1698
1699 mask = 1L << (idx%32);
1700 if (scm_is_true (val))
1701 bits[idx/32] |= mask;
1702 else
1703 bits[idx/32] &= ~mask;
1704
1705 if (!IS_BITVECTOR (vec))
1706 scm_array_handle_release (&handle);
1707 }
1708
1709 SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1710 (SCM vec, SCM idx, SCM val),
1711 "Set the element at index @var{idx} of the bitvector\n"
1712 "@var{vec} when @var{val} is true, else clear it.")
1713 #define FUNC_NAME s_scm_bitvector_set_x
1714 {
1715 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1716 return SCM_UNSPECIFIED;
1717 }
1718 #undef FUNC_NAME
1719
1720 SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1721 (SCM vec, SCM val),
1722 "Set all elements of the bitvector\n"
1723 "@var{vec} when @var{val} is true, else clear them.")
1724 #define FUNC_NAME s_scm_bitvector_fill_x
1725 {
1726 scm_t_array_handle handle;
1727 size_t off, len;
1728 ssize_t inc;
1729 scm_t_uint32 *bits;
1730
1731 bits = scm_bitvector_writable_elements (vec, &handle,
1732 &off, &len, &inc);
1733
1734 if (off == 0 && inc == 1 && len > 0)
1735 {
1736 /* the usual case
1737 */
1738 size_t word_len = (len + 31) / 32;
1739 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1740
1741 if (scm_is_true (val))
1742 {
1743 memset (bits, 0xFF, sizeof(scm_t_uint32)*(word_len-1));
1744 bits[word_len-1] |= last_mask;
1745 }
1746 else
1747 {
1748 memset (bits, 0x00, sizeof(scm_t_uint32)*(word_len-1));
1749 bits[word_len-1] &= ~last_mask;
1750 }
1751 }
1752 else
1753 {
1754 size_t i;
1755 for (i = 0; i < len; i++)
1756 scm_array_handle_set (&handle, i*inc, val);
1757 }
1758
1759 scm_array_handle_release (&handle);
1760
1761 return SCM_UNSPECIFIED;
1762 }
1763 #undef FUNC_NAME
1764
1765 SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1766 (SCM list),
1767 "Return a new bitvector initialized with the elements\n"
1768 "of @var{list}.")
1769 #define FUNC_NAME s_scm_list_to_bitvector
1770 {
1771 size_t bit_len = scm_to_size_t (scm_length (list));
1772 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1773 size_t word_len = (bit_len+31)/32;
1774 scm_t_array_handle handle;
1775 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec, &handle,
1776 NULL, NULL, NULL);
1777 size_t i, j;
1778
1779 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1780 {
1781 scm_t_uint32 mask = 1;
1782 bits[i] = 0;
1783 for (j = 0; j < 32 && j < bit_len;
1784 j++, mask <<= 1, list = SCM_CDR (list))
1785 if (scm_is_true (SCM_CAR (list)))
1786 bits[i] |= mask;
1787 }
1788
1789 scm_array_handle_release (&handle);
1790
1791 return vec;
1792 }
1793 #undef FUNC_NAME
1794
1795 SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1796 (SCM vec),
1797 "Return a new list initialized with the elements\n"
1798 "of the bitvector @var{vec}.")
1799 #define FUNC_NAME s_scm_bitvector_to_list
1800 {
1801 scm_t_array_handle handle;
1802 size_t off, len;
1803 ssize_t inc;
1804 scm_t_uint32 *bits;
1805 SCM res = SCM_EOL;
1806
1807 bits = scm_bitvector_writable_elements (vec, &handle,
1808 &off, &len, &inc);
1809
1810 if (off == 0 && inc == 1)
1811 {
1812 /* the usual case
1813 */
1814 size_t word_len = (len + 31) / 32;
1815 size_t i, j;
1816
1817 for (i = 0; i < word_len; i++, len -= 32)
1818 {
1819 scm_t_uint32 mask = 1;
1820 for (j = 0; j < 32 && j < len; j++, mask <<= 1)
1821 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1822 }
1823 }
1824 else
1825 {
1826 size_t i;
1827 for (i = 0; i < len; i++)
1828 res = scm_cons (scm_array_handle_ref (&handle, i*inc), res);
1829 }
1830
1831 scm_array_handle_release (&handle);
1832
1833 return scm_reverse_x (res, SCM_EOL);
1834 }
1835 #undef FUNC_NAME
1836
1837 /* From mmix-arith.w by Knuth.
1838
1839 Here's a fun way to count the number of bits in a tetrabyte.
1840
1841 [This classical trick is called the ``Gillies--Miller method for
1842 sideways addition'' in {\sl The Preparation of Programs for an
1843 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1844 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1845 the tricks used here were suggested by Balbir Singh, Peter
1846 Rossmanith, and Stefan Schwoon.]
1847 */
1848
1849 static size_t
1850 count_ones (scm_t_uint32 x)
1851 {
1852 x=x-((x>>1)&0x55555555);
1853 x=(x&0x33333333)+((x>>2)&0x33333333);
1854 x=(x+(x>>4))&0x0f0f0f0f;
1855 x=x+(x>>8);
1856 return (x+(x>>16)) & 0xff;
1857 }
1858
1859 SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
1860 (SCM b, SCM bitvector),
1861 "Return the number of occurrences of the boolean @var{b} in\n"
1862 "@var{bitvector}.")
1863 #define FUNC_NAME s_scm_bit_count
1864 {
1865 scm_t_array_handle handle;
1866 size_t off, len;
1867 ssize_t inc;
1868 scm_t_uint32 *bits;
1869 int bit = scm_to_bool (b);
1870 size_t count = 0;
1871
1872 bits = scm_bitvector_writable_elements (bitvector, &handle,
1873 &off, &len, &inc);
1874
1875 if (off == 0 && inc == 1 && len > 0)
1876 {
1877 /* the usual case
1878 */
1879 size_t word_len = (len + 31) / 32;
1880 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1881 size_t i;
1882
1883 for (i = 0; i < word_len-1; i++)
1884 count += count_ones (bits[i]);
1885 count += count_ones (bits[i] & last_mask);
1886 }
1887 else
1888 {
1889 size_t i;
1890 for (i = 0; i < len; i++)
1891 if (scm_is_true (scm_array_handle_ref (&handle, i*inc)))
1892 count++;
1893 }
1894
1895 scm_array_handle_release (&handle);
1896
1897 return scm_from_size_t (bit? count : len-count);
1898 }
1899 #undef FUNC_NAME
1900
1901 /* returns 32 for x == 0.
1902 */
1903 static size_t
1904 find_first_one (scm_t_uint32 x)
1905 {
1906 size_t pos = 0;
1907 /* do a binary search in x. */
1908 if ((x & 0xFFFF) == 0)
1909 x >>= 16, pos += 16;
1910 if ((x & 0xFF) == 0)
1911 x >>= 8, pos += 8;
1912 if ((x & 0xF) == 0)
1913 x >>= 4, pos += 4;
1914 if ((x & 0x3) == 0)
1915 x >>= 2, pos += 2;
1916 if ((x & 0x1) == 0)
1917 pos += 1;
1918 return pos;
1919 }
1920
1921 SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1922 (SCM item, SCM v, SCM k),
1923 "Return the index of the first occurrance of @var{item} in bit\n"
1924 "vector @var{v}, starting from @var{k}. If there is no\n"
1925 "@var{item} entry between @var{k} and the end of\n"
1926 "@var{bitvector}, then return @code{#f}. For example,\n"
1927 "\n"
1928 "@example\n"
1929 "(bit-position #t #*000101 0) @result{} 3\n"
1930 "(bit-position #f #*0001111 3) @result{} #f\n"
1931 "@end example")
1932 #define FUNC_NAME s_scm_bit_position
1933 {
1934 scm_t_array_handle handle;
1935 size_t off, len, first_bit;
1936 ssize_t inc;
1937 const scm_t_uint32 *bits;
1938 int bit = scm_to_bool (item);
1939 SCM res = SCM_BOOL_F;
1940
1941 bits = scm_bitvector_elements (v, &handle, &off, &len, &inc);
1942 first_bit = scm_to_unsigned_integer (k, 0, len);
1943
1944 if (off == 0 && inc == 1 && len > 0)
1945 {
1946 size_t i, word_len = (len + 31) / 32;
1947 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1948 size_t first_word = first_bit / 32;
1949 scm_t_uint32 first_mask =
1950 ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1951 scm_t_uint32 w;
1952
1953 for (i = first_word; i < word_len; i++)
1954 {
1955 w = (bit? bits[i] : ~bits[i]);
1956 if (i == first_word)
1957 w &= first_mask;
1958 if (i == word_len-1)
1959 w &= last_mask;
1960 if (w)
1961 {
1962 res = scm_from_size_t (32*i + find_first_one (w));
1963 break;
1964 }
1965 }
1966 }
1967 else
1968 {
1969 size_t i;
1970 for (i = first_bit; i < len; i++)
1971 {
1972 SCM elt = scm_array_handle_ref (&handle, i*inc);
1973 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
1974 {
1975 res = scm_from_size_t (i);
1976 break;
1977 }
1978 }
1979 }
1980
1981 scm_array_handle_release (&handle);
1982
1983 return res;
1984 }
1985 #undef FUNC_NAME
1986
1987 SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
1988 (SCM v, SCM kv, SCM obj),
1989 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1990 "selecting the entries to change. The return value is\n"
1991 "unspecified.\n"
1992 "\n"
1993 "If @var{kv} is a bit vector, then those entries where it has\n"
1994 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1995 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1996 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1997 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1998 "\n"
1999 "@example\n"
2000 "(define bv #*01000010)\n"
2001 "(bit-set*! bv #*10010001 #t)\n"
2002 "bv\n"
2003 "@result{} #*11010011\n"
2004 "@end example\n"
2005 "\n"
2006 "If @var{kv} is a u32vector, then its elements are\n"
2007 "indices into @var{v} which are set to @var{obj}.\n"
2008 "\n"
2009 "@example\n"
2010 "(define bv #*01000010)\n"
2011 "(bit-set*! bv #u32(5 2 7) #t)\n"
2012 "bv\n"
2013 "@result{} #*01100111\n"
2014 "@end example")
2015 #define FUNC_NAME s_scm_bit_set_star_x
2016 {
2017 scm_t_array_handle v_handle;
2018 size_t v_off, v_len;
2019 ssize_t v_inc;
2020 scm_t_uint32 *v_bits;
2021 int bit;
2022
2023 /* Validate that OBJ is a boolean so this is done even if we don't
2024 need BIT.
2025 */
2026 bit = scm_to_bool (obj);
2027
2028 v_bits = scm_bitvector_writable_elements (v, &v_handle,
2029 &v_off, &v_len, &v_inc);
2030
2031 if (scm_is_bitvector (kv))
2032 {
2033 scm_t_array_handle kv_handle;
2034 size_t kv_off, kv_len;
2035 ssize_t kv_inc;
2036 const scm_t_uint32 *kv_bits;
2037
2038 kv_bits = scm_bitvector_elements (v, &kv_handle,
2039 &kv_off, &kv_len, &kv_inc);
2040
2041 if (v_len != kv_len)
2042 scm_misc_error (NULL,
2043 "bit vectors must have equal length",
2044 SCM_EOL);
2045
2046 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2047 {
2048 size_t word_len = (kv_len + 31) / 32;
2049 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2050 size_t i;
2051
2052 if (bit == 0)
2053 {
2054 for (i = 0; i < word_len-1; i++)
2055 v_bits[i] &= ~kv_bits[i];
2056 v_bits[i] &= ~(kv_bits[i] & last_mask);
2057 }
2058 else
2059 {
2060 for (i = 0; i < word_len-1; i++)
2061 v_bits[i] |= kv_bits[i];
2062 v_bits[i] |= kv_bits[i] & last_mask;
2063 }
2064 }
2065 else
2066 {
2067 size_t i;
2068 for (i = 0; i < kv_len; i++)
2069 if (scm_is_true (scm_array_handle_ref (&kv_handle, i*kv_inc)))
2070 scm_array_handle_set (&v_handle, i*v_inc, obj);
2071 }
2072
2073 scm_array_handle_release (&kv_handle);
2074
2075 }
2076 else if (scm_is_true (scm_u32vector_p (kv)))
2077 {
2078 scm_t_array_handle kv_handle;
2079 size_t i, kv_len;
2080 ssize_t kv_inc;
2081 const scm_t_uint32 *kv_elts;
2082
2083 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2084 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2085 scm_array_handle_set (&v_handle, (*kv_elts)*v_inc, obj);
2086
2087 scm_array_handle_release (&kv_handle);
2088 }
2089 else
2090 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2091
2092 scm_array_handle_release (&v_handle);
2093
2094 return SCM_UNSPECIFIED;
2095 }
2096 #undef FUNC_NAME
2097
2098
2099 SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
2100 (SCM v, SCM kv, SCM obj),
2101 "Return a count of how many entries in bit vector @var{v} are\n"
2102 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
2103 "consider.\n"
2104 "\n"
2105 "If @var{kv} is a bit vector, then those entries where it has\n"
2106 "@code{#t} are the ones in @var{v} which are considered.\n"
2107 "@var{kv} and @var{v} must be the same length.\n"
2108 "\n"
2109 "If @var{kv} is a u32vector, then it contains\n"
2110 "the indexes in @var{v} to consider.\n"
2111 "\n"
2112 "For example,\n"
2113 "\n"
2114 "@example\n"
2115 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
2116 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
2117 "@end example")
2118 #define FUNC_NAME s_scm_bit_count_star
2119 {
2120 scm_t_array_handle v_handle;
2121 size_t v_off, v_len;
2122 ssize_t v_inc;
2123 const scm_t_uint32 *v_bits;
2124 size_t count = 0;
2125 int bit;
2126
2127 /* Validate that OBJ is a boolean so this is done even if we don't
2128 need BIT.
2129 */
2130 bit = scm_to_bool (obj);
2131
2132 v_bits = scm_bitvector_elements (v, &v_handle,
2133 &v_off, &v_len, &v_inc);
2134
2135 if (scm_is_bitvector (kv))
2136 {
2137 scm_t_array_handle kv_handle;
2138 size_t kv_off, kv_len;
2139 ssize_t kv_inc;
2140 const scm_t_uint32 *kv_bits;
2141
2142 kv_bits = scm_bitvector_elements (v, &kv_handle,
2143 &kv_off, &kv_len, &kv_inc);
2144
2145 if (v_len != kv_len)
2146 scm_misc_error (NULL,
2147 "bit vectors must have equal length",
2148 SCM_EOL);
2149
2150 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2151 {
2152 size_t i, word_len = (kv_len + 31) / 32;
2153 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2154 scm_t_uint32 xor_mask = bit? 0 : ((scm_t_uint32)-1);
2155
2156 for (i = 0; i < word_len-1; i++)
2157 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i]);
2158 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i] & last_mask);
2159 }
2160 else
2161 {
2162 size_t i;
2163 for (i = 0; i < kv_len; i++)
2164 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2165 {
2166 SCM elt = scm_array_handle_ref (&v_handle, i*v_inc);
2167 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2168 count++;
2169 }
2170 }
2171
2172 scm_array_handle_release (&kv_handle);
2173
2174 }
2175 else if (scm_is_true (scm_u32vector_p (kv)))
2176 {
2177 scm_t_array_handle kv_handle;
2178 size_t i, kv_len;
2179 ssize_t kv_inc;
2180 const scm_t_uint32 *kv_elts;
2181
2182 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2183 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2184 {
2185 SCM elt = scm_array_handle_ref (&v_handle, (*kv_elts)*v_inc);
2186 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2187 count++;
2188 }
2189
2190 scm_array_handle_release (&kv_handle);
2191 }
2192 else
2193 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2194
2195 scm_array_handle_release (&v_handle);
2196
2197 return scm_from_size_t (count);
2198 }
2199 #undef FUNC_NAME
2200
2201 SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
2202 (SCM v),
2203 "Modify the bit vector @var{v} by replacing each element with\n"
2204 "its negation.")
2205 #define FUNC_NAME s_scm_bit_invert_x
2206 {
2207 scm_t_array_handle handle;
2208 size_t off, len;
2209 ssize_t inc;
2210 scm_t_uint32 *bits;
2211
2212 bits = scm_bitvector_writable_elements (v, &handle, &off, &len, &inc);
2213
2214 if (off == 0 && inc == 1 && len > 0)
2215 {
2216 size_t word_len = (len + 31) / 32;
2217 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
2218 size_t i;
2219
2220 for (i = 0; i < word_len-1; i++)
2221 bits[i] = ~bits[i];
2222 bits[i] = bits[i] ^ last_mask;
2223 }
2224 else
2225 {
2226 size_t i;
2227 for (i = 0; i < len; i++)
2228 scm_array_handle_set (&handle, i*inc,
2229 scm_not (scm_array_handle_ref (&handle, i*inc)));
2230 }
2231
2232 scm_array_handle_release (&handle);
2233
2234 return SCM_UNSPECIFIED;
2235 }
2236 #undef FUNC_NAME
2237
2238
2239 SCM
2240 scm_istr2bve (SCM str)
2241 {
2242 scm_t_array_handle handle;
2243 size_t len = scm_i_string_length (str);
2244 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
2245 SCM res = vec;
2246
2247 scm_t_uint32 mask;
2248 size_t k, j;
2249 const char *c_str;
2250 scm_t_uint32 *data;
2251
2252 data = scm_bitvector_writable_elements (vec, &handle, NULL, NULL, NULL);
2253 c_str = scm_i_string_chars (str);
2254
2255 for (k = 0; k < (len + 31) / 32; k++)
2256 {
2257 data[k] = 0L;
2258 j = len - k * 32;
2259 if (j > 32)
2260 j = 32;
2261 for (mask = 1L; j--; mask <<= 1)
2262 switch (*c_str++)
2263 {
2264 case '0':
2265 break;
2266 case '1':
2267 data[k] |= mask;
2268 break;
2269 default:
2270 res = SCM_BOOL_F;
2271 goto exit;
2272 }
2273 }
2274
2275 exit:
2276 scm_array_handle_release (&handle);
2277 scm_remember_upto_here_1 (str);
2278 return res;
2279 }
2280
2281
2282
2283 static SCM
2284 ra2l (SCM ra, unsigned long base, unsigned long k)
2285 {
2286 SCM res = SCM_EOL;
2287 long inc;
2288 size_t i;
2289 int enclosed = SCM_I_ENCLOSED_ARRAYP (ra);
2290
2291 if (k == SCM_I_ARRAY_NDIM (ra))
2292 return scm_i_cvref (SCM_I_ARRAY_V (ra), base, enclosed);
2293
2294 inc = SCM_I_ARRAY_DIMS (ra)[k].inc;
2295 if (SCM_I_ARRAY_DIMS (ra)[k].ubnd < SCM_I_ARRAY_DIMS (ra)[k].lbnd)
2296 return SCM_EOL;
2297 i = base + (1 + SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * inc;
2298 do
2299 {
2300 i -= inc;
2301 res = scm_cons (ra2l (ra, i, k + 1), res);
2302 }
2303 while (i != base);
2304 return res;
2305 }
2306
2307
2308 SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
2309 (SCM v),
2310 "Return a list consisting of all the elements, in order, of\n"
2311 "@var{array}.")
2312 #define FUNC_NAME s_scm_array_to_list
2313 {
2314 if (scm_is_generalized_vector (v))
2315 return scm_generalized_vector_to_list (v);
2316 else if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
2317 return ra2l (v, SCM_I_ARRAY_BASE (v), 0);
2318
2319 scm_wrong_type_arg_msg (NULL, 0, v, "array");
2320 }
2321 #undef FUNC_NAME
2322
2323
2324 static void l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k);
2325
2326 SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2327 (SCM type, SCM shape, SCM lst),
2328 "Return an array of the type @var{type}\n"
2329 "with elements the same as those of @var{lst}.\n"
2330 "\n"
2331 "The argument @var{shape} determines the number of dimensions\n"
2332 "of the array and their shape. It is either an exact integer,\n"
2333 "giving the\n"
2334 "number of dimensions directly, or a list whose length\n"
2335 "specifies the number of dimensions and each element specified\n"
2336 "the lower and optionally the upper bound of the corresponding\n"
2337 "dimension.\n"
2338 "When the element is list of two elements, these elements\n"
2339 "give the lower and upper bounds. When it is an exact\n"
2340 "integer, it gives only the lower bound.")
2341 #define FUNC_NAME s_scm_list_to_typed_array
2342 {
2343 SCM row;
2344 SCM ra;
2345 scm_t_array_handle handle;
2346
2347 row = lst;
2348 if (scm_is_integer (shape))
2349 {
2350 size_t k = scm_to_size_t (shape);
2351 shape = SCM_EOL;
2352 while (k-- > 0)
2353 {
2354 shape = scm_cons (scm_length (row), shape);
2355 if (k > 0 && !scm_is_null (row))
2356 row = scm_car (row);
2357 }
2358 }
2359 else
2360 {
2361 SCM shape_spec = shape;
2362 shape = SCM_EOL;
2363 while (1)
2364 {
2365 SCM spec = scm_car (shape_spec);
2366 if (scm_is_pair (spec))
2367 shape = scm_cons (spec, shape);
2368 else
2369 shape = scm_cons (scm_list_2 (spec,
2370 scm_sum (scm_sum (spec,
2371 scm_length (row)),
2372 scm_from_int (-1))),
2373 shape);
2374 shape_spec = scm_cdr (shape_spec);
2375 if (scm_is_pair (shape_spec))
2376 {
2377 if (!scm_is_null (row))
2378 row = scm_car (row);
2379 }
2380 else
2381 break;
2382 }
2383 }
2384
2385 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
2386 scm_reverse_x (shape, SCM_EOL));
2387
2388 scm_array_get_handle (ra, &handle);
2389 l2ra (lst, &handle, 0, 0);
2390 scm_array_handle_release (&handle);
2391
2392 return ra;
2393 }
2394 #undef FUNC_NAME
2395
2396 SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
2397 (SCM ndim, SCM lst),
2398 "Return an array with elements the same as those of @var{lst}.")
2399 #define FUNC_NAME s_scm_list_to_array
2400 {
2401 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
2402 }
2403 #undef FUNC_NAME
2404
2405 static void
2406 l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
2407 {
2408 if (k == scm_array_handle_rank (handle))
2409 scm_array_handle_set (handle, pos, lst);
2410 else
2411 {
2412 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
2413 ssize_t inc = dim->inc;
2414 size_t len = 1 + dim->ubnd - dim->lbnd, n;
2415 char *errmsg = NULL;
2416
2417 n = len;
2418 while (n > 0 && scm_is_pair (lst))
2419 {
2420 l2ra (SCM_CAR (lst), handle, pos, k + 1);
2421 pos += inc;
2422 lst = SCM_CDR (lst);
2423 n -= 1;
2424 }
2425 if (n != 0)
2426 errmsg = "too few elements for array dimension ~a, need ~a";
2427 if (!scm_is_null (lst))
2428 errmsg = "too many elements for array dimension ~a, want ~a";
2429 if (errmsg)
2430 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
2431 scm_from_size_t (len)));
2432 }
2433 }
2434
2435 #if SCM_ENABLE_DEPRECATED
2436
2437 SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
2438 (SCM ndim, SCM prot, SCM lst),
2439 "Return a uniform array of the type indicated by prototype\n"
2440 "@var{prot} with elements the same as those of @var{lst}.\n"
2441 "Elements must be of the appropriate type, no coercions are\n"
2442 "done.\n"
2443 "\n"
2444 "The argument @var{ndim} determines the number of dimensions\n"
2445 "of the array. It is either an exact integer, giving the\n"
2446 "number directly, or a list of exact integers, whose length\n"
2447 "specifies the number of dimensions and each element is the\n"
2448 "lower index bound of its dimension.")
2449 #define FUNC_NAME s_scm_list_to_uniform_array
2450 {
2451 return scm_list_to_typed_array (prototype_to_type (prot), ndim, lst);
2452 }
2453 #undef FUNC_NAME
2454
2455 #endif
2456
2457 /* Print dimension DIM of ARRAY.
2458 */
2459
2460 static int
2461 scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
2462 SCM port, scm_print_state *pstate)
2463 {
2464 scm_t_array_dim *dim_spec = SCM_I_ARRAY_DIMS (array) + dim;
2465 long idx;
2466
2467 scm_putc ('(', port);
2468
2469 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2470 {
2471 if (dim < SCM_I_ARRAY_NDIM(array)-1)
2472 scm_i_print_array_dimension (array, dim+1, base, enclosed,
2473 port, pstate);
2474 else
2475 scm_iprin1 (scm_i_cvref (SCM_I_ARRAY_V (array), base, enclosed),
2476 port, pstate);
2477 if (idx < dim_spec->ubnd)
2478 scm_putc (' ', port);
2479 base += dim_spec->inc;
2480 }
2481
2482 scm_putc (')', port);
2483 return 1;
2484 }
2485
2486 /* Print an array. (Only for strict arrays, not for generalized vectors.)
2487 */
2488
2489 static int
2490 scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2491 {
2492 long ndim = SCM_I_ARRAY_NDIM (array);
2493 scm_t_array_dim *dim_specs = SCM_I_ARRAY_DIMS (array);
2494 SCM v = SCM_I_ARRAY_V (array);
2495 unsigned long base = SCM_I_ARRAY_BASE (array);
2496 long i;
2497 int print_lbnds = 0, zero_size = 0, print_lens = 0;
2498
2499 scm_putc ('#', port);
2500 if (ndim != 1 || dim_specs[0].lbnd != 0)
2501 scm_intprint (ndim, 10, port);
2502 if (scm_is_uniform_vector (v))
2503 scm_puts (scm_i_uniform_vector_tag (v), port);
2504 else if (scm_is_bitvector (v))
2505 scm_puts ("b", port);
2506 else if (scm_is_string (v))
2507 scm_puts ("a", port);
2508 else if (!scm_is_vector (v))
2509 scm_puts ("?", port);
2510
2511 for (i = 0; i < ndim; i++)
2512 {
2513 if (dim_specs[i].lbnd != 0)
2514 print_lbnds = 1;
2515 if (dim_specs[i].ubnd - dim_specs[i].lbnd + 1 == 0)
2516 zero_size = 1;
2517 else if (zero_size)
2518 print_lens = 1;
2519 }
2520
2521 if (print_lbnds || print_lens)
2522 for (i = 0; i < ndim; i++)
2523 {
2524 if (print_lbnds)
2525 {
2526 scm_putc ('@', port);
2527 scm_intprint (dim_specs[i].lbnd, 10, port);
2528 }
2529 if (print_lens)
2530 {
2531 scm_putc (':', port);
2532 scm_intprint (dim_specs[i].ubnd - dim_specs[i].lbnd + 1,
2533 10, port);
2534 }
2535 }
2536
2537 if (ndim == 0)
2538 {
2539 /* Rank zero arrays, which are really just scalars, are printed
2540 specially. The consequent way would be to print them as
2541
2542 #0 OBJ
2543
2544 where OBJ is the printed representation of the scalar, but we
2545 print them instead as
2546
2547 #0(OBJ)
2548
2549 to make them look less strange.
2550
2551 Just printing them as
2552
2553 OBJ
2554
2555 would be correct in a way as well, but zero rank arrays are
2556 not really the same as Scheme values since they are boxed and
2557 can be modified with array-set!, say.
2558 */
2559 scm_putc ('(', port);
2560 scm_iprin1 (scm_i_cvref (v, base, 0), port, pstate);
2561 scm_putc (')', port);
2562 return 1;
2563 }
2564 else
2565 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
2566 }
2567
2568 static int
2569 scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
2570 {
2571 size_t base;
2572
2573 scm_putc ('#', port);
2574 base = SCM_I_ARRAY_BASE (array);
2575 scm_puts ("<enclosed-array ", port);
2576 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
2577 scm_putc ('>', port);
2578 return 1;
2579 }
2580
2581 /* Read an array. This function can also read vectors and uniform
2582 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2583 handled here.
2584
2585 C is the first character read after the '#'.
2586 */
2587
2588 static SCM
2589 tag_to_type (const char *tag, SCM port)
2590 {
2591 #if SCM_ENABLE_DEPRECATED
2592 {
2593 /* Recognize the old syntax.
2594 */
2595 const char *instead;
2596 switch (tag[0])
2597 {
2598 case 'u':
2599 instead = "u32";
2600 break;
2601 case 'e':
2602 instead = "s32";
2603 break;
2604 case 's':
2605 instead = "f32";
2606 break;
2607 case 'i':
2608 instead = "f64";
2609 break;
2610 case 'y':
2611 instead = "s8";
2612 break;
2613 case 'h':
2614 instead = "s16";
2615 break;
2616 case 'l':
2617 instead = "s64";
2618 break;
2619 case 'c':
2620 instead = "c64";
2621 break;
2622 default:
2623 instead = NULL;
2624 break;
2625 }
2626
2627 if (instead && tag[1] == '\0')
2628 {
2629 scm_c_issue_deprecation_warning_fmt
2630 ("The tag '%c' is deprecated for uniform vectors. "
2631 "Use '%s' instead.", tag[0], instead);
2632 return scm_from_locale_symbol (instead);
2633 }
2634 }
2635 #endif
2636
2637 if (*tag == '\0')
2638 return SCM_BOOL_T;
2639 else
2640 return scm_from_locale_symbol (tag);
2641 }
2642
2643 static int
2644 read_decimal_integer (SCM port, int c, ssize_t *resp)
2645 {
2646 ssize_t sign = 1;
2647 ssize_t res = 0;
2648 int got_it = 0;
2649
2650 if (c == '-')
2651 {
2652 sign = -1;
2653 c = scm_getc (port);
2654 }
2655
2656 while ('0' <= c && c <= '9')
2657 {
2658 res = 10*res + c-'0';
2659 got_it = 1;
2660 c = scm_getc (port);
2661 }
2662
2663 if (got_it)
2664 *resp = res;
2665 return c;
2666 }
2667
2668 SCM
2669 scm_i_read_array (SCM port, int c)
2670 {
2671 ssize_t rank;
2672 int got_rank;
2673 char tag[80];
2674 int tag_len;
2675
2676 SCM shape = SCM_BOOL_F, elements;
2677
2678 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2679 the array code can not deal with zero-length dimensions yet, and
2680 we want to allow zero-length vectors, of course.
2681 */
2682 if (c == '(')
2683 {
2684 scm_ungetc (c, port);
2685 return scm_vector (scm_read (port));
2686 }
2687
2688 /* Disambiguate between '#f' and uniform floating point vectors.
2689 */
2690 if (c == 'f')
2691 {
2692 c = scm_getc (port);
2693 if (c != '3' && c != '6')
2694 {
2695 if (c != EOF)
2696 scm_ungetc (c, port);
2697 return SCM_BOOL_F;
2698 }
2699 rank = 1;
2700 got_rank = 1;
2701 tag[0] = 'f';
2702 tag_len = 1;
2703 goto continue_reading_tag;
2704 }
2705
2706 /* Read rank.
2707 */
2708 rank = 1;
2709 c = read_decimal_integer (port, c, &rank);
2710 if (rank < 0)
2711 scm_i_input_error (NULL, port, "array rank must be non-negative",
2712 SCM_EOL);
2713
2714 /* Read tag.
2715 */
2716 tag_len = 0;
2717 continue_reading_tag:
2718 while (c != EOF && c != '(' && c != '@' && c != ':' && tag_len < 80)
2719 {
2720 tag[tag_len++] = c;
2721 c = scm_getc (port);
2722 }
2723 tag[tag_len] = '\0';
2724
2725 /* Read shape.
2726 */
2727 if (c == '@' || c == ':')
2728 {
2729 shape = SCM_EOL;
2730
2731 do
2732 {
2733 ssize_t lbnd = 0, len = 0;
2734 SCM s;
2735
2736 if (c == '@')
2737 {
2738 c = scm_getc (port);
2739 c = read_decimal_integer (port, c, &lbnd);
2740 }
2741
2742 s = scm_from_ssize_t (lbnd);
2743
2744 if (c == ':')
2745 {
2746 c = scm_getc (port);
2747 c = read_decimal_integer (port, c, &len);
2748 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
2749 }
2750
2751 shape = scm_cons (s, shape);
2752 } while (c == '@' || c == ':');
2753
2754 shape = scm_reverse_x (shape, SCM_EOL);
2755 }
2756
2757 /* Read nested lists of elements.
2758 */
2759 if (c != '(')
2760 scm_i_input_error (NULL, port,
2761 "missing '(' in vector or array literal",
2762 SCM_EOL);
2763 scm_ungetc (c, port);
2764 elements = scm_read (port);
2765
2766 if (scm_is_false (shape))
2767 shape = scm_from_ssize_t (rank);
2768 else if (scm_ilength (shape) != rank)
2769 scm_i_input_error
2770 (NULL, port,
2771 "the number of shape specifications must match the array rank",
2772 SCM_EOL);
2773
2774 /* Handle special print syntax of rank zero arrays; see
2775 scm_i_print_array for a rationale.
2776 */
2777 if (rank == 0)
2778 {
2779 if (!scm_is_pair (elements))
2780 scm_i_input_error (NULL, port,
2781 "too few elements in array literal, need 1",
2782 SCM_EOL);
2783 if (!scm_is_null (SCM_CDR (elements)))
2784 scm_i_input_error (NULL, port,
2785 "too many elements in array literal, want 1",
2786 SCM_EOL);
2787 elements = SCM_CAR (elements);
2788 }
2789
2790 /* Construct array.
2791 */
2792 return scm_list_to_typed_array (tag_to_type (tag, port), shape, elements);
2793 }
2794
2795 SCM_DEFINE (scm_array_type, "array-type", 1, 0, 0,
2796 (SCM ra),
2797 "")
2798 #define FUNC_NAME s_scm_array_type
2799 {
2800 if (SCM_I_ARRAYP (ra))
2801 return scm_i_generalized_vector_type (SCM_I_ARRAY_V (ra));
2802 else if (scm_is_generalized_vector (ra))
2803 return scm_i_generalized_vector_type (ra);
2804 else if (SCM_I_ENCLOSED_ARRAYP (ra))
2805 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
2806 else
2807 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2808 }
2809 #undef FUNC_NAME
2810
2811 #if SCM_ENABLE_DEPRECATED
2812
2813 SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
2814 (SCM ra),
2815 "Return an object that would produce an array of the same type\n"
2816 "as @var{array}, if used as the @var{prototype} for\n"
2817 "@code{make-uniform-array}.")
2818 #define FUNC_NAME s_scm_array_prototype
2819 {
2820 if (SCM_I_ARRAYP (ra))
2821 return scm_i_get_old_prototype (SCM_I_ARRAY_V (ra));
2822 else if (scm_is_generalized_vector (ra))
2823 return scm_i_get_old_prototype (ra);
2824 else if (SCM_I_ENCLOSED_ARRAYP (ra))
2825 return SCM_UNSPECIFIED;
2826 else
2827 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2828 }
2829 #undef FUNC_NAME
2830
2831 #endif
2832
2833
2834 #if SCM_ENABLE_DEPRECATED
2835
2836 SCM
2837 scm_make_ra (int ndim)
2838 {
2839 scm_c_issue_deprecation_warning
2840 ("scm_make_ra is deprecated. Use scm_make_array or similar instead.");
2841 return scm_i_make_ra (ndim, 0);
2842 }
2843
2844 SCM
2845 scm_shap2ra (SCM args, const char *what)
2846 {
2847 scm_c_issue_deprecation_warning
2848 ("scm_shap2ra is deprecated. Use scm_make_array or similar instead.");
2849 return scm_i_shap2ra (args);
2850 }
2851
2852 SCM
2853 scm_cvref (SCM v, unsigned long pos, SCM last)
2854 {
2855 scm_c_issue_deprecation_warning
2856 ("scm_cvref is deprecated. Use scm_c_generalized_vector_ref instead.");
2857 return scm_c_generalized_vector_ref (v, pos);
2858 }
2859
2860 void
2861 scm_ra_set_contp (SCM ra)
2862 {
2863 scm_c_issue_deprecation_warning
2864 ("scm_ra_set_contp is deprecated. There should be no need for it.");
2865 scm_i_ra_set_contp (ra);
2866 }
2867
2868 long
2869 scm_aind (SCM ra, SCM args, const char *what)
2870 {
2871 scm_t_array_handle handle;
2872 ssize_t pos;
2873
2874 scm_c_issue_deprecation_warning
2875 ("scm_aind is deprecated. Use scm_array_handle_pos instead.");
2876
2877 if (scm_is_integer (args))
2878 args = scm_list_1 (args);
2879
2880 scm_array_get_handle (ra, &handle);
2881 pos = scm_array_handle_pos (&handle, args) + SCM_I_ARRAY_BASE (ra);
2882 scm_array_handle_release (&handle);
2883 return pos;
2884 }
2885
2886 int
2887 scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
2888 {
2889 scm_c_issue_deprecation_warning
2890 ("scm_raprin1 is deprecated. Use scm_display or scm_write instead.");
2891
2892 scm_iprin1 (exp, port, pstate);
2893 return 1;
2894 }
2895
2896 #endif
2897
2898 void
2899 scm_init_unif ()
2900 {
2901 scm_i_tc16_array = scm_make_smob_type ("array", 0);
2902 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
2903 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
2904
2905 scm_i_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
2906 scm_set_smob_print (scm_i_tc16_enclosed_array, scm_i_print_enclosed_array);
2907 scm_set_smob_equalp (scm_i_tc16_enclosed_array, scm_array_equal_p);
2908
2909 scm_add_feature ("array");
2910
2911 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2912 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2913 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2914
2915 init_type_creator_table ();
2916
2917 #include "libguile/unif.x"
2918
2919 }
2920
2921 /*
2922 Local Variables:
2923 c-file-style: "gnu"
2924 End:
2925 */