Run some of arrays.test under both compiler & interpreter
[bpt/guile.git] / libguile / arrays.c
CommitLineData
493ceb99 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004,2005,
1fadf369 2 * 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
0f2d19dd 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd
JB
21\f
22
dbb605f5 23#ifdef HAVE_CONFIG_H
2a5cd898
RB
24# include <config.h>
25#endif
26
0f2d19dd 27#include <stdio.h>
e6e2e95a 28#include <errno.h>
783e7774 29#include <string.h>
13af75bf 30#include <assert.h>
e6e2e95a 31
a0599745 32#include "libguile/_scm.h"
e0e49670
MV
33#include "libguile/__scm.h"
34#include "libguile/eq.h"
a0599745
MD
35#include "libguile/chars.h"
36#include "libguile/eval.h"
37#include "libguile/fports.h"
a0599745
MD
38#include "libguile/feature.h"
39#include "libguile/root.h"
40#include "libguile/strings.h"
c44ca4fe 41#include "libguile/srfi-13.h"
e0e49670 42#include "libguile/srfi-4.h"
a0599745 43#include "libguile/vectors.h"
cf396142 44#include "libguile/bitvectors.h"
438974d0 45#include "libguile/bytevectors.h"
bfad4005 46#include "libguile/list.h"
d44ff083 47#include "libguile/dynwind.h"
943a0a87 48#include "libguile/read.h"
a0599745
MD
49
50#include "libguile/validate.h"
2fa901a5 51#include "libguile/arrays.h"
943a0a87 52#include "libguile/array-map.h"
f332e957 53#include "libguile/generalized-vectors.h"
943a0a87 54#include "libguile/generalized-arrays.h"
476b894c 55#include "libguile/uniform.h"
0f2d19dd 56
0f2d19dd 57
04b87de5 58#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 59 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | (SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
04b87de5 60#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 61 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~(SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
1cc91f1b 62
0f2d19dd 63
c2cb82f8 64SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
e2d37336
MD
65 (SCM ra),
66 "Return the root vector of a shared array.")
67#define FUNC_NAME s_scm_shared_array_root
68{
1e2a55e4 69 if (SCM_I_ARRAYP (ra))
04b87de5 70 return SCM_I_ARRAY_V (ra);
1e2a55e4
DL
71 else if (!scm_is_array (ra))
72 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
c2cb82f8 73 else
52372719 74 return ra;
e2d37336
MD
75}
76#undef FUNC_NAME
77
78
c2cb82f8 79SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
e2d37336
MD
80 (SCM ra),
81 "Return the root vector index of the first element in the array.")
82#define FUNC_NAME s_scm_shared_array_offset
83{
52372719
MV
84 scm_t_array_handle handle;
85 SCM res;
86
87 scm_array_get_handle (ra, &handle);
88 res = scm_from_size_t (handle.base);
89 scm_array_handle_release (&handle);
90 return res;
e2d37336
MD
91}
92#undef FUNC_NAME
93
94
95SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
96 (SCM ra),
97 "For each dimension, return the distance between elements in the root vector.")
98#define FUNC_NAME s_scm_shared_array_increments
99{
52372719 100 scm_t_array_handle handle;
e2d37336 101 SCM res = SCM_EOL;
1be6b49c 102 size_t k;
92c2555f 103 scm_t_array_dim *s;
02339e5b 104
52372719
MV
105 scm_array_get_handle (ra, &handle);
106 k = scm_array_handle_rank (&handle);
107 s = scm_array_handle_dims (&handle);
e2d37336 108 while (k--)
52372719
MV
109 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
110 scm_array_handle_release (&handle);
e2d37336
MD
111 return res;
112}
113#undef FUNC_NAME
114
67543d07 115SCM
66b9d7d3 116scm_i_make_array (int ndim)
0f2d19dd
JB
117{
118 SCM ra;
b2637c98 119 ra = scm_cell (((scm_t_bits) ndim << 17) + scm_tc7_array,
67543d07
LC
120 (scm_t_bits) scm_gc_malloc (sizeof (scm_i_t_array) +
121 ndim * sizeof (scm_t_array_dim),
122 "array"));
04b87de5 123 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
124 return ra;
125}
126
127static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 128
1cc91f1b 129
02339e5b
MV
130/* Increments will still need to be set. */
131
1e2a55e4 132static SCM
0cd6cb2f 133scm_i_shap2ra (SCM args)
0f2d19dd 134{
92c2555f 135 scm_t_array_dim *s;
1e2a55e4 136 SCM ra, spec;
0f2d19dd 137 int ndim = scm_ilength (args);
b3fcac34 138 if (ndim < 0)
0cd6cb2f 139 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 140
66b9d7d3 141 ra = scm_i_make_array (ndim);
04b87de5
MV
142 SCM_I_ARRAY_BASE (ra) = 0;
143 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 144 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
145 {
146 spec = SCM_CAR (args);
e11e83f3 147 if (scm_is_integer (spec))
0f2d19dd 148 {
0f2d19dd 149 s->lbnd = 0;
1e2a55e4
DL
150 s->ubnd = scm_to_ssize_t (spec);
151 if (s->ubnd < 0)
152 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
153 --s->ubnd;
0f2d19dd
JB
154 }
155 else
156 {
d2e53ed6 157 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 158 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
1e2a55e4
DL
159 s->lbnd = scm_to_ssize_t (SCM_CAR (spec));
160 spec = SCM_CDR (spec);
161 if (!scm_is_pair (spec)
162 || !scm_is_integer (SCM_CAR (spec))
163 || !scm_is_null (SCM_CDR (spec)))
0cd6cb2f 164 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
1e2a55e4
DL
165 s->ubnd = scm_to_ssize_t (SCM_CAR (spec));
166 if (s->ubnd - s->lbnd < -1)
167 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 168 }
1e2a55e4 169 s->inc = 1;
0f2d19dd
JB
170 }
171 return ra;
172}
173
f301dbf3
MV
174SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
175 (SCM type, SCM fill, SCM bounds),
176 "Create and return an array of type @var{type}.")
177#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 178{
f301dbf3 179 size_t k, rlen = 1;
92c2555f 180 scm_t_array_dim *s;
0f2d19dd 181 SCM ra;
1be6b49c 182
0cd6cb2f 183 ra = scm_i_shap2ra (bounds);
e038c042 184 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
185 s = SCM_I_ARRAY_DIMS (ra);
186 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 187
0f2d19dd
JB
188 while (k--)
189 {
a3a32939 190 s[k].inc = rlen;
2caaadd1 191 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 192 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 193 }
a3a32939 194
f0b91039 195 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 196 fill = SCM_UNDEFINED;
a3a32939 197
943a0a87
AW
198 SCM_I_ARRAY_V (ra) =
199 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
a3a32939 200
04b87de5 201 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 202 if (0 == s->lbnd)
04b87de5 203 return SCM_I_ARRAY_V (ra);
2bee653a 204
0f2d19dd
JB
205 return ra;
206}
1bbd0b84 207#undef FUNC_NAME
0f2d19dd 208
782a82ee
AW
209SCM
210scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
211 size_t byte_len)
212#define FUNC_NAME "scm_from_contiguous_typed_array"
213{
214 size_t k, rlen = 1;
215 scm_t_array_dim *s;
782a82ee
AW
216 SCM ra;
217 scm_t_array_handle h;
f5a51cae 218 void *elts;
782a82ee
AW
219 size_t sz;
220
782a82ee
AW
221 ra = scm_i_shap2ra (bounds);
222 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
223 s = SCM_I_ARRAY_DIMS (ra);
224 k = SCM_I_ARRAY_NDIM (ra);
225
226 while (k--)
227 {
228 s[k].inc = rlen;
229 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
230 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
231 }
943a0a87
AW
232 SCM_I_ARRAY_V (ra) =
233 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
782a82ee
AW
234
235
236 scm_array_get_handle (ra, &h);
f5a51cae
AW
237 elts = h.writable_elements;
238 sz = scm_array_handle_uniform_element_bit_size (&h);
782a82ee
AW
239 scm_array_handle_release (&h);
240
f5a51cae
AW
241 if (sz >= 8 && ((sz % 8) == 0))
242 {
243 if (byte_len % (sz / 8))
244 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
245 if (byte_len / (sz / 8) != rlen)
246 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
247 }
b0fae4ec 248 else if (sz < 8)
f5a51cae 249 {
d65514a2
AW
250 /* Elements of sub-byte size (bitvectors) are addressed in 32-bit
251 units. */
252 if (byte_len != ((rlen * sz + 31) / 32) * 4)
f5a51cae
AW
253 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
254 }
b0fae4ec
AW
255 else
256 /* an internal guile error, really */
257 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
782a82ee 258
f5a51cae 259 memcpy (elts, bytes, byte_len);
782a82ee
AW
260
261 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 262 if (0 == s->lbnd)
782a82ee
AW
263 return SCM_I_ARRAY_V (ra);
264 return ra;
265}
266#undef FUNC_NAME
267
73788ca8
AW
268SCM
269scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
270#define FUNC_NAME "scm_from_contiguous_array"
271{
272 size_t k, rlen = 1;
273 scm_t_array_dim *s;
274 SCM ra;
275 scm_t_array_handle h;
276
277 ra = scm_i_shap2ra (bounds);
278 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
279 s = SCM_I_ARRAY_DIMS (ra);
280 k = SCM_I_ARRAY_NDIM (ra);
281
282 while (k--)
283 {
284 s[k].inc = rlen;
285 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
286 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
287 }
288 if (rlen != len)
289 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
290
291 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
292 scm_array_get_handle (ra, &h);
293 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
294 scm_array_handle_release (&h);
295
296 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 297 if (0 == s->lbnd)
73788ca8
AW
298 return SCM_I_ARRAY_V (ra);
299 return ra;
300}
301#undef FUNC_NAME
302
f301dbf3
MV
303SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
304 (SCM fill, SCM bounds),
305 "Create and return an array.")
306#define FUNC_NAME s_scm_make_array
307{
308 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
309}
310#undef FUNC_NAME
311
1e2a55e4 312static void
0cd6cb2f 313scm_i_ra_set_contp (SCM ra)
0f2d19dd 314{
04b87de5 315 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 316 if (k)
0f2d19dd 317 {
1e2a55e4 318 ssize_t inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 319 while (k--)
0f2d19dd 320 {
04b87de5 321 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 322 {
e038c042 323 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
324 return;
325 }
04b87de5
MV
326 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
327 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 328 }
0f2d19dd 329 }
e038c042 330 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
331}
332
333
3b3b36dd 334SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 335 (SCM oldra, SCM mapfunc, SCM dims),
b7e64f8b
BT
336 "@code{make-shared-array} can be used to create shared subarrays\n"
337 "of other arrays. The @var{mapfunc} is a function that\n"
338 "translates coordinates in the new array into coordinates in the\n"
339 "old array. A @var{mapfunc} must be linear, and its range must\n"
340 "stay within the bounds of the old array, but it can be\n"
341 "otherwise arbitrary. A simple example:\n"
1e6808ea 342 "@lisp\n"
b380b885
MD
343 "(define fred (make-array #f 8 8))\n"
344 "(define freds-diagonal\n"
345 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
346 "(array-set! freds-diagonal 'foo 3)\n"
347 "(array-ref fred 3 3) @result{} foo\n"
348 "(define freds-center\n"
349 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
350 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 351 "@end lisp")
1bbd0b84 352#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 353{
112ba0ac 354 scm_t_array_handle old_handle;
0f2d19dd
JB
355 SCM ra;
356 SCM inds, indptr;
357 SCM imap;
112ba0ac
MV
358 size_t k;
359 ssize_t i;
2b829bbb 360 long old_base, old_min, new_min, old_max, new_max;
92c2555f 361 scm_t_array_dim *s;
b3fcac34
DH
362
363 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 364 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 365 ra = scm_i_shap2ra (dims);
112ba0ac
MV
366
367 scm_array_get_handle (oldra, &old_handle);
368
04b87de5 369 if (SCM_I_ARRAYP (oldra))
0f2d19dd 370 {
04b87de5 371 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 372 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
373 s = scm_array_handle_dims (&old_handle);
374 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
375 while (k--)
376 {
377 if (s[k].inc > 0)
378 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
379 else
380 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
381 }
382 }
383 else
384 {
04b87de5 385 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 386 old_base = old_min = 0;
9da9c22f 387 old_max = scm_c_array_length (oldra) - 1;
0f2d19dd 388 }
112ba0ac 389
0f2d19dd 390 inds = SCM_EOL;
04b87de5
MV
391 s = SCM_I_ARRAY_DIMS (ra);
392 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 393 {
1e2a55e4 394 inds = scm_cons (scm_from_ssize_t (s[k].lbnd), inds);
0f2d19dd
JB
395 if (s[k].ubnd < s[k].lbnd)
396 {
04b87de5 397 if (1 == SCM_I_ARRAY_NDIM (ra))
943a0a87
AW
398 ra = scm_make_generalized_vector (scm_array_type (ra),
399 SCM_INUM0, SCM_UNDEFINED);
0f2d19dd 400 else
943a0a87
AW
401 SCM_I_ARRAY_V (ra) =
402 scm_make_generalized_vector (scm_array_type (ra),
403 SCM_INUM0, SCM_UNDEFINED);
112ba0ac 404 scm_array_handle_release (&old_handle);
0f2d19dd
JB
405 return ra;
406 }
407 }
112ba0ac 408
fdc28395 409 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 410 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 411 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 412 indptr = inds;
04b87de5 413 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
414 while (k--)
415 {
416 if (s[k].ubnd > s[k].lbnd)
417 {
e11e83f3 418 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 419 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 420 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
421 i += s[k].inc;
422 if (s[k].inc > 0)
423 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
424 else
425 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
426 }
427 else
428 s[k].inc = new_max - new_min + 1; /* contiguous by default */
429 indptr = SCM_CDR (indptr);
430 }
112ba0ac
MV
431
432 scm_array_handle_release (&old_handle);
433
b3fcac34
DH
434 if (old_min > new_min || old_max < new_max)
435 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 436 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 437 {
04b87de5 438 SCM v = SCM_I_ARRAY_V (ra);
9da9c22f 439 size_t length = scm_c_array_length (v);
74014c46
DH
440 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
441 return v;
0f2d19dd 442 if (s->ubnd < s->lbnd)
943a0a87
AW
443 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
444 SCM_UNDEFINED);
0f2d19dd 445 }
0cd6cb2f 446 scm_i_ra_set_contp (ra);
0f2d19dd
JB
447 return ra;
448}
1bbd0b84 449#undef FUNC_NAME
0f2d19dd
JB
450
451
452/* args are RA . DIMS */
af45e3b0
DH
453SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
454 (SCM ra, SCM args),
b7e64f8b 455 "Return an array sharing contents with @var{ra}, but with\n"
1e6808ea 456 "dimensions arranged in a different order. There must be one\n"
b7e64f8b 457 "@var{dim} argument for each dimension of @var{ra}.\n"
1e6808ea
MG
458 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
459 "and the rank of the array to be returned. Each integer in that\n"
460 "range must appear at least once in the argument list.\n"
461 "\n"
462 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
463 "dimensions in the array to be returned, their positions in the\n"
b7e64f8b 464 "argument list to dimensions of @var{ra}. Several @var{dim}s\n"
1e6808ea 465 "may have the same value, in which case the returned array will\n"
b7e64f8b 466 "have smaller rank than @var{ra}.\n"
1e6808ea
MG
467 "\n"
468 "@lisp\n"
b380b885
MD
469 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
470 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
471 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
472 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 473 "@end lisp")
1bbd0b84 474#define FUNC_NAME s_scm_transpose_array
0f2d19dd 475{
34d19ef6 476 SCM res, vargs;
92c2555f 477 scm_t_array_dim *s, *r;
0f2d19dd 478 int ndim, i, k;
af45e3b0 479
b3fcac34 480 SCM_VALIDATE_REST_ARGUMENT (args);
8c5bb729 481 SCM_ASSERT (SCM_HEAP_OBJECT_P (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 482
a6f8d3dd 483 switch (scm_c_array_rank (ra))
e0e49670 484 {
a6f8d3dd
DL
485 case 0:
486 if (!scm_is_null (args))
487 SCM_WRONG_NUM_ARGS ();
488 return ra;
489 case 1:
e0e49670 490 /* Make sure that we are called with a single zero as
a6f8d3dd 491 arguments.
e0e49670
MV
492 */
493 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
494 SCM_WRONG_NUM_ARGS ();
495 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
496 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
497 return ra;
a6f8d3dd 498 default:
0f2d19dd 499 vargs = scm_vector (args);
04b87de5 500 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 501 SCM_WRONG_NUM_ARGS ();
0f2d19dd 502 ndim = 0;
04b87de5 503 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 504 {
6e708ef2 505 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 506 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
507 if (ndim < i)
508 ndim = i;
509 }
510 ndim++;
66b9d7d3 511 res = scm_i_make_array (ndim);
04b87de5
MV
512 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
513 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
514 for (k = ndim; k--;)
515 {
04b87de5
MV
516 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
517 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 518 }
04b87de5 519 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 520 {
6e708ef2 521 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
522 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
523 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
524 if (r->ubnd < r->lbnd)
525 {
526 r->lbnd = s->lbnd;
527 r->ubnd = s->ubnd;
528 r->inc = s->inc;
529 ndim--;
530 }
531 else
532 {
533 if (r->ubnd > s->ubnd)
534 r->ubnd = s->ubnd;
535 if (r->lbnd < s->lbnd)
536 {
04b87de5 537 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
538 r->lbnd = s->lbnd;
539 }
540 r->inc += s->inc;
541 }
542 }
b3fcac34
DH
543 if (ndim > 0)
544 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 545 scm_i_ra_set_contp (res);
0f2d19dd
JB
546 return res;
547 }
548}
1bbd0b84 549#undef FUNC_NAME
0f2d19dd 550
1d7bdb25
GH
551/* attempts to unroll an array into a one-dimensional array.
552 returns the unrolled array or #f if it can't be done. */
35f45ed6
DL
553/* if strict is true, return #f if returned array
554 wouldn't have contiguous elements. */
3b3b36dd 555SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 556 (SCM ra, SCM strict),
b7e64f8b
BT
557 "If @var{ra} may be @dfn{unrolled} into a one dimensional shared\n"
558 "array without changing their order (last subscript changing\n"
559 "fastest), then @code{array-contents} returns that shared array,\n"
560 "otherwise it returns @code{#f}. All arrays made by\n"
561 "@code{make-array} and @code{make-uniform-array} may be unrolled,\n"
562 "some arrays made by @code{make-shared-array} may not be. If\n"
563 "the optional argument @var{strict} is provided, a shared array\n"
564 "will be returned only if its elements are stored internally\n"
565 "contiguous in memory.")
1bbd0b84 566#define FUNC_NAME s_scm_array_contents
0f2d19dd 567{
c545f716
DL
568 if (!scm_is_array (ra))
569 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
570 else if (SCM_I_ARRAYP (ra))
0f2d19dd 571 {
c545f716 572 SCM v;
04b87de5 573 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
c545f716 574 if (!SCM_I_ARRAY_CONTP (ra))
20930f28
MV
575 return SCM_BOOL_F;
576 for (k = 0; k < ndim; k++)
04b87de5 577 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
943a0a87 578 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
74014c46 579 {
04b87de5 580 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 581 return SCM_BOOL_F;
04b87de5 582 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 583 {
04b87de5
MV
584 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
585 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
586 len % SCM_LONG_BIT)
587 return SCM_BOOL_F;
588 }
74014c46 589 }
9da9c22f 590
c545f716 591 v = SCM_I_ARRAY_V (ra);
2c1ccb02
DL
592 if ((len == scm_c_array_length (v)) && (0 == SCM_I_ARRAY_BASE (ra)))
593 return v;
c545f716
DL
594 else
595 {
596 SCM sra = scm_i_make_array (1);
597 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
598 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
599 SCM_I_ARRAY_V (sra) = v;
600 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
601 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
602 return sra;
603 }
0f2d19dd 604 }
02339e5b 605 else
c545f716 606 return ra;
0f2d19dd 607}
1bbd0b84 608#undef FUNC_NAME
0f2d19dd 609
1cc91f1b 610
943a0a87
AW
611static void
612list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
613{
614 if (k == scm_array_handle_rank (handle))
615 scm_array_handle_set (handle, pos, lst);
616 else
617 {
618 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
619 ssize_t inc = dim->inc;
620 size_t len = 1 + dim->ubnd - dim->lbnd, n;
621 char *errmsg = NULL;
622
623 n = len;
624 while (n > 0 && scm_is_pair (lst))
625 {
626 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
627 pos += inc;
628 lst = SCM_CDR (lst);
629 n -= 1;
630 }
631 if (n != 0)
632 errmsg = "too few elements for array dimension ~a, need ~a";
633 if (!scm_is_null (lst))
634 errmsg = "too many elements for array dimension ~a, want ~a";
635 if (errmsg)
1e2a55e4 636 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_size_t (k),
943a0a87
AW
637 scm_from_size_t (len)));
638 }
639}
1e2a55e4 640
1cc91f1b 641
f301dbf3 642SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 643 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
644 "Return an array of the type @var{type}\n"
645 "with elements the same as those of @var{lst}.\n"
bfad4005 646 "\n"
2caaadd1
MV
647 "The argument @var{shape} determines the number of dimensions\n"
648 "of the array and their shape. It is either an exact integer,\n"
649 "giving the\n"
650 "number of dimensions directly, or a list whose length\n"
651 "specifies the number of dimensions and each element specified\n"
652 "the lower and optionally the upper bound of the corresponding\n"
653 "dimension.\n"
654 "When the element is list of two elements, these elements\n"
655 "give the lower and upper bounds. When it is an exact\n"
656 "integer, it gives only the lower bound.")
f301dbf3 657#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 658{
2caaadd1 659 SCM row;
0f2d19dd 660 SCM ra;
bcbbea0e 661 scm_t_array_handle handle;
bfad4005 662
bfad4005 663 row = lst;
2caaadd1 664 if (scm_is_integer (shape))
0f2d19dd 665 {
2caaadd1
MV
666 size_t k = scm_to_size_t (shape);
667 shape = SCM_EOL;
bfad4005
MV
668 while (k-- > 0)
669 {
670 shape = scm_cons (scm_length (row), shape);
2caaadd1 671 if (k > 0 && !scm_is_null (row))
bfad4005
MV
672 row = scm_car (row);
673 }
674 }
675 else
676 {
2caaadd1
MV
677 SCM shape_spec = shape;
678 shape = SCM_EOL;
bfad4005
MV
679 while (1)
680 {
2caaadd1
MV
681 SCM spec = scm_car (shape_spec);
682 if (scm_is_pair (spec))
683 shape = scm_cons (spec, shape);
684 else
685 shape = scm_cons (scm_list_2 (spec,
686 scm_sum (scm_sum (spec,
687 scm_length (row)),
688 scm_from_int (-1))),
689 shape);
690 shape_spec = scm_cdr (shape_spec);
691 if (scm_is_pair (shape_spec))
692 {
693 if (!scm_is_null (row))
694 row = scm_car (row);
695 }
bfad4005
MV
696 else
697 break;
698 }
0f2d19dd 699 }
bfad4005 700
f0b91039
MV
701 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
702 scm_reverse_x (shape, SCM_EOL));
20930f28 703
bcbbea0e 704 scm_array_get_handle (ra, &handle);
943a0a87 705 list_to_array (lst, &handle, 0, 0);
bcbbea0e
MV
706 scm_array_handle_release (&handle);
707
708 return ra;
0f2d19dd 709}
1bbd0b84 710#undef FUNC_NAME
0f2d19dd 711
f301dbf3
MV
712SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
713 (SCM ndim, SCM lst),
714 "Return an array with elements the same as those of @var{lst}.")
715#define FUNC_NAME s_scm_list_to_array
716{
717 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
718}
719#undef FUNC_NAME
720
e0e49670
MV
721/* Print dimension DIM of ARRAY.
722 */
0f2d19dd 723
e0e49670 724static int
943a0a87 725scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
e0e49670
MV
726 SCM port, scm_print_state *pstate)
727{
943a0a87
AW
728 if (dim == h->ndims)
729 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
730 else
e0e49670 731 {
943a0a87 732 ssize_t i;
0607ebbf 733 scm_putc_unlocked ('(', port);
943a0a87
AW
734 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
735 i++, pos += h->dims[dim].inc)
736 {
737 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
738 if (i < h->dims[dim].ubnd)
0607ebbf 739 scm_putc_unlocked (' ', port);
943a0a87 740 }
0607ebbf 741 scm_putc_unlocked (')', port);
e0e49670 742 }
e0e49670
MV
743 return 1;
744}
745
943a0a87 746/* Print an array.
e0e49670
MV
747*/
748
b2637c98 749int
e0e49670
MV
750scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
751{
943a0a87 752 scm_t_array_handle h;
1e2a55e4 753 size_t i;
2caaadd1 754 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670 755
943a0a87
AW
756 scm_array_get_handle (array, &h);
757
0607ebbf 758 scm_putc_unlocked ('#', port);
943a0a87
AW
759 if (h.ndims != 1 || h.dims[0].lbnd != 0)
760 scm_intprint (h.ndims, 10, port);
761 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
762 scm_write (scm_array_handle_element_type (&h), port);
20930f28 763
943a0a87 764 for (i = 0; i < h.ndims; i++)
2caaadd1 765 {
943a0a87 766 if (h.dims[i].lbnd != 0)
2caaadd1 767 print_lbnds = 1;
943a0a87 768 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
2caaadd1
MV
769 zero_size = 1;
770 else if (zero_size)
771 print_lens = 1;
772 }
773
774 if (print_lbnds || print_lens)
943a0a87 775 for (i = 0; i < h.ndims; i++)
e0e49670 776 {
2caaadd1 777 if (print_lbnds)
e0e49670 778 {
0607ebbf 779 scm_putc_unlocked ('@', port);
943a0a87 780 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
781 }
782 if (print_lens)
783 {
0607ebbf 784 scm_putc_unlocked (':', port);
943a0a87 785 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
2caaadd1 786 10, port);
e0e49670 787 }
e0e49670
MV
788 }
789
943a0a87 790 if (h.ndims == 0)
5f37cb63
MV
791 {
792 /* Rank zero arrays, which are really just scalars, are printed
793 specially. The consequent way would be to print them as
794
795 #0 OBJ
796
797 where OBJ is the printed representation of the scalar, but we
798 print them instead as
799
800 #0(OBJ)
801
802 to make them look less strange.
803
804 Just printing them as
805
806 OBJ
807
808 would be correct in a way as well, but zero rank arrays are
809 not really the same as Scheme values since they are boxed and
810 can be modified with array-set!, say.
811 */
0607ebbf 812 scm_putc_unlocked ('(', port);
943a0a87 813 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
0607ebbf 814 scm_putc_unlocked (')', port);
5f37cb63
MV
815 return 1;
816 }
817 else
943a0a87 818 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 819}
1cc91f1b 820
0f2d19dd 821void
2fa901a5 822scm_init_arrays ()
0f2d19dd 823{
0f2d19dd 824 scm_add_feature ("array");
20930f28 825
2fa901a5 826#include "libguile/arrays.x"
bfad4005 827
0f2d19dd 828}
89e00824
ML
829
830/*
831 Local Variables:
832 c-file-style: "gnu"
833 End:
834*/