*** empty log message ***
[bpt/guile.git] / libguile / unif.c
CommitLineData
18e2aba3 1/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
c209c88e
GB
19/*
20 This file has code for arrays in lots of variants (double, integer,
21 unsigned etc. ). It suffers from hugely repetitive code because
22 there is similar (but different) code for every variant included. (urg.)
23
24 --hwn
25*/
0f2d19dd
JB
26\f
27
2a5cd898
RB
28#if HAVE_CONFIG_H
29# include <config.h>
30#endif
31
0f2d19dd 32#include <stdio.h>
e6e2e95a 33#include <errno.h>
783e7774 34#include <string.h>
e6e2e95a 35
a0599745 36#include "libguile/_scm.h"
e0e49670
MV
37#include "libguile/__scm.h"
38#include "libguile/eq.h"
a0599745
MD
39#include "libguile/chars.h"
40#include "libguile/eval.h"
41#include "libguile/fports.h"
42#include "libguile/smob.h"
a0599745
MD
43#include "libguile/feature.h"
44#include "libguile/root.h"
45#include "libguile/strings.h"
c44ca4fe 46#include "libguile/srfi-13.h"
e0e49670 47#include "libguile/srfi-4.h"
a0599745 48#include "libguile/vectors.h"
bfad4005
MV
49#include "libguile/list.h"
50#include "libguile/deprecation.h"
d44ff083 51#include "libguile/dynwind.h"
a0599745
MD
52
53#include "libguile/validate.h"
54#include "libguile/unif.h"
55#include "libguile/ramap.h"
f27d2057 56#include "libguile/print.h"
bfad4005 57#include "libguile/read.h"
0f2d19dd 58
3d8d56df
GH
59#ifdef HAVE_UNISTD_H
60#include <unistd.h>
61#endif
62
7beabedb
MG
63#ifdef HAVE_IO_H
64#include <io.h>
65#endif
66
0f2d19dd
JB
67\f
68/* The set of uniform scm_vector types is:
e0e49670 69 * Vector of: Called: Replaced by:
bfad4005 70 * unsigned char string
85368844 71 * char byvect s8 or u8, depending on signedness of 'char'
e0e49670
MV
72 * boolean bvect
73 * signed long ivect s32
74 * unsigned long uvect u32
75 * float fvect f32
76 * double dvect d32
85368844 77 * complex double cvect c64
e0e49670
MV
78 * short svect s16
79 * long long llvect s64
0f2d19dd
JB
80 */
81
92c2555f 82scm_t_bits scm_tc16_array;
02339e5b 83scm_t_bits scm_tc16_enclosed_array;
1cc91f1b 84
f301dbf3
MV
85typedef SCM creator_proc (SCM len, SCM fill);
86
87struct {
88 char *type_name;
89 SCM type;
90 creator_proc *creator;
91} type_creator_table[] = {
92 { "a", SCM_UNSPECIFIED, scm_make_string },
93 { "b", SCM_UNSPECIFIED, scm_make_bitvector },
94 { "u8", SCM_UNSPECIFIED, scm_make_u8vector },
95 { "s8", SCM_UNSPECIFIED, scm_make_s8vector },
96 { "u16", SCM_UNSPECIFIED, scm_make_u16vector },
97 { "s16", SCM_UNSPECIFIED, scm_make_s16vector },
98 { "u32", SCM_UNSPECIFIED, scm_make_u32vector },
99 { "s32", SCM_UNSPECIFIED, scm_make_s32vector },
100 { "u64", SCM_UNSPECIFIED, scm_make_u64vector },
101 { "s64", SCM_UNSPECIFIED, scm_make_s64vector },
102 { "f32", SCM_UNSPECIFIED, scm_make_f32vector },
103 { "f64", SCM_UNSPECIFIED, scm_make_f64vector },
104 { "c32", SCM_UNSPECIFIED, scm_make_c32vector },
105 { "c64", SCM_UNSPECIFIED, scm_make_c64vector },
106 { NULL }
107};
108
109static void
110init_type_creator_table ()
111{
112 int i;
113 for (i = 0; type_creator_table[i].type_name; i++)
114 {
115 SCM sym = scm_from_locale_symbol (type_creator_table[i].type_name);
116 type_creator_table[i].type = scm_permanent_object (sym);
117 }
118}
119
120static creator_proc *
121type_to_creator (SCM type)
122{
123 int i;
124
125 if (scm_is_eq (type, SCM_BOOL_T))
126 return scm_make_vector;
127 for (i = 0; type_creator_table[i].type_name; i++)
128 if (scm_is_eq (type, type_creator_table[i].type))
129 return type_creator_table[i].creator;
130
131 scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (type));
132}
133
134static SCM
135make_typed_vector (SCM type, size_t len)
136{
137 creator_proc *creator = type_to_creator (type);
138 return creator (scm_from_size_t (len), SCM_UNDEFINED);
139}
bfad4005
MV
140
141#if SCM_ENABLE_DEPRECATED
142
143SCM_SYMBOL (scm_sym_s, "s");
144SCM_SYMBOL (scm_sym_l, "l");
145
711a9fd7 146static SCM
f301dbf3 147prototype_to_type (SCM proto)
711a9fd7 148{
f301dbf3 149 const char *type_name;
bfad4005
MV
150
151 if (scm_is_eq (proto, SCM_BOOL_T))
f301dbf3 152 type_name = "b";
bfad4005 153 else if (scm_is_eq (proto, SCM_MAKE_CHAR ('a')))
f301dbf3 154 type_name = "a";
bfad4005 155 else if (scm_is_eq (proto, SCM_MAKE_CHAR (0)))
f301dbf3 156 type_name = "s8";
bfad4005 157 else if (scm_is_eq (proto, scm_sym_s))
f301dbf3 158 type_name = "s16";
bfad4005 159 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (1))))
f301dbf3 160 type_name = "u32";
bfad4005 161 else if (scm_is_true (scm_eqv_p (proto, scm_from_int (-1))))
f301dbf3 162 type_name = "s32";
bfad4005 163 else if (scm_is_eq (proto, scm_sym_l))
f301dbf3 164 type_name = "s64";
bfad4005 165 else if (scm_is_true (scm_eqv_p (proto, scm_from_double (1.0))))
f301dbf3 166 type_name = "f32";
bfad4005 167 else if (scm_is_true (scm_eqv_p (proto, scm_divide (scm_from_int (1),
f301dbf3
MV
168 scm_from_int (3)))))
169 type_name = "f64";
bfad4005 170 else if (scm_is_true (scm_eqv_p (proto, scm_c_make_rectangular (0, 1))))
f301dbf3 171 type_name = "c64";
bfad4005 172 else if (scm_is_null (proto))
f301dbf3 173 type_name = NULL;
bfad4005 174 else
f301dbf3 175 type_name = NULL;
711a9fd7 176
f301dbf3
MV
177 if (type_name)
178 return scm_from_locale_symbol (type_name);
179 else
180 return SCM_BOOL_T;
711a9fd7 181}
bfad4005 182
ab1be174
MV
183static SCM
184scm_i_get_old_prototype (SCM uvec)
185{
20930f28 186 if (scm_is_bitvector (uvec))
ab1be174
MV
187 return SCM_BOOL_T;
188 else if (scm_is_string (uvec))
189 return SCM_MAKE_CHAR ('a');
190 else if (scm_is_true (scm_s8vector_p (uvec)))
191 return SCM_MAKE_CHAR ('\0');
192 else if (scm_is_true (scm_s16vector_p (uvec)))
193 return scm_sym_s;
194 else if (scm_is_true (scm_u32vector_p (uvec)))
195 return scm_from_int (1);
196 else if (scm_is_true (scm_s32vector_p (uvec)))
197 return scm_from_int (-1);
198 else if (scm_is_true (scm_s64vector_p (uvec)))
199 return scm_sym_l;
200 else if (scm_is_true (scm_f32vector_p (uvec)))
201 return scm_from_double (1.0);
202 else if (scm_is_true (scm_f64vector_p (uvec)))
203 return scm_divide (scm_from_int (1), scm_from_int (3));
204 else if (scm_is_true (scm_c64vector_p (uvec)))
205 return scm_c_make_rectangular (0, 1);
20930f28 206 else if (scm_is_vector (uvec))
ab1be174
MV
207 return SCM_EOL;
208 else
03a5397a 209 scm_misc_error (NULL, "~a has no prototype", scm_list_1 (uvec));
ab1be174
MV
210}
211
0f2d19dd 212SCM
c014a02e 213scm_make_uve (long k, SCM prot)
a3a32939 214#define FUNC_NAME "scm_make_uve"
0f2d19dd 215{
f301dbf3
MV
216 scm_c_issue_deprecation_warning
217 ("`scm_make_uve' is deprecated, see the manual for alternatives.");
218
219 return make_typed_vector (prototype_to_type (prot), k);
0f2d19dd 220}
a3a32939
DH
221#undef FUNC_NAME
222
f301dbf3
MV
223#endif
224
225int
226scm_is_array (SCM obj)
0f2d19dd 227{
f301dbf3
MV
228 return (SCM_ENCLOSED_ARRAYP (obj)
229 || SCM_ARRAYP (obj)
230 || scm_is_generalized_vector (obj));
231}
232
233int
234scm_is_typed_array (SCM obj, SCM type)
235{
236 if (SCM_ENCLOSED_ARRAYP (obj))
0f2d19dd 237 {
f301dbf3 238 /* Enclosed arrays are arrays but are not of any type.
02339e5b 239 */
f301dbf3 240 return 0;
e0e49670
MV
241 }
242
02339e5b
MV
243 /* Get storage vector.
244 */
f301dbf3
MV
245 if (SCM_ARRAYP (obj))
246 obj = SCM_ARRAY_V (obj);
02339e5b 247
20930f28 248 /* It must be a generalized vector (which includes vectors, strings, etc).
bfad4005 249 */
f301dbf3
MV
250 if (!scm_is_generalized_vector (obj))
251 return 0;
9b0018a1 252
f301dbf3
MV
253 return scm_is_eq (type, scm_i_generalized_vector_type (obj));
254}
20930f28 255
6e708ef2
MV
256void
257scm_array_get_handle (SCM array, scm_t_array_handle *h)
258{
259 h->array = array;
260 if (SCM_ARRAYP (array) || SCM_ENCLOSED_ARRAYP (array))
261 {
262 h->dims = SCM_ARRAY_DIMS (array);
263 h->base = SCM_ARRAY_BASE (array);
264 }
265 else if (scm_is_generalized_vector (array))
266 {
267 h->dim0.lbnd = 0;
268 h->dim0.ubnd = scm_c_generalized_vector_length (array) - 1;
269 h->dim0.inc = 1;
270 h->dims = &h->dim0;
271 h->base = 0;
272 }
273 else
274 scm_wrong_type_arg_msg (NULL, 0, array, "array");
275}
276
277size_t
278scm_array_handle_rank (scm_t_array_handle *h)
279{
280 if (SCM_ARRAYP (h->array) || SCM_ENCLOSED_ARRAYP (h->array))
281 return SCM_ARRAY_NDIM (h->array);
282 else
283 return 1;
284}
285
286scm_t_array_dim *
287scm_array_handle_dims (scm_t_array_handle *h)
288{
289 return h->dims;
290}
291
292SCM
293scm_array_handle_ref (scm_t_array_handle *h, size_t pos)
294{
295 pos += h->base;
296 if (SCM_ARRAYP (h->array))
297 return scm_i_cvref (SCM_ARRAY_V (h->array), pos, 0);
298 if (SCM_ENCLOSED_ARRAYP (h->array))
299 return scm_i_cvref (SCM_ARRAY_V (h->array), pos, 1);
300 return scm_c_generalized_vector_ref (h->array, pos);
301}
302
303void
304scm_array_handle_set (scm_t_array_handle *h, size_t pos, SCM val)
305{
306 pos += h->base;
307 if (SCM_ARRAYP (h->array))
308 scm_c_generalized_vector_set_x (SCM_ARRAY_V (h->array), pos, val);
309 if (SCM_ENCLOSED_ARRAYP (h->array))
310 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-enclosed array");
311 scm_c_generalized_vector_set_x (h->array, pos, val);
312}
313
314const SCM *
315scm_array_handle_elements (scm_t_array_handle *h)
316{
317 SCM vec = h->array;
318 if (SCM_ARRAYP (vec))
319 vec = SCM_ARRAY_V (vec);
320 if (SCM_I_IS_VECTOR (vec))
321 return SCM_I_VECTOR_ELTS (vec) + h->base;
322 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
323}
324
325SCM *
326scm_array_handle_writable_elements (scm_t_array_handle *h)
327{
328 SCM vec = h->array;
329 if (SCM_ARRAYP (vec))
330 vec = SCM_ARRAY_V (vec);
331 if (SCM_I_IS_VECTOR (vec))
332 return SCM_I_VECTOR_WELTS (vec) + h->base;
333 scm_wrong_type_arg_msg (NULL, 0, h->array, "non-uniform array");
334}
335
336void
337scm_vector_get_handle (SCM vec, scm_t_array_handle *h)
338{
339 scm_array_get_handle (vec, h);
340 if (scm_array_handle_rank (h) != 1)
341 scm_wrong_type_arg_msg (NULL, 0, vec, "vector");
342}
343
344const SCM *
345scm_vector_elements (SCM vec, scm_t_array_handle *h,
346 size_t *lenp, ssize_t *incp)
347{
348 scm_vector_get_handle (vec, h);
349 if (lenp)
350 {
351 scm_t_array_dim *dim = scm_array_handle_dims (h);
352 *lenp = dim->ubnd - dim->lbnd + 1;
353 *incp = dim->inc;
354 }
355 return scm_array_handle_elements (h);
356}
357
358SCM *
359scm_vector_writable_elements (SCM vec, scm_t_array_handle *h,
360 size_t *lenp, ssize_t *incp)
361{
362 scm_vector_get_handle (vec, h);
363 if (lenp)
364 {
365 scm_t_array_dim *dim = scm_array_handle_dims (h);
366 *lenp = dim->ubnd - dim->lbnd + 1;
367 *incp = dim->inc;
368 }
369 return scm_array_handle_writable_elements (h);
370}
371
20930f28 372#if SCM_ENABLE_DEPRECATED
f301dbf3
MV
373
374SCM_DEFINE (scm_array_p, "array?", 1, 1, 0,
375 (SCM obj, SCM prot),
376 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
377 "not.")
378#define FUNC_NAME s_scm_array_p
379{
380 if (!SCM_UNBNDP (prot))
381 {
382 scm_c_issue_deprecation_warning
383 ("Using prototypes with `array?' is deprecated."
384 " Use `typed-array?' instead.");
385
386 return scm_typed_array_p (obj, prototype_to_type (prot));
387 }
388 else
389 return scm_from_bool (scm_is_array (obj));
390}
391#undef FUNC_NAME
392
393#else /* !SCM_ENABLE_DEPRECATED */
394
395/* We keep the old 2-argument C prototype for a while although the old
396 PROT argument is always ignored now. C code should probably use
397 scm_is_array or scm_is_typed_array anyway.
398*/
399
6e708ef2
MV
400static SCM scm_i_array_p (SCM obj);
401
402SCM_DEFINE (scm_i_array_p, "array?", 1, 0, 0,
403 (SCM obj),
f301dbf3
MV
404 "Return @code{#t} if the @var{obj} is an array, and @code{#f} if\n"
405 "not.")
6e708ef2 406#define FUNC_NAME s_scm_i_array_p
f301dbf3
MV
407{
408 return scm_from_bool (scm_is_array (obj));
409}
410#undef FUNC_NAME
411
6e708ef2
MV
412SCM
413scm_array_p (SCM obj, SCM prot)
414{
415 return scm_from_bool (scm_is_array (obj));
416}
417
f301dbf3
MV
418#endif /* !SCM_ENABLE_DEPRECATED */
419
420
421SCM_DEFINE (scm_typed_array_p, "typed-array?", 2, 0, 0,
422 (SCM obj, SCM type),
423 "Return @code{#t} if the @var{obj} is an array of type\n"
424 "@var{type}, and @code{#f} if not.")
425#define FUNC_NAME s_scm_typed_array_p
426{
427 return scm_from_bool (scm_is_typed_array (obj, type));
0f2d19dd 428}
1bbd0b84 429#undef FUNC_NAME
0f2d19dd
JB
430
431
3b3b36dd 432SCM_DEFINE (scm_array_rank, "array-rank", 1, 0, 0,
02339e5b
MV
433 (SCM array),
434 "Return the number of dimensions of the array @var{array.}\n")
1bbd0b84 435#define FUNC_NAME s_scm_array_rank
0f2d19dd 436{
02339e5b 437 if (scm_is_generalized_vector (array))
e0e49670
MV
438 return scm_from_int (1);
439
02339e5b
MV
440 if (SCM_ARRAYP (array) || SCM_ENCLOSED_ARRAYP (array))
441 return scm_from_size_t (SCM_ARRAY_NDIM (array));
20930f28 442
02339e5b 443 scm_wrong_type_arg_msg (NULL, 0, array, "array");
0f2d19dd 444}
1bbd0b84 445#undef FUNC_NAME
0f2d19dd
JB
446
447
3b3b36dd 448SCM_DEFINE (scm_array_dimensions, "array-dimensions", 1, 0, 0,
1bbd0b84 449 (SCM ra),
02339e5b 450 "@code{array-dimensions} is similar to @code{array-shape} but replaces\n"
b380b885 451 "elements with a @code{0} minimum with one greater than the maximum. So:\n"
1e6808ea 452 "@lisp\n"
b380b885 453 "(array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) 5)\n"
1e6808ea 454 "@end lisp")
1bbd0b84 455#define FUNC_NAME s_scm_array_dimensions
0f2d19dd 456{
20930f28 457 if (scm_is_generalized_vector (ra))
f301dbf3 458 return scm_list_1 (scm_generalized_vector_length (ra));
e0e49670 459
02339e5b 460 if (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra))
0f2d19dd 461 {
20930f28
MV
462 SCM res = SCM_EOL;
463 size_t k;
464 scm_t_array_dim *s;
465
0f2d19dd
JB
466 k = SCM_ARRAY_NDIM (ra);
467 s = SCM_ARRAY_DIMS (ra);
468 while (k--)
e2d37336 469 res = scm_cons (s[k].lbnd
e11e83f3
MV
470 ? scm_cons2 (scm_from_long (s[k].lbnd),
471 scm_from_long (s[k].ubnd),
e2d37336 472 SCM_EOL)
e11e83f3 473 : scm_from_long (1 + s[k].ubnd),
e2d37336 474 res);
0f2d19dd
JB
475 return res;
476 }
20930f28
MV
477
478 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 479}
1bbd0b84 480#undef FUNC_NAME
0f2d19dd
JB
481
482
e2d37336
MD
483SCM_DEFINE (scm_shared_array_root, "shared-array-root", 1, 0, 0,
484 (SCM ra),
485 "Return the root vector of a shared array.")
486#define FUNC_NAME s_scm_shared_array_root
487{
02339e5b
MV
488 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
489 SCM_ARG1, FUNC_NAME);
e2d37336
MD
490 return SCM_ARRAY_V (ra);
491}
492#undef FUNC_NAME
493
494
495SCM_DEFINE (scm_shared_array_offset, "shared-array-offset", 1, 0, 0,
496 (SCM ra),
497 "Return the root vector index of the first element in the array.")
498#define FUNC_NAME s_scm_shared_array_offset
499{
02339e5b
MV
500 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
501 SCM_ARG1, FUNC_NAME);
e11e83f3 502 return scm_from_int (SCM_ARRAY_BASE (ra));
e2d37336
MD
503}
504#undef FUNC_NAME
505
506
507SCM_DEFINE (scm_shared_array_increments, "shared-array-increments", 1, 0, 0,
508 (SCM ra),
509 "For each dimension, return the distance between elements in the root vector.")
510#define FUNC_NAME s_scm_shared_array_increments
511{
512 SCM res = SCM_EOL;
1be6b49c 513 size_t k;
92c2555f 514 scm_t_array_dim *s;
02339e5b
MV
515
516 SCM_ASSERT (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra), ra,
517 SCM_ARG1, FUNC_NAME);
e2d37336
MD
518 k = SCM_ARRAY_NDIM (ra);
519 s = SCM_ARRAY_DIMS (ra);
520 while (k--)
e11e83f3 521 res = scm_cons (scm_from_long (s[k].inc), res);
e2d37336
MD
522 return res;
523}
524#undef FUNC_NAME
525
526
0f2d19dd
JB
527static char s_bad_ind[] = "Bad scm_array index";
528
1cc91f1b 529
c014a02e 530long
1bbd0b84 531scm_aind (SCM ra, SCM args, const char *what)
0f2d19dd
JB
532{
533 SCM ind;
c014a02e
ML
534 register long j;
535 register unsigned long pos = SCM_ARRAY_BASE (ra);
536 register unsigned long k = SCM_ARRAY_NDIM (ra);
92c2555f 537 scm_t_array_dim *s = SCM_ARRAY_DIMS (ra);
02339e5b 538
e11e83f3 539 if (scm_is_integer (args))
0f2d19dd 540 {
b3fcac34
DH
541 if (k != 1)
542 scm_error_num_args_subr (what);
e11e83f3 543 return pos + (scm_to_long (args) - s->lbnd) * (s->inc);
0f2d19dd 544 }
d2e53ed6 545 while (k && scm_is_pair (args))
0f2d19dd
JB
546 {
547 ind = SCM_CAR (args);
548 args = SCM_CDR (args);
e11e83f3 549 if (!scm_is_integer (ind))
b3fcac34 550 scm_misc_error (what, s_bad_ind, SCM_EOL);
e11e83f3 551 j = scm_to_long (ind);
685c0d71
DH
552 if (j < s->lbnd || j > s->ubnd)
553 scm_out_of_range (what, ind);
0f2d19dd
JB
554 pos += (j - s->lbnd) * (s->inc);
555 k--;
556 s++;
557 }
d2e53ed6 558 if (k != 0 || !scm_is_null (args))
b3fcac34
DH
559 scm_error_num_args_subr (what);
560
0f2d19dd
JB
561 return pos;
562}
0f2d19dd 563
1cc91f1b 564
02339e5b
MV
565static SCM
566scm_i_make_ra (int ndim, scm_t_bits tag)
0f2d19dd
JB
567{
568 SCM ra;
02339e5b 569 SCM_NEWSMOB(ra, ((scm_t_bits) ndim << 17) + tag,
4c9419ac
MV
570 scm_gc_malloc ((sizeof (scm_t_array) +
571 ndim * sizeof (scm_t_array_dim)),
572 "array"));
02339e5b 573 SCM_ARRAY_V (ra) = SCM_BOOL_F;
0f2d19dd
JB
574 return ra;
575}
576
02339e5b
MV
577SCM
578scm_make_ra (int ndim)
579{
580 return scm_i_make_ra (ndim, scm_tc16_array);
581}
582
583
0f2d19dd 584static char s_bad_spec[] = "Bad scm_array dimension";
0f2d19dd 585
1cc91f1b 586
02339e5b
MV
587/* Increments will still need to be set. */
588
0f2d19dd 589SCM
1bbd0b84 590scm_shap2ra (SCM args, const char *what)
0f2d19dd 591{
92c2555f 592 scm_t_array_dim *s;
0f2d19dd
JB
593 SCM ra, spec, sp;
594 int ndim = scm_ilength (args);
b3fcac34
DH
595 if (ndim < 0)
596 scm_misc_error (what, s_bad_spec, SCM_EOL);
597
0f2d19dd
JB
598 ra = scm_make_ra (ndim);
599 SCM_ARRAY_BASE (ra) = 0;
600 s = SCM_ARRAY_DIMS (ra);
d2e53ed6 601 for (; !scm_is_null (args); s++, args = SCM_CDR (args))
0f2d19dd
JB
602 {
603 spec = SCM_CAR (args);
e11e83f3 604 if (scm_is_integer (spec))
0f2d19dd 605 {
e11e83f3 606 if (scm_to_long (spec) < 0)
b3fcac34 607 scm_misc_error (what, s_bad_spec, SCM_EOL);
0f2d19dd 608 s->lbnd = 0;
e11e83f3 609 s->ubnd = scm_to_long (spec) - 1;
0f2d19dd
JB
610 s->inc = 1;
611 }
612 else
613 {
d2e53ed6 614 if (!scm_is_pair (spec) || !scm_is_integer (SCM_CAR (spec)))
b3fcac34 615 scm_misc_error (what, s_bad_spec, SCM_EOL);
e11e83f3 616 s->lbnd = scm_to_long (SCM_CAR (spec));
0f2d19dd 617 sp = SCM_CDR (spec);
d2e53ed6 618 if (!scm_is_pair (sp)
e11e83f3 619 || !scm_is_integer (SCM_CAR (sp))
d2e53ed6 620 || !scm_is_null (SCM_CDR (sp)))
b3fcac34 621 scm_misc_error (what, s_bad_spec, SCM_EOL);
e11e83f3 622 s->ubnd = scm_to_long (SCM_CAR (sp));
0f2d19dd
JB
623 s->inc = 1;
624 }
625 }
626 return ra;
627}
628
f301dbf3
MV
629SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
630 (SCM type, SCM fill, SCM bounds),
631 "Create and return an array of type @var{type}.")
632#define FUNC_NAME s_scm_make_typed_array
0f2d19dd 633{
f301dbf3 634 size_t k, rlen = 1;
92c2555f 635 scm_t_array_dim *s;
f301dbf3 636 creator_proc *creator;
0f2d19dd 637 SCM ra;
1be6b49c 638
f301dbf3
MV
639 creator = type_to_creator (type);
640 ra = scm_shap2ra (bounds, FUNC_NAME);
e038c042 641 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
642 s = SCM_ARRAY_DIMS (ra);
643 k = SCM_ARRAY_NDIM (ra);
1be6b49c 644
0f2d19dd
JB
645 while (k--)
646 {
a3a32939 647 s[k].inc = rlen;
f301dbf3 648 SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd);
0f2d19dd 649 rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
0f2d19dd 650 }
a3a32939 651
f0b91039 652 if (scm_is_eq (fill, SCM_UNSPECIFIED))
f301dbf3 653 fill = SCM_UNDEFINED;
a3a32939 654
f301dbf3 655 SCM_ARRAY_V (ra) = creator (scm_from_size_t (rlen), fill);
a3a32939 656
0f2d19dd 657 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
c014a02e 658 if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
0f2d19dd
JB
659 return SCM_ARRAY_V (ra);
660 return ra;
661}
1bbd0b84 662#undef FUNC_NAME
0f2d19dd 663
f301dbf3
MV
664SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
665 (SCM fill, SCM bounds),
666 "Create and return an array.")
667#define FUNC_NAME s_scm_make_array
668{
669 return scm_make_typed_array (SCM_BOOL_T, fill, bounds);
670}
671#undef FUNC_NAME
672
673#if SCM_ENABLE_DEPRECATED
674
675SCM_DEFINE (scm_dimensions_to_uniform_array, "dimensions->uniform-array", 2, 1, 0,
676 (SCM dims, SCM prot, SCM fill),
677 "@deffnx {Scheme Procedure} make-uniform-vector length prototype [fill]\n"
678 "Create and return a uniform array or vector of type\n"
679 "corresponding to @var{prototype} with dimensions @var{dims} or\n"
680 "length @var{length}. If @var{fill} is supplied, it's used to\n"
681 "fill the array, otherwise @var{prototype} is used.")
682#define FUNC_NAME s_scm_dimensions_to_uniform_array
683{
684 scm_c_issue_deprecation_warning
685 ("`dimensions->uniform-array' is deprecated. "
686 "Use `make-typed-array' instead.");
687
688 if (scm_is_integer (dims))
689 dims = scm_list_1 (dims);
690 return scm_make_typed_array (prototype_to_type (prot), fill, dims);
691}
692#undef FUNC_NAME
693
694#endif
1cc91f1b 695
0f2d19dd 696void
1bbd0b84 697scm_ra_set_contp (SCM ra)
0f2d19dd 698{
02339e5b
MV
699 /* XXX - correct? one-dimensional arrays are always 'contiguous',
700 is that right?
701 */
1be6b49c 702 size_t k = SCM_ARRAY_NDIM (ra);
0f2d19dd 703 if (k)
0f2d19dd 704 {
c014a02e 705 long inc = SCM_ARRAY_DIMS (ra)[k - 1].inc;
fe0c6dae 706 while (k--)
0f2d19dd 707 {
fe0c6dae
JB
708 if (inc != SCM_ARRAY_DIMS (ra)[k].inc)
709 {
e038c042 710 SCM_CLR_ARRAY_CONTIGUOUS_FLAG (ra);
fe0c6dae
JB
711 return;
712 }
713 inc *= (SCM_ARRAY_DIMS (ra)[k].ubnd
714 - SCM_ARRAY_DIMS (ra)[k].lbnd + 1);
0f2d19dd 715 }
0f2d19dd 716 }
e038c042 717 SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
0f2d19dd
JB
718}
719
720
3b3b36dd 721SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
1bbd0b84 722 (SCM oldra, SCM mapfunc, SCM dims),
b380b885
MD
723 "@code{make-shared-array} can be used to create shared subarrays of other\n"
724 "arrays. The @var{mapper} is a function that translates coordinates in\n"
725 "the new array into coordinates in the old array. A @var{mapper} must be\n"
726 "linear, and its range must stay within the bounds of the old array, but\n"
727 "it can be otherwise arbitrary. A simple example:\n"
1e6808ea 728 "@lisp\n"
b380b885
MD
729 "(define fred (make-array #f 8 8))\n"
730 "(define freds-diagonal\n"
731 " (make-shared-array fred (lambda (i) (list i i)) 8))\n"
732 "(array-set! freds-diagonal 'foo 3)\n"
733 "(array-ref fred 3 3) @result{} foo\n"
734 "(define freds-center\n"
735 " (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))\n"
736 "(array-ref freds-center 0 0) @result{} foo\n"
1e6808ea 737 "@end lisp")
1bbd0b84 738#define FUNC_NAME s_scm_make_shared_array
0f2d19dd
JB
739{
740 SCM ra;
741 SCM inds, indptr;
742 SCM imap;
c014a02e
ML
743 size_t k, i;
744 long old_min, new_min, old_max, new_max;
92c2555f 745 scm_t_array_dim *s;
b3fcac34
DH
746
747 SCM_VALIDATE_REST_ARGUMENT (dims);
34d19ef6
HWN
748 SCM_VALIDATE_ARRAY (1, oldra);
749 SCM_VALIDATE_PROC (2, mapfunc);
1bbd0b84 750 ra = scm_shap2ra (dims, FUNC_NAME);
0f2d19dd
JB
751 if (SCM_ARRAYP (oldra))
752 {
753 SCM_ARRAY_V (ra) = SCM_ARRAY_V (oldra);
754 old_min = old_max = SCM_ARRAY_BASE (oldra);
755 s = SCM_ARRAY_DIMS (oldra);
756 k = SCM_ARRAY_NDIM (oldra);
757 while (k--)
758 {
759 if (s[k].inc > 0)
760 old_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
761 else
762 old_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
763 }
764 }
765 else
766 {
767 SCM_ARRAY_V (ra) = oldra;
768 old_min = 0;
02339e5b 769 old_max = scm_c_generalized_vector_length (oldra) - 1;
0f2d19dd
JB
770 }
771 inds = SCM_EOL;
772 s = SCM_ARRAY_DIMS (ra);
773 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
774 {
e11e83f3 775 inds = scm_cons (scm_from_long (s[k].lbnd), inds);
0f2d19dd
JB
776 if (s[k].ubnd < s[k].lbnd)
777 {
778 if (1 == SCM_ARRAY_NDIM (ra))
f301dbf3 779 ra = make_typed_vector (scm_array_type (ra), 0);
0f2d19dd 780 else
f301dbf3 781 SCM_ARRAY_V (ra) = make_typed_vector (scm_array_type (ra), 0);
0f2d19dd
JB
782 return ra;
783 }
784 }
fdc28395 785 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0f2d19dd 786 if (SCM_ARRAYP (oldra))
c014a02e 787 i = (size_t) scm_aind (oldra, imap, FUNC_NAME);
0f2d19dd
JB
788 else
789 {
e11e83f3 790 if (!scm_is_integer (imap))
0f2d19dd 791 {
e11e83f3 792 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
b3fcac34 793 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
0f2d19dd
JB
794 imap = SCM_CAR (imap);
795 }
e11e83f3 796 i = scm_to_size_t (imap);
0f2d19dd
JB
797 }
798 SCM_ARRAY_BASE (ra) = new_min = new_max = i;
799 indptr = inds;
800 k = SCM_ARRAY_NDIM (ra);
801 while (k--)
802 {
803 if (s[k].ubnd > s[k].lbnd)
804 {
e11e83f3 805 SCM_SETCAR (indptr, scm_sum (SCM_CAR (indptr), scm_from_int (1)));
fdc28395 806 imap = scm_apply_0 (mapfunc, scm_reverse (inds));
0f2d19dd
JB
807 if (SCM_ARRAYP (oldra))
808
1bbd0b84 809 s[k].inc = scm_aind (oldra, imap, FUNC_NAME) - i;
0f2d19dd
JB
810 else
811 {
e11e83f3 812 if (!scm_is_integer (imap))
0f2d19dd 813 {
e11e83f3 814 if (scm_ilength (imap) != 1 || !scm_is_integer (SCM_CAR (imap)))
b3fcac34 815 SCM_MISC_ERROR (s_bad_ind, SCM_EOL);
0f2d19dd
JB
816 imap = SCM_CAR (imap);
817 }
e11e83f3 818 s[k].inc = scm_to_long (imap) - i;
0f2d19dd
JB
819 }
820 i += s[k].inc;
821 if (s[k].inc > 0)
822 new_max += (s[k].ubnd - s[k].lbnd) * s[k].inc;
823 else
824 new_min += (s[k].ubnd - s[k].lbnd) * s[k].inc;
825 }
826 else
827 s[k].inc = new_max - new_min + 1; /* contiguous by default */
828 indptr = SCM_CDR (indptr);
829 }
b3fcac34
DH
830 if (old_min > new_min || old_max < new_max)
831 SCM_MISC_ERROR ("mapping out of range", SCM_EOL);
0f2d19dd
JB
832 if (1 == SCM_ARRAY_NDIM (ra) && 0 == SCM_ARRAY_BASE (ra))
833 {
74014c46 834 SCM v = SCM_ARRAY_V (ra);
6e708ef2 835 size_t length = scm_c_generalized_vector_length (v);
74014c46
DH
836 if (1 == s->inc && 0 == s->lbnd && length == 1 + s->ubnd)
837 return v;
0f2d19dd 838 if (s->ubnd < s->lbnd)
f301dbf3 839 return make_typed_vector (scm_array_type (ra), 0);
0f2d19dd
JB
840 }
841 scm_ra_set_contp (ra);
842 return ra;
843}
1bbd0b84 844#undef FUNC_NAME
0f2d19dd
JB
845
846
847/* args are RA . DIMS */
af45e3b0
DH
848SCM_DEFINE (scm_transpose_array, "transpose-array", 1, 0, 1,
849 (SCM ra, SCM args),
1e6808ea
MG
850 "Return an array sharing contents with @var{array}, but with\n"
851 "dimensions arranged in a different order. There must be one\n"
852 "@var{dim} argument for each dimension of @var{array}.\n"
853 "@var{dim0}, @var{dim1}, @dots{} should be integers between 0\n"
854 "and the rank of the array to be returned. Each integer in that\n"
855 "range must appear at least once in the argument list.\n"
856 "\n"
857 "The values of @var{dim0}, @var{dim1}, @dots{} correspond to\n"
858 "dimensions in the array to be returned, their positions in the\n"
859 "argument list to dimensions of @var{array}. Several @var{dim}s\n"
860 "may have the same value, in which case the returned array will\n"
861 "have smaller rank than @var{array}.\n"
862 "\n"
863 "@lisp\n"
b380b885
MD
864 "(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d))\n"
865 "(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d)\n"
866 "(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{}\n"
867 " #2((a 4) (b 5) (c 6))\n"
1e6808ea 868 "@end lisp")
1bbd0b84 869#define FUNC_NAME s_scm_transpose_array
0f2d19dd 870{
34d19ef6 871 SCM res, vargs;
92c2555f 872 scm_t_array_dim *s, *r;
0f2d19dd 873 int ndim, i, k;
af45e3b0 874
b3fcac34 875 SCM_VALIDATE_REST_ARGUMENT (args);
1bbd0b84 876 SCM_ASSERT (SCM_NIMP (ra), ra, SCM_ARG1, FUNC_NAME);
e0e49670 877
20930f28 878 if (scm_is_generalized_vector (ra))
e0e49670
MV
879 {
880 /* Make sure that we are called with a single zero as
881 arguments.
882 */
883 if (scm_is_null (args) || !scm_is_null (SCM_CDR (args)))
884 SCM_WRONG_NUM_ARGS ();
885 SCM_VALIDATE_INT_COPY (SCM_ARG2, SCM_CAR (args), i);
886 SCM_ASSERT_RANGE (SCM_ARG2, SCM_CAR (args), i == 0);
887 return ra;
888 }
889
02339e5b 890 if (SCM_ARRAYP (ra) || SCM_ENCLOSED_ARRAYP (ra))
0f2d19dd 891 {
0f2d19dd 892 vargs = scm_vector (args);
6e708ef2 893 if (SCM_SIMPLE_VECTOR_LENGTH (vargs) != SCM_ARRAY_NDIM (ra))
b3fcac34 894 SCM_WRONG_NUM_ARGS ();
0f2d19dd
JB
895 ndim = 0;
896 for (k = 0; k < SCM_ARRAY_NDIM (ra); k++)
897 {
6e708ef2
MV
898 i = scm_to_signed_integer (SCM_SIMPLE_VECTOR_REF (vargs, k),
899 0, SCM_ARRAY_NDIM(ra));
0f2d19dd
JB
900 if (ndim < i)
901 ndim = i;
902 }
903 ndim++;
904 res = scm_make_ra (ndim);
905 SCM_ARRAY_V (res) = SCM_ARRAY_V (ra);
906 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra);
907 for (k = ndim; k--;)
908 {
909 SCM_ARRAY_DIMS (res)[k].lbnd = 0;
910 SCM_ARRAY_DIMS (res)[k].ubnd = -1;
911 }
912 for (k = SCM_ARRAY_NDIM (ra); k--;)
913 {
6e708ef2 914 i = scm_to_int (SCM_SIMPLE_VECTOR_REF (vargs, k));
0f2d19dd
JB
915 s = &(SCM_ARRAY_DIMS (ra)[k]);
916 r = &(SCM_ARRAY_DIMS (res)[i]);
917 if (r->ubnd < r->lbnd)
918 {
919 r->lbnd = s->lbnd;
920 r->ubnd = s->ubnd;
921 r->inc = s->inc;
922 ndim--;
923 }
924 else
925 {
926 if (r->ubnd > s->ubnd)
927 r->ubnd = s->ubnd;
928 if (r->lbnd < s->lbnd)
929 {
930 SCM_ARRAY_BASE (res) += (s->lbnd - r->lbnd) * r->inc;
931 r->lbnd = s->lbnd;
932 }
933 r->inc += s->inc;
934 }
935 }
b3fcac34
DH
936 if (ndim > 0)
937 SCM_MISC_ERROR ("bad argument list", SCM_EOL);
0f2d19dd
JB
938 scm_ra_set_contp (res);
939 return res;
940 }
20930f28
MV
941
942 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 943}
1bbd0b84 944#undef FUNC_NAME
0f2d19dd
JB
945
946/* args are RA . AXES */
af45e3b0
DH
947SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
948 (SCM ra, SCM axes),
b380b885
MD
949 "@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than\n"
950 "the rank of @var{array}. @var{enclose-array} returns an array\n"
951 "resembling an array of shared arrays. The dimensions of each shared\n"
952 "array are the same as the @var{dim}th dimensions of the original array,\n"
953 "the dimensions of the outer array are the same as those of the original\n"
954 "array that did not match a @var{dim}.\n\n"
955 "An enclosed array is not a general Scheme array. Its elements may not\n"
956 "be set using @code{array-set!}. Two references to the same element of\n"
957 "an enclosed array will be @code{equal?} but will not in general be\n"
958 "@code{eq?}. The value returned by @var{array-prototype} when given an\n"
959 "enclosed array is unspecified.\n\n"
960 "examples:\n"
1e6808ea 961 "@lisp\n"
b380b885
MD
962 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{}\n"
963 " #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))>\n\n"
964 "(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{}\n"
965 " #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))>\n"
1e6808ea 966 "@end lisp")
1bbd0b84 967#define FUNC_NAME s_scm_enclose_array
0f2d19dd 968{
af45e3b0 969 SCM axv, res, ra_inr;
cc95e00a 970 const char *c_axv;
92c2555f 971 scm_t_array_dim vdim, *s = &vdim;
0f2d19dd 972 int ndim, j, k, ninr, noutr;
af45e3b0 973
b3fcac34 974 SCM_VALIDATE_REST_ARGUMENT (axes);
d2e53ed6 975 if (scm_is_null (axes))
02339e5b 976 axes = scm_cons ((SCM_ARRAYP (ra) ? scm_from_size_t (SCM_ARRAY_NDIM (ra) - 1) : SCM_INUM0), SCM_EOL);
0f2d19dd 977 ninr = scm_ilength (axes);
b3fcac34
DH
978 if (ninr < 0)
979 SCM_WRONG_NUM_ARGS ();
0f2d19dd 980 ra_inr = scm_make_ra (ninr);
e0e49670 981
20930f28 982 if (scm_is_generalized_vector (ra))
0f2d19dd 983 {
0f2d19dd 984 s->lbnd = 0;
6e708ef2 985 s->ubnd = scm_c_generalized_vector_length (ra) - 1;
0f2d19dd
JB
986 s->inc = 1;
987 SCM_ARRAY_V (ra_inr) = ra;
988 SCM_ARRAY_BASE (ra_inr) = 0;
989 ndim = 1;
20930f28
MV
990 }
991 else if (SCM_ARRAYP (ra))
992 {
0f2d19dd
JB
993 s = SCM_ARRAY_DIMS (ra);
994 SCM_ARRAY_V (ra_inr) = SCM_ARRAY_V (ra);
995 SCM_ARRAY_BASE (ra_inr) = SCM_ARRAY_BASE (ra);
996 ndim = SCM_ARRAY_NDIM (ra);
0f2d19dd 997 }
20930f28
MV
998 else
999 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
1000
0f2d19dd 1001 noutr = ndim - ninr;
b3fcac34
DH
1002 if (noutr < 0)
1003 SCM_WRONG_NUM_ARGS ();
e11e83f3 1004 axv = scm_make_string (scm_from_int (ndim), SCM_MAKE_CHAR (0));
02339e5b 1005 res = scm_i_make_ra (noutr, scm_tc16_enclosed_array);
0f2d19dd
JB
1006 SCM_ARRAY_BASE (res) = SCM_ARRAY_BASE (ra_inr);
1007 SCM_ARRAY_V (res) = ra_inr;
1008 for (k = 0; k < ninr; k++, axes = SCM_CDR (axes))
1009 {
e11e83f3 1010 if (!scm_is_integer (SCM_CAR (axes)))
b3fcac34 1011 SCM_MISC_ERROR ("bad axis", SCM_EOL);
e11e83f3 1012 j = scm_to_int (SCM_CAR (axes));
0f2d19dd
JB
1013 SCM_ARRAY_DIMS (ra_inr)[k].lbnd = s[j].lbnd;
1014 SCM_ARRAY_DIMS (ra_inr)[k].ubnd = s[j].ubnd;
1015 SCM_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
cc95e00a 1016 scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
0f2d19dd 1017 }
cc95e00a 1018 c_axv = scm_i_string_chars (axv);
0f2d19dd
JB
1019 for (j = 0, k = 0; k < noutr; k++, j++)
1020 {
cc95e00a 1021 while (c_axv[j])
0f2d19dd
JB
1022 j++;
1023 SCM_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
1024 SCM_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
1025 SCM_ARRAY_DIMS (res)[k].inc = s[j].inc;
1026 }
cc95e00a 1027 scm_remember_upto_here_1 (axv);
0f2d19dd
JB
1028 scm_ra_set_contp (ra_inr);
1029 scm_ra_set_contp (res);
1030 return res;
1031}
1bbd0b84 1032#undef FUNC_NAME
0f2d19dd
JB
1033
1034
1035
af45e3b0
DH
1036SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
1037 (SCM v, SCM args),
1e6808ea
MG
1038 "Return @code{#t} if its arguments would be acceptable to\n"
1039 "@code{array-ref}.")
1bbd0b84 1040#define FUNC_NAME s_scm_array_in_bounds_p
0f2d19dd 1041{
02339e5b 1042 SCM res = SCM_BOOL_T;
af45e3b0 1043
b3fcac34 1044 SCM_VALIDATE_REST_ARGUMENT (args);
0f2d19dd 1045
20930f28
MV
1046 if (scm_is_generalized_vector (v))
1047 {
02339e5b
MV
1048 long ind;
1049
1050 if (!scm_is_pair (args))
1051 SCM_WRONG_NUM_ARGS ();
1052 ind = scm_to_long (SCM_CAR (args));
1053 args = SCM_CDR (args);
1054 res = scm_from_bool (ind >= 0
1055 && ind < scm_c_generalized_vector_length (v));
20930f28 1056 }
02339e5b 1057 else if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
0f2d19dd 1058 {
02339e5b
MV
1059 size_t k = SCM_ARRAY_NDIM (v);
1060 scm_t_array_dim *s = SCM_ARRAY_DIMS (v);
1061
1062 while (k > 0)
0f2d19dd 1063 {
02339e5b 1064 long ind;
20930f28 1065
02339e5b
MV
1066 if (!scm_is_pair (args))
1067 SCM_WRONG_NUM_ARGS ();
1068 ind = scm_to_long (SCM_CAR (args));
1069 args = SCM_CDR (args);
1070 k -= 1;
1071
1072 if (ind < s->lbnd || ind > s->ubnd)
1073 {
1074 res = SCM_BOOL_F;
1075 /* We do not stop the checking after finding a violation
1076 since we want to validate the type-correctness and
1077 number of arguments in any case.
1078 */
1079 }
1080 }
0f2d19dd 1081 }
02339e5b
MV
1082 else
1083 scm_wrong_type_arg_msg (NULL, 0, v, "array");
20930f28 1084
02339e5b
MV
1085 if (!scm_is_null (args))
1086 SCM_WRONG_NUM_ARGS ();
1087
1088 return res;
0f2d19dd 1089}
1bbd0b84 1090#undef FUNC_NAME
0f2d19dd 1091
2d4d7f27 1092SCM
02339e5b
MV
1093scm_i_cvref (SCM v, size_t pos, int enclosed)
1094{
1095 if (enclosed)
1096 {
1097 int k = SCM_ARRAY_NDIM (v);
1098 SCM res = scm_make_ra (k);
1099 SCM_ARRAY_V (res) = SCM_ARRAY_V (v);
1100 SCM_ARRAY_BASE (res) = pos;
1101 while (k--)
1102 {
1103 SCM_ARRAY_DIMS (res)[k].ubnd = SCM_ARRAY_DIMS (v)[k].ubnd;
1104 SCM_ARRAY_DIMS (res)[k].lbnd = SCM_ARRAY_DIMS (v)[k].lbnd;
1105 SCM_ARRAY_DIMS (res)[k].inc = SCM_ARRAY_DIMS (v)[k].inc;
1106 }
1107 return res;
1108 }
1109 else
1110 return scm_c_generalized_vector_ref (v, pos);
1111}
1112
1113SCM
1114scm_cvref (SCM v, unsigned long pos, SCM last)
1115{
1116 return scm_i_cvref (v, pos, 0);
1117}
0f2d19dd 1118
e0e49670 1119SCM_DEFINE (scm_array_ref, "array-ref", 1, 0, 1,
1bbd0b84 1120 (SCM v, SCM args),
1e6808ea
MG
1121 "Return the element at the @code{(index1, index2)} element in\n"
1122 "@var{array}.")
e0e49670 1123#define FUNC_NAME s_scm_array_ref
0f2d19dd 1124{
c014a02e 1125 long pos;
02339e5b 1126 int enclosed = 0;
0f2d19dd 1127
02339e5b 1128 if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
0f2d19dd 1129 {
02339e5b 1130 enclosed = SCM_ENCLOSED_ARRAYP (v);
1bbd0b84 1131 pos = scm_aind (v, args, FUNC_NAME);
0f2d19dd
JB
1132 v = SCM_ARRAY_V (v);
1133 }
1134 else
1135 {
20930f28 1136 size_t length;
0f2d19dd 1137 if (SCM_NIMP (args))
0f2d19dd 1138 {
d2e53ed6 1139 SCM_ASSERT (scm_is_pair (args), args, SCM_ARG2, FUNC_NAME);
e11e83f3 1140 pos = scm_to_long (SCM_CAR (args));
d2e53ed6 1141 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
0f2d19dd
JB
1142 }
1143 else
20930f28
MV
1144 pos = scm_to_long (args);
1145 length = scm_c_generalized_vector_length (v);
74014c46 1146 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
0f2d19dd 1147 }
e0e49670 1148
02339e5b 1149 return scm_i_cvref (v, pos, enclosed);
20930f28 1150
20930f28
MV
1151 wna:
1152 scm_wrong_num_args (NULL);
1153 outrng:
1154 scm_out_of_range (NULL, scm_from_long (pos));
0f2d19dd 1155}
1bbd0b84 1156#undef FUNC_NAME
0f2d19dd 1157
0f2d19dd 1158
3b3b36dd 1159SCM_DEFINE (scm_array_set_x, "array-set!", 2, 0, 1,
1bbd0b84 1160 (SCM v, SCM obj, SCM args),
8f85c0c6 1161 "Set the element at the @code{(index1, index2)} element in @var{array} to\n"
b380b885 1162 "@var{new-value}. The value returned by array-set! is unspecified.")
1bbd0b84 1163#define FUNC_NAME s_scm_array_set_x
0f2d19dd 1164{
c014a02e 1165 long pos = 0;
b3fcac34 1166
0f2d19dd 1167 if (SCM_ARRAYP (v))
0f2d19dd 1168 {
1bbd0b84 1169 pos = scm_aind (v, args, FUNC_NAME);
0f2d19dd
JB
1170 v = SCM_ARRAY_V (v);
1171 }
02339e5b
MV
1172 else if (SCM_ENCLOSED_ARRAYP (v))
1173 scm_wrong_type_arg_msg (NULL, 0, v, "non-enclosed array");
1174 else if (scm_is_generalized_vector (v))
0f2d19dd 1175 {
20930f28 1176 size_t length;
d2e53ed6 1177 if (scm_is_pair (args))
0f2d19dd 1178 {
d2e53ed6 1179 SCM_ASRTGO (scm_is_null (SCM_CDR (args)), wna);
e11e83f3 1180 pos = scm_to_long (SCM_CAR (args));
0f2d19dd
JB
1181 }
1182 else
20930f28
MV
1183 pos = scm_to_long (args);
1184 length = scm_c_generalized_vector_length (v);
74014c46 1185 SCM_ASRTGO (pos >= 0 && pos < length, outrng);
0f2d19dd 1186 }
02339e5b
MV
1187 else
1188 scm_wrong_type_arg_msg (NULL, 0, v, "array");
1189
1190 scm_c_generalized_vector_set_x (v, pos, obj);
1191 return SCM_UNSPECIFIED;
20930f28
MV
1192
1193 outrng:
1194 scm_out_of_range (NULL, scm_from_long (pos));
1195 wna:
1196 scm_wrong_num_args (NULL);
0f2d19dd 1197}
1bbd0b84 1198#undef FUNC_NAME
0f2d19dd 1199
1d7bdb25
GH
1200/* attempts to unroll an array into a one-dimensional array.
1201 returns the unrolled array or #f if it can't be done. */
1bbd0b84 1202 /* if strict is not SCM_UNDEFINED, return #f if returned array
1d7bdb25 1203 wouldn't have contiguous elements. */
3b3b36dd 1204SCM_DEFINE (scm_array_contents, "array-contents", 1, 1, 0,
1bbd0b84 1205 (SCM ra, SCM strict),
b380b885
MD
1206 "If @var{array} may be @dfn{unrolled} into a one dimensional shared array\n"
1207 "without changing their order (last subscript changing fastest), then\n"
1208 "@code{array-contents} returns that shared array, otherwise it returns\n"
1209 "@code{#f}. All arrays made by @var{make-array} and\n"
1210 "@var{make-uniform-array} may be unrolled, some arrays made by\n"
1211 "@var{make-shared-array} may not be.\n\n"
1212 "If the optional argument @var{strict} is provided, a shared array will\n"
1213 "be returned only if its elements are stored internally contiguous in\n"
1214 "memory.")
1bbd0b84 1215#define FUNC_NAME s_scm_array_contents
0f2d19dd
JB
1216{
1217 SCM sra;
e0e49670 1218
20930f28 1219 if (scm_is_generalized_vector (ra))
e0e49670
MV
1220 return ra;
1221
20930f28 1222 if (SCM_ARRAYP (ra))
0f2d19dd 1223 {
20930f28
MV
1224 size_t k, ndim = SCM_ARRAY_NDIM (ra), len = 1;
1225 if (!SCM_ARRAYP (ra) || !SCM_ARRAY_CONTP (ra))
1226 return SCM_BOOL_F;
1227 for (k = 0; k < ndim; k++)
1228 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1229 if (!SCM_UNBNDP (strict))
74014c46 1230 {
20930f28
MV
1231 if (ndim && (1 != SCM_ARRAY_DIMS (ra)[ndim - 1].inc))
1232 return SCM_BOOL_F;
1233 if (scm_is_bitvector (SCM_ARRAY_V (ra)))
1234 {
1235 if (len != scm_c_bitvector_length (SCM_ARRAY_V (ra)) ||
1236 SCM_ARRAY_BASE (ra) % SCM_LONG_BIT ||
1237 len % SCM_LONG_BIT)
1238 return SCM_BOOL_F;
1239 }
74014c46 1240 }
20930f28
MV
1241
1242 {
1243 SCM v = SCM_ARRAY_V (ra);
1244 size_t length = scm_c_generalized_vector_length (v);
1245 if ((len == length) && 0 == SCM_ARRAY_BASE (ra) && SCM_ARRAY_DIMS (ra)->inc)
1246 return v;
0f2d19dd 1247 }
20930f28
MV
1248
1249 sra = scm_make_ra (1);
1250 SCM_ARRAY_DIMS (sra)->lbnd = 0;
1251 SCM_ARRAY_DIMS (sra)->ubnd = len - 1;
1252 SCM_ARRAY_V (sra) = SCM_ARRAY_V (ra);
1253 SCM_ARRAY_BASE (sra) = SCM_ARRAY_BASE (ra);
1254 SCM_ARRAY_DIMS (sra)->inc = (ndim ? SCM_ARRAY_DIMS (ra)[ndim - 1].inc : 1);
1255 return sra;
0f2d19dd 1256 }
02339e5b
MV
1257 else if (SCM_ENCLOSED_ARRAYP (ra))
1258 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
1259 else
1260 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 1261}
1bbd0b84 1262#undef FUNC_NAME
0f2d19dd 1263
1cc91f1b 1264
0f2d19dd 1265SCM
6e8d25a6 1266scm_ra2contig (SCM ra, int copy)
0f2d19dd
JB
1267{
1268 SCM ret;
c014a02e
ML
1269 long inc = 1;
1270 size_t k, len = 1;
0f2d19dd
JB
1271 for (k = SCM_ARRAY_NDIM (ra); k--;)
1272 len *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1273 k = SCM_ARRAY_NDIM (ra);
1274 if (SCM_ARRAY_CONTP (ra) && ((0 == k) || (1 == SCM_ARRAY_DIMS (ra)[k - 1].inc)))
1275 {
20930f28 1276 if (!scm_is_bitvector (SCM_ARRAY_V (ra)))
0f2d19dd 1277 return ra;
20930f28 1278 if ((len == scm_c_bitvector_length (SCM_ARRAY_V (ra)) &&
c014a02e
ML
1279 0 == SCM_ARRAY_BASE (ra) % SCM_LONG_BIT &&
1280 0 == len % SCM_LONG_BIT))
0f2d19dd
JB
1281 return ra;
1282 }
1283 ret = scm_make_ra (k);
1284 SCM_ARRAY_BASE (ret) = 0;
1285 while (k--)
1286 {
1287 SCM_ARRAY_DIMS (ret)[k].lbnd = SCM_ARRAY_DIMS (ra)[k].lbnd;
1288 SCM_ARRAY_DIMS (ret)[k].ubnd = SCM_ARRAY_DIMS (ra)[k].ubnd;
1289 SCM_ARRAY_DIMS (ret)[k].inc = inc;
1290 inc *= SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd + 1;
1291 }
f301dbf3 1292 SCM_ARRAY_V (ret) = make_typed_vector (scm_array_type (ra), inc);
0f2d19dd
JB
1293 if (copy)
1294 scm_array_copy_x (ra, ret);
1295 return ret;
1296}
1297
1298
1299
3b3b36dd 1300SCM_DEFINE (scm_uniform_array_read_x, "uniform-array-read!", 1, 3, 0,
03a5397a 1301 (SCM ura, SCM port_or_fd, SCM start, SCM end),
8f85c0c6
NJ
1302 "@deffnx {Scheme Procedure} uniform-vector-read! uve [port-or-fdes] [start] [end]\n"
1303 "Attempt to read all elements of @var{ura}, in lexicographic order, as\n"
b380b885 1304 "binary objects from @var{port-or-fdes}.\n"
8f85c0c6
NJ
1305 "If an end of file is encountered,\n"
1306 "the objects up to that point are put into @var{ura}\n"
b380b885
MD
1307 "(starting at the beginning) and the remainder of the array is\n"
1308 "unchanged.\n\n"
1309 "The optional arguments @var{start} and @var{end} allow\n"
1310 "a specified region of a vector (or linearized array) to be read,\n"
1311 "leaving the remainder of the vector unchanged.\n\n"
1312 "@code{uniform-array-read!} returns the number of objects read.\n"
1313 "@var{port-or-fdes} may be omitted, in which case it defaults to the value\n"
1314 "returned by @code{(current-input-port)}.")
1bbd0b84 1315#define FUNC_NAME s_scm_uniform_array_read_x
0f2d19dd 1316{
3d8d56df
GH
1317 if (SCM_UNBNDP (port_or_fd))
1318 port_or_fd = scm_cur_inp;
35de7ebe 1319
03a5397a 1320 if (scm_is_uniform_vector (ura))
20930f28 1321 {
03a5397a 1322 return scm_uniform_vector_read_x (ura, port_or_fd, start, end);
20930f28 1323 }
03a5397a 1324 else if (SCM_ARRAYP (ura))
20930f28 1325 {
03a5397a
MV
1326 size_t base, vlen, cstart, cend;
1327 SCM cra, ans;
1328
1329 cra = scm_ra2contig (ura, 0);
1330 base = SCM_ARRAY_BASE (cra);
20930f28
MV
1331 vlen = SCM_ARRAY_DIMS (cra)->inc *
1332 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
35de7ebe 1333
03a5397a
MV
1334 cstart = 0;
1335 cend = vlen;
1336 if (!SCM_UNBNDP (start))
1146b6cd 1337 {
03a5397a
MV
1338 cstart = scm_to_unsigned_integer (start, 0, vlen);
1339 if (!SCM_UNBNDP (end))
1340 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1341 }
35de7ebe 1342
03a5397a
MV
1343 ans = scm_uniform_vector_read_x (SCM_ARRAY_V (cra), port_or_fd,
1344 scm_from_size_t (base + cstart),
1345 scm_from_size_t (base + cend));
6c951427 1346
03a5397a
MV
1347 if (!scm_is_eq (cra, ura))
1348 scm_array_copy_x (cra, ura);
1349 return ans;
3d8d56df 1350 }
02339e5b
MV
1351 else if (SCM_ENCLOSED_ARRAYP (ura))
1352 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
03a5397a
MV
1353 else
1354 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1355}
1bbd0b84 1356#undef FUNC_NAME
0f2d19dd 1357
3b3b36dd 1358SCM_DEFINE (scm_uniform_array_write, "uniform-array-write", 1, 3, 0,
03a5397a 1359 (SCM ura, SCM port_or_fd, SCM start, SCM end),
b380b885
MD
1360 "Writes all elements of @var{ura} as binary objects to\n"
1361 "@var{port-or-fdes}.\n\n"
1362 "The optional arguments @var{start}\n"
1363 "and @var{end} allow\n"
1364 "a specified region of a vector (or linearized array) to be written.\n\n"
9401323e 1365 "The number of objects actually written is returned.\n"
b380b885
MD
1366 "@var{port-or-fdes} may be\n"
1367 "omitted, in which case it defaults to the value returned by\n"
1368 "@code{(current-output-port)}.")
1bbd0b84 1369#define FUNC_NAME s_scm_uniform_array_write
0f2d19dd 1370{
3d8d56df
GH
1371 if (SCM_UNBNDP (port_or_fd))
1372 port_or_fd = scm_cur_outp;
20930f28 1373
03a5397a 1374 if (scm_is_uniform_vector (ura))
20930f28 1375 {
03a5397a 1376 return scm_uniform_vector_write (ura, port_or_fd, start, end);
20930f28 1377 }
03a5397a 1378 else if (SCM_ARRAYP (ura))
20930f28 1379 {
03a5397a
MV
1380 size_t base, vlen, cstart, cend;
1381 SCM cra, ans;
1382
1383 cra = scm_ra2contig (ura, 1);
1384 base = SCM_ARRAY_BASE (cra);
1385 vlen = SCM_ARRAY_DIMS (cra)->inc *
1386 (SCM_ARRAY_DIMS (cra)->ubnd - SCM_ARRAY_DIMS (cra)->lbnd + 1);
1146b6cd 1387
03a5397a
MV
1388 cstart = 0;
1389 cend = vlen;
1390 if (!SCM_UNBNDP (start))
1146b6cd 1391 {
03a5397a
MV
1392 cstart = scm_to_unsigned_integer (start, 0, vlen);
1393 if (!SCM_UNBNDP (end))
1394 cend = scm_to_unsigned_integer (end, cstart, vlen);
1146b6cd 1395 }
3d8d56df 1396
03a5397a
MV
1397 ans = scm_uniform_vector_write (SCM_ARRAY_V (cra), port_or_fd,
1398 scm_from_size_t (base + cstart),
1399 scm_from_size_t (base + cend));
6c951427 1400
03a5397a 1401 return ans;
3d8d56df 1402 }
02339e5b
MV
1403 else if (SCM_ENCLOSED_ARRAYP (ura))
1404 scm_wrong_type_arg_msg (NULL, 0, ura, "non-enclosed array");
03a5397a
MV
1405 else
1406 scm_wrong_type_arg_msg (NULL, 0, ura, "array");
0f2d19dd 1407}
1bbd0b84 1408#undef FUNC_NAME
0f2d19dd
JB
1409
1410
20930f28
MV
1411/** Bit vectors */
1412
1413static scm_t_bits scm_tc16_bitvector;
1414
1415#define IS_BITVECTOR(obj) SCM_SMOB_PREDICATE(scm_tc16_bitvector,(obj))
1416#define BITVECTOR_BITS(obj) ((scm_t_uint32 *)SCM_SMOB_DATA(obj))
1417#define BITVECTOR_LENGTH(obj) ((size_t)SCM_SMOB_DATA_2(obj))
1418
1419static size_t
1420bitvector_free (SCM vec)
1421{
1422 scm_gc_free (BITVECTOR_BITS (vec),
1423 sizeof (scm_t_uint32) * ((BITVECTOR_LENGTH (vec)+31)/32),
1424 "bitvector");
1425 return 0;
1426}
1427
1428static int
1429bitvector_print (SCM vec, SCM port, scm_print_state *pstate)
1430{
1431 size_t bit_len = BITVECTOR_LENGTH (vec);
1432 size_t word_len = (bit_len+31)/32;
1433 scm_t_uint32 *bits = BITVECTOR_BITS (vec);
1434 size_t i, j;
1435
1436 scm_puts ("#*", port);
1437 for (i = 0; i < word_len; i++, bit_len -= 32)
1438 {
1439 scm_t_uint32 mask = 1;
1440 for (j = 0; j < 32 && j < bit_len; j++, mask <<= 1)
1441 scm_putc ((bits[i] & mask)? '1' : '0', port);
1442 }
1443
1444 return 1;
1445}
1446
1447static SCM
1448bitvector_equalp (SCM vec1, SCM vec2)
1449{
1450 size_t bit_len = BITVECTOR_LENGTH (vec1);
1451 size_t word_len = (bit_len + 31) / 32;
1452 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - bit_len);
1453 scm_t_uint32 *bits1 = BITVECTOR_BITS (vec1);
1454 scm_t_uint32 *bits2 = BITVECTOR_BITS (vec2);
1455
1456 /* compare lengths */
1457 if (BITVECTOR_LENGTH (vec2) != bit_len)
1458 return SCM_BOOL_F;
1459 /* avoid underflow in word_len-1 below. */
1460 if (bit_len == 0)
1461 return SCM_BOOL_T;
1462 /* compare full words */
1463 if (memcmp (bits1, bits2, sizeof (scm_t_uint32) * (word_len-1)))
1464 return SCM_BOOL_F;
1465 /* compare partial last words */
1466 if ((bits1[word_len-1] & last_mask) != (bits2[word_len-1] & last_mask))
1467 return SCM_BOOL_F;
1468 return SCM_BOOL_T;
1469}
1470
1471int
1472scm_is_bitvector (SCM vec)
1473{
1474 return IS_BITVECTOR (vec);
1475}
1476
1477SCM_DEFINE (scm_bitvector_p, "bitvector?", 1, 0, 0,
1478 (SCM obj),
1479 "Return @code{#t} when @var{obj} is a bitvector, else\n"
1480 "return @code{#f}.")
1481#define FUNC_NAME s_scm_bitvector_p
1482{
1483 return scm_from_bool (scm_is_bitvector (obj));
1484}
1485#undef FUNC_NAME
1486
1487SCM
1488scm_c_make_bitvector (size_t len, SCM fill)
1489{
1490 size_t word_len = (len + 31) / 32;
1491 scm_t_uint32 *bits;
1492 SCM res;
1493
1494 bits = scm_gc_malloc (sizeof (scm_t_uint32) * word_len,
1495 "bitvector");
1496 SCM_NEWSMOB2 (res, scm_tc16_bitvector, bits, len);
1497
1498 if (!SCM_UNBNDP (fill))
1499 scm_bitvector_fill_x (res, fill);
1500
1501 return res;
1502}
1503
1504SCM_DEFINE (scm_make_bitvector, "make-bitvector", 1, 1, 0,
1505 (SCM len, SCM fill),
1506 "Create a new bitvector of length @var{len} and\n"
1507 "optionally initialize all elements to @var{fill}.")
1508#define FUNC_NAME s_scm_make_bitvector
1509{
1510 return scm_c_make_bitvector (scm_to_size_t (len), fill);
1511}
1512#undef FUNC_NAME
1513
1514SCM_DEFINE (scm_bitvector, "bitvector", 0, 0, 1,
1515 (SCM bits),
1516 "Create a new bitvector with the arguments as elements.")
1517#define FUNC_NAME s_scm_bitvector
1518{
1519 return scm_list_to_bitvector (bits);
1520}
1521#undef FUNC_NAME
1522
1523size_t
1524scm_c_bitvector_length (SCM vec)
1525{
1526 scm_assert_smob_type (scm_tc16_bitvector, vec);
1527 return BITVECTOR_LENGTH (vec);
1528}
1529
1530SCM_DEFINE (scm_bitvector_length, "bitvector-length", 1, 0, 0,
1531 (SCM vec),
1532 "Return the length of the bitvector @var{vec}.")
1533#define FUNC_NAME s_scm_bitvector_length
1534{
1535 return scm_from_size_t (scm_c_bitvector_length (vec));
1536}
1537#undef FUNC_NAME
1538
21c487f1 1539const scm_t_uint32 *
f0b91039 1540scm_array_handle_bit_elements (scm_t_array_handle *h)
20930f28 1541{
f0b91039 1542 return scm_array_handle_bit_writable_elements (h);
20930f28
MV
1543}
1544
f0b91039
MV
1545scm_t_uint32 *
1546scm_array_handle_bit_writable_elements (scm_t_array_handle *h)
20930f28 1547{
f0b91039
MV
1548 SCM vec = h->array;
1549 if (SCM_ARRAYP (vec))
1550 vec = SCM_ARRAY_V (vec);
1551 if (IS_BITVECTOR (vec))
1552 return BITVECTOR_BITS (vec) + h->base/32;
1553 scm_wrong_type_arg_msg (NULL, 0, h->array, "bit array");
20930f28
MV
1554}
1555
f0b91039
MV
1556size_t
1557scm_array_handle_bit_elements_offset (scm_t_array_handle *h)
21c487f1 1558{
f0b91039 1559 return h->base % 32;
21c487f1
MV
1560}
1561
f0b91039
MV
1562const scm_t_uint32 *
1563scm_bitvector_elements (SCM vec,
1564 scm_t_array_handle *h,
1565 size_t *offp,
1566 size_t *lenp,
1567 ssize_t *incp)
21c487f1 1568{
f0b91039 1569 return scm_bitvector_writable_elements (vec, h, offp, lenp, incp);
21c487f1
MV
1570}
1571
f0b91039
MV
1572
1573scm_t_uint32 *
1574scm_bitvector_writable_elements (SCM vec,
1575 scm_t_array_handle *h,
1576 size_t *offp,
1577 size_t *lenp,
1578 ssize_t *incp)
21c487f1 1579{
f0b91039
MV
1580 scm_vector_get_handle (vec, h);
1581 if (offp)
1582 {
1583 scm_t_array_dim *dim = scm_array_handle_dims (h);
1584 *offp = scm_array_handle_bit_elements_offset (h);
1585 *lenp = dim->ubnd - dim->lbnd + 1;
1586 *incp = dim->inc;
1587 }
1588 return scm_array_handle_bit_writable_elements (h);
21c487f1
MV
1589}
1590
20930f28
MV
1591SCM
1592scm_c_bitvector_ref (SCM vec, size_t idx)
1593{
f0b91039
MV
1594 scm_t_array_handle handle;
1595 const scm_t_uint32 *bits;
1596
1597 if (IS_BITVECTOR (vec))
20930f28 1598 {
f0b91039
MV
1599 if (idx >= BITVECTOR_LENGTH (vec))
1600 scm_out_of_range (NULL, scm_from_size_t (idx));
1601 bits = BITVECTOR_BITS(vec);
20930f28
MV
1602 }
1603 else
f0b91039
MV
1604 {
1605 size_t len, off;
1606 ssize_t inc;
1607
1608 bits = scm_bitvector_elements (vec, &handle, &off, &len, &inc);
1609 if (idx >= len)
1610 scm_out_of_range (NULL, scm_from_size_t (idx));
1611 idx = idx*inc + off;
1612 }
1613
1614 return scm_from_bool (bits[idx/32] & (1L << (idx%32)));
20930f28
MV
1615}
1616
1617SCM_DEFINE (scm_bitvector_ref, "bitvector-ref", 2, 0, 0,
1618 (SCM vec, SCM idx),
1619 "Return the element at index @var{idx} of the bitvector\n"
1620 "@var{vec}.")
1621#define FUNC_NAME s_scm_bitvector_ref
1622{
1623 return scm_c_bitvector_ref (vec, scm_to_size_t (idx));
1624}
1625#undef FUNC_NAME
1626
1627void
1628scm_c_bitvector_set_x (SCM vec, size_t idx, SCM val)
1629{
f0b91039
MV
1630 scm_t_array_handle handle;
1631 scm_t_uint32 *bits, mask;
1632
1633 if (IS_BITVECTOR (vec))
20930f28 1634 {
f0b91039
MV
1635 if (idx >= BITVECTOR_LENGTH (vec))
1636 scm_out_of_range (NULL, scm_from_size_t (idx));
1637 bits = BITVECTOR_BITS(vec);
20930f28
MV
1638 }
1639 else
f0b91039
MV
1640 {
1641 size_t len, off;
1642 ssize_t inc;
1643
1644 bits = scm_bitvector_writable_elements (vec, &handle, &off, &len, &inc);
1645 if (idx >= len)
1646 scm_out_of_range (NULL, scm_from_size_t (idx));
1647 idx = idx*inc + off;
1648 }
1649
1650 mask = 1L << (idx%32);
1651 if (scm_is_true (val))
1652 bits[idx/32] |= mask;
1653 else
1654 bits[idx/32] &= ~mask;
20930f28
MV
1655}
1656
1657SCM_DEFINE (scm_bitvector_set_x, "bitvector-set!", 3, 0, 0,
1658 (SCM vec, SCM idx, SCM val),
1659 "Set the element at index @var{idx} of the bitvector\n"
1660 "@var{vec} when @var{val} is true, else clear it.")
1661#define FUNC_NAME s_scm_bitvector_set_x
1662{
1663 scm_c_bitvector_set_x (vec, scm_to_size_t (idx), val);
1664 return SCM_UNSPECIFIED;
1665}
1666#undef FUNC_NAME
1667
1668SCM_DEFINE (scm_bitvector_fill_x, "bitvector-fill!", 2, 0, 0,
1669 (SCM vec, SCM val),
1670 "Set all elements of the bitvector\n"
1671 "@var{vec} when @var{val} is true, else clear them.")
1672#define FUNC_NAME s_scm_bitvector_fill_x
1673{
f0b91039
MV
1674 scm_t_array_handle handle;
1675 size_t off, len;
1676 ssize_t inc;
1677 scm_t_uint32 *bits;
1678
1679 bits = scm_bitvector_writable_elements (vec, &handle,
1680 &off, &len, &inc);
1681
1682 if (off == 0 && inc == 1 && len > 0)
1683 {
1684 /* the usual case
1685 */
1686 size_t word_len = (len + 31) / 32;
1687 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1688
1689 if (scm_is_true (val))
1690 {
1691 memset (bits, 0xFF, sizeof(scm_t_uint32)*(word_len-1));
1692 bits[word_len-1] |= last_mask;
1693 }
1694 else
1695 {
1696 memset (bits, 0x00, sizeof(scm_t_uint32)*(word_len-1));
1697 bits[word_len-1] &= ~last_mask;
1698 }
1699 }
1700 else
1701 {
1702 size_t i;
1703 for (i = 0; i < len; i++)
1704 scm_array_handle_set (&handle, i, val);
1705 }
1706
20930f28
MV
1707 return SCM_UNSPECIFIED;
1708}
1709#undef FUNC_NAME
1710
1711SCM_DEFINE (scm_list_to_bitvector, "list->bitvector", 1, 0, 0,
1712 (SCM list),
1713 "Return a new bitvector initialized with the elements\n"
1714 "of @var{list}.")
1715#define FUNC_NAME s_scm_list_to_bitvector
1716{
1717 size_t bit_len = scm_to_size_t (scm_length (list));
1718 SCM vec = scm_c_make_bitvector (bit_len, SCM_UNDEFINED);
1719 size_t word_len = (bit_len+31)/32;
f0b91039
MV
1720 scm_t_array_handle handle;
1721 scm_t_uint32 *bits = scm_bitvector_writable_elements (vec, &handle,
1722 NULL, NULL, NULL);
20930f28
MV
1723 size_t i, j;
1724
1725 for (i = 0; i < word_len && scm_is_pair (list); i++, bit_len -= 32)
1726 {
1727 scm_t_uint32 mask = 1;
1728 bits[i] = 0;
1729 for (j = 0; j < 32 && j < bit_len;
1730 j++, mask <<= 1, list = SCM_CDR (list))
1731 if (scm_is_true (SCM_CAR (list)))
1732 bits[i] |= mask;
1733 }
f0b91039 1734
20930f28
MV
1735 return vec;
1736}
1737#undef FUNC_NAME
1738
1739SCM_DEFINE (scm_bitvector_to_list, "bitvector->list", 1, 0, 0,
1740 (SCM vec),
1741 "Return a new list initialized with the elements\n"
1742 "of the bitvector @var{vec}.")
1743#define FUNC_NAME s_scm_bitvector_to_list
1744{
f0b91039
MV
1745 scm_t_array_handle handle;
1746 size_t off, len;
1747 ssize_t inc;
1748 scm_t_uint32 *bits;
20930f28 1749 SCM res = SCM_EOL;
20930f28 1750
f0b91039
MV
1751 bits = scm_bitvector_writable_elements (vec, &handle,
1752 &off, &len, &inc);
1753
1754 if (off == 0 && inc == 1)
20930f28 1755 {
f0b91039
MV
1756 /* the usual case
1757 */
1758 size_t word_len = (len + 31) / 32;
1759 size_t i, j;
1760
1761 for (i = 0; i < word_len; i++, len -= 32)
1762 {
1763 scm_t_uint32 mask = 1;
1764 for (j = 0; j < 32 && j < len; j++, mask <<= 1)
1765 res = scm_cons ((bits[i] & mask)? SCM_BOOL_T : SCM_BOOL_F, res);
1766 }
1767 }
1768 else
1769 {
1770 size_t i;
1771 for (i = 0; i < len; i++)
1772 res = scm_cons (scm_array_handle_ref (&handle, i), res);
20930f28
MV
1773 }
1774
20930f28
MV
1775 return scm_reverse_x (res, SCM_EOL);
1776}
1777#undef FUNC_NAME
1778
1779/* From mmix-arith.w by Knuth.
1780
1781 Here's a fun way to count the number of bits in a tetrabyte.
1782
1783 [This classical trick is called the ``Gillies--Miller method for
1784 sideways addition'' in {\sl The Preparation of Programs for an
1785 Electronic Digital Computer\/} by Wilkes, Wheeler, and Gill, second
1786 edition (Reading, Mass.:\ Addison--Wesley, 1957), 191--193. Some of
1787 the tricks used here were suggested by Balbir Singh, Peter
1788 Rossmanith, and Stefan Schwoon.]
1789*/
1790
1791static size_t
1792count_ones (scm_t_uint32 x)
1793{
1794 x=x-((x>>1)&0x55555555);
1795 x=(x&0x33333333)+((x>>2)&0x33333333);
1796 x=(x+(x>>4))&0x0f0f0f0f;
1797 x=x+(x>>8);
1798 return (x+(x>>16)) & 0xff;
1799}
0f2d19dd 1800
3b3b36dd 1801SCM_DEFINE (scm_bit_count, "bit-count", 2, 0, 0,
c7eb8761 1802 (SCM b, SCM bitvector),
1e6808ea 1803 "Return the number of occurrences of the boolean @var{b} in\n"
c7eb8761 1804 "@var{bitvector}.")
1bbd0b84 1805#define FUNC_NAME s_scm_bit_count
0f2d19dd 1806{
f0b91039
MV
1807 scm_t_array_handle handle;
1808 size_t off, len;
1809 ssize_t inc;
1810 scm_t_uint32 *bits;
20930f28 1811 int bit = scm_to_bool (b);
f0b91039 1812 size_t count = 0;
20930f28 1813
f0b91039
MV
1814 bits = scm_bitvector_writable_elements (bitvector, &handle,
1815 &off, &len, &inc);
20930f28 1816
f0b91039
MV
1817 if (off == 0 && inc == 1 && len > 0)
1818 {
1819 /* the usual case
1820 */
1821 size_t word_len = (len + 31) / 32;
1822 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1823 size_t i;
20930f28 1824
f0b91039
MV
1825 for (i = 0; i < word_len-1; i++)
1826 count += count_ones (bits[i]);
1827 count += count_ones (bits[i] & last_mask);
1828 }
1829 else
1830 {
1831 size_t i;
1832 for (i = 0; i < len; i++)
1833 if (scm_is_true (scm_array_handle_ref (&handle, i)))
1834 count++;
1835 }
1836
1837 return scm_from_size_t (bit? count : len-count);
0f2d19dd 1838}
1bbd0b84 1839#undef FUNC_NAME
0f2d19dd 1840
20930f28
MV
1841/* returns 32 for x == 0.
1842*/
1843static size_t
1844find_first_one (scm_t_uint32 x)
1845{
1846 size_t pos = 0;
1847 /* do a binary search in x. */
1848 if ((x & 0xFFFF) == 0)
1849 x >>= 16, pos += 16;
1850 if ((x & 0xFF) == 0)
1851 x >>= 8, pos += 8;
1852 if ((x & 0xF) == 0)
1853 x >>= 4, pos += 4;
1854 if ((x & 0x3) == 0)
1855 x >>= 2, pos += 2;
1856 if ((x & 0x1) == 0)
1857 pos += 1;
1858 return pos;
1859}
0f2d19dd 1860
3b3b36dd 1861SCM_DEFINE (scm_bit_position, "bit-position", 3, 0, 0,
1bbd0b84 1862 (SCM item, SCM v, SCM k),
88ecf5cb
KR
1863 "Return the index of the first occurrance of @var{item} in bit\n"
1864 "vector @var{v}, starting from @var{k}. If there is no\n"
1865 "@var{item} entry between @var{k} and the end of\n"
1866 "@var{bitvector}, then return @code{#f}. For example,\n"
1867 "\n"
1868 "@example\n"
1869 "(bit-position #t #*000101 0) @result{} 3\n"
1870 "(bit-position #f #*0001111 3) @result{} #f\n"
1871 "@end example")
1bbd0b84 1872#define FUNC_NAME s_scm_bit_position
0f2d19dd 1873{
f0b91039
MV
1874 scm_t_array_handle handle;
1875 size_t off, len, first_bit;
1876 ssize_t inc;
1877 const scm_t_uint32 *bits;
20930f28 1878 int bit = scm_to_bool (item);
20930f28 1879 SCM res = SCM_BOOL_F;
f0b91039
MV
1880
1881 bits = scm_bitvector_elements (v, &handle, &off, &len, &inc);
1882 first_bit = scm_to_unsigned_integer (k, 0, len);
20930f28 1883
f0b91039
MV
1884 if (off == 0 && inc == 1 && len > 0)
1885 {
1886 size_t i, word_len = (len + 31) / 32;
1887 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
1888 size_t first_word = first_bit / 32;
1889 scm_t_uint32 first_mask =
1890 ((scm_t_uint32)-1) << (first_bit - 32*first_word);
1891 scm_t_uint32 w;
1892
1893 for (i = first_word; i < word_len; i++)
1894 {
1895 w = (bit? bits[i] : ~bits[i]);
1896 if (i == first_word)
1897 w &= first_mask;
1898 if (i == word_len-1)
1899 w &= last_mask;
1900 if (w)
1901 {
1902 res = scm_from_size_t (32*i + find_first_one (w));
1903 break;
1904 }
1905 }
1906 }
1907 else
20930f28 1908 {
f0b91039
MV
1909 size_t i;
1910 for (i = first_bit; i < len; i++)
20930f28 1911 {
f0b91039
MV
1912 SCM elt = scm_array_handle_ref (&handle, i);
1913 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
1914 {
1915 res = scm_from_size_t (i);
1916 break;
1917 }
20930f28 1918 }
0f2d19dd 1919 }
20930f28 1920
20930f28 1921 return res;
0f2d19dd 1922}
1bbd0b84 1923#undef FUNC_NAME
0f2d19dd 1924
3b3b36dd 1925SCM_DEFINE (scm_bit_set_star_x, "bit-set*!", 3, 0, 0,
c7eb8761 1926 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
1927 "Set entries of bit vector @var{v} to @var{obj}, with @var{kv}\n"
1928 "selecting the entries to change. The return value is\n"
1929 "unspecified.\n"
1930 "\n"
1931 "If @var{kv} is a bit vector, then those entries where it has\n"
1932 "@code{#t} are the ones in @var{v} which are set to @var{obj}.\n"
1933 "@var{kv} and @var{v} must be the same length. When @var{obj}\n"
1934 "is @code{#t} it's like @var{kv} is OR'ed into @var{v}. Or when\n"
1935 "@var{obj} is @code{#f} it can be seen as an ANDNOT.\n"
1936 "\n"
1937 "@example\n"
1938 "(define bv #*01000010)\n"
1939 "(bit-set*! bv #*10010001 #t)\n"
1940 "bv\n"
1941 "@result{} #*11010011\n"
1942 "@end example\n"
1943 "\n"
85368844
MV
1944 "If @var{kv} is a u32vector, then its elements are\n"
1945 "indices into @var{v} which are set to @var{obj}.\n"
88ecf5cb
KR
1946 "\n"
1947 "@example\n"
1948 "(define bv #*01000010)\n"
85368844 1949 "(bit-set*! bv #u32(5 2 7) #t)\n"
88ecf5cb
KR
1950 "bv\n"
1951 "@result{} #*01100111\n"
1952 "@end example")
1bbd0b84 1953#define FUNC_NAME s_scm_bit_set_star_x
0f2d19dd 1954{
f0b91039
MV
1955 scm_t_array_handle v_handle;
1956 size_t v_off, v_len;
1957 ssize_t v_inc;
1958 scm_t_uint32 *v_bits;
1959 int bit;
1960
1961 /* Validate that OBJ is a boolean so this is done even if we don't
1962 need BIT.
1963 */
1964 bit = scm_to_bool (obj);
1965
1966 v_bits = scm_bitvector_writable_elements (v, &v_handle,
1967 &v_off, &v_len, &v_inc);
1968
20930f28
MV
1969 if (scm_is_bitvector (kv))
1970 {
f0b91039
MV
1971 scm_t_array_handle kv_handle;
1972 size_t kv_off, kv_len;
1973 ssize_t kv_inc;
1974 const scm_t_uint32 *kv_bits;
1975
1976 kv_bits = scm_bitvector_elements (v, &kv_handle,
1977 &kv_off, &kv_len, &kv_inc);
1978
1979 if (v_len != kv_len)
85368844
MV
1980 scm_misc_error (NULL,
1981 "bit vectors must have equal length",
1982 SCM_EOL);
1983
f0b91039
MV
1984 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
1985 {
1986 size_t word_len = (kv_len + 31) / 32;
1987 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
1988 size_t i;
1989
1990 if (bit == 0)
1991 {
1992 for (i = 0; i < word_len-1; i++)
1993 v_bits[i] &= ~kv_bits[i];
1994 v_bits[i] &= ~(kv_bits[i] & last_mask);
1995 }
1996 else
1997 {
1998 for (i = 0; i < word_len-1; i++)
1999 v_bits[i] |= kv_bits[i];
2000 v_bits[i] |= kv_bits[i] & last_mask;
2001 }
2002 }
85368844 2003 else
f0b91039
MV
2004 {
2005 size_t i;
2006 for (i = 0; i < kv_len; i++)
2007 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2008 scm_array_handle_set (&v_handle, i, obj);
2009 }
85368844
MV
2010 }
2011 else if (scm_is_true (scm_u32vector_p (kv)))
2012 {
f0b91039
MV
2013 scm_t_array_handle kv_handle;
2014 size_t i, kv_len;
2015 ssize_t kv_inc;
2016 const scm_t_uint32 *kv_elts;
2017
2018 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2019 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2020 scm_array_handle_set (&v_handle, (size_t) *kv_elts, obj);
0f2d19dd 2021 }
20930f28 2022 else
85368844
MV
2023 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
2024
0f2d19dd
JB
2025 return SCM_UNSPECIFIED;
2026}
1bbd0b84 2027#undef FUNC_NAME
0f2d19dd
JB
2028
2029
3b3b36dd 2030SCM_DEFINE (scm_bit_count_star, "bit-count*", 3, 0, 0,
1bbd0b84 2031 (SCM v, SCM kv, SCM obj),
88ecf5cb
KR
2032 "Return a count of how many entries in bit vector @var{v} are\n"
2033 "equal to @var{obj}, with @var{kv} selecting the entries to\n"
2034 "consider.\n"
2035 "\n"
2036 "If @var{kv} is a bit vector, then those entries where it has\n"
2037 "@code{#t} are the ones in @var{v} which are considered.\n"
2038 "@var{kv} and @var{v} must be the same length.\n"
2039 "\n"
85368844
MV
2040 "If @var{kv} is a u32vector, then it contains\n"
2041 "the indexes in @var{v} to consider.\n"
88ecf5cb
KR
2042 "\n"
2043 "For example,\n"
2044 "\n"
2045 "@example\n"
2046 "(bit-count* #*01110111 #*11001101 #t) @result{} 3\n"
85368844 2047 "(bit-count* #*01110111 #u32(7 0 4) #f) @result{} 2\n"
88ecf5cb 2048 "@end example")
1bbd0b84 2049#define FUNC_NAME s_scm_bit_count_star
0f2d19dd 2050{
f0b91039
MV
2051 scm_t_array_handle v_handle;
2052 size_t v_off, v_len;
2053 ssize_t v_inc;
2054 const scm_t_uint32 *v_bits;
2055 size_t count = 0;
2056 int bit;
2057
2058 /* Validate that OBJ is a boolean so this is done even if we don't
2059 need BIT.
2060 */
2061 bit = scm_to_bool (obj);
2062
2063 v_bits = scm_bitvector_elements (v, &v_handle,
2064 &v_off, &v_len, &v_inc);
2065
20930f28 2066 if (scm_is_bitvector (kv))
0f2d19dd 2067 {
f0b91039
MV
2068 scm_t_array_handle kv_handle;
2069 size_t kv_off, kv_len;
2070 ssize_t kv_inc;
2071 const scm_t_uint32 *kv_bits;
2072
2073 kv_bits = scm_bitvector_elements (v, &kv_handle,
2074 &kv_off, &kv_len, &kv_inc);
85368844 2075
f0b91039 2076 if (v_len != kv_len)
85368844
MV
2077 scm_misc_error (NULL,
2078 "bit vectors must have equal length",
2079 SCM_EOL);
2080
f0b91039
MV
2081 if (v_off == 0 && v_inc == 1 && kv_off == 0 && kv_inc == 1 && kv_len > 0)
2082 {
2083 size_t i, word_len = (kv_len + 31) / 32;
2084 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - kv_len);
2085 scm_t_uint32 xor_mask = bit? 0 : ((scm_t_uint32)-1);
2086
2087 for (i = 0; i < word_len-1; i++)
2088 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i]);
2089 count += count_ones ((v_bits[i]^xor_mask) & kv_bits[i] & last_mask);
2090 }
2091 else
2092 {
2093 size_t i;
2094 for (i = 0; i < kv_len; i++)
2095 if (scm_is_true (scm_array_handle_ref (&kv_handle, i)))
2096 {
2097 SCM elt = scm_array_handle_ref (&v_handle, i);
2098 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2099 count++;
2100 }
2101 }
0f2d19dd 2102 }
85368844
MV
2103 else if (scm_is_true (scm_u32vector_p (kv)))
2104 {
f0b91039
MV
2105 scm_t_array_handle kv_handle;
2106 size_t i, kv_len;
2107 ssize_t kv_inc;
2108 const scm_t_uint32 *kv_elts;
d44ff083 2109
f0b91039
MV
2110 kv_elts = scm_u32vector_elements (kv, &kv_handle, &kv_len, &kv_inc);
2111 for (i = 0; i < kv_len; i++, kv_elts += kv_inc)
2112 {
2113 SCM elt = scm_array_handle_ref (&v_handle, *kv_elts);
2114 if ((bit && scm_is_true (elt)) || (!bit && scm_is_false (elt)))
2115 count++;
2116 }
85368844 2117 }
20930f28 2118 else
85368844 2119 scm_wrong_type_arg_msg (NULL, 0, kv, "bitvector or u32vector");
f0b91039
MV
2120
2121 return scm_from_size_t (count);
0f2d19dd 2122}
1bbd0b84 2123#undef FUNC_NAME
0f2d19dd 2124
3b3b36dd 2125SCM_DEFINE (scm_bit_invert_x, "bit-invert!", 1, 0, 0,
1bbd0b84 2126 (SCM v),
88ecf5cb
KR
2127 "Modify the bit vector @var{v} by replacing each element with\n"
2128 "its negation.")
1bbd0b84 2129#define FUNC_NAME s_scm_bit_invert_x
0f2d19dd 2130{
f0b91039
MV
2131 scm_t_array_handle handle;
2132 size_t off, len;
2133 ssize_t inc;
2134 scm_t_uint32 *bits;
74014c46 2135
f0b91039
MV
2136 bits = scm_bitvector_writable_elements (v, &handle, &off, &len, &inc);
2137
2138 if (off == 0 && inc == 1 && len > 0)
2139 {
2140 size_t word_len = (len + 31) / 32;
2141 scm_t_uint32 last_mask = ((scm_t_uint32)-1) >> (32*word_len - len);
2142 size_t i;
2143
2144 for (i = 0; i < word_len-1; i++)
2145 bits[i] = ~bits[i];
2146 bits[i] = bits[i] ^ last_mask;
2147 }
2148 else
2149 {
2150 size_t i;
2151 for (i = 0; i < len; i++)
2152 scm_array_handle_set (&handle, i,
2153 scm_not (scm_array_handle_ref (&handle, i)));
2154 }
74014c46 2155
0f2d19dd
JB
2156 return SCM_UNSPECIFIED;
2157}
1bbd0b84 2158#undef FUNC_NAME
0f2d19dd
JB
2159
2160
0f2d19dd 2161SCM
cc95e00a 2162scm_istr2bve (SCM str)
0f2d19dd 2163{
f0b91039 2164 scm_t_array_handle handle;
cc95e00a 2165 size_t len = scm_i_string_length (str);
20930f28
MV
2166 SCM vec = scm_c_make_bitvector (len, SCM_UNDEFINED);
2167 SCM res = vec;
2168
2169 scm_t_uint32 mask;
2170 size_t k, j;
f0b91039
MV
2171 const char *c_str;
2172 scm_t_uint32 *data;
2173
2174 data = scm_bitvector_writable_elements (vec, &handle, NULL, NULL, NULL);
2175 c_str = scm_i_string_chars (str);
cc95e00a 2176
20930f28 2177 for (k = 0; k < (len + 31) / 32; k++)
0f2d19dd
JB
2178 {
2179 data[k] = 0L;
20930f28
MV
2180 j = len - k * 32;
2181 if (j > 32)
2182 j = 32;
0f2d19dd 2183 for (mask = 1L; j--; mask <<= 1)
cc95e00a 2184 switch (*c_str++)
0f2d19dd
JB
2185 {
2186 case '0':
2187 break;
2188 case '1':
2189 data[k] |= mask;
2190 break;
2191 default:
20930f28
MV
2192 res = SCM_BOOL_F;
2193 goto exit;
0f2d19dd
JB
2194 }
2195 }
20930f28
MV
2196
2197 exit:
2198 scm_remember_upto_here_1 (str);
20930f28 2199 return res;
0f2d19dd
JB
2200}
2201
2202
1cc91f1b 2203
0f2d19dd 2204static SCM
34d19ef6 2205ra2l (SCM ra, unsigned long base, unsigned long k)
0f2d19dd 2206{
02339e5b
MV
2207 SCM res = SCM_EOL;
2208 long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2209 size_t i;
2210 int enclosed = SCM_ENCLOSED_ARRAYP (ra);
2211
0f2d19dd
JB
2212 if (SCM_ARRAY_DIMS (ra)[k].ubnd < SCM_ARRAY_DIMS (ra)[k].lbnd)
2213 return SCM_EOL;
2214 i = base + (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd) * inc;
2215 if (k < SCM_ARRAY_NDIM (ra) - 1)
2216 {
2217 do
2218 {
2219 i -= inc;
2220 res = scm_cons (ra2l (ra, i, k + 1), res);
2221 }
2222 while (i != base);
2223 }
2224 else
2225 do
2226 {
2227 i -= inc;
02339e5b
MV
2228 res = scm_cons (scm_i_cvref (SCM_ARRAY_V (ra), i, enclosed),
2229 res);
0f2d19dd
JB
2230 }
2231 while (i != base);
2232 return res;
2233}
2234
2235
cd328b4f 2236SCM_DEFINE (scm_array_to_list, "array->list", 1, 0, 0,
1bbd0b84 2237 (SCM v),
1e6808ea
MG
2238 "Return a list consisting of all the elements, in order, of\n"
2239 "@var{array}.")
cd328b4f 2240#define FUNC_NAME s_scm_array_to_list
0f2d19dd 2241{
20930f28
MV
2242 if (scm_is_generalized_vector (v))
2243 return scm_generalized_vector_to_list (v);
02339e5b 2244 else if (SCM_ARRAYP (v) || SCM_ENCLOSED_ARRAYP (v))
20930f28 2245 return ra2l (v, SCM_ARRAY_BASE (v), 0);
e0e49670 2246
20930f28 2247 scm_wrong_type_arg_msg (NULL, 0, v, "array");
0f2d19dd 2248}
1bbd0b84 2249#undef FUNC_NAME
0f2d19dd
JB
2250
2251
c014a02e 2252static int l2ra(SCM lst, SCM ra, unsigned long base, unsigned long k);
1cc91f1b 2253
f301dbf3
MV
2254SCM_DEFINE (scm_list_to_typed_array, "list->typed-array", 3, 0, 0,
2255 (SCM type, SCM ndim, SCM lst),
2256 "Return an array of the type @var{type}\n"
2257 "with elements the same as those of @var{lst}.\n"
bfad4005
MV
2258 "\n"
2259 "The argument @var{ndim} determines the number of dimensions\n"
2260 "of the array. It is either an exact integer, giving the\n"
20930f28 2261 "number directly, or a list of exact integers, whose length\n"
bfad4005
MV
2262 "specifies the number of dimensions and each element is the\n"
2263 "lower index bound of its dimension.")
f301dbf3 2264#define FUNC_NAME s_scm_list_to_typed_array
0f2d19dd 2265{
bfad4005 2266 SCM shape, row;
0f2d19dd 2267 SCM ra;
c014a02e 2268 unsigned long k;
bfad4005
MV
2269
2270 shape = SCM_EOL;
2271 row = lst;
2272 if (scm_is_integer (ndim))
0f2d19dd 2273 {
bfad4005
MV
2274 size_t k = scm_to_size_t (ndim);
2275 while (k-- > 0)
2276 {
2277 shape = scm_cons (scm_length (row), shape);
2278 if (k > 0)
2279 row = scm_car (row);
2280 }
2281 }
2282 else
2283 {
2284 while (1)
2285 {
2286 shape = scm_cons (scm_list_2 (scm_car (ndim),
2287 scm_sum (scm_sum (scm_car (ndim),
2288 scm_length (row)),
2289 scm_from_int (-1))),
2290 shape);
2291 ndim = scm_cdr (ndim);
2292 if (scm_is_pair (ndim))
2293 row = scm_car (row);
2294 else
2295 break;
2296 }
0f2d19dd 2297 }
bfad4005 2298
f0b91039
MV
2299 ra = scm_make_typed_array (type, SCM_UNSPECIFIED,
2300 scm_reverse_x (shape, SCM_EOL));
20930f28 2301
bfad4005 2302 if (scm_is_null (shape))
0f2d19dd
JB
2303 {
2304 SCM_ASRTGO (1 == scm_ilength (lst), badlst);
2305 scm_array_set_x (ra, SCM_CAR (lst), SCM_EOL);
2306 return ra;
2307 }
2308 if (!SCM_ARRAYP (ra))
2309 {
20930f28 2310 size_t length = scm_c_generalized_vector_length (ra);
74014c46 2311 for (k = 0; k < length; k++, lst = SCM_CDR (lst))
20930f28 2312 scm_c_generalized_vector_set_x (ra, k, SCM_CAR (lst));
0f2d19dd
JB
2313 return ra;
2314 }
2315 if (l2ra (lst, ra, SCM_ARRAY_BASE (ra), 0))
2316 return ra;
2317 else
1afff620
KN
2318 badlst:SCM_MISC_ERROR ("Bad scm_array contents list: ~S",
2319 scm_list_1 (lst));
0f2d19dd 2320}
1bbd0b84 2321#undef FUNC_NAME
0f2d19dd 2322
f301dbf3
MV
2323SCM_DEFINE (scm_list_to_array, "list->array", 2, 0, 0,
2324 (SCM ndim, SCM lst),
2325 "Return an array with elements the same as those of @var{lst}.")
2326#define FUNC_NAME s_scm_list_to_array
2327{
2328 return scm_list_to_typed_array (SCM_BOOL_T, ndim, lst);
2329}
2330#undef FUNC_NAME
2331
0f2d19dd 2332static int
c014a02e 2333l2ra (SCM lst, SCM ra, unsigned long base, unsigned long k)
0f2d19dd 2334{
c014a02e
ML
2335 register long inc = SCM_ARRAY_DIMS (ra)[k].inc;
2336 register long n = (1 + SCM_ARRAY_DIMS (ra)[k].ubnd - SCM_ARRAY_DIMS (ra)[k].lbnd);
0f2d19dd
JB
2337 int ok = 1;
2338 if (n <= 0)
d2e53ed6 2339 return (scm_is_null (lst));
0f2d19dd
JB
2340 if (k < SCM_ARRAY_NDIM (ra) - 1)
2341 {
2342 while (n--)
2343 {
d2e53ed6 2344 if (!scm_is_pair (lst))
0f2d19dd
JB
2345 return 0;
2346 ok = ok && l2ra (SCM_CAR (lst), ra, base, k + 1);
2347 base += inc;
2348 lst = SCM_CDR (lst);
2349 }
d2e53ed6 2350 if (!scm_is_null (lst))
0f2d19dd
JB
2351 return 0;
2352 }
2353 else
2354 {
2355 while (n--)
2356 {
d2e53ed6 2357 if (!scm_is_pair (lst))
0f2d19dd 2358 return 0;
e11e83f3 2359 scm_array_set_x (SCM_ARRAY_V (ra), SCM_CAR (lst), scm_from_ulong (base));
0f2d19dd
JB
2360 base += inc;
2361 lst = SCM_CDR (lst);
2362 }
d2e53ed6 2363 if (!scm_is_null (lst))
fee7ef83 2364 return 0;
0f2d19dd
JB
2365 }
2366 return ok;
2367}
2368
f301dbf3
MV
2369#if SCM_ENABLE_DEPRECATED
2370
2371SCM_DEFINE (scm_list_to_uniform_array, "list->uniform-array", 3, 0, 0,
2372 (SCM ndim, SCM prot, SCM lst),
2373 "Return a uniform array of the type indicated by prototype\n"
2374 "@var{prot} with elements the same as those of @var{lst}.\n"
2375 "Elements must be of the appropriate type, no coercions are\n"
2376 "done.\n"
2377 "\n"
2378 "The argument @var{ndim} determines the number of dimensions\n"
2379 "of the array. It is either an exact integer, giving the\n"
2380 "number directly, or a list of exact integers, whose length\n"
2381 "specifies the number of dimensions and each element is the\n"
2382 "lower index bound of its dimension.")
2383#define FUNC_NAME s_scm_list_to_uniform_array
2384{
2385 return scm_list_to_typed_array (prototype_to_type (prot), ndim, lst);
2386}
2387#undef FUNC_NAME
2388
2389#endif
1cc91f1b 2390
e0e49670
MV
2391/* Print dimension DIM of ARRAY.
2392 */
0f2d19dd 2393
e0e49670 2394static int
02339e5b 2395scm_i_print_array_dimension (SCM array, int dim, int base, int enclosed,
e0e49670
MV
2396 SCM port, scm_print_state *pstate)
2397{
2398 scm_t_array_dim *dim_spec = SCM_ARRAY_DIMS (array) + dim;
2399 long idx;
2400
2401 scm_putc ('(', port);
2402
e0e49670
MV
2403 for (idx = dim_spec->lbnd; idx <= dim_spec->ubnd; idx++)
2404 {
2405 if (dim < SCM_ARRAY_NDIM(array)-1)
02339e5b
MV
2406 scm_i_print_array_dimension (array, dim+1, base, enclosed,
2407 port, pstate);
e0e49670 2408 else
02339e5b 2409 scm_iprin1 (scm_i_cvref (SCM_ARRAY_V (array), base, enclosed),
e0e49670
MV
2410 port, pstate);
2411 if (idx < dim_spec->ubnd)
2412 scm_putc (' ', port);
2413 base += dim_spec->inc;
2414 }
2415
2416 scm_putc (')', port);
2417 return 1;
2418}
2419
f301dbf3 2420/* Print an array. (Only for strict arrays, not for generalized vectors.)
e0e49670
MV
2421*/
2422
e0e49670
MV
2423static int
2424scm_i_print_array (SCM array, SCM port, scm_print_state *pstate)
2425{
2426 long ndim = SCM_ARRAY_NDIM (array);
2427 scm_t_array_dim *dim_specs = SCM_ARRAY_DIMS (array);
20930f28 2428 SCM v = SCM_ARRAY_V (array);
e0e49670
MV
2429 unsigned long base = SCM_ARRAY_BASE (array);
2430 long i;
2431
2432 scm_putc ('#', port);
c0fc64c8 2433 if (ndim != 1 || dim_specs[0].lbnd != 0)
e0e49670 2434 scm_intprint (ndim, 10, port);
20930f28
MV
2435 if (scm_is_uniform_vector (v))
2436 scm_puts (scm_i_uniform_vector_tag (v), port);
2437 else if (scm_is_bitvector (v))
2438 scm_puts ("b", port);
2439 else if (scm_is_string (v))
2440 scm_puts ("a", port);
2441 else if (!scm_is_vector (v))
2442 scm_puts ("?", port);
2443
e0e49670
MV
2444 for (i = 0; i < ndim; i++)
2445 if (dim_specs[i].lbnd != 0)
2446 {
2447 for (i = 0; i < ndim; i++)
2448 {
2449 scm_putc ('@', port);
2450 scm_uintprint (dim_specs[i].lbnd, 10, port);
2451 }
2452 break;
2453 }
2454
02339e5b
MV
2455 return scm_i_print_array_dimension (array, 0, base, 0, port, pstate);
2456}
2457
2458static int
2459scm_i_print_enclosed_array (SCM array, SCM port, scm_print_state *pstate)
2460{
2461 size_t base;
2462
2463 scm_putc ('#', port);
2464 base = SCM_ARRAY_BASE (array);
2465 scm_puts ("<enclosed-array ", port);
2466 scm_i_print_array_dimension (array, 0, base, 1, port, pstate);
2467 scm_putc ('>', port);
2468 return 1;
e0e49670 2469}
1cc91f1b 2470
bfad4005
MV
2471/* Read an array. This function can also read vectors and uniform
2472 vectors. Also, the conflict between '#f' and '#f32' and '#f64' is
2473 handled here.
2474
2475 C is the first character read after the '#'.
2476*/
2477
bfad4005 2478static SCM
f301dbf3 2479tag_to_type (const char *tag, SCM port)
bfad4005 2480{
bfad4005
MV
2481#if SCM_ENABLE_DEPRECATED
2482 {
f301dbf3 2483 /* Recognize the old syntax.
bfad4005 2484 */
bfad4005
MV
2485 const char *instead;
2486 switch (tag[0])
2487 {
bfad4005 2488 case 'u':
bfad4005
MV
2489 instead = "u32";
2490 break;
2491 case 'e':
bfad4005
MV
2492 instead = "s32";
2493 break;
2494 case 's':
bfad4005
MV
2495 instead = "f32";
2496 break;
2497 case 'i':
bfad4005
MV
2498 instead = "f64";
2499 break;
2500 case 'y':
bfad4005
MV
2501 instead = "s8";
2502 break;
2503 case 'h':
bfad4005
MV
2504 instead = "s16";
2505 break;
2506 case 'l':
bfad4005
MV
2507 instead = "s64";
2508 break;
2509 case 'c':
72d05aa4
MV
2510 instead = "c64";
2511 break;
2512 default:
f301dbf3 2513 instead = NULL;
bfad4005
MV
2514 break;
2515 }
f301dbf3
MV
2516
2517 if (instead && tag[1] == '\0')
bfad4005
MV
2518 {
2519 scm_c_issue_deprecation_warning_fmt
2520 ("The tag '%c' is deprecated for uniform vectors. "
2521 "Use '%s' instead.", tag[0], instead);
f301dbf3 2522 return scm_from_locale_symbol (instead);
bfad4005
MV
2523 }
2524 }
2525#endif
2526
f301dbf3 2527 return scm_from_locale_symbol (tag);
bfad4005
MV
2528}
2529
2530SCM
2531scm_i_read_array (SCM port, int c)
2532{
2533 size_t rank;
2534 int got_rank;
2535 char tag[80];
2536 int tag_len;
2537
2538 SCM lower_bounds, elements;
2539
2540 /* XXX - shortcut for ordinary vectors. Shouldn't be necessary but
2541 the array code can not deal with zero-length dimensions yet, and
2542 we want to allow zero-length vectors, of course.
2543 */
2544 if (c == '(')
2545 {
2546 scm_ungetc (c, port);
2547 return scm_vector (scm_read (port));
2548 }
2549
2550 /* Disambiguate between '#f' and uniform floating point vectors.
2551 */
2552 if (c == 'f')
2553 {
2554 c = scm_getc (port);
2555 if (c != '3' && c != '6')
2556 {
2557 if (c != EOF)
2558 scm_ungetc (c, port);
2559 return SCM_BOOL_F;
2560 }
2561 rank = 1;
2562 got_rank = 1;
2563 tag[0] = 'f';
2564 tag_len = 1;
2565 goto continue_reading_tag;
2566 }
2567
2568 /* Read rank. We disallow arrays of rank zero since they do not
2569 seem to work reliably yet. */
2570 rank = 0;
2571 got_rank = 0;
2572 while ('0' <= c && c <= '9')
2573 {
2574 rank = 10*rank + c-'0';
2575 got_rank = 1;
2576 c = scm_getc (port);
2577 }
2578 if (!got_rank)
2579 rank = 1;
2580 else if (rank == 0)
2581 scm_i_input_error (NULL, port,
2582 "array rank must be positive", SCM_EOL);
2583
2584 /* Read tag. */
2585 tag_len = 0;
2586 continue_reading_tag:
2587 while (c != EOF && c != '(' && c != '@' && tag_len < 80)
2588 {
2589 tag[tag_len++] = c;
2590 c = scm_getc (port);
2591 }
2592 tag[tag_len] = '\0';
2593
2594 /* Read lower bounds. */
2595 lower_bounds = SCM_EOL;
2596 while (c == '@')
2597 {
2598 /* Yeah, right, we should use some ready-made integer parsing
2599 routine for this...
2600 */
2601
2602 long lbnd = 0;
2603 long sign = 1;
2604
2605 c = scm_getc (port);
2606 if (c == '-')
2607 {
2608 sign = -1;
2609 c = scm_getc (port);
2610 }
2611 while ('0' <= c && c <= '9')
2612 {
2613 lbnd = 10*lbnd + c-'0';
2614 c = scm_getc (port);
2615 }
2616 lower_bounds = scm_cons (scm_from_long (sign*lbnd), lower_bounds);
2617 }
2618
2619 /* Read nested lists of elements.
2620 */
2621 if (c != '(')
2622 scm_i_input_error (NULL, port,
2623 "missing '(' in vector or array literal",
2624 SCM_EOL);
2625 scm_ungetc (c, port);
2626 elements = scm_read (port);
2627
2628 if (scm_is_null (lower_bounds))
2629 lower_bounds = scm_from_size_t (rank);
2630 else if (scm_ilength (lower_bounds) != rank)
2631 scm_i_input_error (NULL, port,
2632 "the number of lower bounds must match the array rank",
2633 SCM_EOL);
2634
2635 /* Construct array. */
f301dbf3
MV
2636 return scm_list_to_typed_array (tag_to_type (tag, port),
2637 lower_bounds,
2638 elements);
bfad4005
MV
2639}
2640
0f2d19dd 2641int
1bbd0b84 2642scm_raprin1 (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 2643{
02339e5b 2644 scm_iprin1 (exp, port, pstate);
0f2d19dd
JB
2645 return 1;
2646}
2647
f301dbf3 2648SCM_DEFINE (scm_array_type, "array-type", 1, 0, 0,
ab1be174 2649 (SCM ra),
f301dbf3
MV
2650 "")
2651#define FUNC_NAME s_scm_array_type
ab1be174 2652{
ab1be174 2653 if (SCM_ARRAYP (ra))
f301dbf3 2654 return scm_i_generalized_vector_type (SCM_ARRAY_V (ra));
02339e5b 2655 else if (scm_is_generalized_vector (ra))
f301dbf3 2656 return scm_i_generalized_vector_type (ra);
02339e5b
MV
2657 else if (SCM_ENCLOSED_ARRAYP (ra))
2658 scm_wrong_type_arg_msg (NULL, 0, ra, "non-enclosed array");
ab1be174 2659 else
02339e5b 2660 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
ab1be174
MV
2661}
2662#undef FUNC_NAME
2663
72d05aa4
MV
2664#if SCM_ENABLE_DEPRECATED
2665
3b3b36dd 2666SCM_DEFINE (scm_array_prototype, "array-prototype", 1, 0, 0,
1bbd0b84 2667 (SCM ra),
1e6808ea
MG
2668 "Return an object that would produce an array of the same type\n"
2669 "as @var{array}, if used as the @var{prototype} for\n"
b380b885 2670 "@code{make-uniform-array}.")
1bbd0b84 2671#define FUNC_NAME s_scm_array_prototype
0f2d19dd 2672{
20930f28 2673 if (SCM_ARRAYP (ra))
02339e5b 2674 return scm_i_get_old_prototype (SCM_ARRAY_V (ra));
20930f28
MV
2675 else if (scm_is_generalized_vector (ra))
2676 return scm_i_get_old_prototype (ra);
02339e5b
MV
2677 else if (SCM_ENCLOSED_ARRAYP (ra))
2678 return SCM_UNSPECIFIED;
20930f28
MV
2679 else
2680 scm_wrong_type_arg_msg (NULL, 0, ra, "array");
0f2d19dd 2681}
1bbd0b84 2682#undef FUNC_NAME
0f2d19dd 2683
72d05aa4 2684#endif
1cc91f1b 2685
0f2d19dd 2686static SCM
e841c3e0 2687array_mark (SCM ptr)
0f2d19dd 2688{
0f2d19dd
JB
2689 return SCM_ARRAY_V (ptr);
2690}
2691
1be6b49c 2692static size_t
e841c3e0 2693array_free (SCM ptr)
0f2d19dd 2694{
4c9419ac
MV
2695 scm_gc_free (SCM_ARRAY_MEM (ptr),
2696 (sizeof (scm_t_array)
2697 + SCM_ARRAY_NDIM (ptr) * sizeof (scm_t_array_dim)),
2698 "array");
2699 return 0;
0f2d19dd
JB
2700}
2701
0f2d19dd
JB
2702void
2703scm_init_unif ()
0f2d19dd 2704{
e841c3e0
KN
2705 scm_tc16_array = scm_make_smob_type ("array", 0);
2706 scm_set_smob_mark (scm_tc16_array, array_mark);
2707 scm_set_smob_free (scm_tc16_array, array_free);
02339e5b 2708 scm_set_smob_print (scm_tc16_array, scm_i_print_array);
e841c3e0 2709 scm_set_smob_equalp (scm_tc16_array, scm_array_equal_p);
02339e5b
MV
2710
2711 scm_tc16_enclosed_array = scm_make_smob_type ("enclosed-array", 0);
2712 scm_set_smob_mark (scm_tc16_enclosed_array, array_mark);
2713 scm_set_smob_free (scm_tc16_enclosed_array, array_free);
2714 scm_set_smob_print (scm_tc16_enclosed_array, scm_i_print_enclosed_array);
2715 scm_set_smob_equalp (scm_tc16_enclosed_array, scm_array_equal_p);
2716
0f2d19dd 2717 scm_add_feature ("array");
20930f28
MV
2718
2719 scm_tc16_bitvector = scm_make_smob_type ("bitvector", 0);
2720 scm_set_smob_free (scm_tc16_bitvector, bitvector_free);
2721 scm_set_smob_print (scm_tc16_bitvector, bitvector_print);
2722 scm_set_smob_equalp (scm_tc16_bitvector, bitvector_equalp);
2723
f301dbf3
MV
2724 init_type_creator_table ();
2725
a0599745 2726#include "libguile/unif.x"
bfad4005 2727
0f2d19dd 2728}
89e00824
ML
2729
2730/*
2731 Local Variables:
2732 c-file-style: "gnu"
2733 End:
2734*/