(cind): Changed second arg to be pointer to long instead
[bpt/guile.git] / libguile / unif.c
CommitLineData
18e2aba3 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004 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
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
92c2555f 82scm_t_bits scm_tc16_array;
7c183c95 83static SCM exactly_one_third;
0f2d19dd 84
85368844 85#if 0
bc86da5d
MD
86/* Silly function used not to modify the semantics of the silly
87 * prototype system in order to be backward compatible.
88 */
89static int
90singp (SCM obj)
0f2d19dd 91{
a08b0d00 92 if (!SCM_REALP (obj))
bc86da5d
MD
93 return 0;
94 else
95 {
96 double x = SCM_REAL_VALUE (obj);
97 float fx = x;
98 return (- SCM_FLTMAX < x) && (x < SCM_FLTMAX) && (fx == x);
99 }
0f2d19dd 100}
85368844 101#endif
1cc91f1b 102
20930f28
MV
103SCM scm_i_proc_make_vector;
104SCM scm_i_proc_make_string;
105SCM scm_i_proc_make_bitvector;
bfad4005
MV
106
107#if SCM_ENABLE_DEPRECATED
108
109SCM_SYMBOL (scm_sym_s, "s");
110SCM_SYMBOL (scm_sym_l, "l");
111
711a9fd7 112static SCM
bfad4005 113scm_i_convert_old_prototype (SCM proto)
711a9fd7 114{
bfad4005
MV
115 SCM new_proto;
116
117 /* All new 'prototypes' are creator procedures.
118 */
119 if (scm_is_true (scm_procedure_p (proto)))
120 return proto;
121
122 if (scm_is_eq (proto, SCM_BOOL_T))
20930f28 123 new_proto = scm_i_proc_make_bitvector;
bfad4005
MV
124 else if (scm_is_eq (proto, SCM_MAKE_CHAR ('a')))
125 new_proto = scm_i_proc_make_string;
126 else if (scm_is_eq (proto, SCM_MAKE_CHAR (0)))
127 new_proto = scm_i_proc_make_s8vector;
128 else if (scm_is_eq (proto, scm_sym_s))
129 new_proto = scm_i_proc_make_s16vector;
130 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (1))))
131 new_proto = scm_i_proc_make_u32vector;
132 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (-1))))
133 new_proto = scm_i_proc_make_s32vector;
134 else if (scm_is_eq (proto, scm_sym_l))
135 new_proto = scm_i_proc_make_s64vector;
136 else if (scm_is_true (scm_eqv_p (proto, scm_from_double (1.0))))
137 new_proto = scm_i_proc_make_f32vector;
138 else if (scm_is_true (scm_eqv_p (proto, scm_divide (scm_from_int (1),
139 scm_from_int (3)))))
140 new_proto = scm_i_proc_make_f64vector;
141 else if (scm_is_true (scm_eqv_p (proto, scm_c_make_rectangular (0, 1))))
142 new_proto = scm_i_proc_make_c64vector;
143 else if (scm_is_null (proto))
144 new_proto = scm_i_proc_make_vector;
145 else
146 new_proto = proto;
711a9fd7 147
bfad4005
MV
148 scm_c_issue_deprecation_warning
149 ("Using prototypes with arrays is deprecated. "
150 "Use creator functions instead.");
151
152 return new_proto;
711a9fd7 153}
bfad4005 154
ab1be174
MV
155static SCM
156scm_i_get_old_prototype (SCM uvec)
157{
20930f28 158 if (scm_is_bitvector (uvec))
ab1be174
MV
159 return SCM_BOOL_T;
160 else if (scm_is_string (uvec))
161 return SCM_MAKE_CHAR ('a');
162 else if (scm_is_true (scm_s8vector_p (uvec)))
163 return SCM_MAKE_CHAR ('\0');
164 else if (scm_is_true (scm_s16vector_p (uvec)))
165 return scm_sym_s;
166 else if (scm_is_true (scm_u32vector_p (uvec)))
167 return scm_from_int (1);
168 else if (scm_is_true (scm_s32vector_p (uvec)))
169 return scm_from_int (-1);
170 else if (scm_is_true (scm_s64vector_p (uvec)))
171 return scm_sym_l;
172 else if (scm_is_true (scm_f32vector_p (uvec)))
173 return scm_from_double (1.0);
174 else if (scm_is_true (scm_f64vector_p (uvec)))
175 return scm_divide (scm_from_int (1), scm_from_int (3));
176 else if (scm_is_true (scm_c64vector_p (uvec)))
177 return scm_c_make_rectangular (0, 1);
20930f28 178 else if (scm_is_vector (uvec))
ab1be174
MV
179 return SCM_EOL;
180 else
181 return SCM_UNSPECIFIED;
182}
183
bfad4005 184#endif
711a9fd7 185
0f2d19dd 186SCM
c014a02e 187scm_make_uve (long k, SCM prot)
a3a32939 188#define FUNC_NAME "scm_make_uve"
0f2d19dd 189{
20930f28 190 SCM res;
bfad4005
MV
191#if SCM_ENABLE_DEPRECATED
192 prot = scm_i_convert_old_prototype (prot);
0f2d19dd 193#endif
20930f28
MV
194 res = scm_call_1 (prot, scm_from_long (k));
195 if (!scm_is_generalized_vector (res))
196 scm_wrong_type_arg_msg (NULL, 0, res, "generalized vector");
197 return res;
0f2d19dd 198}
a3a32939
DH
199#undef FUNC_NAME
200
3b3b36dd 201SCM_DEFINE (scm_array_p, "array?", 1, 1, 0,
1bbd0b84 202 (SCM v, SCM prot),
1e6808ea
MG
203 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
204 "not. The @var{prototype} argument is used with uniform arrays\n"
205 "and is described elsewhere.")
1bbd0b84 206#define FUNC_NAME s_scm_array_p
0f2d19dd 207{
20930f28
MV
208 int nprot = SCM_UNBNDP (prot);
209 int enclosed = 0;
c209c88e 210
20930f28
MV
211 /* Get storage vector.
212 */
e0e49670 213 while (SCM_ARRAYP (v))
0f2d19dd 214 {
0f2d19dd
JB
215 if (nprot)
216 return SCM_BOOL_T;
217 if (enclosed++)
218 return SCM_BOOL_F;
219 v = SCM_ARRAY_V (v);
e0e49670
MV
220 }
221
20930f28 222 /* It must be a generalized vector (which includes vectors, strings, etc).
bfad4005 223 */
20930f28
MV
224 if (!scm_is_generalized_vector (v))
225 return SCM_BOOL_F;
9b0018a1 226
c209c88e 227 if (nprot)
20930f28
MV
228 return SCM_BOOL_T;
229
230#if SCM_ENABLE_DEPRECATED
231 prot = scm_i_convert_old_prototype (prot);
232#endif
233 return scm_eq_p (prot, scm_i_generalized_vector_creator (v));
0f2d19dd 234}
1bbd0b84 235#undef FUNC_NAME
0f2d19dd
JB
236
237
3b3b36dd 238SCM_DEFINE (scm_array_rank, "array-rank", 1, 0, 0,
1bbd0b84 239 (SCM ra),
1e6808ea
MG
240 "Return the number of dimensions of @var{obj}. If @var{obj} is\n"
241 "not an array, @code{0} is returned.")
1bbd0b84 242#define FUNC_NAME s_scm_array_rank
0f2d19dd 243{
20930f28 244 if (scm_is_generalized_vector (ra))
e0e49670
MV
245 return scm_from_int (1);
246
20930f28
MV
247 if (SCM_ARRAYP (ra))
248 return scm_from_size_t (SCM_ARRAY_NDIM (ra));
249
250 return scm_from_int (0);
0f2d19dd 251}
1bbd0b84 252#undef FUNC_NAME
0f2d19dd
JB
253
254
3b3b36dd 255SCM_DEFINE (scm_array_dimensions, "array-dimensions", 1, 0, 0,
1bbd0b84 256 (SCM ra),
b380b885
MD
257 "@code{Array-dimensions} is similar to @code{array-shape} but replaces\n"
258 "elements with a @code{0} minimum with one greater than the maximum. So:\n"
1e6808ea 259 "@lisp\n"
b380b885 260 "(array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) 5)\n"
1e6808ea 261 "@end lisp")
1bbd0b84 262#define FUNC_NAME s_scm_array_dimensions
0f2d19dd 263{
20930f28
MV
264 if (scm_is_generalized_vector (ra))
265 return scm_cons (scm_generalized_vector_length (ra), SCM_EOL);
e0e49670 266
20930f28 267 if (SCM_ARRAYP (ra))
0f2d19dd 268 {
20930f28
MV
269 SCM res = SCM_EOL;
270 size_t k;
271 scm_t_array_dim *s;
272
0f2d19dd
JB
273 k = SCM_ARRAY_NDIM (ra);
274 s = SCM_ARRAY_DIMS (ra);
275 while (k--)
e2d37336 276 res = scm_cons (s[k].lbnd
e11e83f3
MV
277 ? scm_cons2 (scm_from_long (s[k].lbnd),
278 scm_from_long (s[k].ubnd),
e2d37336 279 SCM_EOL)
e11e83f3 280 : scm_from_long (1 + s[k].ubnd),
e2d37336 281 res);
0f2d19dd
JB
282 return res;
283 }
20930f28
MV
284
285 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 286}
1bbd0b84 287#undef FUNC_NAME
0f2d19dd
JB
288
289
e2d37336
MD
290SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
291 (SCM ra),
292 "Return the root vector of a shared array.")
293#define FUNC_NAME s_scm_shared_array_root
294{
295 SCM_ASSERT (SCM_ARRAYP (ra), ra, SCM_ARG1, FUNC_NAME);
296 return SCM_ARRAY_V (ra);
297}
298#undef FUNC_NAME
299
300
301SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
302 (SCM ra),
303 "Return the root vector index of the first element in the array.")
304#define FUNC_NAME s_scm_shared_array_offset
305{
306 SCM_ASSERT (SCM_ARRAYP (ra), ra, SCM_ARG1, FUNC_NAME);
e11e83f3 307 return scm_from_int (SCM_ARRAY_BASE (ra));
e2d37336
MD
308}
309#undef FUNC_NAME
310
311
312SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
313 (SCM ra),
314 "For each dimension, return the distance between elements in the root vector.")
315#define FUNC_NAME s_scm_shared_array_increments
316{
317 SCM res = SCM_EOL;
1be6b49c 318 size_t k;
92c2555f 319 scm_t_array_dim *s;
e2d37336
MD
320 SCM_ASSERT (SCM_ARRAYP (ra), ra, SCM_ARG1, FUNC_NAME);
321 k = SCM_ARRAY_NDIM (ra);
322 s = SCM_ARRAY_DIMS (ra);
323 while (k--)
e11e83f3 324 res = scm_cons (scm_from_long (s[k].inc), res);
e2d37336
MD
325 return res;
326}
327#undef FUNC_NAME
328
329
0f2d19dd
JB
330static char s_bad_ind[] = "Bad scm_array index";
331
1cc91f1b 332
c014a02e 333long
1bbd0b84 334scm_aind (SCM ra, SCM args, const char *what)
b3fcac34 335#define FUNC_NAME what
0f2d19dd
JB
336{
337 SCM ind;
c014a02e
ML
338 register long j;
339 register unsigned long pos = SCM_ARRAY_BASE (ra);
340 register unsigned long k = SCM_ARRAY_NDIM (ra);
92c2555f 341 scm_t_array_dim *s = SCM_ARRAY_DIMS (ra);
e11e83f3 342 if (scm_is_integer (args))
0f2d19dd 343 {
b3fcac34
DH
344 if (k != 1)
345 scm_error_num_args_subr (what);
e11e83f3 346 return pos + (scm_to_long (args) - s->lbnd) * (s->inc);
0f2d19dd 347 }
d2e53ed6 348 while (k && scm_is_pair (args))
0f2d19dd
JB
349 {
350 ind = SCM_CAR (args);
351 args = SCM_CDR (args);
e11e83f3 352 if (!scm_is_integer (ind))
b3fcac34 353 scm_misc_error (what, s_bad_ind, SCM_EOL);
e11e83f3 354 j = scm_to_long (ind);
685c0d71
DH
355 if (j < s->lbnd || j > s->ubnd)
356 scm_out_of_range (what, ind);
0f2d19dd
JB
357 pos += (j - s->lbnd) * (s->inc);
358 k--;
359 s++;
360 }
d2e53ed6 361 if (k != 0 || !scm_is_null (args))
b3fcac34
DH
362 scm_error_num_args_subr (what);
363
0f2d19dd
JB
364 return pos;
365}
b3fcac34 366#undef FUNC_NAME
0f2d19dd 367
1cc91f1b 368
0f2d19dd 369SCM
1bbd0b84 370scm_make_ra (int ndim)
0f2d19dd
JB
371{
372 SCM ra;
0f2d19dd 373 SCM_DEFER_INTS;
92c2555f 374 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + scm_tc16_array,
4c9419ac
MV
375 scm_gc_malloc ((sizeof (scm_t_array) +
376 ndim * sizeof (scm_t_array_dim)),
377 "array"));
0f2d19dd
JB
378 SCM_ARRAY_V (ra) = scm_nullvect;
379 SCM_ALLOW_INTS;
380 return ra;
381}
382
383static char s_bad_spec[] = "Bad scm_array dimension";
384/* Increments will still need to be set. */
385
1cc91f1b 386
0f2d19dd 387SCM
1bbd0b84 388scm_shap2ra (SCM args, const char *what)
0f2d19dd 389{
92c2555f 390 scm_t_array_dim *s;
0f2d19dd
JB
391 SCM ra, spec, sp;
392 int ndim = scm_ilength (args);
b3fcac34
DH
393 if (ndim < 0)
394 scm_misc_error (what, s_bad_spec, SCM_EOL);
395
0f2d19dd
JB
396 ra = scm_make_ra (ndim);
397 SCM_ARRAY_BASE (ra) = 0;
398 s = SCM_ARRAY_DIMS (ra);
d2e53ed6 399 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
400 {
401 spec = SCM_CAR (args);
e11e83f3 402 if (scm_is_integer (spec))
0f2d19dd 403 {
e11e83f3 404 if (scm_to_long (spec) < 0)
b3fcac34 405 scm_misc_error (what, s_bad_spec, SCM_EOL);
0f2d19dd 406 s->lbnd = 0;
e11e83f3 407 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
408 s->inc = 1;
409 }
410 else
411 {
d2e53ed6 412 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
b3fcac34 413 scm_misc_error (what, s_bad_spec, SCM_EOL);
e11e83f3 414 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 415 sp = SCM_CDR (spec);
d2e53ed6 416 if (!scm_is_pair (sp)
e11e83f3 417 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 418 || !scm_is_null (SCM_CDR (sp)))
b3fcac34 419 scm_misc_error (what, s_bad_spec, SCM_EOL);
e11e83f3 420 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
421 s->inc = 1;
422 }
423 }
424 return ra;
425}
426
3b3b36dd 427SCM_DEFINE (scm_dimensions_to_uniform_array, "dimensions->uniform-array", 2, 1, 0,
1e6808ea 428 (SCM dims, SCM prot, SCM fill),
8f85c0c6 429 "@deffnx {Scheme Procedure} make-uniform-vector length prototype [fill]\n"
1e6808ea
MG
430 "Create and return a uniform array or vector of type\n"
431 "corresponding to @var{prototype} with dimensions @var{dims} or\n"
432 "length @var{length}. If @var{fill} is supplied, it's used to\n"
433 "fill the array, otherwise @var{prototype} is used.")
1bbd0b84 434#define FUNC_NAME s_scm_dimensions_to_uniform_array
0f2d19dd 435{
1be6b49c 436 size_t k;
c014a02e 437 unsigned long rlen = 1;
92c2555f 438 scm_t_array_dim *s;
0f2d19dd 439 SCM ra;
1be6b49c 440
e11e83f3 441 if (scm_is_integer (dims))
cda139a7 442 {
e11e83f3 443 SCM answer = scm_make_uve (scm_to_long (dims), prot);
a3a32939
DH
444 if (!SCM_UNBNDP (fill))
445 scm_array_fill_x (answer, fill);
e0e49670 446 else if (scm_is_symbol (prot) || scm_is_eq (prot, SCM_MAKE_CHAR (0)))
e11e83f3 447 scm_array_fill_x (answer, scm_from_int (0));
bfad4005 448 else if (scm_is_false (scm_procedure_p (prot)))
a3a32939
DH
449 scm_array_fill_x (answer, prot);
450 return answer;
cda139a7 451 }
1be6b49c 452
d2e53ed6 453 SCM_ASSERT (scm_is_null (dims) || scm_is_pair (dims),
0c95b57d 454 dims, SCM_ARG1, FUNC_NAME);
1bbd0b84 455 ra = scm_shap2ra (dims, FUNC_NAME);
e038c042 456 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
457 s = SCM_ARRAY_DIMS (ra);
458 k = SCM_ARRAY_NDIM (ra);
1be6b49c 459
0f2d19dd
JB
460 while (k--)
461 {
a3a32939
DH
462 s[k].inc = rlen;
463 SCM_ASSERT_RANGE (1, dims, s[k].lbnd <= s[k].ubnd);
0f2d19dd 464 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 465 }
a3a32939 466
a3a32939
DH
467 SCM_ARRAY_V (ra) = scm_make_uve (rlen, prot);
468
5c11cc9d 469 if (!SCM_UNBNDP (fill))
a3a32939 470 scm_array_fill_x (ra, fill);
e0e49670 471 else if (scm_is_symbol (prot) || scm_is_eq (prot, SCM_MAKE_CHAR (0)))
e11e83f3 472 scm_array_fill_x (ra, scm_from_int (0));
bfad4005 473 else if (scm_is_false (scm_procedure_p (prot)))
0f2d19dd 474 scm_array_fill_x (ra, prot);
a3a32939 475
0f2d19dd 476 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
c014a02e 477 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
0f2d19dd
JB
478 return SCM_ARRAY_V (ra);
479 return ra;
480}
1bbd0b84 481#undef FUNC_NAME
0f2d19dd 482
1cc91f1b 483
0f2d19dd 484void
1bbd0b84 485scm_ra_set_contp (SCM ra)
0f2d19dd 486{
1be6b49c 487 size_t k = SCM_ARRAY_NDIM (ra);
0f2d19dd 488 if (k)
0f2d19dd 489 {
c014a02e 490 long inc = SCM_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 491 while (k--)
0f2d19dd 492 {
fe0c6dae
JB
493 if (inc != SCM_ARRAY_DIMS (ra)[k].inc)
494 {
e038c042 495 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
496 return;
497 }
498 inc *= (SCM_ARRAY_DIMS (ra)[k].ubnd
499 - SCM_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 500 }
0f2d19dd 501 }
e038c042 502 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
503}
504
505
3b3b36dd 506SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 507 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
508 "@code{make-shared-array} can be used to create shared subarrays of other\n"
509 "arrays. The @var{mapper} is a function that translates coordinates in\n"
510 "the new array into coordinates in the old array. A @var{mapper} must be\n"
511 "linear, and its range must stay within the bounds of the old array, but\n"
512 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 513 "@lisp\n"
b380b885
MD
514 "(define fred (make-array #f 8 8))\n"
515 "(define freds-diagonal\n"
516 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
517 "(array-set! freds-diagonal 'foo 3)\n"
518 "(array-ref fred 3 3) @result{} foo\n"
519 "(define freds-center\n"
520 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
521 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 522 "@end lisp")
1bbd0b84 523#define FUNC_NAME s_scm_make_shared_array
0f2d19dd
JB
524{
525 SCM ra;
526 SCM inds, indptr;
527 SCM imap;
c014a02e
ML
528 size_t k, i;
529 long old_min, new_min, old_max, new_max;
92c2555f 530 scm_t_array_dim *s;
b3fcac34
DH
531
532 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6
HWN
533 SCM_VALIDATE_ARRAY (1, oldra);
534 SCM_VALIDATE_PROC (2, mapfunc);
1bbd0b84 535 ra = scm_shap2ra (dims, FUNC_NAME);
0f2d19dd
JB
536 if (SCM_ARRAYP (oldra))
537 {
538 SCM_ARRAY_V (ra) = SCM_ARRAY_V (oldra);
539 old_min = old_max = SCM_ARRAY_BASE (oldra);
540 s = SCM_ARRAY_DIMS (oldra);
541 k = SCM_ARRAY_NDIM (oldra);
542 while (k--)
543 {
544 if (s[k].inc > 0)
545 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
546 else
547 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
548 }
549 }
550 else
551 {
552 SCM_ARRAY_V (ra) = oldra;
553 old_min = 0;
e11e83f3 554 old_max = scm_to_long (scm_uniform_vector_length (oldra)) - 1;
0f2d19dd
JB
555 }
556 inds = SCM_EOL;
557 s = SCM_ARRAY_DIMS (ra);
558 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
559 {
e11e83f3 560 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
561 if (s[k].ubnd < s[k].lbnd)
562 {
563 if (1 == SCM_ARRAY_NDIM (ra))
564 ra = scm_make_uve (0L, scm_array_prototype (ra));
565 else
566 SCM_ARRAY_V (ra) = scm_make_uve (0L, scm_array_prototype (ra));
567 return ra;
568 }
569 }
fdc28395 570 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0f2d19dd 571 if (SCM_ARRAYP (oldra))
c014a02e 572 i = (size_t) scm_aind (oldra, imap, FUNC_NAME);
0f2d19dd
JB
573 else
574 {
e11e83f3 575 if (!scm_is_integer (imap))
0f2d19dd 576 {
e11e83f3 577 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
b3fcac34 578 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
0f2d19dd
JB
579 imap = SCM_CAR (imap);
580 }
e11e83f3 581 i = scm_to_size_t (imap);
0f2d19dd
JB
582 }
583 SCM_ARRAY_BASE (ra) = new_min = new_max = i;
584 indptr = inds;
585 k = SCM_ARRAY_NDIM (ra);
586 while (k--)
587 {
588 if (s[k].ubnd > s[k].lbnd)
589 {
e11e83f3 590 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 591 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0f2d19dd
JB
592 if (SCM_ARRAYP (oldra))
593
1bbd0b84 594 s[k].inc = scm_aind (oldra, imap, FUNC_NAME) - i;
0f2d19dd
JB
595 else
596 {
e11e83f3 597 if (!scm_is_integer (imap))
0f2d19dd 598 {
e11e83f3 599 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
b3fcac34 600 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
0f2d19dd
JB
601 imap = SCM_CAR (imap);
602 }
e11e83f3 603 s[k].inc = scm_to_long (imap) - i;
0f2d19dd
JB
604 }
605 i += s[k].inc;
606 if (s[k].inc > 0)
607 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
608 else
609 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
610 }
611 else
612 s[k].inc = new_max - new_min + 1; /* contiguous by default */
613 indptr = SCM_CDR (indptr);
614 }
b3fcac34
DH
615 if (old_min > new_min || old_max < new_max)
616 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
0f2d19dd
JB
617 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
618 {
74014c46 619 SCM v = SCM_ARRAY_V (ra);
e11e83f3 620 unsigned long int length = scm_to_ulong (scm_uniform_vector_length (v));
74014c46
DH
621 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
622 return v;
0f2d19dd
JB
623 if (s->ubnd < s->lbnd)
624 return scm_make_uve (0L, scm_array_prototype (ra));
625 }
626 scm_ra_set_contp (ra);
627 return ra;
628}
1bbd0b84 629#undef FUNC_NAME
0f2d19dd
JB
630
631
632/* args are RA . DIMS */
af45e3b0
DH
633SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
634 (SCM ra, SCM args),
1e6808ea
MG
635 "Return an array sharing contents with @var{array}, but with\n"
636 "dimensions arranged in a different order. There must be one\n"
637 "@var{dim} argument for each dimension of @var{array}.\n"
638 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
639 "and the rank of the array to be returned. Each integer in that\n"
640 "range must appear at least once in the argument list.\n"
641 "\n"
642 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
643 "dimensions in the array to be returned, their positions in the\n"
644 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
645 "may have the same value, in which case the returned array will\n"
646 "have smaller rank than @var{array}.\n"
647 "\n"
648 "@lisp\n"
b380b885
MD
649 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
650 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
651 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
652 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 653 "@end lisp")
1bbd0b84 654#define FUNC_NAME s_scm_transpose_array
0f2d19dd 655{
34d19ef6
HWN
656 SCM res, vargs;
657 SCM const *ve = &vargs;
92c2555f 658 scm_t_array_dim *s, *r;
0f2d19dd 659 int ndim, i, k;
af45e3b0 660
b3fcac34 661 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 662 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 663
20930f28 664 if (scm_is_generalized_vector (ra))
e0e49670
MV
665 {
666 /* Make sure that we are called with a single zero as
667 arguments.
668 */
669 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
670 SCM_WRONG_NUM_ARGS ();
671 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
672 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
673 return ra;
674 }
675
20930f28 676 if (SCM_ARRAYP (ra))
0f2d19dd 677 {
0f2d19dd 678 vargs = scm_vector (args);
b3fcac34
DH
679 if (SCM_VECTOR_LENGTH (vargs) != SCM_ARRAY_NDIM (ra))
680 SCM_WRONG_NUM_ARGS ();
681 ve = SCM_VELTS (vargs);
0f2d19dd
JB
682 ndim = 0;
683 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
684 {
e11e83f3 685 i = scm_to_signed_integer (ve[k], 0, SCM_ARRAY_NDIM(ra));
0f2d19dd
JB
686 if (ndim < i)
687 ndim = i;
688 }
689 ndim++;
690 res = scm_make_ra (ndim);
691 SCM_ARRAY_V (res) = SCM_ARRAY_V (ra);
692 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra);
693 for (k = ndim; k--;)
694 {
695 SCM_ARRAY_DIMS (res)[k].lbnd = 0;
696 SCM_ARRAY_DIMS (res)[k].ubnd = -1;
697 }
698 for (k = SCM_ARRAY_NDIM (ra); k--;)
699 {
e11e83f3 700 i = scm_to_int (ve[k]);
0f2d19dd
JB
701 s = &(SCM_ARRAY_DIMS (ra)[k]);
702 r = &(SCM_ARRAY_DIMS (res)[i]);
703 if (r->ubnd < r->lbnd)
704 {
705 r->lbnd = s->lbnd;
706 r->ubnd = s->ubnd;
707 r->inc = s->inc;
708 ndim--;
709 }
710 else
711 {
712 if (r->ubnd > s->ubnd)
713 r->ubnd = s->ubnd;
714 if (r->lbnd < s->lbnd)
715 {
716 SCM_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
717 r->lbnd = s->lbnd;
718 }
719 r->inc += s->inc;
720 }
721 }
b3fcac34
DH
722 if (ndim > 0)
723 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0f2d19dd
JB
724 scm_ra_set_contp (res);
725 return res;
726 }
20930f28
MV
727
728 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 729}
1bbd0b84 730#undef FUNC_NAME
0f2d19dd
JB
731
732/* args are RA . AXES */
af45e3b0
DH
733SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
734 (SCM ra, SCM axes),
b380b885
MD
735 "@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than\n"
736 "the rank of @var{array}. @var{enclose-array} returns an array\n"
737 "resembling an array of shared arrays. The dimensions of each shared\n"
738 "array are the same as the @var{dim}th dimensions of the original array,\n"
739 "the dimensions of the outer array are the same as those of the original\n"
740 "array that did not match a @var{dim}.\n\n"
741 "An enclosed array is not a general Scheme array. Its elements may not\n"
742 "be set using @code{array-set!}. Two references to the same element of\n"
743 "an enclosed array will be @code{equal?} but will not in general be\n"
744 "@code{eq?}. The value returned by @var{array-prototype} when given an\n"
745 "enclosed array is unspecified.\n\n"
746 "examples:\n"
1e6808ea 747 "@lisp\n"
b380b885
MD
748 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{}\n"
749 " #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>\n\n"
750 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{}\n"
751 " #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>\n"
1e6808ea 752 "@end lisp")
1bbd0b84 753#define FUNC_NAME s_scm_enclose_array
0f2d19dd 754{
af45e3b0 755 SCM axv, res, ra_inr;
cc95e00a 756 const char *c_axv;
92c2555f 757 scm_t_array_dim vdim, *s = &vdim;
0f2d19dd 758 int ndim, j, k, ninr, noutr;
af45e3b0 759
b3fcac34 760 SCM_VALIDATE_REST_ARGUMENT (axes);
d2e53ed6 761 if (scm_is_null (axes))
e11e83f3 762 axes = scm_cons ((SCM_ARRAYP (ra) ? scm_from_size_t (SCM_ARRAY_NDIM (ra) - 1) : SCM_INUM0), SCM_EOL);
0f2d19dd 763 ninr = scm_ilength (axes);
b3fcac34
DH
764 if (ninr < 0)
765 SCM_WRONG_NUM_ARGS ();
0f2d19dd 766 ra_inr = scm_make_ra (ninr);
e0e49670 767
20930f28 768 if (scm_is_generalized_vector (ra))
0f2d19dd 769 {
0f2d19dd 770 s->lbnd = 0;
e11e83f3 771 s->ubnd = scm_to_long (scm_uniform_vector_length (ra)) - 1;
0f2d19dd
JB
772 s->inc = 1;
773 SCM_ARRAY_V (ra_inr) = ra;
774 SCM_ARRAY_BASE (ra_inr) = 0;
775 ndim = 1;
20930f28
MV
776 }
777 else if (SCM_ARRAYP (ra))
778 {
0f2d19dd
JB
779 s = SCM_ARRAY_DIMS (ra);
780 SCM_ARRAY_V (ra_inr) = SCM_ARRAY_V (ra);
781 SCM_ARRAY_BASE (ra_inr) = SCM_ARRAY_BASE (ra);
782 ndim = SCM_ARRAY_NDIM (ra);
0f2d19dd 783 }
20930f28
MV
784 else
785 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
786
0f2d19dd 787 noutr = ndim - ninr;
b3fcac34
DH
788 if (noutr < 0)
789 SCM_WRONG_NUM_ARGS ();
e11e83f3 790 axv = scm_make_string (scm_from_int (ndim), SCM_MAKE_CHAR (0));
0f2d19dd
JB
791 res = scm_make_ra (noutr);
792 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra_inr);
793 SCM_ARRAY_V (res) = ra_inr;
794 for (k = 0; k < ninr; k++, axes = SCM_CDR (axes))
795 {
e11e83f3 796 if (!scm_is_integer (SCM_CAR (axes)))
b3fcac34 797 SCM_MISC_ERROR ("bad axis", SCM_EOL);
e11e83f3 798 j = scm_to_int (SCM_CAR (axes));
0f2d19dd
JB
799 SCM_ARRAY_DIMS (ra_inr)[k].lbnd = s[j].lbnd;
800 SCM_ARRAY_DIMS (ra_inr)[k].ubnd = s[j].ubnd;
801 SCM_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
cc95e00a 802 scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
0f2d19dd 803 }
cc95e00a 804 c_axv = scm_i_string_chars (axv);
0f2d19dd
JB
805 for (j = 0, k = 0; k < noutr; k++, j++)
806 {
cc95e00a 807 while (c_axv[j])
0f2d19dd
JB
808 j++;
809 SCM_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
810 SCM_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
811 SCM_ARRAY_DIMS (res)[k].inc = s[j].inc;
812 }
cc95e00a 813 scm_remember_upto_here_1 (axv);
0f2d19dd
JB
814 scm_ra_set_contp (ra_inr);
815 scm_ra_set_contp (res);
816 return res;
817}
1bbd0b84 818#undef FUNC_NAME
0f2d19dd
JB
819
820
821
af45e3b0
DH
822SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
823 (SCM v, SCM args),
1e6808ea
MG
824 "Return @code{#t} if its arguments would be acceptable to\n"
825 "@code{array-ref}.")
1bbd0b84 826#define FUNC_NAME s_scm_array_in_bounds_p
0f2d19dd 827{
af45e3b0 828 SCM ind = SCM_EOL;
c014a02e 829 long pos = 0;
1be6b49c 830 register size_t k;
c014a02e 831 register long j;
92c2555f 832 scm_t_array_dim *s;
af45e3b0 833
b3fcac34 834 SCM_VALIDATE_REST_ARGUMENT (args);
0f2d19dd 835
20930f28 836 if (scm_is_pair (args))
0f2d19dd
JB
837 {
838 ind = SCM_CAR (args);
839 args = SCM_CDR (args);
e11e83f3 840 pos = scm_to_long (ind);
0f2d19dd 841 }
e0e49670 842
20930f28
MV
843tail:
844 if (scm_is_generalized_vector (v))
845 {
846 size_t length = scm_c_generalized_vector_length (v);
847 SCM_ASRTGO (scm_is_null (args) && scm_is_integer (ind), wna);
848 return scm_from_bool (pos >= 0 && pos < length);
849 }
850
851 if (SCM_ARRAYP (v))
0f2d19dd 852 {
0f2d19dd
JB
853 k = SCM_ARRAY_NDIM (v);
854 s = SCM_ARRAY_DIMS (v);
855 pos = SCM_ARRAY_BASE (v);
856 if (!k)
857 {
d2e53ed6 858 SCM_ASRTGO (scm_is_null (ind), wna);
0f2d19dd
JB
859 ind = SCM_INUM0;
860 }
861 else
862 while (!0)
863 {
e11e83f3 864 j = scm_to_long (ind);
0f2d19dd
JB
865 if (!(j >= (s->lbnd) && j <= (s->ubnd)))
866 {
867 SCM_ASRTGO (--k == scm_ilength (args), wna);
868 return SCM_BOOL_F;
869 }
870 pos += (j - s->lbnd) * (s->inc);
871 if (!(--k && SCM_NIMP (args)))
872 break;
873 ind = SCM_CAR (args);
874 args = SCM_CDR (args);
875 s++;
e11e83f3 876 if (!scm_is_integer (ind))
b3fcac34 877 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
0f2d19dd
JB
878 }
879 SCM_ASRTGO (0 == k, wna);
880 v = SCM_ARRAY_V (v);
881 goto tail;
20930f28
MV
882
883 wna:
884 SCM_WRONG_NUM_ARGS ();
0f2d19dd 885 }
20930f28
MV
886
887 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 888}
1bbd0b84 889#undef FUNC_NAME
0f2d19dd
JB
890
891
e0e49670 892SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1bbd0b84 893 (SCM v, SCM args),
1e6808ea
MG
894 "Return the element at the @code{(index1, index2)} element in\n"
895 "@var{array}.")
e0e49670 896#define FUNC_NAME s_scm_array_ref
0f2d19dd 897{
c014a02e 898 long pos;
0f2d19dd 899
35de7ebe 900 if (SCM_IMP (v))
0f2d19dd 901 {
d2e53ed6 902 SCM_ASRTGO (scm_is_null (args), badarg);
0f2d19dd
JB
903 return v;
904 }
905 else if (SCM_ARRAYP (v))
0f2d19dd 906 {
1bbd0b84 907 pos = scm_aind (v, args, FUNC_NAME);
0f2d19dd
JB
908 v = SCM_ARRAY_V (v);
909 }
910 else
911 {
20930f28 912 size_t length;
0f2d19dd 913 if (SCM_NIMP (args))
0f2d19dd 914 {
d2e53ed6 915 SCM_ASSERT (scm_is_pair (args), args, SCM_ARG2, FUNC_NAME);
e11e83f3 916 pos = scm_to_long (SCM_CAR (args));
d2e53ed6 917 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
0f2d19dd
JB
918 }
919 else
20930f28
MV
920 pos = scm_to_long (args);
921 length = scm_c_generalized_vector_length (v);
74014c46 922 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
0f2d19dd 923 }
e0e49670 924
20930f28
MV
925 if (scm_is_generalized_vector (v))
926 return scm_c_generalized_vector_ref (v, pos);
e0e49670 927
20930f28
MV
928 if (SCM_ARRAYP (v))
929 { /* enclosed */
930 int k = SCM_ARRAY_NDIM (v);
931 SCM res = scm_make_ra (k);
932 SCM_ARRAY_V (res) = SCM_ARRAY_V (v);
933 SCM_ARRAY_BASE (res) = pos;
934 while (k--)
935 {
936 SCM_ARRAY_DIMS (res)[k].lbnd = SCM_ARRAY_DIMS (v)[k].lbnd;
937 SCM_ARRAY_DIMS (res)[k].ubnd = SCM_ARRAY_DIMS (v)[k].ubnd;
938 SCM_ARRAY_DIMS (res)[k].inc = SCM_ARRAY_DIMS (v)[k].inc;
939 }
940 return res;
0f2d19dd 941 }
20930f28
MV
942
943 badarg:
944 scm_wrong_type_arg_msg (NULL, 0, v, "array");
945 wna:
946 scm_wrong_num_args (NULL);
947 outrng:
948 scm_out_of_range (NULL, scm_from_long (pos));
0f2d19dd 949}
1bbd0b84 950#undef FUNC_NAME
0f2d19dd
JB
951
952/* Internal version of scm_uniform_vector_ref for uves that does no error checking and
953 tries to recycle conses. (Make *sure* you want them recycled.) */
1cc91f1b 954
0f2d19dd 955SCM
c014a02e 956scm_cvref (SCM v, unsigned long pos, SCM last)
0f2d19dd 957{
20930f28
MV
958 if (scm_is_generalized_vector (v))
959 return scm_c_generalized_vector_ref (v, pos);
e0e49670 960
20930f28
MV
961 if (SCM_ARRAYP (v))
962 { /* enclosed scm_array */
963 int k = SCM_ARRAY_NDIM (v);
964 SCM res = scm_make_ra (k);
965 SCM_ARRAY_V (res) = SCM_ARRAY_V (v);
966 SCM_ARRAY_BASE (res) = pos;
967 while (k--)
968 {
969 SCM_ARRAY_DIMS (res)[k].ubnd = SCM_ARRAY_DIMS (v)[k].ubnd;
970 SCM_ARRAY_DIMS (res)[k].lbnd = SCM_ARRAY_DIMS (v)[k].lbnd;
971 SCM_ARRAY_DIMS (res)[k].inc = SCM_ARRAY_DIMS (v)[k].inc;
972 }
973 return res;
0f2d19dd 974 }
20930f28
MV
975
976 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 977}
db4b4ca6 978
0f2d19dd 979
1bbd0b84
GB
980SCM_REGISTER_PROC(s_uniform_array_set1_x, "uniform-array-set1!", 3, 0, 0, scm_array_set_x);
981
1cc91f1b 982
0aa0871f
GH
983/* Note that args may be a list or an immediate object, depending which
984 PROC is used (and it's called from C too). */
3b3b36dd 985SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1bbd0b84 986 (SCM v, SCM obj, SCM args),
8f85c0c6 987 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
b380b885 988 "@var{new-value}. The value returned by array-set! is unspecified.")
1bbd0b84 989#define FUNC_NAME s_scm_array_set_x
0f2d19dd 990{
c014a02e 991 long pos = 0;
b3fcac34 992
0f2d19dd 993 if (SCM_ARRAYP (v))
0f2d19dd 994 {
1bbd0b84 995 pos = scm_aind (v, args, FUNC_NAME);
0f2d19dd
JB
996 v = SCM_ARRAY_V (v);
997 }
998 else
999 {
20930f28 1000 size_t length;
d2e53ed6 1001 if (scm_is_pair (args))
0f2d19dd 1002 {
d2e53ed6 1003 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
e11e83f3 1004 pos = scm_to_long (SCM_CAR (args));
0f2d19dd
JB
1005 }
1006 else
20930f28
MV
1007 pos = scm_to_long (args);
1008 length = scm_c_generalized_vector_length (v);
74014c46 1009 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
0f2d19dd 1010 }
e0e49670 1011
20930f28 1012 if (scm_is_generalized_vector (v))
0f2d19dd 1013 {
20930f28
MV
1014 scm_c_generalized_vector_set_x (v, pos, obj);
1015 return SCM_UNSPECIFIED;
0f2d19dd 1016 }
20930f28
MV
1017
1018 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1019
1020 outrng:
1021 scm_out_of_range (NULL, scm_from_long (pos));
1022 wna:
1023 scm_wrong_num_args (NULL);
0f2d19dd 1024}
1bbd0b84 1025#undef FUNC_NAME
0f2d19dd 1026
1d7bdb25
GH
1027/* attempts to unroll an array into a one-dimensional array.
1028 returns the unrolled array or #f if it can't be done. */
1bbd0b84 1029 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 1030 wouldn't have contiguous elements. */
3b3b36dd 1031SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 1032 (SCM ra, SCM strict),
b380b885
MD
1033 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
1034 "without changing their order (last subscript changing fastest), then\n"
1035 "@code{array-contents} returns that shared array, otherwise it returns\n"
1036 "@code{#f}. All arrays made by @var{make-array} and\n"
1037 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
1038 "@var{make-shared-array} may not be.\n\n"
1039 "If the optional argument @var{strict} is provided, a shared array will\n"
1040 "be returned only if its elements are stored internally contiguous in\n"
1041 "memory.")
1bbd0b84 1042#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
1043{
1044 SCM sra;
e0e49670 1045
20930f28 1046 if (scm_is_generalized_vector (ra))
e0e49670
MV
1047 return ra;
1048
20930f28 1049 if (SCM_ARRAYP (ra))
0f2d19dd 1050 {
20930f28
MV
1051 size_t k, ndim = SCM_ARRAY_NDIM (ra), len = 1;
1052 if (!SCM_ARRAYP (ra) || !SCM_ARRAY_CONTP (ra))
1053 return SCM_BOOL_F;
1054 for (k = 0; k < ndim; k++)
1055 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1056 if (!SCM_UNBNDP (strict))
74014c46 1057 {
20930f28
MV
1058 if (ndim && (1 != SCM_ARRAY_DIMS (ra)[ndim - 1].inc))
1059 return SCM_BOOL_F;
1060 if (scm_is_bitvector (SCM_ARRAY_V (ra)))
1061 {
1062 if (len != scm_c_bitvector_length (SCM_ARRAY_V (ra)) ||
1063 SCM_ARRAY_BASE (ra) % SCM_LONG_BIT ||
1064 len % SCM_LONG_BIT)
1065 return SCM_BOOL_F;
1066 }
74014c46 1067 }
20930f28
MV
1068
1069 {
1070 SCM v = SCM_ARRAY_V (ra);
1071 size_t length = scm_c_generalized_vector_length (v);
1072 if ((len == length) && 0 == SCM_ARRAY_BASE (ra) && SCM_ARRAY_DIMS (ra)->inc)
1073 return v;
0f2d19dd 1074 }
20930f28
MV
1075
1076 sra = scm_make_ra (1);
1077 SCM_ARRAY_DIMS (sra)->lbnd = 0;
1078 SCM_ARRAY_DIMS (sra)->ubnd = len - 1;
1079 SCM_ARRAY_V (sra) = SCM_ARRAY_V (ra);
1080 SCM_ARRAY_BASE (sra) = SCM_ARRAY_BASE (ra);
1081 SCM_ARRAY_DIMS (sra)->inc = (ndim ? SCM_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
1082 return sra;
0f2d19dd 1083 }
20930f28
MV
1084
1085 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 1086}
1bbd0b84 1087#undef FUNC_NAME
0f2d19dd 1088
1cc91f1b 1089
0f2d19dd 1090SCM
6e8d25a6 1091scm_ra2contig (SCM ra, int copy)
0f2d19dd
JB
1092{
1093 SCM ret;
c014a02e
ML
1094 long inc = 1;
1095 size_t k, len = 1;
0f2d19dd
JB
1096 for (k = SCM_ARRAY_NDIM (ra); k--;)
1097 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1098 k = SCM_ARRAY_NDIM (ra);
1099 if (SCM_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_ARRAY_DIMS (ra)[k - 1].inc)))
1100 {
20930f28 1101 if (!scm_is_bitvector (SCM_ARRAY_V (ra)))
0f2d19dd 1102 return ra;
20930f28 1103 if ((len == scm_c_bitvector_length (SCM_ARRAY_V (ra)) &&
c014a02e
ML
1104 0 == SCM_ARRAY_BASE (ra) % SCM_LONG_BIT &&
1105 0 == len % SCM_LONG_BIT))
0f2d19dd
JB
1106 return ra;
1107 }
1108 ret = scm_make_ra (k);
1109 SCM_ARRAY_BASE (ret) = 0;
1110 while (k--)
1111 {
1112 SCM_ARRAY_DIMS (ret)[k].lbnd = SCM_ARRAY_DIMS (ra)[k].lbnd;
1113 SCM_ARRAY_DIMS (ret)[k].ubnd = SCM_ARRAY_DIMS (ra)[k].ubnd;
1114 SCM_ARRAY_DIMS (ret)[k].inc = inc;
1115 inc *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1116 }
08112c95 1117 SCM_ARRAY_V (ret) = scm_make_uve (inc, scm_array_prototype (ra));
0f2d19dd
JB
1118 if (copy)
1119 scm_array_copy_x (ra, ret);
1120 return ret;
1121}
1122
1123
1124
3b3b36dd 1125SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
1bbd0b84 1126 (SCM ra, SCM port_or_fd, SCM start, SCM end),
8f85c0c6
NJ
1127 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1128 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
b380b885 1129 "binary objects from @var{port-or-fdes}.\n"
8f85c0c6
NJ
1130 "If an end of file is encountered,\n"
1131 "the objects up to that point are put into @var{ura}\n"
b380b885
MD
1132 "(starting at the beginning) and the remainder of the array is\n"
1133 "unchanged.\n\n"
1134 "The optional arguments @var{start} and @var{end} allow\n"
1135 "a specified region of a vector (or linearized array) to be read,\n"
1136 "leaving the remainder of the vector unchanged.\n\n"
1137 "@code{uniform-array-read!} returns the number of objects read.\n"
1138 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1139 "returned by @code{(current-input-port)}.")
1bbd0b84 1140#define FUNC_NAME s_scm_uniform_array_read_x
0f2d19dd 1141{
35de7ebe 1142 SCM cra = SCM_UNDEFINED, v = ra;
20930f28 1143 long sz, ans;
c014a02e
ML
1144 long cstart = 0;
1145 long cend;
1146 long offset = 0;
20930f28 1147 size_t vlen;
405aaef9 1148 char *base;
35de7ebe 1149
3d8d56df
GH
1150 if (SCM_UNBNDP (port_or_fd))
1151 port_or_fd = scm_cur_inp;
1152 else
e11e83f3 1153 SCM_ASSERT (scm_is_integer (port_or_fd)
0c95b57d 1154 || (SCM_OPINPORTP (port_or_fd)),
1bbd0b84 1155 port_or_fd, SCM_ARG2, FUNC_NAME);
20930f28
MV
1156 vlen = (SCM_ARRAYP (v) ?
1157 0 : scm_c_generalized_vector_length (v));
1158
1159 scm_frame_begin (0);
35de7ebe 1160
0f2d19dd 1161loop:
e0e49670 1162 if (scm_is_uniform_vector (v))
0f2d19dd 1163 {
e0e49670
MV
1164 base = scm_uniform_vector_elements (v);
1165 sz = scm_uniform_vector_element_size (v);
20930f28
MV
1166 scm_frame_uniform_vector_release (v);
1167 }
1168 else if (scm_is_bitvector (v))
1169 {
1170 base = (char *) scm_bitvector_elements (v);
1171 scm_frame_bitvector_release (v);
1172 vlen = (vlen + 31) / 32;
1173 cstart /= 32;
1174 sz = sizeof (scm_t_uint32);
1175 }
1176 else if (scm_is_string (v))
1177 {
1178 base = NULL; /* writing to strings is special, see below. */
1179 sz = sizeof (char);
1180 }
1181 else if (SCM_ARRAYP (v))
1182 {
1183 cra = scm_ra2contig (ra, 0);
1184 cstart += SCM_ARRAY_BASE (cra);
1185 vlen = SCM_ARRAY_DIMS (cra)->inc *
1186 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
1187 v = SCM_ARRAY_V (cra);
1188 goto loop;
e0e49670
MV
1189 }
1190 else
20930f28 1191 scm_wrong_type_arg_msg (NULL, 0, v, "array");
e0e49670 1192
1146b6cd
GH
1193 cend = vlen;
1194 if (!SCM_UNBNDP (start))
3d8d56df 1195 {
1146b6cd 1196 offset =
c014a02e 1197 SCM_NUM2LONG (3, start);
35de7ebe 1198
1146b6cd 1199 if (offset < 0 || offset >= cend)
1bbd0b84 1200 scm_out_of_range (FUNC_NAME, start);
1146b6cd
GH
1201
1202 if (!SCM_UNBNDP (end))
1203 {
c014a02e
ML
1204 long tend =
1205 SCM_NUM2LONG (4, end);
3d8d56df 1206
1146b6cd 1207 if (tend <= offset || tend > cend)
1bbd0b84 1208 scm_out_of_range (FUNC_NAME, end);
1146b6cd
GH
1209 cend = tend;
1210 }
0f2d19dd 1211 }
35de7ebe 1212
3d8d56df
GH
1213 if (SCM_NIMP (port_or_fd))
1214 {
92c2555f 1215 scm_t_port *pt = SCM_PTAB_ENTRY (port_or_fd);
6c951427 1216 int remaining = (cend - offset) * sz;
cc95e00a 1217 size_t off = (cstart + offset) * sz;
6c951427
GH
1218
1219 if (pt->rw_active == SCM_PORT_WRITE)
affc96b5 1220 scm_flush (port_or_fd);
6c951427
GH
1221
1222 ans = cend - offset;
1223 while (remaining > 0)
3d8d56df 1224 {
6c951427
GH
1225 if (pt->read_pos < pt->read_end)
1226 {
1227 int to_copy = min (pt->read_end - pt->read_pos,
1228 remaining);
1229
cc95e00a
MV
1230 if (base == NULL)
1231 {
1232 /* strings */
1233 char *b = scm_i_string_writable_chars (v);
1234 memcpy (b + off, pt->read_pos, to_copy);
1235 scm_i_string_stop_writing ();
1236 }
1237 else
1238 memcpy (base + off, pt->read_pos, to_copy);
6c951427
GH
1239 pt->read_pos += to_copy;
1240 remaining -= to_copy;
cc95e00a 1241 off += to_copy;
6c951427
GH
1242 }
1243 else
1244 {
affc96b5 1245 if (scm_fill_input (port_or_fd) == EOF)
6c951427
GH
1246 {
1247 if (remaining % sz != 0)
1248 {
5d2d2ffc 1249 SCM_MISC_ERROR ("unexpected EOF", SCM_EOL);
6c951427
GH
1250 }
1251 ans -= remaining / sz;
1252 break;
1253 }
6c951427 1254 }
3d8d56df 1255 }
6c951427
GH
1256
1257 if (pt->rw_random)
1258 pt->rw_active = SCM_PORT_READ;
3d8d56df
GH
1259 }
1260 else /* file descriptor. */
1261 {
cc95e00a
MV
1262 if (base == NULL)
1263 {
1264 /* strings */
1265 char *b = scm_i_string_writable_chars (v);
1266 SCM_SYSCALL (ans = read (scm_to_int (port_or_fd),
1267 b + (cstart + offset) * sz,
1268 (sz * (cend - offset))));
1269 scm_i_string_stop_writing ();
1270 }
1271 else
1272 SCM_SYSCALL (ans = read (scm_to_int (port_or_fd),
1273 base + (cstart + offset) * sz,
1274 (sz * (cend - offset))));
3d8d56df 1275 if (ans == -1)
1bbd0b84 1276 SCM_SYSERROR;
3d8d56df 1277 }
20930f28
MV
1278 if (scm_is_bitvector (v))
1279 ans *= 32;
35de7ebe 1280
bc36d050 1281 if (!scm_is_eq (v, ra) && !scm_is_eq (cra, ra))
0f2d19dd 1282 scm_array_copy_x (cra, ra);
35de7ebe 1283
20930f28
MV
1284 scm_frame_end ();
1285
e11e83f3 1286 return scm_from_long (ans);
0f2d19dd 1287}
1bbd0b84 1288#undef FUNC_NAME
0f2d19dd 1289
3b3b36dd 1290SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
1bbd0b84 1291 (SCM v, SCM port_or_fd, SCM start, SCM end),
8f85c0c6 1292 "@deffnx {Scheme Procedure} uniform-vector-write uve [port-or-fdes] [start] [end]\n"
b380b885
MD
1293 "Writes all elements of @var{ura} as binary objects to\n"
1294 "@var{port-or-fdes}.\n\n"
1295 "The optional arguments @var{start}\n"
1296 "and @var{end} allow\n"
1297 "a specified region of a vector (or linearized array) to be written.\n\n"
9401323e 1298 "The number of objects actually written is returned.\n"
b380b885
MD
1299 "@var{port-or-fdes} may be\n"
1300 "omitted, in which case it defaults to the value returned by\n"
1301 "@code{(current-output-port)}.")
1bbd0b84 1302#define FUNC_NAME s_scm_uniform_array_write
0f2d19dd 1303{
20930f28 1304 long sz, ans;
c014a02e
ML
1305 long offset = 0;
1306 long cstart = 0;
1307 long cend;
cc95e00a 1308 const char *base;
20930f28 1309 size_t vlen;
3d8d56df 1310
78446828
MV
1311 port_or_fd = SCM_COERCE_OUTPORT (port_or_fd);
1312
3d8d56df
GH
1313 if (SCM_UNBNDP (port_or_fd))
1314 port_or_fd = scm_cur_outp;
1315 else
e11e83f3 1316 SCM_ASSERT (scm_is_integer (port_or_fd)
0c95b57d 1317 || (SCM_OPOUTPORTP (port_or_fd)),
1bbd0b84 1318 port_or_fd, SCM_ARG2, FUNC_NAME);
20930f28 1319 vlen = (SCM_ARRAYP(v)
d245ce23 1320 ? 0
20930f28
MV
1321 : scm_c_generalized_vector_length (v));
1322
1323 scm_frame_begin (0);
1324
0f2d19dd 1325loop:
e0e49670 1326 if (scm_is_uniform_vector (v))
0f2d19dd 1327 {
e0e49670
MV
1328 base = scm_uniform_vector_elements (v);
1329 sz = scm_uniform_vector_element_size (v);
20930f28
MV
1330 scm_frame_uniform_vector_release (v);
1331 }
1332 else if (scm_is_bitvector (v))
1333 {
1334 base = (char *) scm_bitvector_elements (v);
1335 scm_frame_bitvector_release (v);
1336 vlen = (vlen + 31) / 32;
1337 cstart /= 32;
1338 sz = sizeof (scm_t_uint32);
1339 }
1340 else if (scm_is_string (v))
1341 {
1342 base = scm_i_string_chars (v);
1343 sz = sizeof (char);
1344 }
1345 else if (SCM_ARRAYP (v))
1346 {
1347 v = scm_ra2contig (v, 1);
1348 cstart = SCM_ARRAY_BASE (v);
1349 vlen = (SCM_ARRAY_DIMS (v)->inc
1350 * (SCM_ARRAY_DIMS (v)->ubnd - SCM_ARRAY_DIMS (v)->lbnd + 1));
1351 v = SCM_ARRAY_V (v);
1352 goto loop;
e0e49670
MV
1353 }
1354 else
20930f28 1355 scm_wrong_type_arg_msg (NULL, 0, v, "array");
e0e49670 1356
1146b6cd
GH
1357 cend = vlen;
1358 if (!SCM_UNBNDP (start))
3d8d56df 1359 {
1146b6cd 1360 offset =
c014a02e 1361 SCM_NUM2LONG (3, start);
3d8d56df 1362
1146b6cd 1363 if (offset < 0 || offset >= cend)
1bbd0b84 1364 scm_out_of_range (FUNC_NAME, start);
1146b6cd
GH
1365
1366 if (!SCM_UNBNDP (end))
1367 {
c014a02e
ML
1368 long tend =
1369 SCM_NUM2LONG (4, end);
3d8d56df 1370
1146b6cd 1371 if (tend <= offset || tend > cend)
1bbd0b84 1372 scm_out_of_range (FUNC_NAME, end);
1146b6cd
GH
1373 cend = tend;
1374 }
3d8d56df
GH
1375 }
1376
1377 if (SCM_NIMP (port_or_fd))
1378 {
cc95e00a 1379 const char *source = base + (cstart + offset) * sz;
6c951427
GH
1380
1381 ans = cend - offset;
265e6a4d 1382 scm_lfwrite (source, ans * sz, port_or_fd);
3d8d56df
GH
1383 }
1384 else /* file descriptor. */
1385 {
e11e83f3 1386 SCM_SYSCALL (ans = write (scm_to_int (port_or_fd),
405aaef9 1387 base + (cstart + offset) * sz,
1be6b49c 1388 (sz * (cend - offset))));
3d8d56df 1389 if (ans == -1)
1bbd0b84 1390 SCM_SYSERROR;
3d8d56df 1391 }
20930f28
MV
1392 if (scm_is_bitvector (v))
1393 ans *= 32;
1394
1395 scm_frame_end ();
3d8d56df 1396
e11e83f3 1397 return scm_from_long (ans);
0f2d19dd 1398}
1bbd0b84 1399#undef FUNC_NAME
0f2d19dd
JB
1400
1401
20930f28
MV
1402/** Bit vectors */
1403
1404static scm_t_bits scm_tc16_bitvector;
1405
1406#define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1407#define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1408#define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1409
1410static size_t
1411bitvector_free (SCM vec)
1412{
1413 scm_gc_free (BITVECTOR_BITS (vec),
1414 sizeof (scm_t_uint32) * ((BITVECTOR_LENGTH (vec)+31)/32),
1415 "bitvector");
1416 return 0;
1417}
1418
1419static int
1420bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1421{
1422 size_t bit_len = BITVECTOR_LENGTH (vec);
1423 size_t word_len = (bit_len+31)/32;
1424 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1425 size_t i, j;
1426
1427 scm_puts ("#*", port);
1428 for (i = 0; i < word_len; i++, bit_len -= 32)
1429 {
1430 scm_t_uint32 mask = 1;
1431 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1432 scm_putc ((bits[i] & mask)? '1' : '0', port);
1433 }
1434
1435 return 1;
1436}
1437
1438static SCM
1439bitvector_equalp (SCM vec1, SCM vec2)
1440{
1441 size_t bit_len = BITVECTOR_LENGTH (vec1);
1442 size_t word_len = (bit_len + 31) / 32;
1443 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1444 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1445 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1446
1447 /* compare lengths */
1448 if (BITVECTOR_LENGTH (vec2) != bit_len)
1449 return SCM_BOOL_F;
1450 /* avoid underflow in word_len-1 below. */
1451 if (bit_len == 0)
1452 return SCM_BOOL_T;
1453 /* compare full words */
1454 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1455 return SCM_BOOL_F;
1456 /* compare partial last words */
1457 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1458 return SCM_BOOL_F;
1459 return SCM_BOOL_T;
1460}
1461
1462int
1463scm_is_bitvector (SCM vec)
1464{
1465 return IS_BITVECTOR (vec);
1466}
1467
1468SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1469 (SCM obj),
1470 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1471 "return @code{#f}.")
1472#define FUNC_NAME s_scm_bitvector_p
1473{
1474 return scm_from_bool (scm_is_bitvector (obj));
1475}
1476#undef FUNC_NAME
1477
1478SCM
1479scm_c_make_bitvector (size_t len, SCM fill)
1480{
1481 size_t word_len = (len + 31) / 32;
1482 scm_t_uint32 *bits;
1483 SCM res;
1484
1485 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1486 "bitvector");
1487 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1488
1489 if (!SCM_UNBNDP (fill))
1490 scm_bitvector_fill_x (res, fill);
1491
1492 return res;
1493}
1494
1495SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1496 (SCM len, SCM fill),
1497 "Create a new bitvector of length @var{len} and\n"
1498 "optionally initialize all elements to @var{fill}.")
1499#define FUNC_NAME s_scm_make_bitvector
1500{
1501 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1502}
1503#undef FUNC_NAME
1504
1505SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1506 (SCM bits),
1507 "Create a new bitvector with the arguments as elements.")
1508#define FUNC_NAME s_scm_bitvector
1509{
1510 return scm_list_to_bitvector (bits);
1511}
1512#undef FUNC_NAME
1513
1514size_t
1515scm_c_bitvector_length (SCM vec)
1516{
1517 scm_assert_smob_type (scm_tc16_bitvector, vec);
1518 return BITVECTOR_LENGTH (vec);
1519}
1520
1521SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1522 (SCM vec),
1523 "Return the length of the bitvector @var{vec}.")
1524#define FUNC_NAME s_scm_bitvector_length
1525{
1526 return scm_from_size_t (scm_c_bitvector_length (vec));
1527}
1528#undef FUNC_NAME
1529
1530scm_t_uint32 *
1531scm_bitvector_elements (SCM vec)
1532{
1533 scm_assert_smob_type (scm_tc16_bitvector, vec);
1534 return BITVECTOR_BITS (vec);
1535}
1536
1537void
1538scm_bitvector_release (SCM vec)
1539{
1540 /* Nothing to do right now, but this function might come in handy
1541 when bitvectors need to be locked when giving away a pointer
1542 to their elements.
1543
1544 Also, a call to scm_bitvector_release acts like
1545 scm_remember_upto_here, which is needed in any case.
1546 */
1547}
1548
1549void
1550scm_frame_bitvector_release (SCM vec)
1551{
1552 scm_frame_unwind_handler_with_scm (scm_bitvector_release, vec,
1553 SCM_F_WIND_EXPLICITLY);
1554}
1555
1556SCM
1557scm_c_bitvector_ref (SCM vec, size_t idx)
1558{
1559 if (idx < scm_c_bitvector_length (vec))
1560 {
1561 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1562 SCM res = (bits[idx/32] & (1L << (idx%32)))? SCM_BOOL_T : SCM_BOOL_F;
1563 scm_bitvector_release (vec);
1564 return res;
1565 }
1566 else
1567 scm_out_of_range (NULL, scm_from_size_t (idx));
1568}
1569
1570SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1571 (SCM vec, SCM idx),
1572 "Return the element at index @var{idx} of the bitvector\n"
1573 "@var{vec}.")
1574#define FUNC_NAME s_scm_bitvector_ref
1575{
1576 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1577}
1578#undef FUNC_NAME
1579
1580void
1581scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1582{
1583 if (idx < scm_c_bitvector_length (vec))
1584 {
1585 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1586 scm_t_uint32 mask = 1L << (idx%32);
1587 if (scm_is_true (val))
1588 bits[idx/32] |= mask;
1589 else
1590 bits[idx/32] &= ~mask;
1591 scm_bitvector_release (vec);
1592 }
1593 else
1594 scm_out_of_range (NULL, scm_from_size_t (idx));
1595}
1596
1597SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1598 (SCM vec, SCM idx, SCM val),
1599 "Set the element at index @var{idx} of the bitvector\n"
1600 "@var{vec} when @var{val} is true, else clear it.")
1601#define FUNC_NAME s_scm_bitvector_set_x
1602{
1603 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1604 return SCM_UNSPECIFIED;
1605}
1606#undef FUNC_NAME
1607
1608SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1609 (SCM vec, SCM val),
1610 "Set all elements of the bitvector\n"
1611 "@var{vec} when @var{val} is true, else clear them.")
1612#define FUNC_NAME s_scm_bitvector_fill_x
1613{
1614 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1615 size_t bit_len = BITVECTOR_LENGTH (vec);
1616 size_t word_len = (bit_len + 31) / 32;
1617 memset (bits, scm_is_true (val)? -1:0, sizeof (scm_t_uint32) * word_len);
1618 scm_bitvector_release (vec);
1619 return SCM_UNSPECIFIED;
1620}
1621#undef FUNC_NAME
1622
1623SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1624 (SCM list),
1625 "Return a new bitvector initialized with the elements\n"
1626 "of @var{list}.")
1627#define FUNC_NAME s_scm_list_to_bitvector
1628{
1629 size_t bit_len = scm_to_size_t (scm_length (list));
1630 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1631 size_t word_len = (bit_len+31)/32;
1632 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1633 size_t i, j;
1634
1635 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1636 {
1637 scm_t_uint32 mask = 1;
1638 bits[i] = 0;
1639 for (j = 0; j < 32 && j < bit_len;
1640 j++, mask <<= 1, list = SCM_CDR (list))
1641 if (scm_is_true (SCM_CAR (list)))
1642 bits[i] |= mask;
1643 }
1644
1645 scm_bitvector_release (vec);
1646 return vec;
1647}
1648#undef FUNC_NAME
1649
1650SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1651 (SCM vec),
1652 "Return a new list initialized with the elements\n"
1653 "of the bitvector @var{vec}.")
1654#define FUNC_NAME s_scm_bitvector_to_list
1655{
1656 size_t bit_len = scm_c_bitvector_length (vec);
1657 SCM res = SCM_EOL;
1658 size_t word_len = (bit_len+31)/32;
1659 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1660 size_t i, j;
1661
1662 for (i = 0; i < word_len; i++, bit_len -= 32)
1663 {
1664 scm_t_uint32 mask = 1;
1665 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1666 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1667 }
1668
1669 scm_bitvector_release (vec);
1670 return scm_reverse_x (res, SCM_EOL);
1671}
1672#undef FUNC_NAME
1673
1674/* From mmix-arith.w by Knuth.
1675
1676 Here's a fun way to count the number of bits in a tetrabyte.
1677
1678 [This classical trick is called the ``Gillies--Miller method for
1679 sideways addition'' in {\sl The Preparation of Programs for an
1680 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1681 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1682 the tricks used here were suggested by Balbir Singh, Peter
1683 Rossmanith, and Stefan Schwoon.]
1684*/
1685
1686static size_t
1687count_ones (scm_t_uint32 x)
1688{
1689 x=x-((x>>1)&0x55555555);
1690 x=(x&0x33333333)+((x>>2)&0x33333333);
1691 x=(x+(x>>4))&0x0f0f0f0f;
1692 x=x+(x>>8);
1693 return (x+(x>>16)) & 0xff;
1694}
0f2d19dd 1695
3b3b36dd 1696SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
c7eb8761 1697 (SCM b, SCM bitvector),
1e6808ea 1698 "Return the number of occurrences of the boolean @var{b} in\n"
c7eb8761 1699 "@var{bitvector}.")
1bbd0b84 1700#define FUNC_NAME s_scm_bit_count
0f2d19dd 1701{
20930f28
MV
1702 size_t bit_len = scm_c_bitvector_length (bitvector);
1703 size_t word_len = (bit_len + 31) / 32;
1704 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1705 scm_t_uint32 *bits = scm_bitvector_elements (bitvector);
1706
1707 int bit = scm_to_bool (b);
1708 size_t count = 0, i;
1709
1710 if (bit_len == 0)
1711 return 0;
1712
1713 for (i = 0; i < word_len-1; i++)
1714 count += count_ones (bits[i]);
1715 count += count_ones (bits[i] & last_mask);
1716
1717 scm_bitvector_release (bitvector);
1718 return scm_from_size_t (bit? count : bit_len-count);
0f2d19dd 1719}
1bbd0b84 1720#undef FUNC_NAME
0f2d19dd 1721
20930f28
MV
1722/* returns 32 for x == 0.
1723*/
1724static size_t
1725find_first_one (scm_t_uint32 x)
1726{
1727 size_t pos = 0;
1728 /* do a binary search in x. */
1729 if ((x & 0xFFFF) == 0)
1730 x >>= 16, pos += 16;
1731 if ((x & 0xFF) == 0)
1732 x >>= 8, pos += 8;
1733 if ((x & 0xF) == 0)
1734 x >>= 4, pos += 4;
1735 if ((x & 0x3) == 0)
1736 x >>= 2, pos += 2;
1737 if ((x & 0x1) == 0)
1738 pos += 1;
1739 return pos;
1740}
0f2d19dd 1741
3b3b36dd 1742SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1bbd0b84 1743 (SCM item, SCM v, SCM k),
88ecf5cb
KR
1744 "Return the index of the first occurrance of @var{item} in bit\n"
1745 "vector @var{v}, starting from @var{k}. If there is no\n"
1746 "@var{item} entry between @var{k} and the end of\n"
1747 "@var{bitvector}, then return @code{#f}. For example,\n"
1748 "\n"
1749 "@example\n"
1750 "(bit-position #t #*000101 0) @result{} 3\n"
1751 "(bit-position #f #*0001111 3) @result{} #f\n"
1752 "@end example")
1bbd0b84 1753#define FUNC_NAME s_scm_bit_position
0f2d19dd 1754{
20930f28
MV
1755 size_t bit_len = scm_c_bitvector_length (v);
1756 size_t word_len = (bit_len + 31) / 32;
1757 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1758 scm_t_uint32 *bits = scm_bitvector_elements (v);
1759 size_t first_bit = scm_to_unsigned_integer (k, 0, bit_len);
1760 size_t first_word = first_bit / 32;
1761 scm_t_uint32 first_mask = ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1762 scm_t_uint32 w;
1763
1764 int bit = scm_to_bool (item);
1765 size_t i;
1766 SCM res = SCM_BOOL_F;
1767
1768 if (bit_len == 0)
1769 return 0;
74014c46 1770
20930f28
MV
1771 for (i = first_word; i < word_len; i++)
1772 {
1773 w = (bit? bits[i] : ~bits[i]);
1774 if (i == first_word)
1775 w &= first_mask;
1776 if (i == word_len-1)
1777 w &= last_mask;
74014c46 1778 if (w)
20930f28
MV
1779 {
1780 res = scm_from_size_t (32*i + find_first_one (w));
1781 break;
1782 }
0f2d19dd 1783 }
20930f28
MV
1784
1785 scm_bitvector_release (v);
1786 return res;
0f2d19dd 1787}
1bbd0b84 1788#undef FUNC_NAME
0f2d19dd 1789
3b3b36dd 1790SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
c7eb8761 1791 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
1792 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1793 "selecting the entries to change. The return value is\n"
1794 "unspecified.\n"
1795 "\n"
1796 "If @var{kv} is a bit vector, then those entries where it has\n"
1797 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1798 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1799 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1800 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1801 "\n"
1802 "@example\n"
1803 "(define bv #*01000010)\n"
1804 "(bit-set*! bv #*10010001 #t)\n"
1805 "bv\n"
1806 "@result{} #*11010011\n"
1807 "@end example\n"
1808 "\n"
85368844
MV
1809 "If @var{kv} is a u32vector, then its elements are\n"
1810 "indices into @var{v} which are set to @var{obj}.\n"
88ecf5cb
KR
1811 "\n"
1812 "@example\n"
1813 "(define bv #*01000010)\n"
85368844 1814 "(bit-set*! bv #u32(5 2 7) #t)\n"
88ecf5cb
KR
1815 "bv\n"
1816 "@result{} #*01100111\n"
1817 "@end example")
1bbd0b84 1818#define FUNC_NAME s_scm_bit_set_star_x
0f2d19dd 1819{
20930f28
MV
1820 if (scm_is_bitvector (kv))
1821 {
1822 size_t bit_len = scm_c_bitvector_length (kv);
1823 size_t word_len = (bit_len + 31) / 32;
1824 scm_t_uint32 *bits1, *bits2;
1825 size_t i;
1826 int bit = scm_to_bool (obj);
1827
1828 if (scm_c_bitvector_length (v) != bit_len)
85368844
MV
1829 scm_misc_error (NULL,
1830 "bit vectors must have equal length",
1831 SCM_EOL);
1832
20930f28
MV
1833 bits1 = scm_bitvector_elements (v);
1834 bits2 = scm_bitvector_elements (kv);
1835
1836 if (bit == 0)
1837 for (i = 0; i < word_len; i++)
1838 bits1[i] &= ~bits2[i];
85368844 1839 else
20930f28
MV
1840 for (i = 0; i < word_len; i++)
1841 bits1[i] |= bits2[i];
1842
1843 scm_bitvector_release (kv);
1844 scm_bitvector_release (v);
85368844
MV
1845 }
1846 else if (scm_is_true (scm_u32vector_p (kv)))
1847 {
d44ff083 1848 size_t ulen, i;
20930f28
MV
1849 scm_t_uint32 *indices;
1850
1851 /* assert that obj is a boolean.
1852 */
1853 scm_to_bool (obj);
d44ff083
MV
1854
1855 scm_frame_begin (0);
1856
1857 ulen = scm_c_uniform_vector_length (kv);
1858 indices = scm_u32vector_elements (kv);
1859 scm_frame_uniform_vector_release (kv);
85368844 1860
20930f28
MV
1861 for (i = 0; i < ulen; i++)
1862 scm_c_bitvector_set_x (v, (size_t)indices[i], obj);
d44ff083
MV
1863
1864 scm_frame_end ();
0f2d19dd 1865 }
20930f28 1866 else
85368844
MV
1867 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
1868
0f2d19dd
JB
1869 return SCM_UNSPECIFIED;
1870}
1bbd0b84 1871#undef FUNC_NAME
0f2d19dd
JB
1872
1873
3b3b36dd 1874SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
1bbd0b84 1875 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
1876 "Return a count of how many entries in bit vector @var{v} are\n"
1877 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
1878 "consider.\n"
1879 "\n"
1880 "If @var{kv} is a bit vector, then those entries where it has\n"
1881 "@code{#t} are the ones in @var{v} which are considered.\n"
1882 "@var{kv} and @var{v} must be the same length.\n"
1883 "\n"
85368844
MV
1884 "If @var{kv} is a u32vector, then it contains\n"
1885 "the indexes in @var{v} to consider.\n"
88ecf5cb
KR
1886 "\n"
1887 "For example,\n"
1888 "\n"
1889 "@example\n"
1890 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
85368844 1891 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
88ecf5cb 1892 "@end example")
1bbd0b84 1893#define FUNC_NAME s_scm_bit_count_star
0f2d19dd 1894{
20930f28 1895 if (scm_is_bitvector (kv))
0f2d19dd 1896 {
20930f28
MV
1897 size_t bit_len = scm_c_bitvector_length (kv);
1898 size_t word_len = (bit_len + 31) / 32;
1899 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1900 scm_t_uint32 xor_mask = scm_to_bool (obj)? 0 : ((scm_t_uint32)-1);
1901 scm_t_uint32 *bits1, *bits2;
1902 size_t count = 0, i;
85368844 1903
20930f28 1904 if (scm_c_bitvector_length (v) != bit_len)
85368844
MV
1905 scm_misc_error (NULL,
1906 "bit vectors must have equal length",
1907 SCM_EOL);
1908
20930f28
MV
1909 if (bit_len == 0)
1910 return scm_from_size_t (0);
85368844 1911
20930f28
MV
1912 bits1 = scm_bitvector_elements (v);
1913 bits2 = scm_bitvector_elements (kv);
85368844 1914
20930f28
MV
1915 for (i = 0; i < word_len-1; i++)
1916 count += count_ones ((bits1[i]^xor_mask) & bits2[i]);
1917 count += count_ones ((bits1[i]^xor_mask) & bits2[i] & last_mask);
c209c88e 1918
20930f28
MV
1919 scm_bitvector_release (kv);
1920 scm_bitvector_release (v);
1921
1922 return scm_from_size_t (count);
0f2d19dd 1923 }
85368844
MV
1924 else if (scm_is_true (scm_u32vector_p (kv)))
1925 {
20930f28
MV
1926 size_t count = 0, ulen, i;
1927 scm_t_uint32 *indices;
1928 int bit = scm_to_bool (obj);
d44ff083
MV
1929
1930 scm_frame_begin (0);
1931
1932 ulen = scm_c_uniform_vector_length (kv);
1933 indices = scm_u32vector_elements (kv);
1934 scm_frame_uniform_vector_release (kv);
85368844 1935
20930f28
MV
1936 for (i = 0; i < ulen; i++)
1937 if ((scm_is_true (scm_c_bitvector_ref (v, (size_t)indices[i])) != 0)
1938 == (bit != 0))
1939 count++;
d44ff083
MV
1940
1941 scm_frame_end ();
20930f28
MV
1942
1943 return scm_from_size_t (count);
85368844 1944 }
20930f28 1945 else
85368844 1946 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
0f2d19dd 1947}
1bbd0b84 1948#undef FUNC_NAME
0f2d19dd
JB
1949
1950
3b3b36dd 1951SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
1bbd0b84 1952 (SCM v),
88ecf5cb
KR
1953 "Modify the bit vector @var{v} by replacing each element with\n"
1954 "its negation.")
1bbd0b84 1955#define FUNC_NAME s_scm_bit_invert_x
0f2d19dd 1956{
20930f28
MV
1957 size_t bit_len = scm_c_bitvector_length (v);
1958 size_t word_len = (bit_len + 31) / 32;
1959 scm_t_uint32 *bits = scm_bitvector_elements (v);
1960 size_t i;
74014c46 1961
20930f28
MV
1962 for (i = 0; i < word_len; i++)
1963 bits[i] = ~bits[i];
74014c46 1964
20930f28 1965 scm_bitvector_release (v);
0f2d19dd
JB
1966 return SCM_UNSPECIFIED;
1967}
1bbd0b84 1968#undef FUNC_NAME
0f2d19dd
JB
1969
1970
0f2d19dd 1971SCM
cc95e00a 1972scm_istr2bve (SCM str)
0f2d19dd 1973{
cc95e00a 1974 size_t len = scm_i_string_length (str);
20930f28
MV
1975 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
1976 SCM res = vec;
1977
1978 scm_t_uint32 mask;
1979 size_t k, j;
cc95e00a 1980 const char *c_str = scm_i_string_chars (str);
20930f28 1981 scm_t_uint32 *data = scm_bitvector_elements (vec);
cc95e00a 1982
20930f28 1983 for (k = 0; k < (len + 31) / 32; k++)
0f2d19dd
JB
1984 {
1985 data[k] = 0L;
20930f28
MV
1986 j = len - k * 32;
1987 if (j > 32)
1988 j = 32;
0f2d19dd 1989 for (mask = 1L; j--; mask <<= 1)
cc95e00a 1990 switch (*c_str++)
0f2d19dd
JB
1991 {
1992 case '0':
1993 break;
1994 case '1':
1995 data[k] |= mask;
1996 break;
1997 default:
20930f28
MV
1998 res = SCM_BOOL_F;
1999 goto exit;
0f2d19dd
JB
2000 }
2001 }
20930f28
MV
2002
2003 exit:
2004 scm_remember_upto_here_1 (str);
2005 scm_bitvector_release (vec);
2006 return res;
0f2d19dd
JB
2007}
2008
2009
1cc91f1b 2010
0f2d19dd 2011static SCM
34d19ef6 2012ra2l (SCM ra, unsigned long base, unsigned long k)
0f2d19dd
JB
2013{
2014 register SCM res = SCM_EOL;
c014a02e
ML
2015 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2016 register size_t i;
0f2d19dd
JB
2017 if (SCM_ARRAY_DIMS (ra)[k].ubnd < SCM_ARRAY_DIMS (ra)[k].lbnd)
2018 return SCM_EOL;
2019 i = base + (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd) * inc;
2020 if (k < SCM_ARRAY_NDIM (ra) - 1)
2021 {
2022 do
2023 {
2024 i -= inc;
2025 res = scm_cons (ra2l (ra, i, k + 1), res);
2026 }
2027 while (i != base);
2028 }
2029 else
2030 do
2031 {
2032 i -= inc;
e11e83f3 2033 res = scm_cons (scm_uniform_vector_ref (SCM_ARRAY_V (ra), scm_from_size_t (i)), res);
0f2d19dd
JB
2034 }
2035 while (i != base);
2036 return res;
2037}
2038
2039
cd328b4f 2040SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
1bbd0b84 2041 (SCM v),
1e6808ea
MG
2042 "Return a list consisting of all the elements, in order, of\n"
2043 "@var{array}.")
cd328b4f 2044#define FUNC_NAME s_scm_array_to_list
0f2d19dd 2045{
20930f28
MV
2046 if (scm_is_generalized_vector (v))
2047 return scm_generalized_vector_to_list (v);
2048 else if (SCM_ARRAYP (v))
2049 return ra2l (v, SCM_ARRAY_BASE (v), 0);
e0e49670 2050
20930f28 2051 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 2052}
1bbd0b84 2053#undef FUNC_NAME
0f2d19dd
JB
2054
2055
c014a02e 2056static int l2ra(SCM lst, SCM ra, unsigned long base, unsigned long k);
1cc91f1b 2057
3b3b36dd 2058SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
1bbd0b84 2059 (SCM ndim, SCM prot, SCM lst),
8f85c0c6 2060 "@deffnx {Scheme Procedure} list->uniform-vector prot lst\n"
1e6808ea
MG
2061 "Return a uniform array of the type indicated by prototype\n"
2062 "@var{prot} with elements the same as those of @var{lst}.\n"
2063 "Elements must be of the appropriate type, no coercions are\n"
bfad4005
MV
2064 "done.\n"
2065 "\n"
2066 "The argument @var{ndim} determines the number of dimensions\n"
2067 "of the array. It is either an exact integer, giving the\n"
20930f28 2068 "number directly, or a list of exact integers, whose length\n"
bfad4005
MV
2069 "specifies the number of dimensions and each element is the\n"
2070 "lower index bound of its dimension.")
1bbd0b84 2071#define FUNC_NAME s_scm_list_to_uniform_array
0f2d19dd 2072{
bfad4005 2073 SCM shape, row;
0f2d19dd 2074 SCM ra;
c014a02e 2075 unsigned long k;
bfad4005
MV
2076
2077 shape = SCM_EOL;
2078 row = lst;
2079 if (scm_is_integer (ndim))
0f2d19dd 2080 {
bfad4005
MV
2081 size_t k = scm_to_size_t (ndim);
2082 while (k-- > 0)
2083 {
2084 shape = scm_cons (scm_length (row), shape);
2085 if (k > 0)
2086 row = scm_car (row);
2087 }
2088 }
2089 else
2090 {
2091 while (1)
2092 {
2093 shape = scm_cons (scm_list_2 (scm_car (ndim),
2094 scm_sum (scm_sum (scm_car (ndim),
2095 scm_length (row)),
2096 scm_from_int (-1))),
2097 shape);
2098 ndim = scm_cdr (ndim);
2099 if (scm_is_pair (ndim))
2100 row = scm_car (row);
2101 else
2102 break;
2103 }
0f2d19dd 2104 }
bfad4005
MV
2105
2106 ra = scm_dimensions_to_uniform_array (scm_reverse_x (shape, SCM_EOL), prot,
d12feca3 2107 SCM_UNDEFINED);
20930f28 2108
bfad4005 2109 if (scm_is_null (shape))
0f2d19dd
JB
2110 {
2111 SCM_ASRTGO (1 == scm_ilength (lst), badlst);
2112 scm_array_set_x (ra, SCM_CAR (lst), SCM_EOL);
2113 return ra;
2114 }
2115 if (!SCM_ARRAYP (ra))
2116 {
20930f28 2117 size_t length = scm_c_generalized_vector_length (ra);
74014c46 2118 for (k = 0; k < length; k++, lst = SCM_CDR (lst))
20930f28 2119 scm_c_generalized_vector_set_x (ra, k, SCM_CAR (lst));
0f2d19dd
JB
2120 return ra;
2121 }
2122 if (l2ra (lst, ra, SCM_ARRAY_BASE (ra), 0))
2123 return ra;
2124 else
1afff620
KN
2125 badlst:SCM_MISC_ERROR ("Bad scm_array contents list: ~S",
2126 scm_list_1 (lst));
0f2d19dd 2127}
1bbd0b84 2128#undef FUNC_NAME
0f2d19dd 2129
0f2d19dd 2130static int
c014a02e 2131l2ra (SCM lst, SCM ra, unsigned long base, unsigned long k)
0f2d19dd 2132{
c014a02e
ML
2133 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2134 register long n = (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd);
0f2d19dd
JB
2135 int ok = 1;
2136 if (n <= 0)
d2e53ed6 2137 return (scm_is_null (lst));
0f2d19dd
JB
2138 if (k < SCM_ARRAY_NDIM (ra) - 1)
2139 {
2140 while (n--)
2141 {
d2e53ed6 2142 if (!scm_is_pair (lst))
0f2d19dd
JB
2143 return 0;
2144 ok = ok && l2ra (SCM_CAR (lst), ra, base, k + 1);
2145 base += inc;
2146 lst = SCM_CDR (lst);
2147 }
d2e53ed6 2148 if (!scm_is_null (lst))
0f2d19dd
JB
2149 return 0;
2150 }
2151 else
2152 {
2153 while (n--)
2154 {
d2e53ed6 2155 if (!scm_is_pair (lst))
0f2d19dd 2156 return 0;
e11e83f3 2157 scm_array_set_x (SCM_ARRAY_V (ra), SCM_CAR (lst), scm_from_ulong (base));
0f2d19dd
JB
2158 base += inc;
2159 lst = SCM_CDR (lst);
2160 }
d2e53ed6 2161 if (!scm_is_null (lst))
fee7ef83 2162 return 0;
0f2d19dd
JB
2163 }
2164 return ok;
2165}
2166
1cc91f1b 2167
0f2d19dd 2168static void
34d19ef6 2169rapr1 (SCM ra, unsigned long j, unsigned long k, SCM port, scm_print_state *pstate)
0f2d19dd 2170{
c014a02e
ML
2171 long inc = 1;
2172 long n = (SCM_TYP7 (ra) == scm_tc7_smob
b8446ce8 2173 ? 0
e11e83f3 2174 : scm_to_long (scm_uniform_vector_length (ra)));
0f2d19dd
JB
2175 int enclosed = 0;
2176tail:
5c11cc9d 2177 switch SCM_TYP7 (ra)
0f2d19dd
JB
2178 {
2179 case scm_tc7_smob:
2180 if (enclosed++)
2181 {
2182 SCM_ARRAY_BASE (ra) = j;
2183 if (n-- > 0)
9882ea19 2184 scm_iprin1 (ra, port, pstate);
0f2d19dd
JB
2185 for (j += inc; n-- > 0; j += inc)
2186 {
b7f3516f 2187 scm_putc (' ', port);
0f2d19dd 2188 SCM_ARRAY_BASE (ra) = j;
9882ea19 2189 scm_iprin1 (ra, port, pstate);
0f2d19dd
JB
2190 }
2191 break;
2192 }
2193 if (k + 1 < SCM_ARRAY_NDIM (ra))
2194 {
c014a02e 2195 long i;
0f2d19dd
JB
2196 inc = SCM_ARRAY_DIMS (ra)[k].inc;
2197 for (i = SCM_ARRAY_DIMS (ra)[k].lbnd; i < SCM_ARRAY_DIMS (ra)[k].ubnd; i++)
2198 {
b7f3516f 2199 scm_putc ('(', port);
9882ea19 2200 rapr1 (ra, j, k + 1, port, pstate);
b7f3516f 2201 scm_puts (") ", port);
0f2d19dd
JB
2202 j += inc;
2203 }
2204 if (i == SCM_ARRAY_DIMS (ra)[k].ubnd)
2205 { /* could be zero size. */
b7f3516f 2206 scm_putc ('(', port);
9882ea19 2207 rapr1 (ra, j, k + 1, port, pstate);
b7f3516f 2208 scm_putc (')', port);
0f2d19dd
JB
2209 }
2210 break;
2211 }
1be6b49c 2212 if (SCM_ARRAY_NDIM (ra) > 0)
0f2d19dd
JB
2213 { /* Could be zero-dimensional */
2214 inc = SCM_ARRAY_DIMS (ra)[k].inc;
2215 n = (SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1);
2216 }
2217 else
2218 n = 1;
2219 ra = SCM_ARRAY_V (ra);
2220 goto tail;
2221 default:
5c11cc9d 2222 /* scm_tc7_bvect and scm_tc7_llvect only? */
0f2d19dd 2223 if (n-- > 0)
e0e49670 2224 scm_iprin1 (scm_cvref (ra, j, SCM_UNDEFINED), port, pstate);
0f2d19dd
JB
2225 for (j += inc; n-- > 0; j += inc)
2226 {
b7f3516f 2227 scm_putc (' ', port);
9882ea19 2228 scm_iprin1 (scm_cvref (ra, j, SCM_UNDEFINED), port, pstate);
0f2d19dd
JB
2229 }
2230 break;
2231 case scm_tc7_string:
cc95e00a
MV
2232 {
2233 const char *src;
2234 src = scm_i_string_chars (ra);
2235 if (n-- > 0)
2236 scm_iprin1 (SCM_MAKE_CHAR (src[j]), port, pstate);
2237 if (SCM_WRITINGP (pstate))
2238 for (j += inc; n-- > 0; j += inc)
2239 {
2240 scm_putc (' ', port);
2241 scm_iprin1 (SCM_MAKE_CHAR (src[j]), port, pstate);
2242 }
2243 else
2244 for (j += inc; n-- > 0; j += inc)
2245 scm_putc (src[j], port);
2246 scm_remember_upto_here_1 (ra);
2247 }
0f2d19dd 2248 break;
e0e49670 2249
0f2d19dd
JB
2250 }
2251}
2252
e0e49670
MV
2253/* Print dimension DIM of ARRAY.
2254 */
0f2d19dd 2255
e0e49670
MV
2256static int
2257scm_i_print_array_dimension (SCM array, int dim, int base,
2258 SCM port, scm_print_state *pstate)
2259{
2260 scm_t_array_dim *dim_spec = SCM_ARRAY_DIMS (array) + dim;
2261 long idx;
2262
2263 scm_putc ('(', port);
2264
2265#if 0
2266 scm_putc ('{', port);
2267 scm_intprint (dim_spec->lbnd, 10, port);
2268 scm_putc (':', port);
2269 scm_intprint (dim_spec->ubnd, 10, port);
2270 scm_putc (':', port);
2271 scm_intprint (dim_spec->inc, 10, port);
2272 scm_putc ('}', port);
2273#endif
2274
2275 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2276 {
2277 if (dim < SCM_ARRAY_NDIM(array)-1)
2278 scm_i_print_array_dimension (array, dim+1, base, port, pstate);
2279 else
2280 scm_iprin1 (scm_cvref (SCM_ARRAY_V (array), base, SCM_UNDEFINED),
2281 port, pstate);
2282 if (idx < dim_spec->ubnd)
2283 scm_putc (' ', port);
2284 base += dim_spec->inc;
2285 }
2286
2287 scm_putc (')', port);
2288 return 1;
2289}
2290
20930f28 2291/* Print an array. (Only for strict arrays, not for strings, uniform
e0e49670
MV
2292 vectors, vectors and other stuff that can masquerade as an array.)
2293*/
2294
2295/* The array tag is generally of the form
2296 *
2297 * #<rank><unif><@lower><@lower>...
2298 *
2299 * <rank> is a positive integer in decimal giving the rank of the
bfad4005
MV
2300 * array. It is omitted when the rank is 1 and the array is
2301 * non-shared and has zero-origin. For shared arrays and for a
2302 * non-zero origin, the rank is always printed even when it is 1 to
2303 * dinstinguish them from ordinary vectors.
e0e49670
MV
2304 *
2305 * <unif> is the tag for a uniform (or homogenous) numeric vector,
2306 * like u8, s16, etc, as defined by SRFI-4. It is omitted when the
2307 * array is not uniform.
2308 *
2309 * <@lower> is a 'at' sign followed by a integer in decimal giving the
2310 * lower bound of a dimension. There is one <@lower> for each
2311 * dimension. When all lower bounds are zero, all <@lower> are
2312 * omitted.
2313 *
2314 * Thus,
2315 *
2316 * #(1 2 3) is non-uniform array of rank 1 with lower bound 0 in
2317 * dimension 0. (I.e., a regular vector.)
2318 *
2319 * #@2(1 2 3) is non-uniform array of rank 1 with lower bound 2 in
2320 * dimension 0.
2321 *
2322 * #2((1 2 3) (4 5 6)) is a non-uniform array of rank 2; a 3x3
2323 * matrix with index ranges 0..2 and 0..2.
2324 *
2325 * #u32(0 1 2) is a uniform u8 array of rank 1.
2326 *
2327 * #2u32@2@3((1 2) (2 3)) is a uniform u8 array of rank 2 with index
2328 * ranges 2..3 and 3..4.
2329 */
2330
2331static int
2332scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2333{
2334 long ndim = SCM_ARRAY_NDIM (array);
2335 scm_t_array_dim *dim_specs = SCM_ARRAY_DIMS (array);
20930f28 2336 SCM v = SCM_ARRAY_V (array);
e0e49670
MV
2337 unsigned long base = SCM_ARRAY_BASE (array);
2338 long i;
2339
2340 scm_putc ('#', port);
c0fc64c8 2341 if (ndim != 1 || dim_specs[0].lbnd != 0)
e0e49670 2342 scm_intprint (ndim, 10, port);
20930f28
MV
2343 if (scm_is_uniform_vector (v))
2344 scm_puts (scm_i_uniform_vector_tag (v), port);
2345 else if (scm_is_bitvector (v))
2346 scm_puts ("b", port);
2347 else if (scm_is_string (v))
2348 scm_puts ("a", port);
2349 else if (!scm_is_vector (v))
2350 scm_puts ("?", port);
2351
e0e49670
MV
2352 for (i = 0; i < ndim; i++)
2353 if (dim_specs[i].lbnd != 0)
2354 {
2355 for (i = 0; i < ndim; i++)
2356 {
2357 scm_putc ('@', port);
2358 scm_uintprint (dim_specs[i].lbnd, 10, port);
2359 }
2360 break;
2361 }
2362
e0e49670
MV
2363 return scm_i_print_array_dimension (array, 0, base, port, pstate);
2364}
1cc91f1b 2365
bfad4005
MV
2366/* Read an array. This function can also read vectors and uniform
2367 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2368 handled here.
2369
2370 C is the first character read after the '#'.
2371*/
2372
2373typedef struct {
2374 const char *tag;
2375 SCM *proto_var;
2376} tag_proto;
2377
bfad4005
MV
2378static tag_proto tag_proto_table[] = {
2379 { "", &scm_i_proc_make_vector },
2380 { "u8", &scm_i_proc_make_u8vector },
2381 { "s8", &scm_i_proc_make_s8vector },
2382 { "u16", &scm_i_proc_make_u16vector },
2383 { "s16", &scm_i_proc_make_s16vector },
2384 { "u32", &scm_i_proc_make_u32vector },
2385 { "s32", &scm_i_proc_make_s32vector },
2386 { "u64", &scm_i_proc_make_u64vector },
2387 { "s64", &scm_i_proc_make_s64vector },
2388 { "f32", &scm_i_proc_make_f32vector },
2389 { "f64", &scm_i_proc_make_f64vector },
2390 { NULL, NULL }
2391};
2392
2393static SCM
2394scm_i_tag_to_prototype (const char *tag, SCM port)
2395{
2396 tag_proto *tp;
2397
2398 for (tp = tag_proto_table; tp->tag; tp++)
2399 if (!strcmp (tp->tag, tag))
2400 return *(tp->proto_var);
2401
2402#if SCM_ENABLE_DEPRECATED
2403 {
2404 /* Recognize the old syntax, producing the old prototypes.
2405 */
2406 SCM proto = SCM_EOL;
2407 const char *instead;
2408 switch (tag[0])
2409 {
2410 case 'a':
2411 proto = SCM_MAKE_CHAR ('a');
2412 instead = "???";
2413 break;
2414 case 'u':
2415 proto = scm_from_int (1);
2416 instead = "u32";
2417 break;
2418 case 'e':
2419 proto = scm_from_int (-1);
2420 instead = "s32";
2421 break;
2422 case 's':
2423 proto = scm_from_double (1.0);
2424 instead = "f32";
2425 break;
2426 case 'i':
2427 proto = scm_divide (scm_from_int (1), scm_from_int (3));
2428 instead = "f64";
2429 break;
2430 case 'y':
2431 proto = SCM_MAKE_CHAR (0);
2432 instead = "s8";
2433 break;
2434 case 'h':
2435 proto = scm_from_locale_symbol ("s");
2436 instead = "s16";
2437 break;
2438 case 'l':
2439 proto = scm_from_locale_symbol ("l");
2440 instead = "s64";
2441 break;
2442 case 'c':
2443 proto = scm_c_make_rectangular (0.0, 1.0);
72d05aa4
MV
2444 instead = "c64";
2445 break;
2446 default:
bfad4005
MV
2447 instead = "???";
2448 break;
2449 }
2450 if (!scm_is_eq (proto, SCM_EOL) && tag[1] == '\0')
2451 {
2452 scm_c_issue_deprecation_warning_fmt
2453 ("The tag '%c' is deprecated for uniform vectors. "
2454 "Use '%s' instead.", tag[0], instead);
2455 return proto;
2456 }
2457 }
2458#endif
2459
2460 scm_i_input_error (NULL, port,
2461 "unrecognized uniform array tag: ~a",
2462 scm_list_1 (scm_from_locale_string (tag)));
2463 return SCM_BOOL_F;
2464}
2465
2466SCM
2467scm_i_read_array (SCM port, int c)
2468{
2469 size_t rank;
2470 int got_rank;
2471 char tag[80];
2472 int tag_len;
2473
2474 SCM lower_bounds, elements;
2475
2476 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2477 the array code can not deal with zero-length dimensions yet, and
2478 we want to allow zero-length vectors, of course.
2479 */
2480 if (c == '(')
2481 {
2482 scm_ungetc (c, port);
2483 return scm_vector (scm_read (port));
2484 }
2485
2486 /* Disambiguate between '#f' and uniform floating point vectors.
2487 */
2488 if (c == 'f')
2489 {
2490 c = scm_getc (port);
2491 if (c != '3' && c != '6')
2492 {
2493 if (c != EOF)
2494 scm_ungetc (c, port);
2495 return SCM_BOOL_F;
2496 }
2497 rank = 1;
2498 got_rank = 1;
2499 tag[0] = 'f';
2500 tag_len = 1;
2501 goto continue_reading_tag;
2502 }
2503
2504 /* Read rank. We disallow arrays of rank zero since they do not
2505 seem to work reliably yet. */
2506 rank = 0;
2507 got_rank = 0;
2508 while ('0' <= c && c <= '9')
2509 {
2510 rank = 10*rank + c-'0';
2511 got_rank = 1;
2512 c = scm_getc (port);
2513 }
2514 if (!got_rank)
2515 rank = 1;
2516 else if (rank == 0)
2517 scm_i_input_error (NULL, port,
2518 "array rank must be positive", SCM_EOL);
2519
2520 /* Read tag. */
2521 tag_len = 0;
2522 continue_reading_tag:
2523 while (c != EOF && c != '(' && c != '@' && tag_len < 80)
2524 {
2525 tag[tag_len++] = c;
2526 c = scm_getc (port);
2527 }
2528 tag[tag_len] = '\0';
2529
2530 /* Read lower bounds. */
2531 lower_bounds = SCM_EOL;
2532 while (c == '@')
2533 {
2534 /* Yeah, right, we should use some ready-made integer parsing
2535 routine for this...
2536 */
2537
2538 long lbnd = 0;
2539 long sign = 1;
2540
2541 c = scm_getc (port);
2542 if (c == '-')
2543 {
2544 sign = -1;
2545 c = scm_getc (port);
2546 }
2547 while ('0' <= c && c <= '9')
2548 {
2549 lbnd = 10*lbnd + c-'0';
2550 c = scm_getc (port);
2551 }
2552 lower_bounds = scm_cons (scm_from_long (sign*lbnd), lower_bounds);
2553 }
2554
2555 /* Read nested lists of elements.
2556 */
2557 if (c != '(')
2558 scm_i_input_error (NULL, port,
2559 "missing '(' in vector or array literal",
2560 SCM_EOL);
2561 scm_ungetc (c, port);
2562 elements = scm_read (port);
2563
2564 if (scm_is_null (lower_bounds))
2565 lower_bounds = scm_from_size_t (rank);
2566 else if (scm_ilength (lower_bounds) != rank)
2567 scm_i_input_error (NULL, port,
2568 "the number of lower bounds must match the array rank",
2569 SCM_EOL);
2570
2571 /* Construct array. */
2572 return scm_list_to_uniform_array (lower_bounds,
2573 scm_i_tag_to_prototype (tag, port),
2574 elements);
2575}
2576
0f2d19dd 2577int
1bbd0b84 2578scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
2579{
2580 SCM v = exp;
c014a02e 2581 unsigned long base = 0;
20930f28 2582 long ndim;
e0e49670 2583
bfad4005 2584 if (SCM_ARRAYP (exp) && !SCM_ARRAYP (SCM_ARRAY_V (exp)))
e0e49670
MV
2585 return scm_i_print_array (exp, port, pstate);
2586
b7f3516f 2587 scm_putc ('#', port);
20930f28
MV
2588 ndim = SCM_ARRAY_NDIM (v);
2589 base = SCM_ARRAY_BASE (v);
2590 v = SCM_ARRAY_V (v);
2591 scm_puts ("<enclosed-array ", port);
9882ea19 2592 rapr1 (exp, base, 0, port, pstate);
20930f28 2593 scm_putc ('>', port);
0f2d19dd
JB
2594 return 1;
2595}
2596
ab1be174
MV
2597SCM_DEFINE (scm_array_creator, "array-creator", 1, 0, 0,
2598 (SCM ra),
2599 "Return a procedure that would produce an array of the same type\n"
2600 "as @var{array}, if used as the @var{creator} with\n"
2601 "@code{make-uniform-array}.")
2602#define FUNC_NAME s_scm_array_creator
2603{
2604 int outer = 1;
2605 SCM orig_ra = ra;
2606
2607 if (SCM_ARRAYP (ra))
2608 {
2609 ra = SCM_ARRAY_V (ra);
2610 outer = 0;
2611 }
2612
20930f28
MV
2613 if (scm_is_generalized_vector (ra))
2614 return scm_i_generalized_vector_creator (ra);
ab1be174
MV
2615 else if (SCM_ARRAYP (ra))
2616 scm_misc_error (NULL, "creator not known for enclosed array: ~a",
2617 scm_list_1 (orig_ra));
2618 else if (outer)
2619 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2620 else
2621 scm_misc_error (NULL, "creator not known for array content: ~a",
2622 scm_list_1 (ra));
2623}
2624#undef FUNC_NAME
2625
72d05aa4
MV
2626#if SCM_ENABLE_DEPRECATED
2627
3b3b36dd 2628SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
1bbd0b84 2629 (SCM ra),
1e6808ea
MG
2630 "Return an object that would produce an array of the same type\n"
2631 "as @var{array}, if used as the @var{prototype} for\n"
b380b885 2632 "@code{make-uniform-array}.")
1bbd0b84 2633#define FUNC_NAME s_scm_array_prototype
0f2d19dd
JB
2634{
2635 int enclosed = 0;
20930f28
MV
2636
2637 loop:
2638 if (SCM_ARRAYP (ra))
0f2d19dd 2639 {
20930f28
MV
2640 if (enclosed++)
2641 return SCM_UNSPECIFIED;
2642 ra = SCM_ARRAY_V (ra);
2643 goto loop;
0f2d19dd 2644 }
20930f28
MV
2645 else if (scm_is_generalized_vector (ra))
2646 return scm_i_get_old_prototype (ra);
2647 else
2648 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 2649}
1bbd0b84 2650#undef FUNC_NAME
0f2d19dd 2651
72d05aa4 2652#endif
1cc91f1b 2653
0f2d19dd 2654static SCM
e841c3e0 2655array_mark (SCM ptr)
0f2d19dd 2656{
0f2d19dd
JB
2657 return SCM_ARRAY_V (ptr);
2658}
2659
1cc91f1b 2660
1be6b49c 2661static size_t
e841c3e0 2662array_free (SCM ptr)
0f2d19dd 2663{
4c9419ac
MV
2664 scm_gc_free (SCM_ARRAY_MEM (ptr),
2665 (sizeof (scm_t_array)
2666 + SCM_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2667 "array");
2668 return 0;
0f2d19dd
JB
2669}
2670
0f2d19dd
JB
2671void
2672scm_init_unif ()
0f2d19dd 2673{
e841c3e0
KN
2674 scm_tc16_array = scm_make_smob_type ("array", 0);
2675 scm_set_smob_mark (scm_tc16_array, array_mark);
2676 scm_set_smob_free (scm_tc16_array, array_free);
2677 scm_set_smob_print (scm_tc16_array, scm_raprin1);
2678 scm_set_smob_equalp (scm_tc16_array, scm_array_equal_p);
cba42c93
MV
2679 exactly_one_third = scm_permanent_object (scm_divide (scm_from_int (1),
2680 scm_from_int (3)));
0f2d19dd 2681 scm_add_feature ("array");
20930f28
MV
2682
2683 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2684 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2685 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2686 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2687
a0599745 2688#include "libguile/unif.x"
bfad4005
MV
2689
2690 scm_i_proc_make_vector = scm_variable_ref (scm_c_lookup ("make-vector"));
2691 scm_i_proc_make_string = scm_variable_ref (scm_c_lookup ("make-string"));
20930f28
MV
2692 scm_i_proc_make_bitvector =
2693 scm_variable_ref (scm_c_lookup ("make-bitvector"));
0f2d19dd 2694}
89e00824
ML
2695
2696/*
2697 Local Variables:
2698 c-file-style: "gnu"
2699 End:
2700*/