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