1 /* Copyright (C) 1995,1996,1998,1999,2000,2001, 2006, 2008, 2009, 2010,
2 * 2011, 2012 Free Software Foundation, Inc.
4 * This library is free software; you can redistribute it and/or
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.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
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
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include "libguile/_scm.h"
27 #include "libguile/eq.h"
28 #include "libguile/root.h"
29 #include "libguile/strings.h"
31 #include "libguile/validate.h"
32 #include "libguile/vectors.h"
33 #include "libguile/arrays.h" /* Hit me with the ugly stick */
34 #include "libguile/generalized-vectors.h"
35 #include "libguile/strings.h"
36 #include "libguile/srfi-13.h"
37 #include "libguile/dynwind.h"
38 #include "libguile/deprecation.h"
40 #include "libguile/bdw-gc.h"
45 #define VECTOR_MAX_LENGTH (SCM_T_BITS_MAX >> 8)
48 scm_is_vector (SCM obj
)
50 if (SCM_I_IS_VECTOR (obj
))
52 if (SCM_I_ARRAYP (obj
) && SCM_I_ARRAY_NDIM (obj
) == 1)
54 SCM v
= SCM_I_ARRAY_V (obj
);
55 return SCM_I_IS_VECTOR (v
);
61 scm_is_simple_vector (SCM obj
)
63 return SCM_I_IS_VECTOR (obj
);
67 scm_vector_elements (SCM vec
, scm_t_array_handle
*h
,
68 size_t *lenp
, ssize_t
*incp
)
70 if (SCM_I_WVECTP (vec
))
71 /* FIXME: We should check each (weak) element of the vector for NULL and
72 convert it to SCM_BOOL_F. */
75 scm_generalized_vector_get_handle (vec
, h
);
78 scm_t_array_dim
*dim
= scm_array_handle_dims (h
);
79 *lenp
= dim
->ubnd
- dim
->lbnd
+ 1;
82 return scm_array_handle_elements (h
);
86 scm_vector_writable_elements (SCM vec
, scm_t_array_handle
*h
,
87 size_t *lenp
, ssize_t
*incp
)
89 if (SCM_I_WVECTP (vec
))
90 /* FIXME: We should check each (weak) element of the vector for NULL and
91 convert it to SCM_BOOL_F. */
94 scm_generalized_vector_get_handle (vec
, h
);
97 scm_t_array_dim
*dim
= scm_array_handle_dims (h
);
98 *lenp
= dim
->ubnd
- dim
->lbnd
+ 1;
101 return scm_array_handle_writable_elements (h
);
104 SCM_DEFINE (scm_vector_p
, "vector?", 1, 0, 0,
106 "Return @code{#t} if @var{obj} is a vector, otherwise return\n"
108 #define FUNC_NAME s_scm_vector_p
110 return scm_from_bool (scm_is_vector (obj
));
114 SCM_GPROC (s_vector_length
, "vector-length", 1, 0, 0, scm_vector_length
, g_vector_length
);
115 /* Returns the number of elements in @var{vector} as an exact integer. */
117 scm_vector_length (SCM v
)
119 if (SCM_I_IS_VECTOR (v
))
120 return scm_from_size_t (SCM_I_VECTOR_LENGTH (v
));
121 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
123 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
124 return scm_from_size_t (dim
->ubnd
- dim
->lbnd
+ 1);
127 SCM_WTA_DISPATCH_1 (g_vector_length
, v
, 1, NULL
);
131 scm_c_vector_length (SCM v
)
133 if (SCM_I_IS_VECTOR (v
))
134 return SCM_I_VECTOR_LENGTH (v
);
136 return scm_to_size_t (scm_vector_length (v
));
139 SCM_REGISTER_PROC (s_list_to_vector
, "list->vector", 1, 0, 0, scm_vector
);
141 "Return a newly created vector initialized to the elements of"
142 "the list @var{list}.\n\n"
144 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
145 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
148 SCM_DEFINE (scm_vector
, "vector", 0, 0, 1,
150 "@deffnx {Scheme Procedure} list->vector l\n"
151 "Return a newly allocated vector composed of the\n"
152 "given arguments. Analogous to @code{list}.\n"
155 "(vector 'a 'b 'c) @result{} #(a b c)\n"
157 #define FUNC_NAME s_scm_vector
162 scm_t_array_handle handle
;
164 SCM_VALIDATE_LIST_COPYLEN (1, l
, len
);
166 res
= scm_c_make_vector (len
, SCM_UNSPECIFIED
);
167 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
169 while (scm_is_pair (l
) && i
< len
)
171 data
[i
] = SCM_CAR (l
);
176 scm_array_handle_release (&handle
);
182 SCM_GPROC (s_vector_ref
, "vector-ref", 2, 0, 0, scm_vector_ref
, g_vector_ref
);
185 "@var{k} must be a valid index of @var{vector}.\n"
186 "@samp{Vector-ref} returns the contents of element @var{k} of\n"
189 "(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8\n"
190 "(vector-ref '#(1 1 2 3 5 8 13 21)\n"
191 " (let ((i (round (* 2 (acos -1)))))\n"
192 " (if (inexact? i)\n"
193 " (inexact->exact i)\n"
194 " i))) @result{} 13\n"
199 scm_vector_ref (SCM v
, SCM k
)
200 #define FUNC_NAME s_vector_ref
202 return scm_c_vector_ref (v
, scm_to_size_t (k
));
207 scm_c_vector_ref (SCM v
, size_t k
)
209 if (SCM_I_IS_VECTOR (v
))
213 if (k
>= SCM_I_VECTOR_LENGTH (v
))
214 scm_out_of_range (NULL
, scm_from_size_t (k
));
215 elt
= (SCM_I_VECTOR_ELTS(v
))[k
];
217 if (SCM_UNPACK (elt
) == 0 && SCM_I_WVECTP (v
))
218 /* ELT was a weak pointer and got nullified by the GC. */
223 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
225 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
226 SCM vv
= SCM_I_ARRAY_V (v
);
227 if (SCM_I_IS_VECTOR (vv
))
231 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
232 scm_out_of_range (NULL
, scm_from_size_t (k
));
233 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
234 elt
= (SCM_I_VECTOR_ELTS (vv
))[k
];
236 if (SCM_UNPACK (elt
) == 0 && (SCM_I_WVECTP (vv
)))
237 /* ELT was a weak pointer and got nullified by the GC. */
242 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
245 SCM_WTA_DISPATCH_2 (g_vector_ref
, v
, scm_from_size_t (k
), 2, NULL
);
248 SCM_GPROC (s_vector_set_x
, "vector-set!", 3, 0, 0, scm_vector_set_x
, g_vector_set_x
);
250 /* "@var{k} must be a valid index of @var{vector}.\n"
251 "@code{Vector-set!} stores @var{obj} in element @var{k} of @var{vector}.\n"
252 "The value returned by @samp{vector-set!} is unspecified.\n"
254 "(let ((vec (vector 0 '(2 2 2 2) "Anna")))\n"
255 " (vector-set! vec 1 '("Sue" "Sue"))\n"
256 " vec) @result{} #(0 ("Sue" "Sue") "Anna")\n"
257 "(vector-set! '#(0 1 2) 1 "doe") @result{} @emph{error} ; constant vector\n"
262 scm_vector_set_x (SCM v
, SCM k
, SCM obj
)
263 #define FUNC_NAME s_vector_set_x
265 scm_c_vector_set_x (v
, scm_to_size_t (k
), obj
);
266 return SCM_UNSPECIFIED
;
271 scm_c_vector_set_x (SCM v
, size_t k
, SCM obj
)
273 if (SCM_I_IS_VECTOR (v
))
275 if (k
>= SCM_I_VECTOR_LENGTH (v
))
276 scm_out_of_range (NULL
, scm_from_size_t (k
));
277 (SCM_I_VECTOR_WELTS(v
))[k
] = obj
;
278 if (SCM_I_WVECTP (v
))
280 /* Make it a weak pointer. */
281 SCM
*link
= & SCM_I_VECTOR_WELTS (v
)[k
];
282 SCM_I_REGISTER_DISAPPEARING_LINK ((void **) link
, SCM2PTR (obj
));
285 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
287 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
288 SCM vv
= SCM_I_ARRAY_V (v
);
289 if (SCM_I_IS_VECTOR (vv
))
291 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
292 scm_out_of_range (NULL
, scm_from_size_t (k
));
293 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
294 (SCM_I_VECTOR_WELTS (vv
))[k
] = obj
;
296 if (SCM_I_WVECTP (vv
))
298 /* Make it a weak pointer. */
299 SCM
*link
= & SCM_I_VECTOR_WELTS (vv
)[k
];
300 SCM_I_REGISTER_DISAPPEARING_LINK ((void **) link
, SCM2PTR (obj
));
304 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
308 if (SCM_UNPACK (g_vector_set_x
))
309 scm_apply_generic (g_vector_set_x
,
310 scm_list_3 (v
, scm_from_size_t (k
), obj
));
312 scm_wrong_type_arg_msg (NULL
, 0, v
, "vector");
316 SCM_DEFINE (scm_make_vector
, "make-vector", 1, 1, 0,
318 "Return a newly allocated vector of @var{k} elements. If a\n"
319 "second argument is given, then each position is initialized to\n"
320 "@var{fill}. Otherwise the initial contents of each position is\n"
322 #define FUNC_NAME s_scm_make_vector
324 size_t l
= scm_to_unsigned_integer (k
, 0, VECTOR_MAX_LENGTH
);
326 if (SCM_UNBNDP (fill
))
327 fill
= SCM_UNSPECIFIED
;
329 return scm_c_make_vector (l
, fill
);
335 scm_c_make_vector (size_t k
, SCM fill
)
336 #define FUNC_NAME s_scm_make_vector
341 scm_gc_malloc ((k
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
),
349 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
351 base
= vector
+ SCM_I_VECTOR_HEADER_SIZE
;
352 for (j
= 0; j
!= k
; ++j
)
356 ((scm_t_bits
*) vector
)[0] = (k
<< 8) | scm_tc7_vector
;
357 ((scm_t_bits
*) vector
)[1] = 0;
359 return PTR2SCM (vector
);
363 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
365 "Return a copy of @var{vec}.")
366 #define FUNC_NAME s_scm_vector_copy
368 scm_t_array_handle handle
;
374 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
376 result
= scm_c_make_vector (len
, SCM_UNDEFINED
);
377 dst
= SCM_I_VECTOR_WELTS (result
);
378 for (i
= 0; i
< len
; i
++, src
+= inc
)
381 scm_array_handle_release (&handle
);
390 /* Allocate memory for the elements of a weak vector on behalf of the
393 make_weak_vector (scm_t_bits type
, size_t c_size
)
398 total_size
= (c_size
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
);
399 vector
= (SCM
*) scm_gc_malloc_pointerless (total_size
, "weak vector");
401 ((scm_t_bits
*) vector
)[0] = (c_size
<< 8) | scm_tc7_wvect
;
402 ((scm_t_bits
*) vector
)[1] = type
;
404 return PTR2SCM (vector
);
407 /* Return a new weak vector. The allocated vector will be of the given weak
408 vector subtype. It will contain SIZE elements which are initialized with
409 the FILL object, or, if FILL is undefined, with an unspecified object. */
411 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
416 if (SCM_UNBNDP (fill
))
417 fill
= SCM_UNSPECIFIED
;
419 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
420 wv
= make_weak_vector (type
, c_size
);
421 base
= SCM_I_WVECT_GC_WVELTS (wv
);
423 for (j
= 0; j
!= c_size
; ++j
)
429 /* Return a new weak vector with type TYPE and whose content are taken from
432 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
437 c_size
= scm_ilength (lst
);
438 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
440 wv
= make_weak_vector(type
, (size_t) c_size
);
442 for (elt
= SCM_I_WVECT_GC_WVELTS (wv
);
444 lst
= SCM_CDR (lst
), elt
++)
446 *elt
= SCM_CAR (lst
);
454 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
456 "Return a newly allocated list composed of the elements of @var{v}.\n"
459 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
460 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
462 #define FUNC_NAME s_scm_vector_to_list
466 scm_t_array_handle handle
;
467 size_t i
, count
, len
;
470 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
471 for (i
= (len
- 1) * inc
, count
= 0;
474 res
= scm_cons (data
[i
], res
);
476 scm_array_handle_release (&handle
);
482 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
484 "Store @var{fill} in every position of @var{vector}. The value\n"
485 "returned by @code{vector-fill!} is unspecified.")
486 #define FUNC_NAME s_scm_vector_fill_x
488 scm_t_array_handle handle
;
493 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
494 for (i
= 0; i
< len
; i
+= inc
)
496 scm_array_handle_release (&handle
);
497 return SCM_UNSPECIFIED
;
503 scm_i_vector_equal_p (SCM x
, SCM y
)
506 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
507 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
508 SCM_I_VECTOR_ELTS (y
)[i
])))
514 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
515 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
516 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
517 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
518 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
519 "@code{vector-move-left!} copies elements in leftmost order.\n"
520 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
521 "same vector, @code{vector-move-left!} is usually appropriate when\n"
522 "@var{start1} is greater than @var{start2}.")
523 #define FUNC_NAME s_scm_vector_move_left_x
525 scm_t_array_handle handle1
, handle2
;
532 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
533 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
535 i
= scm_to_unsigned_integer (start1
, 0, len1
);
536 e
= scm_to_unsigned_integer (end1
, i
, len1
);
537 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
538 j
= scm_to_unsigned_integer (start2
, 0, len2
);
539 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
544 for (; i
< e
; i
+= inc1
, j
+= inc2
)
547 scm_array_handle_release (&handle2
);
548 scm_array_handle_release (&handle1
);
550 return SCM_UNSPECIFIED
;
554 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
555 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
556 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
557 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
558 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
559 "@code{vector-move-right!} copies elements in rightmost order.\n"
560 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
561 "same vector, @code{vector-move-right!} is usually appropriate when\n"
562 "@var{start1} is less than @var{start2}.")
563 #define FUNC_NAME s_scm_vector_move_right_x
565 scm_t_array_handle handle1
, handle2
;
572 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
573 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
575 i
= scm_to_unsigned_integer (start1
, 0, len1
);
576 e
= scm_to_unsigned_integer (end1
, i
, len1
);
577 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
578 j
= scm_to_unsigned_integer (start2
, 0, len2
);
579 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
593 scm_array_handle_release (&handle2
);
594 scm_array_handle_release (&handle1
);
596 return SCM_UNSPECIFIED
;
602 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
604 if (idx
> h
->dims
[0].ubnd
)
605 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
606 return ((SCM
*)h
->elements
)[idx
];
610 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
612 if (idx
> h
->dims
[0].ubnd
)
613 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
614 ((SCM
*)h
->writable_elements
)[idx
] = val
;
618 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
624 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
626 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
627 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
630 /* the & ~2 allows catching scm_tc7_wvect as well. needs changing if you change
632 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
633 vector_handle_ref
, vector_handle_set
,
635 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
)
641 #include "libguile/vectors.x"