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