Check the documented matching behavior of array-map!/copy!
[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{
c2cb82f8
DL
69 if (!scm_is_array (ra))
70 scm_wrong_type_arg_msg (FUNC_NAME, SCM_ARG1, ra, "array");
71 else if (SCM_I_ARRAYP (ra))
04b87de5 72 return SCM_I_ARRAY_V (ra);
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
0cd6cb2f
MV
132static SCM
133scm_i_shap2ra (SCM args)
0f2d19dd 134{
92c2555f 135 scm_t_array_dim *s;
0f2d19dd
JB
136 SCM ra, spec, sp;
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 {
e11e83f3 149 if (scm_to_long (spec) < 0)
0cd6cb2f 150 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
0f2d19dd 151 s->lbnd = 0;
e11e83f3 152 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
153 s->inc = 1;
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);
e11e83f3 159 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 160 sp = SCM_CDR (spec);
d2e53ed6 161 if (!scm_is_pair (sp)
e11e83f3 162 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 163 || !scm_is_null (SCM_CDR (sp)))
0cd6cb2f 164 scm_misc_error (NULL, s_bad_spec, SCM_EOL);
e11e83f3 165 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
166 s->inc = 1;
167 }
168 }
169 return ra;
170}
171
f301dbf3
MV
172SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
173 (SCM type, SCM fill, SCM bounds),
174 "Create and return an array of type @var{type}.")
175#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 176{
f301dbf3 177 size_t k, rlen = 1;
92c2555f 178 scm_t_array_dim *s;
0f2d19dd 179 SCM ra;
1be6b49c 180
0cd6cb2f 181 ra = scm_i_shap2ra (bounds);
e038c042 182 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
04b87de5
MV
183 s = SCM_I_ARRAY_DIMS (ra);
184 k = SCM_I_ARRAY_NDIM (ra);
1be6b49c 185
0f2d19dd
JB
186 while (k--)
187 {
a3a32939 188 s[k].inc = rlen;
2caaadd1 189 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
0f2d19dd 190 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 191 }
a3a32939 192
f0b91039 193 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 194 fill = SCM_UNDEFINED;
a3a32939 195
943a0a87
AW
196 SCM_I_ARRAY_V (ra) =
197 scm_make_generalized_vector (type, scm_from_size_t (rlen), fill);
a3a32939 198
04b87de5 199 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 200 if (0 == s->lbnd)
04b87de5 201 return SCM_I_ARRAY_V (ra);
2bee653a 202
0f2d19dd
JB
203 return ra;
204}
1bbd0b84 205#undef FUNC_NAME
0f2d19dd 206
782a82ee
AW
207SCM
208scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
209 size_t byte_len)
210#define FUNC_NAME "scm_from_contiguous_typed_array"
211{
212 size_t k, rlen = 1;
213 scm_t_array_dim *s;
782a82ee
AW
214 SCM ra;
215 scm_t_array_handle h;
f5a51cae 216 void *elts;
782a82ee
AW
217 size_t sz;
218
782a82ee
AW
219 ra = scm_i_shap2ra (bounds);
220 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
221 s = SCM_I_ARRAY_DIMS (ra);
222 k = SCM_I_ARRAY_NDIM (ra);
223
224 while (k--)
225 {
226 s[k].inc = rlen;
227 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
228 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
229 }
943a0a87
AW
230 SCM_I_ARRAY_V (ra) =
231 scm_make_generalized_vector (type, scm_from_size_t (rlen), SCM_UNDEFINED);
782a82ee
AW
232
233
234 scm_array_get_handle (ra, &h);
f5a51cae
AW
235 elts = h.writable_elements;
236 sz = scm_array_handle_uniform_element_bit_size (&h);
782a82ee
AW
237 scm_array_handle_release (&h);
238
f5a51cae
AW
239 if (sz >= 8 && ((sz % 8) == 0))
240 {
241 if (byte_len % (sz / 8))
242 SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
243 if (byte_len / (sz / 8) != rlen)
244 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
245 }
b0fae4ec 246 else if (sz < 8)
f5a51cae 247 {
d65514a2
AW
248 /* Elements of sub-byte size (bitvectors) are addressed in 32-bit
249 units. */
250 if (byte_len != ((rlen * sz + 31) / 32) * 4)
f5a51cae
AW
251 SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
252 }
b0fae4ec
AW
253 else
254 /* an internal guile error, really */
255 SCM_MISC_ERROR ("uniform elements larger than 8 bits must fill whole bytes", SCM_EOL);
782a82ee 256
f5a51cae 257 memcpy (elts, bytes, byte_len);
782a82ee
AW
258
259 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 260 if (0 == s->lbnd)
782a82ee
AW
261 return SCM_I_ARRAY_V (ra);
262 return ra;
263}
264#undef FUNC_NAME
265
73788ca8
AW
266SCM
267scm_from_contiguous_array (SCM bounds, const SCM *elts, size_t len)
268#define FUNC_NAME "scm_from_contiguous_array"
269{
270 size_t k, rlen = 1;
271 scm_t_array_dim *s;
272 SCM ra;
273 scm_t_array_handle h;
274
275 ra = scm_i_shap2ra (bounds);
276 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
277 s = SCM_I_ARRAY_DIMS (ra);
278 k = SCM_I_ARRAY_NDIM (ra);
279
280 while (k--)
281 {
282 s[k].inc = rlen;
283 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
284 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
285 }
286 if (rlen != len)
287 SCM_MISC_ERROR ("element length and dimensions do not match", SCM_EOL);
288
289 SCM_I_ARRAY_V (ra) = scm_c_make_vector (rlen, SCM_UNDEFINED);
290 scm_array_get_handle (ra, &h);
291 memcpy (h.writable_elements, elts, rlen * sizeof(SCM));
292 scm_array_handle_release (&h);
293
294 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
2bee653a 295 if (0 == s->lbnd)
73788ca8
AW
296 return SCM_I_ARRAY_V (ra);
297 return ra;
298}
299#undef FUNC_NAME
300
f301dbf3
MV
301SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
302 (SCM fill, SCM bounds),
303 "Create and return an array.")
304#define FUNC_NAME s_scm_make_array
305{
306 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
307}
308#undef FUNC_NAME
309
0cd6cb2f
MV
310static void
311scm_i_ra_set_contp (SCM ra)
0f2d19dd 312{
04b87de5 313 size_t k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd 314 if (k)
0f2d19dd 315 {
04b87de5 316 long inc = SCM_I_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 317 while (k--)
0f2d19dd 318 {
04b87de5 319 if (inc != SCM_I_ARRAY_DIMS (ra)[k].inc)
fe0c6dae 320 {
e038c042 321 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
322 return;
323 }
04b87de5
MV
324 inc *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
325 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 326 }
0f2d19dd 327 }
e038c042 328 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
329}
330
331
3b3b36dd 332SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 333 (SCM oldra, SCM mapfunc, SCM dims),
b7e64f8b
BT
334 "@code{make-shared-array} can be used to create shared subarrays\n"
335 "of other arrays. The @var{mapfunc} is a function that\n"
336 "translates coordinates in the new array into coordinates in the\n"
337 "old array. A @var{mapfunc} must be linear, and its range must\n"
338 "stay within the bounds of the old array, but it can be\n"
339 "otherwise arbitrary. A simple example:\n"
1e6808ea 340 "@lisp\n"
b380b885
MD
341 "(define fred (make-array #f 8 8))\n"
342 "(define freds-diagonal\n"
343 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
344 "(array-set! freds-diagonal 'foo 3)\n"
345 "(array-ref fred 3 3) @result{} foo\n"
346 "(define freds-center\n"
347 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
348 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 349 "@end lisp")
1bbd0b84 350#define FUNC_NAME s_scm_make_shared_array
0f2d19dd 351{
112ba0ac 352 scm_t_array_handle old_handle;
0f2d19dd
JB
353 SCM ra;
354 SCM inds, indptr;
355 SCM imap;
112ba0ac
MV
356 size_t k;
357 ssize_t i;
2b829bbb 358 long old_base, old_min, new_min, old_max, new_max;
92c2555f 359 scm_t_array_dim *s;
b3fcac34
DH
360
361 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6 362 SCM_VALIDATE_PROC (2, mapfunc);
0cd6cb2f 363 ra = scm_i_shap2ra (dims);
112ba0ac
MV
364
365 scm_array_get_handle (oldra, &old_handle);
366
04b87de5 367 if (SCM_I_ARRAYP (oldra))
0f2d19dd 368 {
04b87de5 369 SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
2b829bbb 370 old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
112ba0ac
MV
371 s = scm_array_handle_dims (&old_handle);
372 k = scm_array_handle_rank (&old_handle);
0f2d19dd
JB
373 while (k--)
374 {
375 if (s[k].inc > 0)
376 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
377 else
378 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
379 }
380 }
381 else
382 {
04b87de5 383 SCM_I_ARRAY_V (ra) = oldra;
2b829bbb 384 old_base = old_min = 0;
9da9c22f 385 old_max = scm_c_array_length (oldra) - 1;
0f2d19dd 386 }
112ba0ac 387
0f2d19dd 388 inds = SCM_EOL;
04b87de5
MV
389 s = SCM_I_ARRAY_DIMS (ra);
390 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 391 {
e11e83f3 392 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
393 if (s[k].ubnd < s[k].lbnd)
394 {
04b87de5 395 if (1 == SCM_I_ARRAY_NDIM (ra))
943a0a87
AW
396 ra = scm_make_generalized_vector (scm_array_type (ra),
397 SCM_INUM0, SCM_UNDEFINED);
0f2d19dd 398 else
943a0a87
AW
399 SCM_I_ARRAY_V (ra) =
400 scm_make_generalized_vector (scm_array_type (ra),
401 SCM_INUM0, SCM_UNDEFINED);
112ba0ac 402 scm_array_handle_release (&old_handle);
0f2d19dd
JB
403 return ra;
404 }
405 }
112ba0ac 406
fdc28395 407 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 408 i = scm_array_handle_pos (&old_handle, imap);
2b829bbb 409 SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
0f2d19dd 410 indptr = inds;
04b87de5 411 k = SCM_I_ARRAY_NDIM (ra);
0f2d19dd
JB
412 while (k--)
413 {
414 if (s[k].ubnd > s[k].lbnd)
415 {
e11e83f3 416 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 417 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0cd6cb2f 418 s[k].inc = scm_array_handle_pos (&old_handle, imap) - i;
0f2d19dd
JB
419 i += s[k].inc;
420 if (s[k].inc > 0)
421 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
422 else
423 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
424 }
425 else
426 s[k].inc = new_max - new_min + 1; /* contiguous by default */
427 indptr = SCM_CDR (indptr);
428 }
112ba0ac
MV
429
430 scm_array_handle_release (&old_handle);
431
b3fcac34
DH
432 if (old_min > new_min || old_max < new_max)
433 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
04b87de5 434 if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
0f2d19dd 435 {
04b87de5 436 SCM v = SCM_I_ARRAY_V (ra);
9da9c22f 437 size_t length = scm_c_array_length (v);
74014c46
DH
438 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
439 return v;
0f2d19dd 440 if (s->ubnd < s->lbnd)
943a0a87
AW
441 return scm_make_generalized_vector (scm_array_type (ra), SCM_INUM0,
442 SCM_UNDEFINED);
0f2d19dd 443 }
0cd6cb2f 444 scm_i_ra_set_contp (ra);
0f2d19dd
JB
445 return ra;
446}
1bbd0b84 447#undef FUNC_NAME
0f2d19dd
JB
448
449
450/* args are RA . DIMS */
af45e3b0
DH
451SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
452 (SCM ra, SCM args),
b7e64f8b 453 "Return an array sharing contents with @var{ra}, but with\n"
1e6808ea 454 "dimensions arranged in a different order. There must be one\n"
b7e64f8b 455 "@var{dim} argument for each dimension of @var{ra}.\n"
1e6808ea
MG
456 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
457 "and the rank of the array to be returned. Each integer in that\n"
458 "range must appear at least once in the argument list.\n"
459 "\n"
460 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
461 "dimensions in the array to be returned, their positions in the\n"
b7e64f8b 462 "argument list to dimensions of @var{ra}. Several @var{dim}s\n"
1e6808ea 463 "may have the same value, in which case the returned array will\n"
b7e64f8b 464 "have smaller rank than @var{ra}.\n"
1e6808ea
MG
465 "\n"
466 "@lisp\n"
b380b885
MD
467 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
468 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
469 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
470 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 471 "@end lisp")
1bbd0b84 472#define FUNC_NAME s_scm_transpose_array
0f2d19dd 473{
34d19ef6 474 SCM res, vargs;
92c2555f 475 scm_t_array_dim *s, *r;
0f2d19dd 476 int ndim, i, k;
af45e3b0 477
b3fcac34 478 SCM_VALIDATE_REST_ARGUMENT (args);
8c5bb729 479 SCM_ASSERT (SCM_HEAP_OBJECT_P (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 480
a6f8d3dd 481 switch (scm_c_array_rank (ra))
e0e49670 482 {
a6f8d3dd
DL
483 case 0:
484 if (!scm_is_null (args))
485 SCM_WRONG_NUM_ARGS ();
486 return ra;
487 case 1:
e0e49670 488 /* Make sure that we are called with a single zero as
a6f8d3dd 489 arguments.
e0e49670
MV
490 */
491 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
492 SCM_WRONG_NUM_ARGS ();
493 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
494 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
495 return ra;
a6f8d3dd 496 default:
0f2d19dd 497 vargs = scm_vector (args);
04b87de5 498 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_I_ARRAY_NDIM (ra))
b3fcac34 499 SCM_WRONG_NUM_ARGS ();
0f2d19dd 500 ndim = 0;
04b87de5 501 for (k = 0; k < SCM_I_ARRAY_NDIM (ra); k++)
0f2d19dd 502 {
6e708ef2 503 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
04b87de5 504 0, SCM_I_ARRAY_NDIM(ra));
0f2d19dd
JB
505 if (ndim < i)
506 ndim = i;
507 }
508 ndim++;
66b9d7d3 509 res = scm_i_make_array (ndim);
04b87de5
MV
510 SCM_I_ARRAY_V (res) = SCM_I_ARRAY_V (ra);
511 SCM_I_ARRAY_BASE (res) = SCM_I_ARRAY_BASE (ra);
0f2d19dd
JB
512 for (k = ndim; k--;)
513 {
04b87de5
MV
514 SCM_I_ARRAY_DIMS (res)[k].lbnd = 0;
515 SCM_I_ARRAY_DIMS (res)[k].ubnd = -1;
0f2d19dd 516 }
04b87de5 517 for (k = SCM_I_ARRAY_NDIM (ra); k--;)
0f2d19dd 518 {
6e708ef2 519 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
04b87de5
MV
520 s = &(SCM_I_ARRAY_DIMS (ra)[k]);
521 r = &(SCM_I_ARRAY_DIMS (res)[i]);
0f2d19dd
JB
522 if (r->ubnd < r->lbnd)
523 {
524 r->lbnd = s->lbnd;
525 r->ubnd = s->ubnd;
526 r->inc = s->inc;
527 ndim--;
528 }
529 else
530 {
531 if (r->ubnd > s->ubnd)
532 r->ubnd = s->ubnd;
533 if (r->lbnd < s->lbnd)
534 {
04b87de5 535 SCM_I_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
0f2d19dd
JB
536 r->lbnd = s->lbnd;
537 }
538 r->inc += s->inc;
539 }
540 }
b3fcac34
DH
541 if (ndim > 0)
542 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0cd6cb2f 543 scm_i_ra_set_contp (res);
0f2d19dd
JB
544 return res;
545 }
546}
1bbd0b84 547#undef FUNC_NAME
0f2d19dd 548
1d7bdb25
GH
549/* attempts to unroll an array into a one-dimensional array.
550 returns the unrolled array or #f if it can't be done. */
1bbd0b84 551 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 552 wouldn't have contiguous elements. */
3b3b36dd 553SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 554 (SCM ra, SCM strict),
b7e64f8b
BT
555 "If @var{ra} may be @dfn{unrolled} into a one dimensional shared\n"
556 "array without changing their order (last subscript changing\n"
557 "fastest), then @code{array-contents} returns that shared array,\n"
558 "otherwise it returns @code{#f}. All arrays made by\n"
559 "@code{make-array} and @code{make-uniform-array} may be unrolled,\n"
560 "some arrays made by @code{make-shared-array} may not be. If\n"
561 "the optional argument @var{strict} is provided, a shared array\n"
562 "will be returned only if its elements are stored internally\n"
563 "contiguous in memory.")
1bbd0b84 564#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
565{
566 SCM sra;
e0e49670 567
20930f28 568 if (scm_is_generalized_vector (ra))
e0e49670
MV
569 return ra;
570
04b87de5 571 if (SCM_I_ARRAYP (ra))
0f2d19dd 572 {
04b87de5
MV
573 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
574 if (!SCM_I_ARRAYP (ra) || !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
20930f28 591 {
04b87de5 592 SCM v = SCM_I_ARRAY_V (ra);
9da9c22f 593 size_t length = scm_c_array_length (v);
04b87de5 594 if ((len == length) && 0 == SCM_I_ARRAY_BASE (ra) && SCM_I_ARRAY_DIMS (ra)->inc)
20930f28 595 return v;
0f2d19dd 596 }
9da9c22f 597
66b9d7d3 598 sra = scm_i_make_array (1);
04b87de5
MV
599 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
600 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
601 SCM_I_ARRAY_V (sra) = SCM_I_ARRAY_V (ra);
602 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
603 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
20930f28 604 return sra;
0f2d19dd 605 }
02339e5b
MV
606 else
607 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 608}
1bbd0b84 609#undef FUNC_NAME
0f2d19dd 610
1cc91f1b 611
943a0a87
AW
612static void
613list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
614{
615 if (k == scm_array_handle_rank (handle))
616 scm_array_handle_set (handle, pos, lst);
617 else
618 {
619 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
620 ssize_t inc = dim->inc;
621 size_t len = 1 + dim->ubnd - dim->lbnd, n;
622 char *errmsg = NULL;
623
624 n = len;
625 while (n > 0 && scm_is_pair (lst))
626 {
627 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
628 pos += inc;
629 lst = SCM_CDR (lst);
630 n -= 1;
631 }
632 if (n != 0)
633 errmsg = "too few elements for array dimension ~a, need ~a";
634 if (!scm_is_null (lst))
635 errmsg = "too many elements for array dimension ~a, want ~a";
636 if (errmsg)
637 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
638 scm_from_size_t (len)));
639 }
640}
641
1cc91f1b 642
f301dbf3 643SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 644 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
645 "Return an array of the type @var{type}\n"
646 "with elements the same as those of @var{lst}.\n"
bfad4005 647 "\n"
2caaadd1
MV
648 "The argument @var{shape} determines the number of dimensions\n"
649 "of the array and their shape. It is either an exact integer,\n"
650 "giving the\n"
651 "number of dimensions directly, or a list whose length\n"
652 "specifies the number of dimensions and each element specified\n"
653 "the lower and optionally the upper bound of the corresponding\n"
654 "dimension.\n"
655 "When the element is list of two elements, these elements\n"
656 "give the lower and upper bounds. When it is an exact\n"
657 "integer, it gives only the lower bound.")
f301dbf3 658#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 659{
2caaadd1 660 SCM row;
0f2d19dd 661 SCM ra;
bcbbea0e 662 scm_t_array_handle handle;
bfad4005 663
bfad4005 664 row = lst;
2caaadd1 665 if (scm_is_integer (shape))
0f2d19dd 666 {
2caaadd1
MV
667 size_t k = scm_to_size_t (shape);
668 shape = SCM_EOL;
bfad4005
MV
669 while (k-- > 0)
670 {
671 shape = scm_cons (scm_length (row), shape);
2caaadd1 672 if (k > 0 && !scm_is_null (row))
bfad4005
MV
673 row = scm_car (row);
674 }
675 }
676 else
677 {
2caaadd1
MV
678 SCM shape_spec = shape;
679 shape = SCM_EOL;
bfad4005
MV
680 while (1)
681 {
2caaadd1
MV
682 SCM spec = scm_car (shape_spec);
683 if (scm_is_pair (spec))
684 shape = scm_cons (spec, shape);
685 else
686 shape = scm_cons (scm_list_2 (spec,
687 scm_sum (scm_sum (spec,
688 scm_length (row)),
689 scm_from_int (-1))),
690 shape);
691 shape_spec = scm_cdr (shape_spec);
692 if (scm_is_pair (shape_spec))
693 {
694 if (!scm_is_null (row))
695 row = scm_car (row);
696 }
bfad4005
MV
697 else
698 break;
699 }
0f2d19dd 700 }
bfad4005 701
f0b91039
MV
702 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
703 scm_reverse_x (shape, SCM_EOL));
20930f28 704
bcbbea0e 705 scm_array_get_handle (ra, &handle);
943a0a87 706 list_to_array (lst, &handle, 0, 0);
bcbbea0e
MV
707 scm_array_handle_release (&handle);
708
709 return ra;
0f2d19dd 710}
1bbd0b84 711#undef FUNC_NAME
0f2d19dd 712
f301dbf3
MV
713SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
714 (SCM ndim, SCM lst),
715 "Return an array with elements the same as those of @var{lst}.")
716#define FUNC_NAME s_scm_list_to_array
717{
718 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
719}
720#undef FUNC_NAME
721
e0e49670
MV
722/* Print dimension DIM of ARRAY.
723 */
0f2d19dd 724
e0e49670 725static int
943a0a87 726scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
e0e49670
MV
727 SCM port, scm_print_state *pstate)
728{
943a0a87
AW
729 if (dim == h->ndims)
730 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
731 else
e0e49670 732 {
943a0a87 733 ssize_t i;
0607ebbf 734 scm_putc_unlocked ('(', port);
943a0a87
AW
735 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
736 i++, pos += h->dims[dim].inc)
737 {
738 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
739 if (i < h->dims[dim].ubnd)
0607ebbf 740 scm_putc_unlocked (' ', port);
943a0a87 741 }
0607ebbf 742 scm_putc_unlocked (')', port);
e0e49670 743 }
e0e49670
MV
744 return 1;
745}
746
943a0a87 747/* Print an array.
e0e49670
MV
748*/
749
b2637c98 750int
e0e49670
MV
751scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
752{
943a0a87 753 scm_t_array_handle h;
e0e49670 754 long i;
2caaadd1 755 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670 756
943a0a87
AW
757 scm_array_get_handle (array, &h);
758
0607ebbf 759 scm_putc_unlocked ('#', port);
943a0a87
AW
760 if (h.ndims != 1 || h.dims[0].lbnd != 0)
761 scm_intprint (h.ndims, 10, port);
762 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
763 scm_write (scm_array_handle_element_type (&h), port);
20930f28 764
943a0a87 765 for (i = 0; i < h.ndims; i++)
2caaadd1 766 {
943a0a87 767 if (h.dims[i].lbnd != 0)
2caaadd1 768 print_lbnds = 1;
943a0a87 769 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
2caaadd1
MV
770 zero_size = 1;
771 else if (zero_size)
772 print_lens = 1;
773 }
774
775 if (print_lbnds || print_lens)
943a0a87 776 for (i = 0; i < h.ndims; i++)
e0e49670 777 {
2caaadd1 778 if (print_lbnds)
e0e49670 779 {
0607ebbf 780 scm_putc_unlocked ('@', port);
943a0a87 781 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
782 }
783 if (print_lens)
784 {
0607ebbf 785 scm_putc_unlocked (':', port);
943a0a87 786 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
2caaadd1 787 10, port);
e0e49670 788 }
e0e49670
MV
789 }
790
943a0a87 791 if (h.ndims == 0)
5f37cb63
MV
792 {
793 /* Rank zero arrays, which are really just scalars, are printed
794 specially. The consequent way would be to print them as
795
796 #0 OBJ
797
798 where OBJ is the printed representation of the scalar, but we
799 print them instead as
800
801 #0(OBJ)
802
803 to make them look less strange.
804
805 Just printing them as
806
807 OBJ
808
809 would be correct in a way as well, but zero rank arrays are
810 not really the same as Scheme values since they are boxed and
811 can be modified with array-set!, say.
812 */
0607ebbf 813 scm_putc_unlocked ('(', port);
943a0a87 814 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
0607ebbf 815 scm_putc_unlocked (')', port);
5f37cb63
MV
816 return 1;
817 }
818 else
943a0a87 819 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 820}
1cc91f1b 821
0f2d19dd 822void
2fa901a5 823scm_init_arrays ()
0f2d19dd 824{
0f2d19dd 825 scm_add_feature ("array");
20930f28 826
2fa901a5 827#include "libguile/arrays.x"
bfad4005 828
0f2d19dd 829}
89e00824
ML
830
831/*
832 Local Variables:
833 c-file-style: "gnu"
834 End:
835*/