Tests for transpose-array
[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>
e6e2e95a 30
a0599745 31#include "libguile/_scm.h"
e0e49670
MV
32#include "libguile/__scm.h"
33#include "libguile/eq.h"
a0599745
MD
34#include "libguile/chars.h"
35#include "libguile/eval.h"
36#include "libguile/fports.h"
a0599745
MD
37#include "libguile/feature.h"
38#include "libguile/root.h"
39#include "libguile/strings.h"
c44ca4fe 40#include "libguile/srfi-13.h"
e0e49670 41#include "libguile/srfi-4.h"
a0599745 42#include "libguile/vectors.h"
cf396142 43#include "libguile/bitvectors.h"
438974d0 44#include "libguile/bytevectors.h"
bfad4005 45#include "libguile/list.h"
d44ff083 46#include "libguile/dynwind.h"
943a0a87 47#include "libguile/read.h"
a0599745
MD
48
49#include "libguile/validate.h"
2fa901a5 50#include "libguile/arrays.h"
943a0a87 51#include "libguile/array-map.h"
f332e957 52#include "libguile/generalized-vectors.h"
943a0a87 53#include "libguile/generalized-arrays.h"
476b894c 54#include "libguile/uniform.h"
0f2d19dd 55
0f2d19dd 56
04b87de5 57#define SCM_SET_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 58 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) | (SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
04b87de5 59#define SCM_CLR_ARRAY_CONTIGUOUS_FLAG(x) \
b2637c98 60 (SCM_SET_CELL_WORD_0 ((x), SCM_CELL_WORD_0 (x) & ~(SCM_I_ARRAY_FLAG_CONTIGUOUS << 16)))
1cc91f1b 61
0f2d19dd 62
c2cb82f8 63SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
e2d37336
MD
64 (SCM ra),
65 "Return the root vector of a shared array.")
66#define FUNC_NAME s_scm_shared_array_root
67{
c2cb82f8
DL
68 if (!scm_is_array (ra))
69 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
70 else if (SCM_I_ARRAYP (ra))
04b87de5 71 return SCM_I_ARRAY_V (ra);
c2cb82f8 72 else
52372719 73 return ra;
e2d37336
MD
74}
75#undef FUNC_NAME
76
77
c2cb82f8 78SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
e2d37336
MD
79 (SCM ra),
80 "Return the root vector index of the first element in the array.")
81#define FUNC_NAME s_scm_shared_array_offset
82{
52372719
MV
83 scm_t_array_handle handle;
84 SCM res;
85
86 scm_array_get_handle (ra, &handle);
87 res = scm_from_size_t (handle.base);
88 scm_array_handle_release (&handle);
89 return res;
e2d37336
MD
90}
91#undef FUNC_NAME
92
93
94SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
95 (SCM ra),
96 "For each dimension, return the distance between elements in the root vector.")
97#define FUNC_NAME s_scm_shared_array_increments
98{
52372719 99 scm_t_array_handle handle;
e2d37336 100 SCM res = SCM_EOL;
1be6b49c 101 size_t k;
92c2555f 102 scm_t_array_dim *s;
02339e5b 103
52372719
MV
104 scm_array_get_handle (ra, &handle);
105 k = scm_array_handle_rank (&handle);
106 s = scm_array_handle_dims (&handle);
e2d37336 107 while (k--)
52372719
MV
108 res = scm_cons (scm_from_ssize_t (s[k].inc), res);
109 scm_array_handle_release (&handle);
e2d37336
MD
110 return res;
111}
112#undef FUNC_NAME
113
67543d07 114SCM
66b9d7d3 115scm_i_make_array (int ndim)
0f2d19dd
JB
116{
117 SCM ra;
b2637c98 118 ra = scm_cell (((scm_t_bits) ndim << 17) + scm_tc7_array,
67543d07
LC
119 (scm_t_bits) scm_gc_malloc (sizeof (scm_i_t_array) +
120 ndim * sizeof (scm_t_array_dim),
121 "array"));
04b87de5 122 SCM_I_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
123 return ra;
124}
125
126static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 127
1cc91f1b 128
02339e5b
MV
129/* Increments will still need to be set. */
130
0cd6cb2f
MV
131static SCM
132scm_i_shap2ra (SCM args)
0f2d19dd 133{
92c2555f 134 scm_t_array_dim *s;
0f2d19dd
JB
135 SCM ra, spec, sp;
136 int ndim = scm_ilength (args);
b3fcac34 137 if (ndim < 0)
0cd6cb2f 138 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
b3fcac34 139
66b9d7d3 140 ra = scm_i_make_array (ndim);
04b87de5
MV
141 SCM_I_ARRAY_BASE (ra) = 0;
142 s = SCM_I_ARRAY_DIMS (ra);
d2e53ed6 143 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
144 {
145 spec = SCM_CAR (args);
e11e83f3 146 if (scm_is_integer (spec))
0f2d19dd 147 {
e11e83f3 148 if (scm_to_long (spec) < 0)
0cd6cb2f 149 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 150 s->lbnd = 0;
e11e83f3 151 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
152 s->inc = 1;
153 }
154 else
155 {
d2e53ed6 156 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
0cd6cb2f 157 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 158 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 159 sp = SCM_CDR (spec);
d2e53ed6 160 if (!scm_is_pair (sp)
e11e83f3 161 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 162 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 163 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 164 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
165 s->inc = 1;
166 }
167 }
168 return ra;
169}
170
f301dbf3
MV
171SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
172 (SCM type, SCM fill, SCM bounds),
173 "Create and return an array of type @var{type}.")
174#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 175{
f301dbf3 176 size_t k, rlen = 1;
92c2555f 177 scm_t_array_dim *s;
0f2d19dd 178 SCM ra;
1be6b49c 179
0cd6cb2f 180 ra = scm_i_shap2ra (bounds);
e038c042 181 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
182 s = SCM_I_ARRAY_DIMS (ra);
183 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 184
0f2d19dd
JB
185 while (k--)
186 {
a3a32939 187 s[k].inc = rlen;
2caaadd1 188 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 189 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 190 }
a3a32939 191
f0b91039 192 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 193 fill = SCM_UNDEFINED;
a3a32939 194
943a0a87
AW
195 SCM_I_ARRAY_V (ra) =
196 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
a3a32939 197
04b87de5 198 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 199 if (0 == s->lbnd)
04b87de5 200 return SCM_I_ARRAY_V (ra);
2bee653a 201
0f2d19dd
JB
202 return ra;
203}
1bbd0b84 204#undef FUNC_NAME
0f2d19dd 205
782a82ee
AW
206SCM
207scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
208 size_t byte_len)
209#define FUNC_NAME "scm_from_contiguous_typed_array"
210{
211 size_t k, rlen = 1;
212 scm_t_array_dim *s;
782a82ee
AW
213 SCM ra;
214 scm_t_array_handle h;
f5a51cae 215 void *elts;
782a82ee
AW
216 size_t sz;
217
782a82ee
AW
218 ra = scm_i_shap2ra (bounds);
219 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
220 s = SCM_I_ARRAY_DIMS (ra);
221 k = SCM_I_ARRAY_NDIM (ra);
222
223 while (k--)
224 {
225 s[k].inc = rlen;
226 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
227 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
228 }
943a0a87
AW
229 SCM_I_ARRAY_V (ra) =
230 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
782a82ee
AW
231
232
233 scm_array_get_handle (ra, &h);
f5a51cae
AW
234 elts = h.writable_elements;
235 sz = scm_array_handle_uniform_element_bit_size (&h);
782a82ee
AW
236 scm_array_handle_release (&h);
237
f5a51cae
AW
238 if (sz >= 8 && ((sz % 8) == 0))
239 {
240 if (byte_len % (sz / 8))
241 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
242 if (byte_len / (sz / 8) != rlen)
243 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
244 }
b0fae4ec 245 else if (sz < 8)
f5a51cae 246 {
d65514a2
AW
247 /* Elements of sub-byte size (bitvectors) are addressed in 32-bit
248 units. */
249 if (byte_len != ((rlen * sz + 31) / 32) * 4)
f5a51cae
AW
250 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
251 }
b0fae4ec
AW
252 else
253 /* an internal guile error, really */
254 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
782a82ee 255
f5a51cae 256 memcpy (elts, bytes, byte_len);
782a82ee
AW
257
258 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 259 if (0 == s->lbnd)
782a82ee
AW
260 return SCM_I_ARRAY_V (ra);
261 return ra;
262}
263#undef FUNC_NAME
264
73788ca8
AW
265SCM
266scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
267#define FUNC_NAME "scm_from_contiguous_array"
268{
269 size_t k, rlen = 1;
270 scm_t_array_dim *s;
271 SCM ra;
272 scm_t_array_handle h;
273
274 ra = scm_i_shap2ra (bounds);
275 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
276 s = SCM_I_ARRAY_DIMS (ra);
277 k = SCM_I_ARRAY_NDIM (ra);
278
279 while (k--)
280 {
281 s[k].inc = rlen;
282 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
283 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
284 }
285 if (rlen != len)
286 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
287
288 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
289 scm_array_get_handle (ra, &h);
290 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
291 scm_array_handle_release (&h);
292
293 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 294 if (0 == s->lbnd)
73788ca8
AW
295 return SCM_I_ARRAY_V (ra);
296 return ra;
297}
298#undef FUNC_NAME
299
f301dbf3
MV
300SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
301 (SCM fill, SCM bounds),
302 "Create and return an array.")
303#define FUNC_NAME s_scm_make_array
304{
305 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
306}
307#undef FUNC_NAME
308
0cd6cb2f
MV
309static void
310scm_i_ra_set_contp (SCM ra)
0f2d19dd 311{
04b87de5 312 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 313 if (k)
0f2d19dd 314 {
04b87de5 315 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 316 while (k--)
0f2d19dd 317 {
04b87de5 318 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 319 {
e038c042 320 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
321 return;
322 }
04b87de5
MV
323 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
324 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 325 }
0f2d19dd 326 }
e038c042 327 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
328}
329
330
3b3b36dd 331SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 332 (SCM oldra, SCM mapfunc, SCM dims),
b7e64f8b
BT
333 "@code{make-shared-array} can be used to create shared subarrays\n"
334 "of other arrays. The @var{mapfunc} is a function that\n"
335 "translates coordinates in the new array into coordinates in the\n"
336 "old array. A @var{mapfunc} must be linear, and its range must\n"
337 "stay within the bounds of the old array, but it can be\n"
338 "otherwise arbitrary. A simple example:\n"
1e6808ea 339 "@lisp\n"
b380b885
MD
340 "(define fred (make-array #f 8 8))\n"
341 "(define freds-diagonal\n"
342 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
343 "(array-set! freds-diagonal 'foo 3)\n"
344 "(array-ref fred 3 3) @result{} foo\n"
345 "(define freds-center\n"
346 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
347 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 348 "@end lisp")
1bbd0b84 349#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 350{
112ba0ac 351 scm_t_array_handle old_handle;
0f2d19dd
JB
352 SCM ra;
353 SCM inds, indptr;
354 SCM imap;
112ba0ac
MV
355 size_t k;
356 ssize_t i;
2b829bbb 357 long old_base, old_min, new_min, old_max, new_max;
92c2555f 358 scm_t_array_dim *s;
b3fcac34
DH
359
360 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 361 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 362 ra = scm_i_shap2ra (dims);
112ba0ac
MV
363
364 scm_array_get_handle (oldra, &old_handle);
365
04b87de5 366 if (SCM_I_ARRAYP (oldra))
0f2d19dd 367 {
04b87de5 368 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 369 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
370 s = scm_array_handle_dims (&old_handle);
371 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
372 while (k--)
373 {
374 if (s[k].inc > 0)
375 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
376 else
377 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
378 }
379 }
380 else
381 {
04b87de5 382 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 383 old_base = old_min = 0;
9da9c22f 384 old_max = scm_c_array_length (oldra) - 1;
0f2d19dd 385 }
112ba0ac 386
0f2d19dd 387 inds = SCM_EOL;
04b87de5
MV
388 s = SCM_I_ARRAY_DIMS (ra);
389 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 390 {
e11e83f3 391 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
392 if (s[k].ubnd < s[k].lbnd)
393 {
04b87de5 394 if (1 == SCM_I_ARRAY_NDIM (ra))
943a0a87
AW
395 ra = scm_make_generalized_vector (scm_array_type (ra),
396 SCM_INUM0, SCM_UNDEFINED);
0f2d19dd 397 else
943a0a87
AW
398 SCM_I_ARRAY_V (ra) =
399 scm_make_generalized_vector (scm_array_type (ra),
400 SCM_INUM0, SCM_UNDEFINED);
112ba0ac 401 scm_array_handle_release (&old_handle);
0f2d19dd
JB
402 return ra;
403 }
404 }
112ba0ac 405
fdc28395 406 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 407 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 408 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 409 indptr = inds;
04b87de5 410 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
411 while (k--)
412 {
413 if (s[k].ubnd > s[k].lbnd)
414 {
e11e83f3 415 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 416 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 417 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
418 i += s[k].inc;
419 if (s[k].inc > 0)
420 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
421 else
422 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
423 }
424 else
425 s[k].inc = new_max - new_min + 1; /* contiguous by default */
426 indptr = SCM_CDR (indptr);
427 }
112ba0ac
MV
428
429 scm_array_handle_release (&old_handle);
430
b3fcac34
DH
431 if (old_min > new_min || old_max < new_max)
432 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 433 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 434 {
04b87de5 435 SCM v = SCM_I_ARRAY_V (ra);
9da9c22f 436 size_t length = scm_c_array_length (v);
74014c46
DH
437 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
438 return v;
0f2d19dd 439 if (s->ubnd < s->lbnd)
943a0a87
AW
440 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
441 SCM_UNDEFINED);
0f2d19dd 442 }
0cd6cb2f 443 scm_i_ra_set_contp (ra);
0f2d19dd
JB
444 return ra;
445}
1bbd0b84 446#undef FUNC_NAME
0f2d19dd
JB
447
448
449/* args are RA . DIMS */
af45e3b0
DH
450SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
451 (SCM ra, SCM args),
b7e64f8b 452 "Return an array sharing contents with @var{ra}, but with\n"
1e6808ea 453 "dimensions arranged in a different order. There must be one\n"
b7e64f8b 454 "@var{dim} argument for each dimension of @var{ra}.\n"
1e6808ea
MG
455 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
456 "and the rank of the array to be returned. Each integer in that\n"
457 "range must appear at least once in the argument list.\n"
458 "\n"
459 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
460 "dimensions in the array to be returned, their positions in the\n"
b7e64f8b 461 "argument list to dimensions of @var{ra}. Several @var{dim}s\n"
1e6808ea 462 "may have the same value, in which case the returned array will\n"
b7e64f8b 463 "have smaller rank than @var{ra}.\n"
1e6808ea
MG
464 "\n"
465 "@lisp\n"
b380b885
MD
466 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
467 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
468 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
469 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 470 "@end lisp")
1bbd0b84 471#define FUNC_NAME s_scm_transpose_array
0f2d19dd 472{
34d19ef6 473 SCM res, vargs;
92c2555f 474 scm_t_array_dim *s, *r;
0f2d19dd 475 int ndim, i, k;
af45e3b0 476
b3fcac34 477 SCM_VALIDATE_REST_ARGUMENT (args);
8c5bb729 478 SCM_ASSERT (SCM_HEAP_OBJECT_P (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 479
20930f28 480 if (scm_is_generalized_vector (ra))
e0e49670
MV
481 {
482 /* Make sure that we are called with a single zero as
483 arguments.
484 */
485 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
486 SCM_WRONG_NUM_ARGS ();
487 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
488 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
489 return ra;
490 }
491
66b9d7d3 492 if (SCM_I_ARRAYP (ra))
0f2d19dd 493 {
0f2d19dd 494 vargs = scm_vector (args);
04b87de5 495 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 496 SCM_WRONG_NUM_ARGS ();
0f2d19dd 497 ndim = 0;
04b87de5 498 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 499 {
6e708ef2 500 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 501 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
502 if (ndim < i)
503 ndim = i;
504 }
505 ndim++;
66b9d7d3 506 res = scm_i_make_array (ndim);
04b87de5
MV
507 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
508 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
509 for (k = ndim; k--;)
510 {
04b87de5
MV
511 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
512 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 513 }
04b87de5 514 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 515 {
6e708ef2 516 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
517 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
518 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
519 if (r->ubnd < r->lbnd)
520 {
521 r->lbnd = s->lbnd;
522 r->ubnd = s->ubnd;
523 r->inc = s->inc;
524 ndim--;
525 }
526 else
527 {
528 if (r->ubnd > s->ubnd)
529 r->ubnd = s->ubnd;
530 if (r->lbnd < s->lbnd)
531 {
04b87de5 532 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
533 r->lbnd = s->lbnd;
534 }
535 r->inc += s->inc;
536 }
537 }
b3fcac34
DH
538 if (ndim > 0)
539 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 540 scm_i_ra_set_contp (res);
0f2d19dd
JB
541 return res;
542 }
20930f28
MV
543
544 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 545}
1bbd0b84 546#undef FUNC_NAME
0f2d19dd 547
1d7bdb25
GH
548/* attempts to unroll an array into a one-dimensional array.
549 returns the unrolled array or #f if it can't be done. */
1bbd0b84 550 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 551 wouldn't have contiguous elements. */
3b3b36dd 552SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 553 (SCM ra, SCM strict),
b7e64f8b
BT
554 "If @var{ra} may be @dfn{unrolled} into a one dimensional shared\n"
555 "array without changing their order (last subscript changing\n"
556 "fastest), then @code{array-contents} returns that shared array,\n"
557 "otherwise it returns @code{#f}. All arrays made by\n"
558 "@code{make-array} and @code{make-uniform-array} may be unrolled,\n"
559 "some arrays made by @code{make-shared-array} may not be. If\n"
560 "the optional argument @var{strict} is provided, a shared array\n"
561 "will be returned only if its elements are stored internally\n"
562 "contiguous in memory.")
1bbd0b84 563#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
564{
565 SCM sra;
e0e49670 566
20930f28 567 if (scm_is_generalized_vector (ra))
e0e49670
MV
568 return ra;
569
04b87de5 570 if (SCM_I_ARRAYP (ra))
0f2d19dd 571 {
04b87de5
MV
572 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
573 if (!SCM_I_ARRAYP (ra) || !SCM_I_ARRAY_CONTP (ra))
20930f28
MV
574 return SCM_BOOL_F;
575 for (k = 0; k < ndim; k++)
04b87de5 576 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
943a0a87 577 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
74014c46 578 {
04b87de5 579 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 580 return SCM_BOOL_F;
04b87de5 581 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 582 {
04b87de5
MV
583 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
584 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
585 len % SCM_LONG_BIT)
586 return SCM_BOOL_F;
587 }
74014c46 588 }
9da9c22f 589
20930f28 590 {
04b87de5 591 SCM v = SCM_I_ARRAY_V (ra);
9da9c22f 592 size_t length = scm_c_array_length (v);
04b87de5 593 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 594 return v;
0f2d19dd 595 }
9da9c22f 596
66b9d7d3 597 sra = scm_i_make_array (1);
04b87de5
MV
598 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
599 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
600 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
601 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
602 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 603 return sra;
0f2d19dd 604 }
02339e5b
MV
605 else
606 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
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)
636 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
637 scm_from_size_t (len)));
638 }
639}
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;
e0e49670 753 long 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
2a610be5 821static SCM
1fadf369 822array_handle_ref (scm_t_array_handle *hh, size_t pos)
2a610be5 823{
1fadf369 824 return scm_c_array_ref_1 (SCM_I_ARRAY_V (hh->array), pos);
2a610be5
AW
825}
826
827static void
1fadf369 828array_handle_set (scm_t_array_handle *hh, size_t pos, SCM val)
2a610be5 829{
1fadf369 830 scm_c_array_set_1_x (SCM_I_ARRAY_V (hh->array), val, pos);
2a610be5
AW
831}
832
833/* FIXME: should be handle for vect? maybe not, because of dims */
834static void
835array_get_handle (SCM array, scm_t_array_handle *h)
836{
837 scm_t_array_handle vh;
838 scm_array_get_handle (SCM_I_ARRAY_V (array), &vh);
839 h->element_type = vh.element_type;
840 h->elements = vh.elements;
841 h->writable_elements = vh.writable_elements;
842 scm_array_handle_release (&vh);
843
844 h->dims = SCM_I_ARRAY_DIMS (array);
845 h->ndims = SCM_I_ARRAY_NDIM (array);
846 h->base = SCM_I_ARRAY_BASE (array);
847}
848
b2637c98
AW
849SCM_ARRAY_IMPLEMENTATION (scm_tc7_array,
850 0x7f,
2a610be5 851 array_handle_ref, array_handle_set,
f65e0168 852 array_get_handle)
2a610be5 853
0f2d19dd 854void
2fa901a5 855scm_init_arrays ()
0f2d19dd 856{
0f2d19dd 857 scm_add_feature ("array");
20930f28 858
2fa901a5 859#include "libguile/arrays.x"
bfad4005 860
0f2d19dd 861}
89e00824
ML
862
863/*
864 Local Variables:
865 c-file-style: "gnu"
866 End:
867*/