Don't use ASET in scm_array_index_map_x
[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. */
35f45ed6
DL
551/* if strict is true, return #f if returned array
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 565{
c545f716
DL
566 if (!scm_is_array (ra))
567 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
568 else if (SCM_I_ARRAYP (ra))
0f2d19dd 569 {
c545f716 570 SCM v;
04b87de5 571 size_t k, ndim = SCM_I_ARRAY_NDIM (ra), len = 1;
c545f716 572 if (!SCM_I_ARRAY_CONTP (ra))
20930f28
MV
573 return SCM_BOOL_F;
574 for (k = 0; k < ndim; k++)
04b87de5 575 len *= SCM_I_ARRAY_DIMS (ra)[k].ubnd - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1;
943a0a87 576 if (!SCM_UNBNDP (strict) && scm_is_true (strict))
74014c46 577 {
04b87de5 578 if (ndim && (1 != SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc))
20930f28 579 return SCM_BOOL_F;
04b87de5 580 if (scm_is_bitvector (SCM_I_ARRAY_V (ra)))
20930f28 581 {
04b87de5
MV
582 if (len != scm_c_bitvector_length (SCM_I_ARRAY_V (ra)) ||
583 SCM_I_ARRAY_BASE (ra) % SCM_LONG_BIT ||
20930f28
MV
584 len % SCM_LONG_BIT)
585 return SCM_BOOL_F;
586 }
74014c46 587 }
9da9c22f 588
c545f716
DL
589 v = SCM_I_ARRAY_V (ra);
590 if ((len == scm_c_array_length (v)) && (0 == SCM_I_ARRAY_BASE (ra))
591 && SCM_I_ARRAY_DIMS (ra)->inc)
592 return v;
593 else
594 {
595 SCM sra = scm_i_make_array (1);
596 SCM_I_ARRAY_DIMS (sra)->lbnd = 0;
597 SCM_I_ARRAY_DIMS (sra)->ubnd = len - 1;
598 SCM_I_ARRAY_V (sra) = v;
599 SCM_I_ARRAY_BASE (sra) = SCM_I_ARRAY_BASE (ra);
600 SCM_I_ARRAY_DIMS (sra)->inc = (ndim ? SCM_I_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
601 return sra;
602 }
0f2d19dd 603 }
02339e5b 604 else
c545f716 605 return ra;
0f2d19dd 606}
1bbd0b84 607#undef FUNC_NAME
0f2d19dd 608
1cc91f1b 609
943a0a87
AW
610static void
611list_to_array (SCM lst, scm_t_array_handle *handle, ssize_t pos, size_t k)
612{
613 if (k == scm_array_handle_rank (handle))
614 scm_array_handle_set (handle, pos, lst);
615 else
616 {
617 scm_t_array_dim *dim = scm_array_handle_dims (handle) + k;
618 ssize_t inc = dim->inc;
619 size_t len = 1 + dim->ubnd - dim->lbnd, n;
620 char *errmsg = NULL;
621
622 n = len;
623 while (n > 0 && scm_is_pair (lst))
624 {
625 list_to_array (SCM_CAR (lst), handle, pos, k + 1);
626 pos += inc;
627 lst = SCM_CDR (lst);
628 n -= 1;
629 }
630 if (n != 0)
631 errmsg = "too few elements for array dimension ~a, need ~a";
632 if (!scm_is_null (lst))
633 errmsg = "too many elements for array dimension ~a, want ~a";
634 if (errmsg)
635 scm_misc_error (NULL, errmsg, scm_list_2 (scm_from_ulong (k),
636 scm_from_size_t (len)));
637 }
638}
639
1cc91f1b 640
f301dbf3 641SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2caaadd1 642 (SCM type, SCM shape, SCM lst),
f301dbf3
MV
643 "Return an array of the type @var{type}\n"
644 "with elements the same as those of @var{lst}.\n"
bfad4005 645 "\n"
2caaadd1
MV
646 "The argument @var{shape} determines the number of dimensions\n"
647 "of the array and their shape. It is either an exact integer,\n"
648 "giving the\n"
649 "number of dimensions directly, or a list whose length\n"
650 "specifies the number of dimensions and each element specified\n"
651 "the lower and optionally the upper bound of the corresponding\n"
652 "dimension.\n"
653 "When the element is list of two elements, these elements\n"
654 "give the lower and upper bounds. When it is an exact\n"
655 "integer, it gives only the lower bound.")
f301dbf3 656#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 657{
2caaadd1 658 SCM row;
0f2d19dd 659 SCM ra;
bcbbea0e 660 scm_t_array_handle handle;
bfad4005 661
bfad4005 662 row = lst;
2caaadd1 663 if (scm_is_integer (shape))
0f2d19dd 664 {
2caaadd1
MV
665 size_t k = scm_to_size_t (shape);
666 shape = SCM_EOL;
bfad4005
MV
667 while (k-- > 0)
668 {
669 shape = scm_cons (scm_length (row), shape);
2caaadd1 670 if (k > 0 && !scm_is_null (row))
bfad4005
MV
671 row = scm_car (row);
672 }
673 }
674 else
675 {
2caaadd1
MV
676 SCM shape_spec = shape;
677 shape = SCM_EOL;
bfad4005
MV
678 while (1)
679 {
2caaadd1
MV
680 SCM spec = scm_car (shape_spec);
681 if (scm_is_pair (spec))
682 shape = scm_cons (spec, shape);
683 else
684 shape = scm_cons (scm_list_2 (spec,
685 scm_sum (scm_sum (spec,
686 scm_length (row)),
687 scm_from_int (-1))),
688 shape);
689 shape_spec = scm_cdr (shape_spec);
690 if (scm_is_pair (shape_spec))
691 {
692 if (!scm_is_null (row))
693 row = scm_car (row);
694 }
bfad4005
MV
695 else
696 break;
697 }
0f2d19dd 698 }
bfad4005 699
f0b91039
MV
700 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
701 scm_reverse_x (shape, SCM_EOL));
20930f28 702
bcbbea0e 703 scm_array_get_handle (ra, &handle);
943a0a87 704 list_to_array (lst, &handle, 0, 0);
bcbbea0e
MV
705 scm_array_handle_release (&handle);
706
707 return ra;
0f2d19dd 708}
1bbd0b84 709#undef FUNC_NAME
0f2d19dd 710
f301dbf3
MV
711SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
712 (SCM ndim, SCM lst),
713 "Return an array with elements the same as those of @var{lst}.")
714#define FUNC_NAME s_scm_list_to_array
715{
716 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
717}
718#undef FUNC_NAME
719
e0e49670
MV
720/* Print dimension DIM of ARRAY.
721 */
0f2d19dd 722
e0e49670 723static int
943a0a87 724scm_i_print_array_dimension (scm_t_array_handle *h, int dim, int pos,
e0e49670
MV
725 SCM port, scm_print_state *pstate)
726{
943a0a87
AW
727 if (dim == h->ndims)
728 scm_iprin1 (scm_array_handle_ref (h, pos), port, pstate);
729 else
e0e49670 730 {
943a0a87 731 ssize_t i;
0607ebbf 732 scm_putc_unlocked ('(', port);
943a0a87
AW
733 for (i = h->dims[dim].lbnd; i <= h->dims[dim].ubnd;
734 i++, pos += h->dims[dim].inc)
735 {
736 scm_i_print_array_dimension (h, dim+1, pos, port, pstate);
737 if (i < h->dims[dim].ubnd)
0607ebbf 738 scm_putc_unlocked (' ', port);
943a0a87 739 }
0607ebbf 740 scm_putc_unlocked (')', port);
e0e49670 741 }
e0e49670
MV
742 return 1;
743}
744
943a0a87 745/* Print an array.
e0e49670
MV
746*/
747
b2637c98 748int
e0e49670
MV
749scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
750{
943a0a87 751 scm_t_array_handle h;
e0e49670 752 long i;
2caaadd1 753 int print_lbnds = 0, zero_size = 0, print_lens = 0;
e0e49670 754
943a0a87
AW
755 scm_array_get_handle (array, &h);
756
0607ebbf 757 scm_putc_unlocked ('#', port);
943a0a87
AW
758 if (h.ndims != 1 || h.dims[0].lbnd != 0)
759 scm_intprint (h.ndims, 10, port);
760 if (h.element_type != SCM_ARRAY_ELEMENT_TYPE_SCM)
761 scm_write (scm_array_handle_element_type (&h), port);
20930f28 762
943a0a87 763 for (i = 0; i < h.ndims; i++)
2caaadd1 764 {
943a0a87 765 if (h.dims[i].lbnd != 0)
2caaadd1 766 print_lbnds = 1;
943a0a87 767 if (h.dims[i].ubnd - h.dims[i].lbnd + 1 == 0)
2caaadd1
MV
768 zero_size = 1;
769 else if (zero_size)
770 print_lens = 1;
771 }
772
773 if (print_lbnds || print_lens)
943a0a87 774 for (i = 0; i < h.ndims; i++)
e0e49670 775 {
2caaadd1 776 if (print_lbnds)
e0e49670 777 {
0607ebbf 778 scm_putc_unlocked ('@', port);
943a0a87 779 scm_intprint (h.dims[i].lbnd, 10, port);
2caaadd1
MV
780 }
781 if (print_lens)
782 {
0607ebbf 783 scm_putc_unlocked (':', port);
943a0a87 784 scm_intprint (h.dims[i].ubnd - h.dims[i].lbnd + 1,
2caaadd1 785 10, port);
e0e49670 786 }
e0e49670
MV
787 }
788
943a0a87 789 if (h.ndims == 0)
5f37cb63
MV
790 {
791 /* Rank zero arrays, which are really just scalars, are printed
792 specially. The consequent way would be to print them as
793
794 #0 OBJ
795
796 where OBJ is the printed representation of the scalar, but we
797 print them instead as
798
799 #0(OBJ)
800
801 to make them look less strange.
802
803 Just printing them as
804
805 OBJ
806
807 would be correct in a way as well, but zero rank arrays are
808 not really the same as Scheme values since they are boxed and
809 can be modified with array-set!, say.
810 */
0607ebbf 811 scm_putc_unlocked ('(', port);
943a0a87 812 scm_i_print_array_dimension (&h, 0, 0, port, pstate);
0607ebbf 813 scm_putc_unlocked (')', port);
5f37cb63
MV
814 return 1;
815 }
816 else
943a0a87 817 return scm_i_print_array_dimension (&h, 0, 0, port, pstate);
e0e49670 818}
1cc91f1b 819
0f2d19dd 820void
2fa901a5 821scm_init_arrays ()
0f2d19dd 822{
0f2d19dd 823 scm_add_feature ("array");
20930f28 824
2fa901a5 825#include "libguile/arrays.x"
bfad4005 826
0f2d19dd 827}
89e00824
ML
828
829/*
830 Local Variables:
831 c-file-style: "gnu"
832 End:
833*/