(scm_make_shared_array): Add old base to new base since
[bpt/guile.git] / libguile / unif.c
1 /* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18
19 /*
20 This file has code for arrays in lots of variants (double, integer,
21 unsigned etc. ). It suffers from hugely repetitive code because
22 there is similar (but different) code for every variant included. (urg.)
23
24 --hwn
25 */
26 \f
27
28 #if HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35
36 #include "libguile/_scm.h"
37 #include "libguile/__scm.h"
38 #include "libguile/eq.h"
39 #include "libguile/chars.h"
40 #include "libguile/eval.h"
41 #include "libguile/fports.h"
42 #include "libguile/smob.h"
43 #include "libguile/feature.h"
44 #include "libguile/root.h"
45 #include "libguile/strings.h"
46 #include "libguile/srfi-13.h"
47 #include "libguile/srfi-4.h"
48 #include "libguile/vectors.h"
49 #include "libguile/list.h"
50 #include "libguile/deprecation.h"
51 #include "libguile/dynwind.h"
52
53 #include "libguile/validate.h"
54 #include "libguile/unif.h"
55 #include "libguile/ramap.h"
56 #include "libguile/print.h"
57 #include "libguile/read.h"
58
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62
63 #ifdef HAVE_IO_H
64 #include <io.h>
65 #endif
66
67 \f
68 /* The set of uniform scm_vector types is:
69 * Vector of: Called: Replaced by:
70 * unsigned char string
71 * char byvect s8 or u8, depending on signedness of 'char'
72 * boolean bvect
73 * signed long ivect s32
74 * unsigned long uvect u32
75 * float fvect f32
76 * double dvect d32
77 * complex double cvect c64
78 * short svect s16
79 * long long llvect s64
80 */
81
82 scm_t_bits scm_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 return scm_c_string_set_x (SCM_I_ARRAY_V (h->array), pos, val);
372 else
373 return 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->elements)[pos/32] |= mask;
384 else
385 ((scm_t_uint32 *)h->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 return scm_make_typed_array (prototype_to_type (prot), fill, dims);
800 }
801 #undef FUNC_NAME
802
803 #endif
804
805 static void
806 scm_i_ra_set_contp (SCM ra)
807 {
808 size_t k = SCM_I_ARRAY_NDIM (ra);
809 if (k)
810 {
811 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
812 while (k--)
813 {
814 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
815 {
816 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
817 return;
818 }
819 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
820 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
821 }
822 }
823 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
824 }
825
826
827 SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
828 (SCM oldra, SCM mapfunc, SCM dims),
829 "@code{make-shared-array} can be used to create shared subarrays of other\n"
830 "arrays. The @var{mapper} is a function that translates coordinates in\n"
831 "the new array into coordinates in the old array. A @var{mapper} must be\n"
832 "linear, and its range must stay within the bounds of the old array, but\n"
833 "it can be otherwise arbitrary. A simple example:\n"
834 "@lisp\n"
835 "(define fred (make-array #f 8 8))\n"
836 "(define freds-diagonal\n"
837 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
838 "(array-set! freds-diagonal 'foo 3)\n"
839 "(array-ref fred 3 3) @result{} foo\n"
840 "(define freds-center\n"
841 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
842 "(array-ref freds-center 0 0) @result{} foo\n"
843 "@end lisp")
844 #define FUNC_NAME s_scm_make_shared_array
845 {
846 scm_t_array_handle old_handle;
847 SCM ra;
848 SCM inds, indptr;
849 SCM imap;
850 size_t k;
851 ssize_t i;
852 long old_min, new_min, old_max, new_max;
853 scm_t_array_dim *s;
854
855 SCM_VALIDATE_REST_ARGUMENT (dims);
856 SCM_VALIDATE_PROC (2, mapfunc);
857 ra = scm_i_shap2ra (dims);
858
859 scm_array_get_handle (oldra, &old_handle);
860
861 if (SCM_I_ARRAYP (oldra))
862 {
863 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
864 old_min = old_max = SCM_I_ARRAY_BASE (oldra);
865 s = scm_array_handle_dims (&old_handle);
866 k = scm_array_handle_rank (&old_handle);
867 while (k--)
868 {
869 if (s[k].inc > 0)
870 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
871 else
872 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
873 }
874 }
875 else
876 {
877 SCM_I_ARRAY_V (ra) = oldra;
878 old_min = 0;
879 old_max = scm_c_generalized_vector_length (oldra) - 1;
880 }
881
882 inds = SCM_EOL;
883 s = SCM_I_ARRAY_DIMS (ra);
884 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
885 {
886 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
887 if (s[k].ubnd < s[k].lbnd)
888 {
889 if (1 == SCM_I_ARRAY_NDIM (ra))
890 ra = make_typed_vector (scm_array_type (ra), 0);
891 else
892 SCM_I_ARRAY_V (ra) = make_typed_vector (scm_array_type (ra), 0);
893 scm_array_handle_release (&old_handle);
894 return ra;
895 }
896 }
897
898 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
899 i = scm_array_handle_pos (&old_handle, imap);
900 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + SCM_I_ARRAY_BASE (oldra);
901 indptr = inds;
902 k = SCM_I_ARRAY_NDIM (ra);
903 while (k--)
904 {
905 if (s[k].ubnd > s[k].lbnd)
906 {
907 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
908 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
909 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
910 i += s[k].inc;
911 if (s[k].inc > 0)
912 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
913 else
914 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
915 }
916 else
917 s[k].inc = new_max - new_min + 1; /* contiguous by default */
918 indptr = SCM_CDR (indptr);
919 }
920
921 scm_array_handle_release (&old_handle);
922
923 if (old_min > new_min || old_max < new_max)
924 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
925 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
926 {
927 SCM v = SCM_I_ARRAY_V (ra);
928 size_t length = scm_c_generalized_vector_length (v);
929 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
930 return v;
931 if (s->ubnd < s->lbnd)
932 return make_typed_vector (scm_array_type (ra), 0);
933 }
934 scm_i_ra_set_contp (ra);
935 return ra;
936 }
937 #undef FUNC_NAME
938
939
940 /* args are RA . DIMS */
941 SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
942 (SCM ra, SCM args),
943 "Return an array sharing contents with @var{array}, but with\n"
944 "dimensions arranged in a different order. There must be one\n"
945 "@var{dim} argument for each dimension of @var{array}.\n"
946 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
947 "and the rank of the array to be returned. Each integer in that\n"
948 "range must appear at least once in the argument list.\n"
949 "\n"
950 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
951 "dimensions in the array to be returned, their positions in the\n"
952 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
953 "may have the same value, in which case the returned array will\n"
954 "have smaller rank than @var{array}.\n"
955 "\n"
956 "@lisp\n"
957 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
958 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
959 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
960 " #2((a 4) (b 5) (c 6))\n"
961 "@end lisp")
962 #define FUNC_NAME s_scm_transpose_array
963 {
964 SCM res, vargs;
965 scm_t_array_dim *s, *r;
966 int ndim, i, k;
967
968 SCM_VALIDATE_REST_ARGUMENT (args);
969 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
970
971 if (scm_is_generalized_vector (ra))
972 {
973 /* Make sure that we are called with a single zero as
974 arguments.
975 */
976 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
977 SCM_WRONG_NUM_ARGS ();
978 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
979 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
980 return ra;
981 }
982
983 if (SCM_I_ARRAYP (ra) || SCM_I_ENCLOSED_ARRAYP (ra))
984 {
985 vargs = scm_vector (args);
986 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
987 SCM_WRONG_NUM_ARGS ();
988 ndim = 0;
989 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
990 {
991 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
992 0, SCM_I_ARRAY_NDIM(ra));
993 if (ndim < i)
994 ndim = i;
995 }
996 ndim++;
997 res = scm_i_make_ra (ndim, 0);
998 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
999 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
1000 for (k = ndim; k--;)
1001 {
1002 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
1003 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
1004 }
1005 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
1006 {
1007 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
1008 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
1009 r = &(SCM_I_ARRAY_DIMS (res)[i]);
1010 if (r->ubnd < r->lbnd)
1011 {
1012 r->lbnd = s->lbnd;
1013 r->ubnd = s->ubnd;
1014 r->inc = s->inc;
1015 ndim--;
1016 }
1017 else
1018 {
1019 if (r->ubnd > s->ubnd)
1020 r->ubnd = s->ubnd;
1021 if (r->lbnd < s->lbnd)
1022 {
1023 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
1024 r->lbnd = s->lbnd;
1025 }
1026 r->inc += s->inc;
1027 }
1028 }
1029 if (ndim > 0)
1030 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
1031 scm_i_ra_set_contp (res);
1032 return res;
1033 }
1034
1035 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1036 }
1037 #undef FUNC_NAME
1038
1039 /* args are RA . AXES */
1040 SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
1041 (SCM ra, SCM axes),
1042 "@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than\n"
1043 "the rank of @var{array}. @var{enclose-array} returns an array\n"
1044 "resembling an array of shared arrays. The dimensions of each shared\n"
1045 "array are the same as the @var{dim}th dimensions of the original array,\n"
1046 "the dimensions of the outer array are the same as those of the original\n"
1047 "array that did not match a @var{dim}.\n\n"
1048 "An enclosed array is not a general Scheme array. Its elements may not\n"
1049 "be set using @code{array-set!}. Two references to the same element of\n"
1050 "an enclosed array will be @code{equal?} but will not in general be\n"
1051 "@code{eq?}. The value returned by @var{array-prototype} when given an\n"
1052 "enclosed array is unspecified.\n\n"
1053 "examples:\n"
1054 "@lisp\n"
1055 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{}\n"
1056 " #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>\n\n"
1057 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{}\n"
1058 " #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>\n"
1059 "@end lisp")
1060 #define FUNC_NAME s_scm_enclose_array
1061 {
1062 SCM axv, res, ra_inr;
1063 const char *c_axv;
1064 scm_t_array_dim vdim, *s = &vdim;
1065 int ndim, j, k, ninr, noutr;
1066
1067 SCM_VALIDATE_REST_ARGUMENT (axes);
1068 if (scm_is_null (axes))
1069 axes = scm_cons ((SCM_I_ARRAYP (ra) ? scm_from_size_t (SCM_I_ARRAY_NDIM (ra) - 1) : SCM_INUM0), SCM_EOL);
1070 ninr = scm_ilength (axes);
1071 if (ninr < 0)
1072 SCM_WRONG_NUM_ARGS ();
1073 ra_inr = scm_i_make_ra (ninr, 0);
1074
1075 if (scm_is_generalized_vector (ra))
1076 {
1077 s->lbnd = 0;
1078 s->ubnd = scm_c_generalized_vector_length (ra) - 1;
1079 s->inc = 1;
1080 SCM_I_ARRAY_V (ra_inr) = ra;
1081 SCM_I_ARRAY_BASE (ra_inr) = 0;
1082 ndim = 1;
1083 }
1084 else if (SCM_I_ARRAYP (ra))
1085 {
1086 s = SCM_I_ARRAY_DIMS (ra);
1087 SCM_I_ARRAY_V (ra_inr) = SCM_I_ARRAY_V (ra);
1088 SCM_I_ARRAY_BASE (ra_inr) = SCM_I_ARRAY_BASE (ra);
1089 ndim = SCM_I_ARRAY_NDIM (ra);
1090 }
1091 else
1092 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1093
1094 noutr = ndim - ninr;
1095 if (noutr < 0)
1096 SCM_WRONG_NUM_ARGS ();
1097 axv = scm_make_string (scm_from_int (ndim), SCM_MAKE_CHAR (0));
1098 res = scm_i_make_ra (noutr, 1);
1099 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra_inr);
1100 SCM_I_ARRAY_V (res) = ra_inr;
1101 for (k = 0; k < ninr; k++, axes = SCM_CDR (axes))
1102 {
1103 if (!scm_is_integer (SCM_CAR (axes)))
1104 SCM_MISC_ERROR ("bad axis", SCM_EOL);
1105 j = scm_to_int (SCM_CAR (axes));
1106 SCM_I_ARRAY_DIMS (ra_inr)[k].lbnd = s[j].lbnd;
1107 SCM_I_ARRAY_DIMS (ra_inr)[k].ubnd = s[j].ubnd;
1108 SCM_I_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
1109 scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
1110 }
1111 c_axv = scm_i_string_chars (axv);
1112 for (j = 0, k = 0; k < noutr; k++, j++)
1113 {
1114 while (c_axv[j])
1115 j++;
1116 SCM_I_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
1117 SCM_I_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
1118 SCM_I_ARRAY_DIMS (res)[k].inc = s[j].inc;
1119 }
1120 scm_remember_upto_here_1 (axv);
1121 scm_i_ra_set_contp (ra_inr);
1122 scm_i_ra_set_contp (res);
1123 return res;
1124 }
1125 #undef FUNC_NAME
1126
1127
1128
1129 SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
1130 (SCM v, SCM args),
1131 "Return @code{#t} if its arguments would be acceptable to\n"
1132 "@code{array-ref}.")
1133 #define FUNC_NAME s_scm_array_in_bounds_p
1134 {
1135 SCM res = SCM_BOOL_T;
1136
1137 SCM_VALIDATE_REST_ARGUMENT (args);
1138
1139 if (scm_is_generalized_vector (v))
1140 {
1141 long ind;
1142
1143 if (!scm_is_pair (args))
1144 SCM_WRONG_NUM_ARGS ();
1145 ind = scm_to_long (SCM_CAR (args));
1146 args = SCM_CDR (args);
1147 res = scm_from_bool (ind >= 0
1148 && ind < scm_c_generalized_vector_length (v));
1149 }
1150 else if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
1151 {
1152 size_t k = SCM_I_ARRAY_NDIM (v);
1153 scm_t_array_dim *s = SCM_I_ARRAY_DIMS (v);
1154
1155 while (k > 0)
1156 {
1157 long ind;
1158
1159 if (!scm_is_pair (args))
1160 SCM_WRONG_NUM_ARGS ();
1161 ind = scm_to_long (SCM_CAR (args));
1162 args = SCM_CDR (args);
1163 k -= 1;
1164
1165 if (ind < s->lbnd || ind > s->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
1176 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1177
1178 if (!scm_is_null (args))
1179 SCM_WRONG_NUM_ARGS ();
1180
1181 return res;
1182 }
1183 #undef FUNC_NAME
1184
1185 SCM
1186 scm_i_cvref (SCM v, size_t pos, int enclosed)
1187 {
1188 if (enclosed)
1189 {
1190 int k = SCM_I_ARRAY_NDIM (v);
1191 SCM res = scm_i_make_ra (k, 0);
1192 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (v);
1193 SCM_I_ARRAY_BASE (res) = pos;
1194 while (k--)
1195 {
1196 SCM_I_ARRAY_DIMS (res)[k].ubnd = SCM_I_ARRAY_DIMS (v)[k].ubnd;
1197 SCM_I_ARRAY_DIMS (res)[k].lbnd = SCM_I_ARRAY_DIMS (v)[k].lbnd;
1198 SCM_I_ARRAY_DIMS (res)[k].inc = SCM_I_ARRAY_DIMS (v)[k].inc;
1199 }
1200 return res;
1201 }
1202 else
1203 return scm_c_generalized_vector_ref (v, pos);
1204 }
1205
1206 SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1207 (SCM v, SCM args),
1208 "Return the element at the @code{(index1, index2)} element in\n"
1209 "@var{array}.")
1210 #define FUNC_NAME s_scm_array_ref
1211 {
1212 scm_t_array_handle handle;
1213 SCM res;
1214
1215 scm_array_get_handle (v, &handle);
1216 res = scm_array_handle_ref (&handle, scm_array_handle_pos (&handle, args));
1217 scm_array_handle_release (&handle);
1218 return res;
1219 }
1220 #undef FUNC_NAME
1221
1222
1223 SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1224 (SCM v, SCM obj, SCM args),
1225 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
1226 "@var{new-value}. The value returned by array-set! is unspecified.")
1227 #define FUNC_NAME s_scm_array_set_x
1228 {
1229 scm_t_array_handle handle;
1230
1231 scm_array_get_handle (v, &handle);
1232 scm_array_handle_set (&handle, scm_array_handle_pos (&handle, args), obj);
1233 scm_array_handle_release (&handle);
1234 return SCM_UNSPECIFIED;
1235 }
1236 #undef FUNC_NAME
1237
1238 /* attempts to unroll an array into a one-dimensional array.
1239 returns the unrolled array or #f if it can't be done. */
1240 /* if strict is not SCM_UNDEFINED, return #f if returned array
1241 wouldn't have contiguous elements. */
1242 SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1243 (SCM ra, SCM strict),
1244 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
1245 "without changing their order (last subscript changing fastest), then\n"
1246 "@code{array-contents} returns that shared array, otherwise it returns\n"
1247 "@code{#f}. All arrays made by @var{make-array} and\n"
1248 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
1249 "@var{make-shared-array} may not be.\n\n"
1250 "If the optional argument @var{strict} is provided, a shared array will\n"
1251 "be returned only if its elements are stored internally contiguous in\n"
1252 "memory.")
1253 #define FUNC_NAME s_scm_array_contents
1254 {
1255 SCM sra;
1256
1257 if (scm_is_generalized_vector (ra))
1258 return ra;
1259
1260 if (SCM_I_ARRAYP (ra))
1261 {
1262 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
1263 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
1264 return SCM_BOOL_F;
1265 for (k = 0; k < ndim; k++)
1266 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1267 if (!SCM_UNBNDP (strict))
1268 {
1269 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
1270 return SCM_BOOL_F;
1271 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
1272 {
1273 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
1274 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
1275 len % SCM_LONG_BIT)
1276 return SCM_BOOL_F;
1277 }
1278 }
1279
1280 {
1281 SCM v = SCM_I_ARRAY_V (ra);
1282 size_t length = scm_c_generalized_vector_length (v);
1283 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
1284 return v;
1285 }
1286
1287 sra = scm_i_make_ra (1, 0);
1288 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
1289 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
1290 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
1291 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
1292 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
1293 return sra;
1294 }
1295 else if (SCM_I_ENCLOSED_ARRAYP (ra))
1296 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
1297 else
1298 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1299 }
1300 #undef FUNC_NAME
1301
1302
1303 SCM
1304 scm_ra2contig (SCM ra, int copy)
1305 {
1306 SCM ret;
1307 long inc = 1;
1308 size_t k, len = 1;
1309 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
1310 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1311 k = SCM_I_ARRAY_NDIM (ra);
1312 if (SCM_I_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_I_ARRAY_DIMS (ra)[k - 1].inc)))
1313 {
1314 if (!scm_is_bitvector (SCM_I_ARRAY_V (ra)))
1315 return ra;
1316 if ((len == scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) &&
1317 0 == SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT &&
1318 0 == len % SCM_LONG_BIT))
1319 return ra;
1320 }
1321 ret = scm_i_make_ra (k, 0);
1322 SCM_I_ARRAY_BASE (ret) = 0;
1323 while (k--)
1324 {
1325 SCM_I_ARRAY_DIMS (ret)[k].lbnd = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
1326 SCM_I_ARRAY_DIMS (ret)[k].ubnd = SCM_I_ARRAY_DIMS (ra)[k].ubnd;
1327 SCM_I_ARRAY_DIMS (ret)[k].inc = inc;
1328 inc *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
1329 }
1330 SCM_I_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
1331 if (copy)
1332 scm_array_copy_x (ra, ret);
1333 return ret;
1334 }
1335
1336
1337
1338 SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
1339 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1340 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1341 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
1342 "binary objects from @var{port-or-fdes}.\n"
1343 "If an end of file is encountered,\n"
1344 "the objects up to that point are put into @var{ura}\n"
1345 "(starting at the beginning) and the remainder of the array is\n"
1346 "unchanged.\n\n"
1347 "The optional arguments @var{start} and @var{end} allow\n"
1348 "a specified region of a vector (or linearized array) to be read,\n"
1349 "leaving the remainder of the vector unchanged.\n\n"
1350 "@code{uniform-array-read!} returns the number of objects read.\n"
1351 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1352 "returned by @code{(current-input-port)}.")
1353 #define FUNC_NAME s_scm_uniform_array_read_x
1354 {
1355 if (SCM_UNBNDP (port_or_fd))
1356 port_or_fd = scm_current_input_port ();
1357
1358 if (scm_is_uniform_vector (ura))
1359 {
1360 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
1361 }
1362 else if (SCM_I_ARRAYP (ura))
1363 {
1364 size_t base, vlen, cstart, cend;
1365 SCM cra, ans;
1366
1367 cra = scm_ra2contig (ura, 0);
1368 base = SCM_I_ARRAY_BASE (cra);
1369 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1370 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1371
1372 cstart = 0;
1373 cend = vlen;
1374 if (!SCM_UNBNDP (start))
1375 {
1376 cstart = scm_to_unsigned_integer (start, 0, vlen);
1377 if (!SCM_UNBNDP (end))
1378 cend = scm_to_unsigned_integer (end, cstart, vlen);
1379 }
1380
1381 ans = scm_uniform_vector_read_x (SCM_I_ARRAY_V (cra), port_or_fd,
1382 scm_from_size_t (base + cstart),
1383 scm_from_size_t (base + cend));
1384
1385 if (!scm_is_eq (cra, ura))
1386 scm_array_copy_x (cra, ura);
1387 return ans;
1388 }
1389 else if (SCM_I_ENCLOSED_ARRAYP (ura))
1390 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1391 else
1392 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1393 }
1394 #undef FUNC_NAME
1395
1396 SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
1397 (SCM ura, SCM port_or_fd, SCM start, SCM end),
1398 "Writes all elements of @var{ura} as binary objects to\n"
1399 "@var{port-or-fdes}.\n\n"
1400 "The optional arguments @var{start}\n"
1401 "and @var{end} allow\n"
1402 "a specified region of a vector (or linearized array) to be written.\n\n"
1403 "The number of objects actually written is returned.\n"
1404 "@var{port-or-fdes} may be\n"
1405 "omitted, in which case it defaults to the value returned by\n"
1406 "@code{(current-output-port)}.")
1407 #define FUNC_NAME s_scm_uniform_array_write
1408 {
1409 if (SCM_UNBNDP (port_or_fd))
1410 port_or_fd = scm_current_output_port ();
1411
1412 if (scm_is_uniform_vector (ura))
1413 {
1414 return scm_uniform_vector_write (ura, port_or_fd, start, end);
1415 }
1416 else if (SCM_I_ARRAYP (ura))
1417 {
1418 size_t base, vlen, cstart, cend;
1419 SCM cra, ans;
1420
1421 cra = scm_ra2contig (ura, 1);
1422 base = SCM_I_ARRAY_BASE (cra);
1423 vlen = SCM_I_ARRAY_DIMS (cra)->inc *
1424 (SCM_I_ARRAY_DIMS (cra)->ubnd - SCM_I_ARRAY_DIMS (cra)->lbnd + 1);
1425
1426 cstart = 0;
1427 cend = vlen;
1428 if (!SCM_UNBNDP (start))
1429 {
1430 cstart = scm_to_unsigned_integer (start, 0, vlen);
1431 if (!SCM_UNBNDP (end))
1432 cend = scm_to_unsigned_integer (end, cstart, vlen);
1433 }
1434
1435 ans = scm_uniform_vector_write (SCM_I_ARRAY_V (cra), port_or_fd,
1436 scm_from_size_t (base + cstart),
1437 scm_from_size_t (base + cend));
1438
1439 return ans;
1440 }
1441 else if (SCM_I_ENCLOSED_ARRAYP (ura))
1442 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
1443 else
1444 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
1445 }
1446 #undef FUNC_NAME
1447
1448
1449 /** Bit vectors */
1450
1451 static scm_t_bits scm_tc16_bitvector;
1452
1453 #define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1454 #define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1455 #define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1456
1457 static size_t
1458 bitvector_free (SCM vec)
1459 {
1460 scm_gc_free (BITVECTOR_BITS (vec),
1461 sizeof (scm_t_uint32) * ((BITVECTOR_LENGTH (vec)+31)/32),
1462 "bitvector");
1463 return 0;
1464 }
1465
1466 static int
1467 bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1468 {
1469 size_t bit_len = BITVECTOR_LENGTH (vec);
1470 size_t word_len = (bit_len+31)/32;
1471 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1472 size_t i, j;
1473
1474 scm_puts ("#*", port);
1475 for (i = 0; i < word_len; i++, bit_len -= 32)
1476 {
1477 scm_t_uint32 mask = 1;
1478 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1479 scm_putc ((bits[i] & mask)? '1' : '0', port);
1480 }
1481
1482 return 1;
1483 }
1484
1485 static SCM
1486 bitvector_equalp (SCM vec1, SCM vec2)
1487 {
1488 size_t bit_len = BITVECTOR_LENGTH (vec1);
1489 size_t word_len = (bit_len + 31) / 32;
1490 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1491 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1492 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1493
1494 /* compare lengths */
1495 if (BITVECTOR_LENGTH (vec2) != bit_len)
1496 return SCM_BOOL_F;
1497 /* avoid underflow in word_len-1 below. */
1498 if (bit_len == 0)
1499 return SCM_BOOL_T;
1500 /* compare full words */
1501 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1502 return SCM_BOOL_F;
1503 /* compare partial last words */
1504 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1505 return SCM_BOOL_F;
1506 return SCM_BOOL_T;
1507 }
1508
1509 int
1510 scm_is_bitvector (SCM vec)
1511 {
1512 return IS_BITVECTOR (vec);
1513 }
1514
1515 SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1516 (SCM obj),
1517 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1518 "return @code{#f}.")
1519 #define FUNC_NAME s_scm_bitvector_p
1520 {
1521 return scm_from_bool (scm_is_bitvector (obj));
1522 }
1523 #undef FUNC_NAME
1524
1525 SCM
1526 scm_c_make_bitvector (size_t len, SCM fill)
1527 {
1528 size_t word_len = (len + 31) / 32;
1529 scm_t_uint32 *bits;
1530 SCM res;
1531
1532 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1533 "bitvector");
1534 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1535
1536 if (!SCM_UNBNDP (fill))
1537 scm_bitvector_fill_x (res, fill);
1538
1539 return res;
1540 }
1541
1542 SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1543 (SCM len, SCM fill),
1544 "Create a new bitvector of length @var{len} and\n"
1545 "optionally initialize all elements to @var{fill}.")
1546 #define FUNC_NAME s_scm_make_bitvector
1547 {
1548 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1549 }
1550 #undef FUNC_NAME
1551
1552 SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1553 (SCM bits),
1554 "Create a new bitvector with the arguments as elements.")
1555 #define FUNC_NAME s_scm_bitvector
1556 {
1557 return scm_list_to_bitvector (bits);
1558 }
1559 #undef FUNC_NAME
1560
1561 size_t
1562 scm_c_bitvector_length (SCM vec)
1563 {
1564 scm_assert_smob_type (scm_tc16_bitvector, vec);
1565 return BITVECTOR_LENGTH (vec);
1566 }
1567
1568 SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1569 (SCM vec),
1570 "Return the length of the bitvector @var{vec}.")
1571 #define FUNC_NAME s_scm_bitvector_length
1572 {
1573 return scm_from_size_t (scm_c_bitvector_length (vec));
1574 }
1575 #undef FUNC_NAME
1576
1577 const scm_t_uint32 *
1578 scm_array_handle_bit_elements (scm_t_array_handle *h)
1579 {
1580 return scm_array_handle_bit_writable_elements (h);
1581 }
1582
1583 scm_t_uint32 *
1584 scm_array_handle_bit_writable_elements (scm_t_array_handle *h)
1585 {
1586 SCM vec = h->array;
1587 if (SCM_I_ARRAYP (vec))
1588 vec = SCM_I_ARRAY_V (vec);
1589 if (IS_BITVECTOR (vec))
1590 return BITVECTOR_BITS (vec) + h->base/32;
1591 scm_wrong_type_arg_msg (NULL, 0, h->array, "bit array");
1592 }
1593
1594 size_t
1595 scm_array_handle_bit_elements_offset (scm_t_array_handle *h)
1596 {
1597 return h->base % 32;
1598 }
1599
1600 const scm_t_uint32 *
1601 scm_bitvector_elements (SCM vec,
1602 scm_t_array_handle *h,
1603 size_t *offp,
1604 size_t *lenp,
1605 ssize_t *incp)
1606 {
1607 return scm_bitvector_writable_elements (vec, h, offp, lenp, incp);
1608 }
1609
1610
1611 scm_t_uint32 *
1612 scm_bitvector_writable_elements (SCM vec,
1613 scm_t_array_handle *h,
1614 size_t *offp,
1615 size_t *lenp,
1616 ssize_t *incp)
1617 {
1618 scm_generalized_vector_get_handle (vec, h);
1619 if (offp)
1620 {
1621 scm_t_array_dim *dim = scm_array_handle_dims (h);
1622 *offp = scm_array_handle_bit_elements_offset (h);
1623 *lenp = dim->ubnd - dim->lbnd + 1;
1624 *incp = dim->inc;
1625 }
1626 return scm_array_handle_bit_writable_elements (h);
1627 }
1628
1629 SCM
1630 scm_c_bitvector_ref (SCM vec, size_t idx)
1631 {
1632 scm_t_array_handle handle;
1633 const scm_t_uint32 *bits;
1634
1635 if (IS_BITVECTOR (vec))
1636 {
1637 if (idx >= BITVECTOR_LENGTH (vec))
1638 scm_out_of_range (NULL, scm_from_size_t (idx));
1639 bits = BITVECTOR_BITS(vec);
1640 return scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1641 }
1642 else
1643 {
1644 SCM res;
1645 size_t len, off;
1646 ssize_t inc;
1647
1648 bits = scm_bitvector_elements (vec, &handle, &off, &len, &inc);
1649 if (idx >= len)
1650 scm_out_of_range (NULL, scm_from_size_t (idx));
1651 idx = idx*inc + off;
1652 res = scm_from_bool (bits[idx/32] & (1L << (idx%32)));
1653 scm_array_handle_release (&handle);
1654 return res;
1655 }
1656 }
1657
1658 SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1659 (SCM vec, SCM idx),
1660 "Return the element at index @var{idx} of the bitvector\n"
1661 "@var{vec}.")
1662 #define FUNC_NAME s_scm_bitvector_ref
1663 {
1664 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1665 }
1666 #undef FUNC_NAME
1667
1668 void
1669 scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1670 {
1671 scm_t_array_handle handle;
1672 scm_t_uint32 *bits, mask;
1673
1674 if (IS_BITVECTOR (vec))
1675 {
1676 if (idx >= BITVECTOR_LENGTH (vec))
1677 scm_out_of_range (NULL, scm_from_size_t (idx));
1678 bits = BITVECTOR_BITS(vec);
1679 }
1680 else
1681 {
1682 size_t len, off;
1683 ssize_t inc;
1684
1685 bits = scm_bitvector_writable_elements (vec, &handle, &off, &len, &inc);
1686 if (idx >= len)
1687 scm_out_of_range (NULL, scm_from_size_t (idx));
1688 idx = idx*inc + off;
1689 }
1690
1691 mask = 1L << (idx%32);
1692 if (scm_is_true (val))
1693 bits[idx/32] |= mask;
1694 else
1695 bits[idx/32] &= ~mask;
1696
1697 if (!IS_BITVECTOR (vec))
1698 scm_array_handle_release (&handle);
1699 }
1700
1701 SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1702 (SCM vec, SCM idx, SCM val),
1703 "Set the element at index @var{idx} of the bitvector\n"
1704 "@var{vec} when @var{val} is true, else clear it.")
1705 #define FUNC_NAME s_scm_bitvector_set_x
1706 {
1707 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1708 return SCM_UNSPECIFIED;
1709 }
1710 #undef FUNC_NAME
1711
1712 SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1713 (SCM vec, SCM val),
1714 "Set all elements of the bitvector\n"
1715 "@var{vec} when @var{val} is true, else clear them.")
1716 #define FUNC_NAME s_scm_bitvector_fill_x
1717 {
1718 scm_t_array_handle handle;
1719 size_t off, len;
1720 ssize_t inc;
1721 scm_t_uint32 *bits;
1722
1723 bits = scm_bitvector_writable_elements (vec, &handle,
1724 &off, &len, &inc);
1725
1726 if (off == 0 && inc == 1 && len > 0)
1727 {
1728 /* the usual case
1729 */
1730 size_t word_len = (len + 31) / 32;
1731 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1732
1733 if (scm_is_true (val))
1734 {
1735 memset (bits, 0xFF, sizeof(scm_t_uint32)*(word_len-1));
1736 bits[word_len-1] |= last_mask;
1737 }
1738 else
1739 {
1740 memset (bits, 0x00, sizeof(scm_t_uint32)*(word_len-1));
1741 bits[word_len-1] &= ~last_mask;
1742 }
1743 }
1744 else
1745 {
1746 size_t i;
1747 for (i = 0; i < len; i++)
1748 scm_array_handle_set (&handle, i*inc, val);
1749 }
1750
1751 scm_array_handle_release (&handle);
1752
1753 return SCM_UNSPECIFIED;
1754 }
1755 #undef FUNC_NAME
1756
1757 SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1758 (SCM list),
1759 "Return a new bitvector initialized with the elements\n"
1760 "of @var{list}.")
1761 #define FUNC_NAME s_scm_list_to_bitvector
1762 {
1763 size_t bit_len = scm_to_size_t (scm_length (list));
1764 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1765 size_t word_len = (bit_len+31)/32;
1766 scm_t_array_handle handle;
1767 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec, &handle,
1768 NULL, NULL, NULL);
1769 size_t i, j;
1770
1771 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1772 {
1773 scm_t_uint32 mask = 1;
1774 bits[i] = 0;
1775 for (j = 0; j < 32 && j < bit_len;
1776 j++, mask <<= 1, list = SCM_CDR (list))
1777 if (scm_is_true (SCM_CAR (list)))
1778 bits[i] |= mask;
1779 }
1780
1781 scm_array_handle_release (&handle);
1782
1783 return vec;
1784 }
1785 #undef FUNC_NAME
1786
1787 SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1788 (SCM vec),
1789 "Return a new list initialized with the elements\n"
1790 "of the bitvector @var{vec}.")
1791 #define FUNC_NAME s_scm_bitvector_to_list
1792 {
1793 scm_t_array_handle handle;
1794 size_t off, len;
1795 ssize_t inc;
1796 scm_t_uint32 *bits;
1797 SCM res = SCM_EOL;
1798
1799 bits = scm_bitvector_writable_elements (vec, &handle,
1800 &off, &len, &inc);
1801
1802 if (off == 0 && inc == 1)
1803 {
1804 /* the usual case
1805 */
1806 size_t word_len = (len + 31) / 32;
1807 size_t i, j;
1808
1809 for (i = 0; i < word_len; i++, len -= 32)
1810 {
1811 scm_t_uint32 mask = 1;
1812 for (j = 0; j < 32 && j < len; j++, mask <<= 1)
1813 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1814 }
1815 }
1816 else
1817 {
1818 size_t i;
1819 for (i = 0; i < len; i++)
1820 res = scm_cons (scm_array_handle_ref (&handle, i*inc), res);
1821 }
1822
1823 scm_array_handle_release (&handle);
1824
1825 return scm_reverse_x (res, SCM_EOL);
1826 }
1827 #undef FUNC_NAME
1828
1829 /* From mmix-arith.w by Knuth.
1830
1831 Here's a fun way to count the number of bits in a tetrabyte.
1832
1833 [This classical trick is called the ``Gillies--Miller method for
1834 sideways addition'' in {\sl The Preparation of Programs for an
1835 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1836 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1837 the tricks used here were suggested by Balbir Singh, Peter
1838 Rossmanith, and Stefan Schwoon.]
1839 */
1840
1841 static size_t
1842 count_ones (scm_t_uint32 x)
1843 {
1844 x=x-((x>>1)&0x55555555);
1845 x=(x&0x33333333)+((x>>2)&0x33333333);
1846 x=(x+(x>>4))&0x0f0f0f0f;
1847 x=x+(x>>8);
1848 return (x+(x>>16)) & 0xff;
1849 }
1850
1851 SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
1852 (SCM b, SCM bitvector),
1853 "Return the number of occurrences of the boolean @var{b} in\n"
1854 "@var{bitvector}.")
1855 #define FUNC_NAME s_scm_bit_count
1856 {
1857 scm_t_array_handle handle;
1858 size_t off, len;
1859 ssize_t inc;
1860 scm_t_uint32 *bits;
1861 int bit = scm_to_bool (b);
1862 size_t count = 0;
1863
1864 bits = scm_bitvector_writable_elements (bitvector, &handle,
1865 &off, &len, &inc);
1866
1867 if (off == 0 && inc == 1 && len > 0)
1868 {
1869 /* the usual case
1870 */
1871 size_t word_len = (len + 31) / 32;
1872 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1873 size_t i;
1874
1875 for (i = 0; i < word_len-1; i++)
1876 count += count_ones (bits[i]);
1877 count += count_ones (bits[i] & last_mask);
1878 }
1879 else
1880 {
1881 size_t i;
1882 for (i = 0; i < len; i++)
1883 if (scm_is_true (scm_array_handle_ref (&handle, i*inc)))
1884 count++;
1885 }
1886
1887 scm_array_handle_release (&handle);
1888
1889 return scm_from_size_t (bit? count : len-count);
1890 }
1891 #undef FUNC_NAME
1892
1893 /* returns 32 for x == 0.
1894 */
1895 static size_t
1896 find_first_one (scm_t_uint32 x)
1897 {
1898 size_t pos = 0;
1899 /* do a binary search in x. */
1900 if ((x & 0xFFFF) == 0)
1901 x >>= 16, pos += 16;
1902 if ((x & 0xFF) == 0)
1903 x >>= 8, pos += 8;
1904 if ((x & 0xF) == 0)
1905 x >>= 4, pos += 4;
1906 if ((x & 0x3) == 0)
1907 x >>= 2, pos += 2;
1908 if ((x & 0x1) == 0)
1909 pos += 1;
1910 return pos;
1911 }
1912
1913 SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1914 (SCM item, SCM v, SCM k),
1915 "Return the index of the first occurrance of @var{item} in bit\n"
1916 "vector @var{v}, starting from @var{k}. If there is no\n"
1917 "@var{item} entry between @var{k} and the end of\n"
1918 "@var{bitvector}, then return @code{#f}. For example,\n"
1919 "\n"
1920 "@example\n"
1921 "(bit-position #t #*000101 0) @result{} 3\n"
1922 "(bit-position #f #*0001111 3) @result{} #f\n"
1923 "@end example")
1924 #define FUNC_NAME s_scm_bit_position
1925 {
1926 scm_t_array_handle handle;
1927 size_t off, len, first_bit;
1928 ssize_t inc;
1929 const scm_t_uint32 *bits;
1930 int bit = scm_to_bool (item);
1931 SCM res = SCM_BOOL_F;
1932
1933 bits = scm_bitvector_elements (v, &handle, &off, &len, &inc);
1934 first_bit = scm_to_unsigned_integer (k, 0, len);
1935
1936 if (off == 0 && inc == 1 && len > 0)
1937 {
1938 size_t i, word_len = (len + 31) / 32;
1939 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1940 size_t first_word = first_bit / 32;
1941 scm_t_uint32 first_mask =
1942 ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1943 scm_t_uint32 w;
1944
1945 for (i = first_word; i < word_len; i++)
1946 {
1947 w = (bit? bits[i] : ~bits[i]);
1948 if (i == first_word)
1949 w &= first_mask;
1950 if (i == word_len-1)
1951 w &= last_mask;
1952 if (w)
1953 {
1954 res = scm_from_size_t (32*i + find_first_one (w));
1955 break;
1956 }
1957 }
1958 }
1959 else
1960 {
1961 size_t i;
1962 for (i = first_bit; i < len; i++)
1963 {
1964 SCM elt = scm_array_handle_ref (&handle, i*inc);
1965 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
1966 {
1967 res = scm_from_size_t (i);
1968 break;
1969 }
1970 }
1971 }
1972
1973 scm_array_handle_release (&handle);
1974
1975 return res;
1976 }
1977 #undef FUNC_NAME
1978
1979 SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
1980 (SCM v, SCM kv, SCM obj),
1981 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1982 "selecting the entries to change. The return value is\n"
1983 "unspecified.\n"
1984 "\n"
1985 "If @var{kv} is a bit vector, then those entries where it has\n"
1986 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1987 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1988 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1989 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1990 "\n"
1991 "@example\n"
1992 "(define bv #*01000010)\n"
1993 "(bit-set*! bv #*10010001 #t)\n"
1994 "bv\n"
1995 "@result{} #*11010011\n"
1996 "@end example\n"
1997 "\n"
1998 "If @var{kv} is a u32vector, then its elements are\n"
1999 "indices into @var{v} which are set to @var{obj}.\n"
2000 "\n"
2001 "@example\n"
2002 "(define bv #*01000010)\n"
2003 "(bit-set*! bv #u32(5 2 7) #t)\n"
2004 "bv\n"
2005 "@result{} #*01100111\n"
2006 "@end example")
2007 #define FUNC_NAME s_scm_bit_set_star_x
2008 {
2009 scm_t_array_handle v_handle;
2010 size_t v_off, v_len;
2011 ssize_t v_inc;
2012 scm_t_uint32 *v_bits;
2013 int bit;
2014
2015 /* Validate that OBJ is a boolean so this is done even if we don't
2016 need BIT.
2017 */
2018 bit = scm_to_bool (obj);
2019
2020 v_bits = scm_bitvector_writable_elements (v, &v_handle,
2021 &v_off, &v_len, &v_inc);
2022
2023 if (scm_is_bitvector (kv))
2024 {
2025 scm_t_array_handle kv_handle;
2026 size_t kv_off, kv_len;
2027 ssize_t kv_inc;
2028 const scm_t_uint32 *kv_bits;
2029
2030 kv_bits = scm_bitvector_elements (v, &kv_handle,
2031 &kv_off, &kv_len, &kv_inc);
2032
2033 if (v_len != kv_len)
2034 scm_misc_error (NULL,
2035 "bit vectors must have equal length",
2036 SCM_EOL);
2037
2038 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2039 {
2040 size_t word_len = (kv_len + 31) / 32;
2041 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2042 size_t i;
2043
2044 if (bit == 0)
2045 {
2046 for (i = 0; i < word_len-1; i++)
2047 v_bits[i] &= ~kv_bits[i];
2048 v_bits[i] &= ~(kv_bits[i] & last_mask);
2049 }
2050 else
2051 {
2052 for (i = 0; i < word_len-1; i++)
2053 v_bits[i] |= kv_bits[i];
2054 v_bits[i] |= kv_bits[i] & last_mask;
2055 }
2056 }
2057 else
2058 {
2059 size_t i;
2060 for (i = 0; i < kv_len; i++)
2061 if (scm_is_true (scm_array_handle_ref (&kv_handle, i*kv_inc)))
2062 scm_array_handle_set (&v_handle, i*v_inc, obj);
2063 }
2064
2065 scm_array_handle_release (&kv_handle);
2066
2067 }
2068 else if (scm_is_true (scm_u32vector_p (kv)))
2069 {
2070 scm_t_array_handle kv_handle;
2071 size_t i, kv_len;
2072 ssize_t kv_inc;
2073 const scm_t_uint32 *kv_elts;
2074
2075 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2076 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2077 scm_array_handle_set (&v_handle, (*kv_elts)*v_inc, obj);
2078
2079 scm_array_handle_release (&kv_handle);
2080 }
2081 else
2082 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2083
2084 scm_array_handle_release (&v_handle);
2085
2086 return SCM_UNSPECIFIED;
2087 }
2088 #undef FUNC_NAME
2089
2090
2091 SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
2092 (SCM v, SCM kv, SCM obj),
2093 "Return a count of how many entries in bit vector @var{v} are\n"
2094 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
2095 "consider.\n"
2096 "\n"
2097 "If @var{kv} is a bit vector, then those entries where it has\n"
2098 "@code{#t} are the ones in @var{v} which are considered.\n"
2099 "@var{kv} and @var{v} must be the same length.\n"
2100 "\n"
2101 "If @var{kv} is a u32vector, then it contains\n"
2102 "the indexes in @var{v} to consider.\n"
2103 "\n"
2104 "For example,\n"
2105 "\n"
2106 "@example\n"
2107 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
2108 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
2109 "@end example")
2110 #define FUNC_NAME s_scm_bit_count_star
2111 {
2112 scm_t_array_handle v_handle;
2113 size_t v_off, v_len;
2114 ssize_t v_inc;
2115 const scm_t_uint32 *v_bits;
2116 size_t count = 0;
2117 int bit;
2118
2119 /* Validate that OBJ is a boolean so this is done even if we don't
2120 need BIT.
2121 */
2122 bit = scm_to_bool (obj);
2123
2124 v_bits = scm_bitvector_elements (v, &v_handle,
2125 &v_off, &v_len, &v_inc);
2126
2127 if (scm_is_bitvector (kv))
2128 {
2129 scm_t_array_handle kv_handle;
2130 size_t kv_off, kv_len;
2131 ssize_t kv_inc;
2132 const scm_t_uint32 *kv_bits;
2133
2134 kv_bits = scm_bitvector_elements (v, &kv_handle,
2135 &kv_off, &kv_len, &kv_inc);
2136
2137 if (v_len != kv_len)
2138 scm_misc_error (NULL,
2139 "bit vectors must have equal length",
2140 SCM_EOL);
2141
2142 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2143 {
2144 size_t i, word_len = (kv_len + 31) / 32;
2145 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2146 scm_t_uint32 xor_mask = bit? 0 : ((scm_t_uint32)-1);
2147
2148 for (i = 0; i < word_len-1; i++)
2149 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i]);
2150 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i] & last_mask);
2151 }
2152 else
2153 {
2154 size_t i;
2155 for (i = 0; i < kv_len; i++)
2156 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2157 {
2158 SCM elt = scm_array_handle_ref (&v_handle, i*v_inc);
2159 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2160 count++;
2161 }
2162 }
2163
2164 scm_array_handle_release (&kv_handle);
2165
2166 }
2167 else if (scm_is_true (scm_u32vector_p (kv)))
2168 {
2169 scm_t_array_handle kv_handle;
2170 size_t i, kv_len;
2171 ssize_t kv_inc;
2172 const scm_t_uint32 *kv_elts;
2173
2174 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2175 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2176 {
2177 SCM elt = scm_array_handle_ref (&v_handle, (*kv_elts)*v_inc);
2178 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2179 count++;
2180 }
2181
2182 scm_array_handle_release (&kv_handle);
2183 }
2184 else
2185 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2186
2187 scm_array_handle_release (&v_handle);
2188
2189 return scm_from_size_t (count);
2190 }
2191 #undef FUNC_NAME
2192
2193 SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
2194 (SCM v),
2195 "Modify the bit vector @var{v} by replacing each element with\n"
2196 "its negation.")
2197 #define FUNC_NAME s_scm_bit_invert_x
2198 {
2199 scm_t_array_handle handle;
2200 size_t off, len;
2201 ssize_t inc;
2202 scm_t_uint32 *bits;
2203
2204 bits = scm_bitvector_writable_elements (v, &handle, &off, &len, &inc);
2205
2206 if (off == 0 && inc == 1 && len > 0)
2207 {
2208 size_t word_len = (len + 31) / 32;
2209 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
2210 size_t i;
2211
2212 for (i = 0; i < word_len-1; i++)
2213 bits[i] = ~bits[i];
2214 bits[i] = bits[i] ^ last_mask;
2215 }
2216 else
2217 {
2218 size_t i;
2219 for (i = 0; i < len; i++)
2220 scm_array_handle_set (&handle, i*inc,
2221 scm_not (scm_array_handle_ref (&handle, i*inc)));
2222 }
2223
2224 scm_array_handle_release (&handle);
2225
2226 return SCM_UNSPECIFIED;
2227 }
2228 #undef FUNC_NAME
2229
2230
2231 SCM
2232 scm_istr2bve (SCM str)
2233 {
2234 scm_t_array_handle handle;
2235 size_t len = scm_i_string_length (str);
2236 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
2237 SCM res = vec;
2238
2239 scm_t_uint32 mask;
2240 size_t k, j;
2241 const char *c_str;
2242 scm_t_uint32 *data;
2243
2244 data = scm_bitvector_writable_elements (vec, &handle, NULL, NULL, NULL);
2245 c_str = scm_i_string_chars (str);
2246
2247 for (k = 0; k < (len + 31) / 32; k++)
2248 {
2249 data[k] = 0L;
2250 j = len - k * 32;
2251 if (j > 32)
2252 j = 32;
2253 for (mask = 1L; j--; mask <<= 1)
2254 switch (*c_str++)
2255 {
2256 case '0':
2257 break;
2258 case '1':
2259 data[k] |= mask;
2260 break;
2261 default:
2262 res = SCM_BOOL_F;
2263 goto exit;
2264 }
2265 }
2266
2267 exit:
2268 scm_array_handle_release (&handle);
2269 scm_remember_upto_here_1 (str);
2270 return res;
2271 }
2272
2273
2274
2275 static SCM
2276 ra2l (SCM ra, unsigned long base, unsigned long k)
2277 {
2278 SCM res = SCM_EOL;
2279 long inc;
2280 size_t i;
2281 int enclosed = SCM_I_ENCLOSED_ARRAYP (ra);
2282
2283 if (k == SCM_I_ARRAY_NDIM (ra))
2284 return scm_i_cvref (SCM_I_ARRAY_V (ra), base, enclosed);
2285
2286 inc = SCM_I_ARRAY_DIMS (ra)[k].inc;
2287 if (SCM_I_ARRAY_DIMS (ra)[k].ubnd < SCM_I_ARRAY_DIMS (ra)[k].lbnd)
2288 return SCM_EOL;
2289 i = base + (1 + SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * inc;
2290 do
2291 {
2292 i -= inc;
2293 res = scm_cons (ra2l (ra, i, k + 1), res);
2294 }
2295 while (i != base);
2296 return res;
2297 }
2298
2299
2300 SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
2301 (SCM v),
2302 "Return a list consisting of all the elements, in order, of\n"
2303 "@var{array}.")
2304 #define FUNC_NAME s_scm_array_to_list
2305 {
2306 if (scm_is_generalized_vector (v))
2307 return scm_generalized_vector_to_list (v);
2308 else if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
2309 return ra2l (v, SCM_I_ARRAY_BASE (v), 0);
2310
2311 scm_wrong_type_arg_msg (NULL, 0, v, "array");
2312 }
2313 #undef FUNC_NAME
2314
2315
2316 static void l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k);
2317
2318 SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2319 (SCM type, SCM shape, SCM lst),
2320 "Return an array of the type @var{type}\n"
2321 "with elements the same as those of @var{lst}.\n"
2322 "\n"
2323 "The argument @var{shape} determines the number of dimensions\n"
2324 "of the array and their shape. It is either an exact integer,\n"
2325 "giving the\n"
2326 "number of dimensions directly, or a list whose length\n"
2327 "specifies the number of dimensions and each element specified\n"
2328 "the lower and optionally the upper bound of the corresponding\n"
2329 "dimension.\n"
2330 "When the element is list of two elements, these elements\n"
2331 "give the lower and upper bounds. When it is an exact\n"
2332 "integer, it gives only the lower bound.")
2333 #define FUNC_NAME s_scm_list_to_typed_array
2334 {
2335 SCM row;
2336 SCM ra;
2337 scm_t_array_handle handle;
2338
2339 row = lst;
2340 if (scm_is_integer (shape))
2341 {
2342 size_t k = scm_to_size_t (shape);
2343 shape = SCM_EOL;
2344 while (k-- > 0)
2345 {
2346 shape = scm_cons (scm_length (row), shape);
2347 if (k > 0 && !scm_is_null (row))
2348 row = scm_car (row);
2349 }
2350 }
2351 else
2352 {
2353 SCM shape_spec = shape;
2354 shape = SCM_EOL;
2355 while (1)
2356 {
2357 SCM spec = scm_car (shape_spec);
2358 if (scm_is_pair (spec))
2359 shape = scm_cons (spec, shape);
2360 else
2361 shape = scm_cons (scm_list_2 (spec,
2362 scm_sum (scm_sum (spec,
2363 scm_length (row)),
2364 scm_from_int (-1))),
2365 shape);
2366 shape_spec = scm_cdr (shape_spec);
2367 if (scm_is_pair (shape_spec))
2368 {
2369 if (!scm_is_null (row))
2370 row = scm_car (row);
2371 }
2372 else
2373 break;
2374 }
2375 }
2376
2377 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
2378 scm_reverse_x (shape, SCM_EOL));
2379
2380 scm_array_get_handle (ra, &handle);
2381 l2ra (lst, &handle, 0, 0);
2382 scm_array_handle_release (&handle);
2383
2384 return ra;
2385 }
2386 #undef FUNC_NAME
2387
2388 SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
2389 (SCM ndim, SCM lst),
2390 "Return an array with elements the same as those of @var{lst}.")
2391 #define FUNC_NAME s_scm_list_to_array
2392 {
2393 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
2394 }
2395 #undef FUNC_NAME
2396
2397 static void
2398 l2ra (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
2399 {
2400 if (k == scm_array_handle_rank (handle))
2401 scm_array_handle_set (handle, pos, lst);
2402 else
2403 {
2404 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
2405 ssize_t inc = dim->inc;
2406 size_t len = 1 + dim->ubnd - dim->lbnd, n;
2407 char *errmsg = NULL;
2408
2409 n = len;
2410 while (n > 0 && scm_is_pair (lst))
2411 {
2412 l2ra (SCM_CAR (lst), handle, pos, k + 1);
2413 pos += inc;
2414 lst = SCM_CDR (lst);
2415 n -= 1;
2416 }
2417 if (n != 0)
2418 errmsg = "too few elements for array dimension ~a, need ~a";
2419 if (!scm_is_null (lst))
2420 errmsg = "too many elements for array dimension ~a, want ~a";
2421 if (errmsg)
2422 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
2423 scm_from_size_t (len)));
2424 }
2425 }
2426
2427 #if SCM_ENABLE_DEPRECATED
2428
2429 SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
2430 (SCM ndim, SCM prot, SCM lst),
2431 "Return a uniform array of the type indicated by prototype\n"
2432 "@var{prot} with elements the same as those of @var{lst}.\n"
2433 "Elements must be of the appropriate type, no coercions are\n"
2434 "done.\n"
2435 "\n"
2436 "The argument @var{ndim} determines the number of dimensions\n"
2437 "of the array. It is either an exact integer, giving the\n"
2438 "number directly, or a list of exact integers, whose length\n"
2439 "specifies the number of dimensions and each element is the\n"
2440 "lower index bound of its dimension.")
2441 #define FUNC_NAME s_scm_list_to_uniform_array
2442 {
2443 return scm_list_to_typed_array (prototype_to_type (prot), ndim, lst);
2444 }
2445 #undef FUNC_NAME
2446
2447 #endif
2448
2449 /* Print dimension DIM of ARRAY.
2450 */
2451
2452 static int
2453 scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
2454 SCM port, scm_print_state *pstate)
2455 {
2456 scm_t_array_dim *dim_spec = SCM_I_ARRAY_DIMS (array) + dim;
2457 long idx;
2458
2459 scm_putc ('(', port);
2460
2461 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2462 {
2463 if (dim < SCM_I_ARRAY_NDIM(array)-1)
2464 scm_i_print_array_dimension (array, dim+1, base, enclosed,
2465 port, pstate);
2466 else
2467 scm_iprin1 (scm_i_cvref (SCM_I_ARRAY_V (array), base, enclosed),
2468 port, pstate);
2469 if (idx < dim_spec->ubnd)
2470 scm_putc (' ', port);
2471 base += dim_spec->inc;
2472 }
2473
2474 scm_putc (')', port);
2475 return 1;
2476 }
2477
2478 /* Print an array. (Only for strict arrays, not for generalized vectors.)
2479 */
2480
2481 static int
2482 scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2483 {
2484 long ndim = SCM_I_ARRAY_NDIM (array);
2485 scm_t_array_dim *dim_specs = SCM_I_ARRAY_DIMS (array);
2486 SCM v = SCM_I_ARRAY_V (array);
2487 unsigned long base = SCM_I_ARRAY_BASE (array);
2488 long i;
2489 int print_lbnds = 0, zero_size = 0, print_lens = 0;
2490
2491 scm_putc ('#', port);
2492 if (ndim != 1 || dim_specs[0].lbnd != 0)
2493 scm_intprint (ndim, 10, port);
2494 if (scm_is_uniform_vector (v))
2495 scm_puts (scm_i_uniform_vector_tag (v), port);
2496 else if (scm_is_bitvector (v))
2497 scm_puts ("b", port);
2498 else if (scm_is_string (v))
2499 scm_puts ("a", port);
2500 else if (!scm_is_vector (v))
2501 scm_puts ("?", port);
2502
2503 for (i = 0; i < ndim; i++)
2504 {
2505 if (dim_specs[i].lbnd != 0)
2506 print_lbnds = 1;
2507 if (dim_specs[i].ubnd - dim_specs[i].lbnd + 1 == 0)
2508 zero_size = 1;
2509 else if (zero_size)
2510 print_lens = 1;
2511 }
2512
2513 if (print_lbnds || print_lens)
2514 for (i = 0; i < ndim; i++)
2515 {
2516 if (print_lbnds)
2517 {
2518 scm_putc ('@', port);
2519 scm_intprint (dim_specs[i].lbnd, 10, port);
2520 }
2521 if (print_lens)
2522 {
2523 scm_putc (':', port);
2524 scm_intprint (dim_specs[i].ubnd - dim_specs[i].lbnd + 1,
2525 10, port);
2526 }
2527 }
2528
2529 if (ndim == 0)
2530 {
2531 /* Rank zero arrays, which are really just scalars, are printed
2532 specially. The consequent way would be to print them as
2533
2534 #0 OBJ
2535
2536 where OBJ is the printed representation of the scalar, but we
2537 print them instead as
2538
2539 #0(OBJ)
2540
2541 to make them look less strange.
2542
2543 Just printing them as
2544
2545 OBJ
2546
2547 would be correct in a way as well, but zero rank arrays are
2548 not really the same as Scheme values since they are boxed and
2549 can be modified with array-set!, say.
2550 */
2551 scm_putc ('(', port);
2552 scm_iprin1 (scm_i_cvref (v, base, 0), port, pstate);
2553 scm_putc (')', port);
2554 return 1;
2555 }
2556 else
2557 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
2558 }
2559
2560 static int
2561 scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
2562 {
2563 size_t base;
2564
2565 scm_putc ('#', port);
2566 base = SCM_I_ARRAY_BASE (array);
2567 scm_puts ("<enclosed-array ", port);
2568 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
2569 scm_putc ('>', port);
2570 return 1;
2571 }
2572
2573 /* Read an array. This function can also read vectors and uniform
2574 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2575 handled here.
2576
2577 C is the first character read after the '#'.
2578 */
2579
2580 static SCM
2581 tag_to_type (const char *tag, SCM port)
2582 {
2583 #if SCM_ENABLE_DEPRECATED
2584 {
2585 /* Recognize the old syntax.
2586 */
2587 const char *instead;
2588 switch (tag[0])
2589 {
2590 case 'u':
2591 instead = "u32";
2592 break;
2593 case 'e':
2594 instead = "s32";
2595 break;
2596 case 's':
2597 instead = "f32";
2598 break;
2599 case 'i':
2600 instead = "f64";
2601 break;
2602 case 'y':
2603 instead = "s8";
2604 break;
2605 case 'h':
2606 instead = "s16";
2607 break;
2608 case 'l':
2609 instead = "s64";
2610 break;
2611 case 'c':
2612 instead = "c64";
2613 break;
2614 default:
2615 instead = NULL;
2616 break;
2617 }
2618
2619 if (instead && tag[1] == '\0')
2620 {
2621 scm_c_issue_deprecation_warning_fmt
2622 ("The tag '%c' is deprecated for uniform vectors. "
2623 "Use '%s' instead.", tag[0], instead);
2624 return scm_from_locale_symbol (instead);
2625 }
2626 }
2627 #endif
2628
2629 if (*tag == '\0')
2630 return SCM_BOOL_T;
2631 else
2632 return scm_from_locale_symbol (tag);
2633 }
2634
2635 static int
2636 read_decimal_integer (SCM port, int c, ssize_t *resp)
2637 {
2638 ssize_t sign = 1;
2639 ssize_t res = 0;
2640 int got_it = 0;
2641
2642 if (c == '-')
2643 {
2644 sign = -1;
2645 c = scm_getc (port);
2646 }
2647
2648 while ('0' <= c && c <= '9')
2649 {
2650 res = 10*res + c-'0';
2651 got_it = 1;
2652 c = scm_getc (port);
2653 }
2654
2655 if (got_it)
2656 *resp = res;
2657 return c;
2658 }
2659
2660 SCM
2661 scm_i_read_array (SCM port, int c)
2662 {
2663 ssize_t rank;
2664 int got_rank;
2665 char tag[80];
2666 int tag_len;
2667
2668 SCM shape = SCM_BOOL_F, elements;
2669
2670 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2671 the array code can not deal with zero-length dimensions yet, and
2672 we want to allow zero-length vectors, of course.
2673 */
2674 if (c == '(')
2675 {
2676 scm_ungetc (c, port);
2677 return scm_vector (scm_read (port));
2678 }
2679
2680 /* Disambiguate between '#f' and uniform floating point vectors.
2681 */
2682 if (c == 'f')
2683 {
2684 c = scm_getc (port);
2685 if (c != '3' && c != '6')
2686 {
2687 if (c != EOF)
2688 scm_ungetc (c, port);
2689 return SCM_BOOL_F;
2690 }
2691 rank = 1;
2692 got_rank = 1;
2693 tag[0] = 'f';
2694 tag_len = 1;
2695 goto continue_reading_tag;
2696 }
2697
2698 /* Read rank.
2699 */
2700 rank = 1;
2701 c = read_decimal_integer (port, c, &rank);
2702 if (rank < 0)
2703 scm_i_input_error (NULL, port, "array rank must be non-negative",
2704 SCM_EOL);
2705
2706 /* Read tag.
2707 */
2708 tag_len = 0;
2709 continue_reading_tag:
2710 while (c != EOF && c != '(' && c != '@' && c != ':' && tag_len < 80)
2711 {
2712 tag[tag_len++] = c;
2713 c = scm_getc (port);
2714 }
2715 tag[tag_len] = '\0';
2716
2717 /* Read shape.
2718 */
2719 if (c == '@' || c == ':')
2720 {
2721 shape = SCM_EOL;
2722
2723 do
2724 {
2725 ssize_t lbnd = 0, len = 0;
2726 SCM s;
2727
2728 if (c == '@')
2729 {
2730 c = scm_getc (port);
2731 c = read_decimal_integer (port, c, &lbnd);
2732 }
2733
2734 s = scm_from_ssize_t (lbnd);
2735
2736 if (c == ':')
2737 {
2738 c = scm_getc (port);
2739 c = read_decimal_integer (port, c, &len);
2740 s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
2741 }
2742
2743 shape = scm_cons (s, shape);
2744 } while (c == '@' || c == ':');
2745
2746 shape = scm_reverse_x (shape, SCM_EOL);
2747 }
2748
2749 /* Read nested lists of elements.
2750 */
2751 if (c != '(')
2752 scm_i_input_error (NULL, port,
2753 "missing '(' in vector or array literal",
2754 SCM_EOL);
2755 scm_ungetc (c, port);
2756 elements = scm_read (port);
2757
2758 if (scm_is_false (shape))
2759 shape = scm_from_ssize_t (rank);
2760 else if (scm_ilength (shape) != rank)
2761 scm_i_input_error
2762 (NULL, port,
2763 "the number of shape specifications must match the array rank",
2764 SCM_EOL);
2765
2766 /* Handle special print syntax of rank zero arrays; see
2767 scm_i_print_array for a rationale.
2768 */
2769 if (rank == 0)
2770 {
2771 if (!scm_is_pair (elements))
2772 scm_i_input_error (NULL, port,
2773 "too few elements in array literal, need 1",
2774 SCM_EOL);
2775 if (!scm_is_null (SCM_CDR (elements)))
2776 scm_i_input_error (NULL, port,
2777 "too many elements in array literal, want 1",
2778 SCM_EOL);
2779 elements = SCM_CAR (elements);
2780 }
2781
2782 /* Construct array.
2783 */
2784 return scm_list_to_typed_array (tag_to_type (tag, port), shape, elements);
2785 }
2786
2787 SCM_DEFINE (scm_array_type, "array-type", 1, 0, 0,
2788 (SCM ra),
2789 "")
2790 #define FUNC_NAME s_scm_array_type
2791 {
2792 if (SCM_I_ARRAYP (ra))
2793 return scm_i_generalized_vector_type (SCM_I_ARRAY_V (ra));
2794 else if (scm_is_generalized_vector (ra))
2795 return scm_i_generalized_vector_type (ra);
2796 else if (SCM_I_ENCLOSED_ARRAYP (ra))
2797 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
2798 else
2799 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2800 }
2801 #undef FUNC_NAME
2802
2803 #if SCM_ENABLE_DEPRECATED
2804
2805 SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
2806 (SCM ra),
2807 "Return an object that would produce an array of the same type\n"
2808 "as @var{array}, if used as the @var{prototype} for\n"
2809 "@code{make-uniform-array}.")
2810 #define FUNC_NAME s_scm_array_prototype
2811 {
2812 if (SCM_I_ARRAYP (ra))
2813 return scm_i_get_old_prototype (SCM_I_ARRAY_V (ra));
2814 else if (scm_is_generalized_vector (ra))
2815 return scm_i_get_old_prototype (ra);
2816 else if (SCM_I_ENCLOSED_ARRAYP (ra))
2817 return SCM_UNSPECIFIED;
2818 else
2819 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2820 }
2821 #undef FUNC_NAME
2822
2823 #endif
2824
2825 static SCM
2826 array_mark (SCM ptr)
2827 {
2828 return SCM_I_ARRAY_V (ptr);
2829 }
2830
2831 static size_t
2832 array_free (SCM ptr)
2833 {
2834 scm_gc_free (SCM_I_ARRAY_MEM (ptr),
2835 (sizeof (scm_i_t_array)
2836 + SCM_I_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2837 "array");
2838 return 0;
2839 }
2840
2841 #if SCM_ENABLE_DEPRECATED
2842
2843 SCM
2844 scm_make_ra (int ndim)
2845 {
2846 scm_c_issue_deprecation_warning
2847 ("scm_make_ra is deprecated. Use scm_make_array or similar instead.");
2848 return scm_i_make_ra (ndim, 0);
2849 }
2850
2851 SCM
2852 scm_shap2ra (SCM args, const char *what)
2853 {
2854 scm_c_issue_deprecation_warning
2855 ("scm_shap2ra is deprecated. Use scm_make_array or similar instead.");
2856 return scm_i_shap2ra (args);
2857 }
2858
2859 SCM
2860 scm_cvref (SCM v, unsigned long pos, SCM last)
2861 {
2862 scm_c_issue_deprecation_warning
2863 ("scm_cvref is deprecated. Use scm_c_generalized_vector_ref instead.");
2864 return scm_c_generalized_vector_ref (v, pos);
2865 }
2866
2867 void
2868 scm_ra_set_contp (SCM ra)
2869 {
2870 scm_c_issue_deprecation_warning
2871 ("scm_ra_set_contp is deprecated. There should be no need for it.");
2872 scm_i_ra_set_contp (ra);
2873 }
2874
2875 long
2876 scm_aind (SCM ra, SCM args, const char *what)
2877 {
2878 scm_t_array_handle handle;
2879 ssize_t pos;
2880
2881 scm_c_issue_deprecation_warning
2882 ("scm_aind is deprecated. Use scm_array_handle_pos instead.");
2883
2884 if (scm_is_integer (args))
2885 args = scm_list_1 (args);
2886
2887 scm_array_get_handle (ra, &handle);
2888 pos = scm_array_handle_pos (&handle, args) + SCM_I_ARRAY_BASE (ra);
2889 scm_array_handle_release (&handle);
2890 return pos;
2891 }
2892
2893 int
2894 scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
2895 {
2896 scm_c_issue_deprecation_warning
2897 ("scm_raprin1 is deprecated. Use scm_display or scm_write instead.");
2898
2899 scm_iprin1 (exp, port, pstate);
2900 return 1;
2901 }
2902
2903 #endif
2904
2905 void
2906 scm_init_unif ()
2907 {
2908 scm_i_tc16_array = scm_make_smob_type ("array", 0);
2909 scm_set_smob_mark (scm_i_tc16_array, array_mark);
2910 scm_set_smob_free (scm_i_tc16_array, array_free);
2911 scm_set_smob_print (scm_i_tc16_array, scm_i_print_array);
2912 scm_set_smob_equalp (scm_i_tc16_array, scm_array_equal_p);
2913
2914 scm_i_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
2915 scm_set_smob_mark (scm_i_tc16_enclosed_array, array_mark);
2916 scm_set_smob_free (scm_i_tc16_enclosed_array, array_free);
2917 scm_set_smob_print (scm_i_tc16_enclosed_array, scm_i_print_enclosed_array);
2918 scm_set_smob_equalp (scm_i_tc16_enclosed_array, scm_array_equal_p);
2919
2920 scm_add_feature ("array");
2921
2922 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2923 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2924 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2925 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2926
2927 init_type_creator_table ();
2928
2929 #include "libguile/unif.x"
2930
2931 }
2932
2933 /*
2934 Local Variables:
2935 c-file-style: "gnu"
2936 End:
2937 */