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