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