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