Updated cross reference to Arrays.
[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
03a5397a 181 scm_misc_error (NULL, "~a has no prototype", scm_list_1 (uvec));
ab1be174
MV
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))
03a5397a 564 ra = scm_make_uve (0L, scm_array_creator (ra));
0f2d19dd 565 else
03a5397a 566 SCM_ARRAY_V (ra) = scm_make_uve (0L, scm_array_creator (ra));
0f2d19dd
JB
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 623 if (s->ubnd < s->lbnd)
03a5397a 624 return scm_make_uve (0L, scm_array_creator (ra));
0f2d19dd
JB
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 }
03a5397a 1117 SCM_ARRAY_V (ret) = scm_make_uve (inc, scm_array_creator (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,
03a5397a 1126 (SCM ura, 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{
3d8d56df
GH
1142 if (SCM_UNBNDP (port_or_fd))
1143 port_or_fd = scm_cur_inp;
35de7ebe 1144
03a5397a 1145 if (scm_is_uniform_vector (ura))
20930f28 1146 {
03a5397a 1147 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
20930f28 1148 }
03a5397a 1149 else if (SCM_ARRAYP (ura))
20930f28 1150 {
03a5397a
MV
1151 size_t base, vlen, cstart, cend;
1152 SCM cra, ans;
1153
1154 cra = scm_ra2contig (ura, 0);
1155 base = SCM_ARRAY_BASE (cra);
20930f28
MV
1156 vlen = SCM_ARRAY_DIMS (cra)->inc *
1157 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
35de7ebe 1158
03a5397a
MV
1159 cstart = 0;
1160 cend = vlen;
1161 if (!SCM_UNBNDP (start))
1146b6cd 1162 {
03a5397a
MV
1163 cstart = scm_to_unsigned_integer (start, 0, vlen);
1164 if (!SCM_UNBNDP (end))
1165 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1166 }
35de7ebe 1167
03a5397a
MV
1168 ans = scm_uniform_vector_read_x (SCM_ARRAY_V (cra), port_or_fd,
1169 scm_from_size_t (base + cstart),
1170 scm_from_size_t (base + cend));
6c951427 1171
03a5397a
MV
1172 if (!scm_is_eq (cra, ura))
1173 scm_array_copy_x (cra, ura);
1174 return ans;
3d8d56df 1175 }
03a5397a
MV
1176 else
1177 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1178}
1bbd0b84 1179#undef FUNC_NAME
0f2d19dd 1180
3b3b36dd 1181SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
03a5397a 1182 (SCM ura, SCM port_or_fd, SCM start, SCM end),
b380b885
MD
1183 "Writes all elements of @var{ura} as binary objects to\n"
1184 "@var{port-or-fdes}.\n\n"
1185 "The optional arguments @var{start}\n"
1186 "and @var{end} allow\n"
1187 "a specified region of a vector (or linearized array) to be written.\n\n"
9401323e 1188 "The number of objects actually written is returned.\n"
b380b885
MD
1189 "@var{port-or-fdes} may be\n"
1190 "omitted, in which case it defaults to the value returned by\n"
1191 "@code{(current-output-port)}.")
1bbd0b84 1192#define FUNC_NAME s_scm_uniform_array_write
0f2d19dd 1193{
3d8d56df
GH
1194 if (SCM_UNBNDP (port_or_fd))
1195 port_or_fd = scm_cur_outp;
20930f28 1196
03a5397a 1197 if (scm_is_uniform_vector (ura))
20930f28 1198 {
03a5397a 1199 return scm_uniform_vector_write (ura, port_or_fd, start, end);
20930f28 1200 }
03a5397a 1201 else if (SCM_ARRAYP (ura))
20930f28 1202 {
03a5397a
MV
1203 size_t base, vlen, cstart, cend;
1204 SCM cra, ans;
1205
1206 cra = scm_ra2contig (ura, 1);
1207 base = SCM_ARRAY_BASE (cra);
1208 vlen = SCM_ARRAY_DIMS (cra)->inc *
1209 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
1146b6cd 1210
03a5397a
MV
1211 cstart = 0;
1212 cend = vlen;
1213 if (!SCM_UNBNDP (start))
1146b6cd 1214 {
03a5397a
MV
1215 cstart = scm_to_unsigned_integer (start, 0, vlen);
1216 if (!SCM_UNBNDP (end))
1217 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1218 }
3d8d56df 1219
03a5397a
MV
1220 ans = scm_uniform_vector_write (SCM_ARRAY_V (cra), port_or_fd,
1221 scm_from_size_t (base + cstart),
1222 scm_from_size_t (base + cend));
6c951427 1223
03a5397a 1224 return ans;
3d8d56df 1225 }
03a5397a
MV
1226 else
1227 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1228}
1bbd0b84 1229#undef FUNC_NAME
0f2d19dd
JB
1230
1231
20930f28
MV
1232/** Bit vectors */
1233
1234static scm_t_bits scm_tc16_bitvector;
1235
1236#define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1237#define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1238#define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1239
1240static size_t
1241bitvector_free (SCM vec)
1242{
1243 scm_gc_free (BITVECTOR_BITS (vec),
1244 sizeof (scm_t_uint32) * ((BITVECTOR_LENGTH (vec)+31)/32),
1245 "bitvector");
1246 return 0;
1247}
1248
1249static int
1250bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1251{
1252 size_t bit_len = BITVECTOR_LENGTH (vec);
1253 size_t word_len = (bit_len+31)/32;
1254 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1255 size_t i, j;
1256
1257 scm_puts ("#*", port);
1258 for (i = 0; i < word_len; i++, bit_len -= 32)
1259 {
1260 scm_t_uint32 mask = 1;
1261 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1262 scm_putc ((bits[i] & mask)? '1' : '0', port);
1263 }
1264
1265 return 1;
1266}
1267
1268static SCM
1269bitvector_equalp (SCM vec1, SCM vec2)
1270{
1271 size_t bit_len = BITVECTOR_LENGTH (vec1);
1272 size_t word_len = (bit_len + 31) / 32;
1273 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1274 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1275 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1276
1277 /* compare lengths */
1278 if (BITVECTOR_LENGTH (vec2) != bit_len)
1279 return SCM_BOOL_F;
1280 /* avoid underflow in word_len-1 below. */
1281 if (bit_len == 0)
1282 return SCM_BOOL_T;
1283 /* compare full words */
1284 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1285 return SCM_BOOL_F;
1286 /* compare partial last words */
1287 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1288 return SCM_BOOL_F;
1289 return SCM_BOOL_T;
1290}
1291
1292int
1293scm_is_bitvector (SCM vec)
1294{
1295 return IS_BITVECTOR (vec);
1296}
1297
1298SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1299 (SCM obj),
1300 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1301 "return @code{#f}.")
1302#define FUNC_NAME s_scm_bitvector_p
1303{
1304 return scm_from_bool (scm_is_bitvector (obj));
1305}
1306#undef FUNC_NAME
1307
1308SCM
1309scm_c_make_bitvector (size_t len, SCM fill)
1310{
1311 size_t word_len = (len + 31) / 32;
1312 scm_t_uint32 *bits;
1313 SCM res;
1314
1315 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1316 "bitvector");
1317 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1318
1319 if (!SCM_UNBNDP (fill))
1320 scm_bitvector_fill_x (res, fill);
1321
1322 return res;
1323}
1324
1325SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1326 (SCM len, SCM fill),
1327 "Create a new bitvector of length @var{len} and\n"
1328 "optionally initialize all elements to @var{fill}.")
1329#define FUNC_NAME s_scm_make_bitvector
1330{
1331 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1332}
1333#undef FUNC_NAME
1334
1335SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1336 (SCM bits),
1337 "Create a new bitvector with the arguments as elements.")
1338#define FUNC_NAME s_scm_bitvector
1339{
1340 return scm_list_to_bitvector (bits);
1341}
1342#undef FUNC_NAME
1343
1344size_t
1345scm_c_bitvector_length (SCM vec)
1346{
1347 scm_assert_smob_type (scm_tc16_bitvector, vec);
1348 return BITVECTOR_LENGTH (vec);
1349}
1350
1351SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1352 (SCM vec),
1353 "Return the length of the bitvector @var{vec}.")
1354#define FUNC_NAME s_scm_bitvector_length
1355{
1356 return scm_from_size_t (scm_c_bitvector_length (vec));
1357}
1358#undef FUNC_NAME
1359
1360scm_t_uint32 *
1361scm_bitvector_elements (SCM vec)
1362{
1363 scm_assert_smob_type (scm_tc16_bitvector, vec);
1364 return BITVECTOR_BITS (vec);
1365}
1366
1367void
1368scm_bitvector_release (SCM vec)
1369{
1370 /* Nothing to do right now, but this function might come in handy
1371 when bitvectors need to be locked when giving away a pointer
1372 to their elements.
1373
1374 Also, a call to scm_bitvector_release acts like
1375 scm_remember_upto_here, which is needed in any case.
1376 */
1377}
1378
1379void
1380scm_frame_bitvector_release (SCM vec)
1381{
1382 scm_frame_unwind_handler_with_scm (scm_bitvector_release, vec,
1383 SCM_F_WIND_EXPLICITLY);
1384}
1385
1386SCM
1387scm_c_bitvector_ref (SCM vec, size_t idx)
1388{
1389 if (idx < scm_c_bitvector_length (vec))
1390 {
1391 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1392 SCM res = (bits[idx/32] & (1L << (idx%32)))? SCM_BOOL_T : SCM_BOOL_F;
1393 scm_bitvector_release (vec);
1394 return res;
1395 }
1396 else
1397 scm_out_of_range (NULL, scm_from_size_t (idx));
1398}
1399
1400SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1401 (SCM vec, SCM idx),
1402 "Return the element at index @var{idx} of the bitvector\n"
1403 "@var{vec}.")
1404#define FUNC_NAME s_scm_bitvector_ref
1405{
1406 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1407}
1408#undef FUNC_NAME
1409
1410void
1411scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1412{
1413 if (idx < scm_c_bitvector_length (vec))
1414 {
1415 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1416 scm_t_uint32 mask = 1L << (idx%32);
1417 if (scm_is_true (val))
1418 bits[idx/32] |= mask;
1419 else
1420 bits[idx/32] &= ~mask;
1421 scm_bitvector_release (vec);
1422 }
1423 else
1424 scm_out_of_range (NULL, scm_from_size_t (idx));
1425}
1426
1427SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1428 (SCM vec, SCM idx, SCM val),
1429 "Set the element at index @var{idx} of the bitvector\n"
1430 "@var{vec} when @var{val} is true, else clear it.")
1431#define FUNC_NAME s_scm_bitvector_set_x
1432{
1433 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1434 return SCM_UNSPECIFIED;
1435}
1436#undef FUNC_NAME
1437
1438SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1439 (SCM vec, SCM val),
1440 "Set all elements of the bitvector\n"
1441 "@var{vec} when @var{val} is true, else clear them.")
1442#define FUNC_NAME s_scm_bitvector_fill_x
1443{
1444 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1445 size_t bit_len = BITVECTOR_LENGTH (vec);
1446 size_t word_len = (bit_len + 31) / 32;
1447 memset (bits, scm_is_true (val)? -1:0, sizeof (scm_t_uint32) * word_len);
1448 scm_bitvector_release (vec);
1449 return SCM_UNSPECIFIED;
1450}
1451#undef FUNC_NAME
1452
1453SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1454 (SCM list),
1455 "Return a new bitvector initialized with the elements\n"
1456 "of @var{list}.")
1457#define FUNC_NAME s_scm_list_to_bitvector
1458{
1459 size_t bit_len = scm_to_size_t (scm_length (list));
1460 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1461 size_t word_len = (bit_len+31)/32;
1462 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1463 size_t i, j;
1464
1465 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1466 {
1467 scm_t_uint32 mask = 1;
1468 bits[i] = 0;
1469 for (j = 0; j < 32 && j < bit_len;
1470 j++, mask <<= 1, list = SCM_CDR (list))
1471 if (scm_is_true (SCM_CAR (list)))
1472 bits[i] |= mask;
1473 }
1474
1475 scm_bitvector_release (vec);
1476 return vec;
1477}
1478#undef FUNC_NAME
1479
1480SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1481 (SCM vec),
1482 "Return a new list initialized with the elements\n"
1483 "of the bitvector @var{vec}.")
1484#define FUNC_NAME s_scm_bitvector_to_list
1485{
1486 size_t bit_len = scm_c_bitvector_length (vec);
1487 SCM res = SCM_EOL;
1488 size_t word_len = (bit_len+31)/32;
1489 scm_t_uint32 *bits = scm_bitvector_elements (vec);
1490 size_t i, j;
1491
1492 for (i = 0; i < word_len; i++, bit_len -= 32)
1493 {
1494 scm_t_uint32 mask = 1;
1495 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1496 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1497 }
1498
1499 scm_bitvector_release (vec);
1500 return scm_reverse_x (res, SCM_EOL);
1501}
1502#undef FUNC_NAME
1503
1504/* From mmix-arith.w by Knuth.
1505
1506 Here's a fun way to count the number of bits in a tetrabyte.
1507
1508 [This classical trick is called the ``Gillies--Miller method for
1509 sideways addition'' in {\sl The Preparation of Programs for an
1510 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1511 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1512 the tricks used here were suggested by Balbir Singh, Peter
1513 Rossmanith, and Stefan Schwoon.]
1514*/
1515
1516static size_t
1517count_ones (scm_t_uint32 x)
1518{
1519 x=x-((x>>1)&0x55555555);
1520 x=(x&0x33333333)+((x>>2)&0x33333333);
1521 x=(x+(x>>4))&0x0f0f0f0f;
1522 x=x+(x>>8);
1523 return (x+(x>>16)) & 0xff;
1524}
0f2d19dd 1525
3b3b36dd 1526SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
c7eb8761 1527 (SCM b, SCM bitvector),
1e6808ea 1528 "Return the number of occurrences of the boolean @var{b} in\n"
c7eb8761 1529 "@var{bitvector}.")
1bbd0b84 1530#define FUNC_NAME s_scm_bit_count
0f2d19dd 1531{
20930f28
MV
1532 size_t bit_len = scm_c_bitvector_length (bitvector);
1533 size_t word_len = (bit_len + 31) / 32;
1534 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1535 scm_t_uint32 *bits = scm_bitvector_elements (bitvector);
1536
1537 int bit = scm_to_bool (b);
1538 size_t count = 0, i;
1539
1540 if (bit_len == 0)
1541 return 0;
1542
1543 for (i = 0; i < word_len-1; i++)
1544 count += count_ones (bits[i]);
1545 count += count_ones (bits[i] & last_mask);
1546
1547 scm_bitvector_release (bitvector);
1548 return scm_from_size_t (bit? count : bit_len-count);
0f2d19dd 1549}
1bbd0b84 1550#undef FUNC_NAME
0f2d19dd 1551
20930f28
MV
1552/* returns 32 for x == 0.
1553*/
1554static size_t
1555find_first_one (scm_t_uint32 x)
1556{
1557 size_t pos = 0;
1558 /* do a binary search in x. */
1559 if ((x & 0xFFFF) == 0)
1560 x >>= 16, pos += 16;
1561 if ((x & 0xFF) == 0)
1562 x >>= 8, pos += 8;
1563 if ((x & 0xF) == 0)
1564 x >>= 4, pos += 4;
1565 if ((x & 0x3) == 0)
1566 x >>= 2, pos += 2;
1567 if ((x & 0x1) == 0)
1568 pos += 1;
1569 return pos;
1570}
0f2d19dd 1571
3b3b36dd 1572SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1bbd0b84 1573 (SCM item, SCM v, SCM k),
88ecf5cb
KR
1574 "Return the index of the first occurrance of @var{item} in bit\n"
1575 "vector @var{v}, starting from @var{k}. If there is no\n"
1576 "@var{item} entry between @var{k} and the end of\n"
1577 "@var{bitvector}, then return @code{#f}. For example,\n"
1578 "\n"
1579 "@example\n"
1580 "(bit-position #t #*000101 0) @result{} 3\n"
1581 "(bit-position #f #*0001111 3) @result{} #f\n"
1582 "@end example")
1bbd0b84 1583#define FUNC_NAME s_scm_bit_position
0f2d19dd 1584{
20930f28
MV
1585 size_t bit_len = scm_c_bitvector_length (v);
1586 size_t word_len = (bit_len + 31) / 32;
1587 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1588 scm_t_uint32 *bits = scm_bitvector_elements (v);
1589 size_t first_bit = scm_to_unsigned_integer (k, 0, bit_len);
1590 size_t first_word = first_bit / 32;
1591 scm_t_uint32 first_mask = ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1592 scm_t_uint32 w;
1593
1594 int bit = scm_to_bool (item);
1595 size_t i;
1596 SCM res = SCM_BOOL_F;
1597
1598 if (bit_len == 0)
1599 return 0;
74014c46 1600
20930f28
MV
1601 for (i = first_word; i < word_len; i++)
1602 {
1603 w = (bit? bits[i] : ~bits[i]);
1604 if (i == first_word)
1605 w &= first_mask;
1606 if (i == word_len-1)
1607 w &= last_mask;
74014c46 1608 if (w)
20930f28
MV
1609 {
1610 res = scm_from_size_t (32*i + find_first_one (w));
1611 break;
1612 }
0f2d19dd 1613 }
20930f28
MV
1614
1615 scm_bitvector_release (v);
1616 return res;
0f2d19dd 1617}
1bbd0b84 1618#undef FUNC_NAME
0f2d19dd 1619
3b3b36dd 1620SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
c7eb8761 1621 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
1622 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1623 "selecting the entries to change. The return value is\n"
1624 "unspecified.\n"
1625 "\n"
1626 "If @var{kv} is a bit vector, then those entries where it has\n"
1627 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1628 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1629 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1630 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1631 "\n"
1632 "@example\n"
1633 "(define bv #*01000010)\n"
1634 "(bit-set*! bv #*10010001 #t)\n"
1635 "bv\n"
1636 "@result{} #*11010011\n"
1637 "@end example\n"
1638 "\n"
85368844
MV
1639 "If @var{kv} is a u32vector, then its elements are\n"
1640 "indices into @var{v} which are set to @var{obj}.\n"
88ecf5cb
KR
1641 "\n"
1642 "@example\n"
1643 "(define bv #*01000010)\n"
85368844 1644 "(bit-set*! bv #u32(5 2 7) #t)\n"
88ecf5cb
KR
1645 "bv\n"
1646 "@result{} #*01100111\n"
1647 "@end example")
1bbd0b84 1648#define FUNC_NAME s_scm_bit_set_star_x
0f2d19dd 1649{
20930f28
MV
1650 if (scm_is_bitvector (kv))
1651 {
1652 size_t bit_len = scm_c_bitvector_length (kv);
1653 size_t word_len = (bit_len + 31) / 32;
1654 scm_t_uint32 *bits1, *bits2;
1655 size_t i;
1656 int bit = scm_to_bool (obj);
1657
1658 if (scm_c_bitvector_length (v) != bit_len)
85368844
MV
1659 scm_misc_error (NULL,
1660 "bit vectors must have equal length",
1661 SCM_EOL);
1662
20930f28
MV
1663 bits1 = scm_bitvector_elements (v);
1664 bits2 = scm_bitvector_elements (kv);
1665
1666 if (bit == 0)
1667 for (i = 0; i < word_len; i++)
1668 bits1[i] &= ~bits2[i];
85368844 1669 else
20930f28
MV
1670 for (i = 0; i < word_len; i++)
1671 bits1[i] |= bits2[i];
1672
1673 scm_bitvector_release (kv);
1674 scm_bitvector_release (v);
85368844
MV
1675 }
1676 else if (scm_is_true (scm_u32vector_p (kv)))
1677 {
d44ff083 1678 size_t ulen, i;
20930f28
MV
1679 scm_t_uint32 *indices;
1680
1681 /* assert that obj is a boolean.
1682 */
1683 scm_to_bool (obj);
d44ff083
MV
1684
1685 scm_frame_begin (0);
1686
1687 ulen = scm_c_uniform_vector_length (kv);
1688 indices = scm_u32vector_elements (kv);
1689 scm_frame_uniform_vector_release (kv);
85368844 1690
20930f28
MV
1691 for (i = 0; i < ulen; i++)
1692 scm_c_bitvector_set_x (v, (size_t)indices[i], obj);
d44ff083
MV
1693
1694 scm_frame_end ();
0f2d19dd 1695 }
20930f28 1696 else
85368844
MV
1697 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
1698
0f2d19dd
JB
1699 return SCM_UNSPECIFIED;
1700}
1bbd0b84 1701#undef FUNC_NAME
0f2d19dd
JB
1702
1703
3b3b36dd 1704SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
1bbd0b84 1705 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
1706 "Return a count of how many entries in bit vector @var{v} are\n"
1707 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
1708 "consider.\n"
1709 "\n"
1710 "If @var{kv} is a bit vector, then those entries where it has\n"
1711 "@code{#t} are the ones in @var{v} which are considered.\n"
1712 "@var{kv} and @var{v} must be the same length.\n"
1713 "\n"
85368844
MV
1714 "If @var{kv} is a u32vector, then it contains\n"
1715 "the indexes in @var{v} to consider.\n"
88ecf5cb
KR
1716 "\n"
1717 "For example,\n"
1718 "\n"
1719 "@example\n"
1720 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
85368844 1721 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
88ecf5cb 1722 "@end example")
1bbd0b84 1723#define FUNC_NAME s_scm_bit_count_star
0f2d19dd 1724{
20930f28 1725 if (scm_is_bitvector (kv))
0f2d19dd 1726 {
20930f28
MV
1727 size_t bit_len = scm_c_bitvector_length (kv);
1728 size_t word_len = (bit_len + 31) / 32;
1729 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1730 scm_t_uint32 xor_mask = scm_to_bool (obj)? 0 : ((scm_t_uint32)-1);
1731 scm_t_uint32 *bits1, *bits2;
1732 size_t count = 0, i;
85368844 1733
20930f28 1734 if (scm_c_bitvector_length (v) != bit_len)
85368844
MV
1735 scm_misc_error (NULL,
1736 "bit vectors must have equal length",
1737 SCM_EOL);
1738
20930f28
MV
1739 if (bit_len == 0)
1740 return scm_from_size_t (0);
85368844 1741
20930f28
MV
1742 bits1 = scm_bitvector_elements (v);
1743 bits2 = scm_bitvector_elements (kv);
85368844 1744
20930f28
MV
1745 for (i = 0; i < word_len-1; i++)
1746 count += count_ones ((bits1[i]^xor_mask) & bits2[i]);
1747 count += count_ones ((bits1[i]^xor_mask) & bits2[i] & last_mask);
c209c88e 1748
20930f28
MV
1749 scm_bitvector_release (kv);
1750 scm_bitvector_release (v);
1751
1752 return scm_from_size_t (count);
0f2d19dd 1753 }
85368844
MV
1754 else if (scm_is_true (scm_u32vector_p (kv)))
1755 {
20930f28
MV
1756 size_t count = 0, ulen, i;
1757 scm_t_uint32 *indices;
1758 int bit = scm_to_bool (obj);
d44ff083
MV
1759
1760 scm_frame_begin (0);
1761
1762 ulen = scm_c_uniform_vector_length (kv);
1763 indices = scm_u32vector_elements (kv);
1764 scm_frame_uniform_vector_release (kv);
85368844 1765
20930f28
MV
1766 for (i = 0; i < ulen; i++)
1767 if ((scm_is_true (scm_c_bitvector_ref (v, (size_t)indices[i])) != 0)
1768 == (bit != 0))
1769 count++;
d44ff083
MV
1770
1771 scm_frame_end ();
20930f28
MV
1772
1773 return scm_from_size_t (count);
85368844 1774 }
20930f28 1775 else
85368844 1776 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
0f2d19dd 1777}
1bbd0b84 1778#undef FUNC_NAME
0f2d19dd
JB
1779
1780
3b3b36dd 1781SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
1bbd0b84 1782 (SCM v),
88ecf5cb
KR
1783 "Modify the bit vector @var{v} by replacing each element with\n"
1784 "its negation.")
1bbd0b84 1785#define FUNC_NAME s_scm_bit_invert_x
0f2d19dd 1786{
20930f28
MV
1787 size_t bit_len = scm_c_bitvector_length (v);
1788 size_t word_len = (bit_len + 31) / 32;
1789 scm_t_uint32 *bits = scm_bitvector_elements (v);
1790 size_t i;
74014c46 1791
20930f28
MV
1792 for (i = 0; i < word_len; i++)
1793 bits[i] = ~bits[i];
74014c46 1794
20930f28 1795 scm_bitvector_release (v);
0f2d19dd
JB
1796 return SCM_UNSPECIFIED;
1797}
1bbd0b84 1798#undef FUNC_NAME
0f2d19dd
JB
1799
1800
0f2d19dd 1801SCM
cc95e00a 1802scm_istr2bve (SCM str)
0f2d19dd 1803{
cc95e00a 1804 size_t len = scm_i_string_length (str);
20930f28
MV
1805 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
1806 SCM res = vec;
1807
1808 scm_t_uint32 mask;
1809 size_t k, j;
cc95e00a 1810 const char *c_str = scm_i_string_chars (str);
20930f28 1811 scm_t_uint32 *data = scm_bitvector_elements (vec);
cc95e00a 1812
20930f28 1813 for (k = 0; k < (len + 31) / 32; k++)
0f2d19dd
JB
1814 {
1815 data[k] = 0L;
20930f28
MV
1816 j = len - k * 32;
1817 if (j > 32)
1818 j = 32;
0f2d19dd 1819 for (mask = 1L; j--; mask <<= 1)
cc95e00a 1820 switch (*c_str++)
0f2d19dd
JB
1821 {
1822 case '0':
1823 break;
1824 case '1':
1825 data[k] |= mask;
1826 break;
1827 default:
20930f28
MV
1828 res = SCM_BOOL_F;
1829 goto exit;
0f2d19dd
JB
1830 }
1831 }
20930f28
MV
1832
1833 exit:
1834 scm_remember_upto_here_1 (str);
1835 scm_bitvector_release (vec);
1836 return res;
0f2d19dd
JB
1837}
1838
1839
1cc91f1b 1840
0f2d19dd 1841static SCM
34d19ef6 1842ra2l (SCM ra, unsigned long base, unsigned long k)
0f2d19dd
JB
1843{
1844 register SCM res = SCM_EOL;
c014a02e
ML
1845 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
1846 register size_t i;
0f2d19dd
JB
1847 if (SCM_ARRAY_DIMS (ra)[k].ubnd < SCM_ARRAY_DIMS (ra)[k].lbnd)
1848 return SCM_EOL;
1849 i = base + (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd) * inc;
1850 if (k < SCM_ARRAY_NDIM (ra) - 1)
1851 {
1852 do
1853 {
1854 i -= inc;
1855 res = scm_cons (ra2l (ra, i, k + 1), res);
1856 }
1857 while (i != base);
1858 }
1859 else
1860 do
1861 {
1862 i -= inc;
e11e83f3 1863 res = scm_cons (scm_uniform_vector_ref (SCM_ARRAY_V (ra), scm_from_size_t (i)), res);
0f2d19dd
JB
1864 }
1865 while (i != base);
1866 return res;
1867}
1868
1869
cd328b4f 1870SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
1bbd0b84 1871 (SCM v),
1e6808ea
MG
1872 "Return a list consisting of all the elements, in order, of\n"
1873 "@var{array}.")
cd328b4f 1874#define FUNC_NAME s_scm_array_to_list
0f2d19dd 1875{
20930f28
MV
1876 if (scm_is_generalized_vector (v))
1877 return scm_generalized_vector_to_list (v);
1878 else if (SCM_ARRAYP (v))
1879 return ra2l (v, SCM_ARRAY_BASE (v), 0);
e0e49670 1880
20930f28 1881 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 1882}
1bbd0b84 1883#undef FUNC_NAME
0f2d19dd
JB
1884
1885
c014a02e 1886static int l2ra(SCM lst, SCM ra, unsigned long base, unsigned long k);
1cc91f1b 1887
3b3b36dd 1888SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
1bbd0b84 1889 (SCM ndim, SCM prot, SCM lst),
8f85c0c6 1890 "@deffnx {Scheme Procedure} list->uniform-vector prot lst\n"
1e6808ea
MG
1891 "Return a uniform array of the type indicated by prototype\n"
1892 "@var{prot} with elements the same as those of @var{lst}.\n"
1893 "Elements must be of the appropriate type, no coercions are\n"
bfad4005
MV
1894 "done.\n"
1895 "\n"
1896 "The argument @var{ndim} determines the number of dimensions\n"
1897 "of the array. It is either an exact integer, giving the\n"
20930f28 1898 "number directly, or a list of exact integers, whose length\n"
bfad4005
MV
1899 "specifies the number of dimensions and each element is the\n"
1900 "lower index bound of its dimension.")
1bbd0b84 1901#define FUNC_NAME s_scm_list_to_uniform_array
0f2d19dd 1902{
bfad4005 1903 SCM shape, row;
0f2d19dd 1904 SCM ra;
c014a02e 1905 unsigned long k;
bfad4005
MV
1906
1907 shape = SCM_EOL;
1908 row = lst;
1909 if (scm_is_integer (ndim))
0f2d19dd 1910 {
bfad4005
MV
1911 size_t k = scm_to_size_t (ndim);
1912 while (k-- > 0)
1913 {
1914 shape = scm_cons (scm_length (row), shape);
1915 if (k > 0)
1916 row = scm_car (row);
1917 }
1918 }
1919 else
1920 {
1921 while (1)
1922 {
1923 shape = scm_cons (scm_list_2 (scm_car (ndim),
1924 scm_sum (scm_sum (scm_car (ndim),
1925 scm_length (row)),
1926 scm_from_int (-1))),
1927 shape);
1928 ndim = scm_cdr (ndim);
1929 if (scm_is_pair (ndim))
1930 row = scm_car (row);
1931 else
1932 break;
1933 }
0f2d19dd 1934 }
bfad4005
MV
1935
1936 ra = scm_dimensions_to_uniform_array (scm_reverse_x (shape, SCM_EOL), prot,
d12feca3 1937 SCM_UNDEFINED);
20930f28 1938
bfad4005 1939 if (scm_is_null (shape))
0f2d19dd
JB
1940 {
1941 SCM_ASRTGO (1 == scm_ilength (lst), badlst);
1942 scm_array_set_x (ra, SCM_CAR (lst), SCM_EOL);
1943 return ra;
1944 }
1945 if (!SCM_ARRAYP (ra))
1946 {
20930f28 1947 size_t length = scm_c_generalized_vector_length (ra);
74014c46 1948 for (k = 0; k < length; k++, lst = SCM_CDR (lst))
20930f28 1949 scm_c_generalized_vector_set_x (ra, k, SCM_CAR (lst));
0f2d19dd
JB
1950 return ra;
1951 }
1952 if (l2ra (lst, ra, SCM_ARRAY_BASE (ra), 0))
1953 return ra;
1954 else
1afff620
KN
1955 badlst:SCM_MISC_ERROR ("Bad scm_array contents list: ~S",
1956 scm_list_1 (lst));
0f2d19dd 1957}
1bbd0b84 1958#undef FUNC_NAME
0f2d19dd 1959
0f2d19dd 1960static int
c014a02e 1961l2ra (SCM lst, SCM ra, unsigned long base, unsigned long k)
0f2d19dd 1962{
c014a02e
ML
1963 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
1964 register long n = (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd);
0f2d19dd
JB
1965 int ok = 1;
1966 if (n <= 0)
d2e53ed6 1967 return (scm_is_null (lst));
0f2d19dd
JB
1968 if (k < SCM_ARRAY_NDIM (ra) - 1)
1969 {
1970 while (n--)
1971 {
d2e53ed6 1972 if (!scm_is_pair (lst))
0f2d19dd
JB
1973 return 0;
1974 ok = ok && l2ra (SCM_CAR (lst), ra, base, k + 1);
1975 base += inc;
1976 lst = SCM_CDR (lst);
1977 }
d2e53ed6 1978 if (!scm_is_null (lst))
0f2d19dd
JB
1979 return 0;
1980 }
1981 else
1982 {
1983 while (n--)
1984 {
d2e53ed6 1985 if (!scm_is_pair (lst))
0f2d19dd 1986 return 0;
e11e83f3 1987 scm_array_set_x (SCM_ARRAY_V (ra), SCM_CAR (lst), scm_from_ulong (base));
0f2d19dd
JB
1988 base += inc;
1989 lst = SCM_CDR (lst);
1990 }
d2e53ed6 1991 if (!scm_is_null (lst))
fee7ef83 1992 return 0;
0f2d19dd
JB
1993 }
1994 return ok;
1995}
1996
1cc91f1b 1997
0f2d19dd 1998static void
34d19ef6 1999rapr1 (SCM ra, unsigned long j, unsigned long k, SCM port, scm_print_state *pstate)
0f2d19dd 2000{
c014a02e
ML
2001 long inc = 1;
2002 long n = (SCM_TYP7 (ra) == scm_tc7_smob
b8446ce8 2003 ? 0
e11e83f3 2004 : scm_to_long (scm_uniform_vector_length (ra)));
0f2d19dd
JB
2005 int enclosed = 0;
2006tail:
5c11cc9d 2007 switch SCM_TYP7 (ra)
0f2d19dd
JB
2008 {
2009 case scm_tc7_smob:
2010 if (enclosed++)
2011 {
2012 SCM_ARRAY_BASE (ra) = j;
2013 if (n-- > 0)
9882ea19 2014 scm_iprin1 (ra, port, pstate);
0f2d19dd
JB
2015 for (j += inc; n-- > 0; j += inc)
2016 {
b7f3516f 2017 scm_putc (' ', port);
0f2d19dd 2018 SCM_ARRAY_BASE (ra) = j;
9882ea19 2019 scm_iprin1 (ra, port, pstate);
0f2d19dd
JB
2020 }
2021 break;
2022 }
2023 if (k + 1 < SCM_ARRAY_NDIM (ra))
2024 {
c014a02e 2025 long i;
0f2d19dd
JB
2026 inc = SCM_ARRAY_DIMS (ra)[k].inc;
2027 for (i = SCM_ARRAY_DIMS (ra)[k].lbnd; i < SCM_ARRAY_DIMS (ra)[k].ubnd; i++)
2028 {
b7f3516f 2029 scm_putc ('(', port);
9882ea19 2030 rapr1 (ra, j, k + 1, port, pstate);
b7f3516f 2031 scm_puts (") ", port);
0f2d19dd
JB
2032 j += inc;
2033 }
2034 if (i == SCM_ARRAY_DIMS (ra)[k].ubnd)
2035 { /* could be zero size. */
b7f3516f 2036 scm_putc ('(', port);
9882ea19 2037 rapr1 (ra, j, k + 1, port, pstate);
b7f3516f 2038 scm_putc (')', port);
0f2d19dd
JB
2039 }
2040 break;
2041 }
1be6b49c 2042 if (SCM_ARRAY_NDIM (ra) > 0)
0f2d19dd
JB
2043 { /* Could be zero-dimensional */
2044 inc = SCM_ARRAY_DIMS (ra)[k].inc;
2045 n = (SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1);
2046 }
2047 else
2048 n = 1;
2049 ra = SCM_ARRAY_V (ra);
2050 goto tail;
2051 default:
5c11cc9d 2052 /* scm_tc7_bvect and scm_tc7_llvect only? */
0f2d19dd 2053 if (n-- > 0)
e0e49670 2054 scm_iprin1 (scm_cvref (ra, j, SCM_UNDEFINED), port, pstate);
0f2d19dd
JB
2055 for (j += inc; n-- > 0; j += inc)
2056 {
b7f3516f 2057 scm_putc (' ', port);
9882ea19 2058 scm_iprin1 (scm_cvref (ra, j, SCM_UNDEFINED), port, pstate);
0f2d19dd
JB
2059 }
2060 break;
2061 case scm_tc7_string:
cc95e00a
MV
2062 {
2063 const char *src;
2064 src = scm_i_string_chars (ra);
2065 if (n-- > 0)
2066 scm_iprin1 (SCM_MAKE_CHAR (src[j]), port, pstate);
2067 if (SCM_WRITINGP (pstate))
2068 for (j += inc; n-- > 0; j += inc)
2069 {
2070 scm_putc (' ', port);
2071 scm_iprin1 (SCM_MAKE_CHAR (src[j]), port, pstate);
2072 }
2073 else
2074 for (j += inc; n-- > 0; j += inc)
2075 scm_putc (src[j], port);
2076 scm_remember_upto_here_1 (ra);
2077 }
0f2d19dd 2078 break;
e0e49670 2079
0f2d19dd
JB
2080 }
2081}
2082
e0e49670
MV
2083/* Print dimension DIM of ARRAY.
2084 */
0f2d19dd 2085
e0e49670
MV
2086static int
2087scm_i_print_array_dimension (SCM array, int dim, int base,
2088 SCM port, scm_print_state *pstate)
2089{
2090 scm_t_array_dim *dim_spec = SCM_ARRAY_DIMS (array) + dim;
2091 long idx;
2092
2093 scm_putc ('(', port);
2094
2095#if 0
2096 scm_putc ('{', port);
2097 scm_intprint (dim_spec->lbnd, 10, port);
2098 scm_putc (':', port);
2099 scm_intprint (dim_spec->ubnd, 10, port);
2100 scm_putc (':', port);
2101 scm_intprint (dim_spec->inc, 10, port);
2102 scm_putc ('}', port);
2103#endif
2104
2105 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2106 {
2107 if (dim < SCM_ARRAY_NDIM(array)-1)
2108 scm_i_print_array_dimension (array, dim+1, base, port, pstate);
2109 else
2110 scm_iprin1 (scm_cvref (SCM_ARRAY_V (array), base, SCM_UNDEFINED),
2111 port, pstate);
2112 if (idx < dim_spec->ubnd)
2113 scm_putc (' ', port);
2114 base += dim_spec->inc;
2115 }
2116
2117 scm_putc (')', port);
2118 return 1;
2119}
2120
20930f28 2121/* Print an array. (Only for strict arrays, not for strings, uniform
e0e49670
MV
2122 vectors, vectors and other stuff that can masquerade as an array.)
2123*/
2124
2125/* The array tag is generally of the form
2126 *
2127 * #<rank><unif><@lower><@lower>...
2128 *
2129 * <rank> is a positive integer in decimal giving the rank of the
bfad4005
MV
2130 * array. It is omitted when the rank is 1 and the array is
2131 * non-shared and has zero-origin. For shared arrays and for a
2132 * non-zero origin, the rank is always printed even when it is 1 to
2133 * dinstinguish them from ordinary vectors.
e0e49670
MV
2134 *
2135 * <unif> is the tag for a uniform (or homogenous) numeric vector,
2136 * like u8, s16, etc, as defined by SRFI-4. It is omitted when the
2137 * array is not uniform.
2138 *
2139 * <@lower> is a 'at' sign followed by a integer in decimal giving the
2140 * lower bound of a dimension. There is one <@lower> for each
2141 * dimension. When all lower bounds are zero, all <@lower> are
2142 * omitted.
2143 *
2144 * Thus,
2145 *
2146 * #(1 2 3) is non-uniform array of rank 1 with lower bound 0 in
2147 * dimension 0. (I.e., a regular vector.)
2148 *
2149 * #@2(1 2 3) is non-uniform array of rank 1 with lower bound 2 in
2150 * dimension 0.
2151 *
2152 * #2((1 2 3) (4 5 6)) is a non-uniform array of rank 2; a 3x3
2153 * matrix with index ranges 0..2 and 0..2.
2154 *
2155 * #u32(0 1 2) is a uniform u8 array of rank 1.
2156 *
2157 * #2u32@2@3((1 2) (2 3)) is a uniform u8 array of rank 2 with index
2158 * ranges 2..3 and 3..4.
2159 */
2160
2161static int
2162scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2163{
2164 long ndim = SCM_ARRAY_NDIM (array);
2165 scm_t_array_dim *dim_specs = SCM_ARRAY_DIMS (array);
20930f28 2166 SCM v = SCM_ARRAY_V (array);
e0e49670
MV
2167 unsigned long base = SCM_ARRAY_BASE (array);
2168 long i;
2169
2170 scm_putc ('#', port);
c0fc64c8 2171 if (ndim != 1 || dim_specs[0].lbnd != 0)
e0e49670 2172 scm_intprint (ndim, 10, port);
20930f28
MV
2173 if (scm_is_uniform_vector (v))
2174 scm_puts (scm_i_uniform_vector_tag (v), port);
2175 else if (scm_is_bitvector (v))
2176 scm_puts ("b", port);
2177 else if (scm_is_string (v))
2178 scm_puts ("a", port);
2179 else if (!scm_is_vector (v))
2180 scm_puts ("?", port);
2181
e0e49670
MV
2182 for (i = 0; i < ndim; i++)
2183 if (dim_specs[i].lbnd != 0)
2184 {
2185 for (i = 0; i < ndim; i++)
2186 {
2187 scm_putc ('@', port);
2188 scm_uintprint (dim_specs[i].lbnd, 10, port);
2189 }
2190 break;
2191 }
2192
e0e49670
MV
2193 return scm_i_print_array_dimension (array, 0, base, port, pstate);
2194}
1cc91f1b 2195
bfad4005
MV
2196/* Read an array. This function can also read vectors and uniform
2197 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2198 handled here.
2199
2200 C is the first character read after the '#'.
2201*/
2202
2203typedef struct {
2204 const char *tag;
2205 SCM *proto_var;
2206} tag_proto;
2207
bfad4005
MV
2208static tag_proto tag_proto_table[] = {
2209 { "", &scm_i_proc_make_vector },
2210 { "u8", &scm_i_proc_make_u8vector },
2211 { "s8", &scm_i_proc_make_s8vector },
2212 { "u16", &scm_i_proc_make_u16vector },
2213 { "s16", &scm_i_proc_make_s16vector },
2214 { "u32", &scm_i_proc_make_u32vector },
2215 { "s32", &scm_i_proc_make_s32vector },
2216 { "u64", &scm_i_proc_make_u64vector },
2217 { "s64", &scm_i_proc_make_s64vector },
2218 { "f32", &scm_i_proc_make_f32vector },
2219 { "f64", &scm_i_proc_make_f64vector },
2220 { NULL, NULL }
2221};
2222
2223static SCM
2224scm_i_tag_to_prototype (const char *tag, SCM port)
2225{
2226 tag_proto *tp;
2227
2228 for (tp = tag_proto_table; tp->tag; tp++)
2229 if (!strcmp (tp->tag, tag))
2230 return *(tp->proto_var);
2231
2232#if SCM_ENABLE_DEPRECATED
2233 {
2234 /* Recognize the old syntax, producing the old prototypes.
2235 */
2236 SCM proto = SCM_EOL;
2237 const char *instead;
2238 switch (tag[0])
2239 {
2240 case 'a':
2241 proto = SCM_MAKE_CHAR ('a');
2242 instead = "???";
2243 break;
2244 case 'u':
2245 proto = scm_from_int (1);
2246 instead = "u32";
2247 break;
2248 case 'e':
2249 proto = scm_from_int (-1);
2250 instead = "s32";
2251 break;
2252 case 's':
2253 proto = scm_from_double (1.0);
2254 instead = "f32";
2255 break;
2256 case 'i':
2257 proto = scm_divide (scm_from_int (1), scm_from_int (3));
2258 instead = "f64";
2259 break;
2260 case 'y':
2261 proto = SCM_MAKE_CHAR (0);
2262 instead = "s8";
2263 break;
2264 case 'h':
2265 proto = scm_from_locale_symbol ("s");
2266 instead = "s16";
2267 break;
2268 case 'l':
2269 proto = scm_from_locale_symbol ("l");
2270 instead = "s64";
2271 break;
2272 case 'c':
2273 proto = scm_c_make_rectangular (0.0, 1.0);
72d05aa4
MV
2274 instead = "c64";
2275 break;
2276 default:
bfad4005
MV
2277 instead = "???";
2278 break;
2279 }
2280 if (!scm_is_eq (proto, SCM_EOL) && tag[1] == '\0')
2281 {
2282 scm_c_issue_deprecation_warning_fmt
2283 ("The tag '%c' is deprecated for uniform vectors. "
2284 "Use '%s' instead.", tag[0], instead);
2285 return proto;
2286 }
2287 }
2288#endif
2289
2290 scm_i_input_error (NULL, port,
2291 "unrecognized uniform array tag: ~a",
2292 scm_list_1 (scm_from_locale_string (tag)));
2293 return SCM_BOOL_F;
2294}
2295
2296SCM
2297scm_i_read_array (SCM port, int c)
2298{
2299 size_t rank;
2300 int got_rank;
2301 char tag[80];
2302 int tag_len;
2303
2304 SCM lower_bounds, elements;
2305
2306 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2307 the array code can not deal with zero-length dimensions yet, and
2308 we want to allow zero-length vectors, of course.
2309 */
2310 if (c == '(')
2311 {
2312 scm_ungetc (c, port);
2313 return scm_vector (scm_read (port));
2314 }
2315
2316 /* Disambiguate between '#f' and uniform floating point vectors.
2317 */
2318 if (c == 'f')
2319 {
2320 c = scm_getc (port);
2321 if (c != '3' && c != '6')
2322 {
2323 if (c != EOF)
2324 scm_ungetc (c, port);
2325 return SCM_BOOL_F;
2326 }
2327 rank = 1;
2328 got_rank = 1;
2329 tag[0] = 'f';
2330 tag_len = 1;
2331 goto continue_reading_tag;
2332 }
2333
2334 /* Read rank. We disallow arrays of rank zero since they do not
2335 seem to work reliably yet. */
2336 rank = 0;
2337 got_rank = 0;
2338 while ('0' <= c && c <= '9')
2339 {
2340 rank = 10*rank + c-'0';
2341 got_rank = 1;
2342 c = scm_getc (port);
2343 }
2344 if (!got_rank)
2345 rank = 1;
2346 else if (rank == 0)
2347 scm_i_input_error (NULL, port,
2348 "array rank must be positive", SCM_EOL);
2349
2350 /* Read tag. */
2351 tag_len = 0;
2352 continue_reading_tag:
2353 while (c != EOF && c != '(' && c != '@' && tag_len < 80)
2354 {
2355 tag[tag_len++] = c;
2356 c = scm_getc (port);
2357 }
2358 tag[tag_len] = '\0';
2359
2360 /* Read lower bounds. */
2361 lower_bounds = SCM_EOL;
2362 while (c == '@')
2363 {
2364 /* Yeah, right, we should use some ready-made integer parsing
2365 routine for this...
2366 */
2367
2368 long lbnd = 0;
2369 long sign = 1;
2370
2371 c = scm_getc (port);
2372 if (c == '-')
2373 {
2374 sign = -1;
2375 c = scm_getc (port);
2376 }
2377 while ('0' <= c && c <= '9')
2378 {
2379 lbnd = 10*lbnd + c-'0';
2380 c = scm_getc (port);
2381 }
2382 lower_bounds = scm_cons (scm_from_long (sign*lbnd), lower_bounds);
2383 }
2384
2385 /* Read nested lists of elements.
2386 */
2387 if (c != '(')
2388 scm_i_input_error (NULL, port,
2389 "missing '(' in vector or array literal",
2390 SCM_EOL);
2391 scm_ungetc (c, port);
2392 elements = scm_read (port);
2393
2394 if (scm_is_null (lower_bounds))
2395 lower_bounds = scm_from_size_t (rank);
2396 else if (scm_ilength (lower_bounds) != rank)
2397 scm_i_input_error (NULL, port,
2398 "the number of lower bounds must match the array rank",
2399 SCM_EOL);
2400
2401 /* Construct array. */
2402 return scm_list_to_uniform_array (lower_bounds,
2403 scm_i_tag_to_prototype (tag, port),
2404 elements);
2405}
2406
0f2d19dd 2407int
1bbd0b84 2408scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
2409{
2410 SCM v = exp;
c014a02e 2411 unsigned long base = 0;
20930f28 2412 long ndim;
e0e49670 2413
bfad4005 2414 if (SCM_ARRAYP (exp) && !SCM_ARRAYP (SCM_ARRAY_V (exp)))
e0e49670
MV
2415 return scm_i_print_array (exp, port, pstate);
2416
b7f3516f 2417 scm_putc ('#', port);
20930f28
MV
2418 ndim = SCM_ARRAY_NDIM (v);
2419 base = SCM_ARRAY_BASE (v);
2420 v = SCM_ARRAY_V (v);
2421 scm_puts ("<enclosed-array ", port);
9882ea19 2422 rapr1 (exp, base, 0, port, pstate);
20930f28 2423 scm_putc ('>', port);
0f2d19dd
JB
2424 return 1;
2425}
2426
ab1be174
MV
2427SCM_DEFINE (scm_array_creator, "array-creator", 1, 0, 0,
2428 (SCM ra),
2429 "Return a procedure that would produce an array of the same type\n"
2430 "as @var{array}, if used as the @var{creator} with\n"
2431 "@code{make-uniform-array}.")
2432#define FUNC_NAME s_scm_array_creator
2433{
2434 int outer = 1;
2435 SCM orig_ra = ra;
2436
2437 if (SCM_ARRAYP (ra))
2438 {
2439 ra = SCM_ARRAY_V (ra);
2440 outer = 0;
2441 }
2442
20930f28
MV
2443 if (scm_is_generalized_vector (ra))
2444 return scm_i_generalized_vector_creator (ra);
ab1be174
MV
2445 else if (SCM_ARRAYP (ra))
2446 scm_misc_error (NULL, "creator not known for enclosed array: ~a",
2447 scm_list_1 (orig_ra));
2448 else if (outer)
2449 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
2450 else
2451 scm_misc_error (NULL, "creator not known for array content: ~a",
2452 scm_list_1 (ra));
2453}
2454#undef FUNC_NAME
2455
72d05aa4
MV
2456#if SCM_ENABLE_DEPRECATED
2457
3b3b36dd 2458SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
1bbd0b84 2459 (SCM ra),
1e6808ea
MG
2460 "Return an object that would produce an array of the same type\n"
2461 "as @var{array}, if used as the @var{prototype} for\n"
b380b885 2462 "@code{make-uniform-array}.")
1bbd0b84 2463#define FUNC_NAME s_scm_array_prototype
0f2d19dd
JB
2464{
2465 int enclosed = 0;
20930f28
MV
2466
2467 loop:
2468 if (SCM_ARRAYP (ra))
0f2d19dd 2469 {
20930f28
MV
2470 if (enclosed++)
2471 return SCM_UNSPECIFIED;
2472 ra = SCM_ARRAY_V (ra);
2473 goto loop;
0f2d19dd 2474 }
20930f28
MV
2475 else if (scm_is_generalized_vector (ra))
2476 return scm_i_get_old_prototype (ra);
2477 else
2478 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 2479}
1bbd0b84 2480#undef FUNC_NAME
0f2d19dd 2481
72d05aa4 2482#endif
1cc91f1b 2483
0f2d19dd 2484static SCM
e841c3e0 2485array_mark (SCM ptr)
0f2d19dd 2486{
0f2d19dd
JB
2487 return SCM_ARRAY_V (ptr);
2488}
2489
1cc91f1b 2490
1be6b49c 2491static size_t
e841c3e0 2492array_free (SCM ptr)
0f2d19dd 2493{
4c9419ac
MV
2494 scm_gc_free (SCM_ARRAY_MEM (ptr),
2495 (sizeof (scm_t_array)
2496 + SCM_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2497 "array");
2498 return 0;
0f2d19dd
JB
2499}
2500
0f2d19dd
JB
2501void
2502scm_init_unif ()
0f2d19dd 2503{
e841c3e0
KN
2504 scm_tc16_array = scm_make_smob_type ("array", 0);
2505 scm_set_smob_mark (scm_tc16_array, array_mark);
2506 scm_set_smob_free (scm_tc16_array, array_free);
2507 scm_set_smob_print (scm_tc16_array, scm_raprin1);
2508 scm_set_smob_equalp (scm_tc16_array, scm_array_equal_p);
cba42c93
MV
2509 exactly_one_third = scm_permanent_object (scm_divide (scm_from_int (1),
2510 scm_from_int (3)));
0f2d19dd 2511 scm_add_feature ("array");
20930f28
MV
2512
2513 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2514 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2515 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2516 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2517
a0599745 2518#include "libguile/unif.x"
bfad4005
MV
2519
2520 scm_i_proc_make_vector = scm_variable_ref (scm_c_lookup ("make-vector"));
2521 scm_i_proc_make_string = scm_variable_ref (scm_c_lookup ("make-string"));
20930f28
MV
2522 scm_i_proc_make_bitvector =
2523 scm_variable_ref (scm_c_lookup ("make-bitvector"));
0f2d19dd 2524}
89e00824
ML
2525
2526/*
2527 Local Variables:
2528 c-file-style: "gnu"
2529 End:
2530*/