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