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