1 /* Copyright (C) 1995,1996,1998,1999,2000,2001, 2006, 2008, 2009, 2010,
2 * 2011, 2012, 2014 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
))
121 if (SCM_I_WVECTP (v
))
122 scm_c_issue_deprecation_warning
123 ("Using vector-length on weak vectors is deprecated. "
124 "Use weak-vector-length from (ice-9 weak-vectors) instead.");
125 return scm_from_size_t (SCM_I_VECTOR_LENGTH (v
));
127 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
129 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
130 return scm_from_size_t (dim
->ubnd
- dim
->lbnd
+ 1);
133 SCM_WTA_DISPATCH_1 (g_vector_length
, v
, 1, NULL
);
137 scm_c_vector_length (SCM v
)
139 if (SCM_I_IS_NONWEAK_VECTOR (v
))
140 return SCM_I_VECTOR_LENGTH (v
);
142 return scm_to_size_t (scm_vector_length (v
));
145 SCM_REGISTER_PROC (s_list_to_vector
, "list->vector", 1, 0, 0, scm_vector
);
147 "Return a newly created vector initialized to the elements of"
148 "the list @var{list}.\n\n"
150 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
151 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
154 SCM_DEFINE (scm_vector
, "vector", 0, 0, 1,
156 "@deffnx {Scheme Procedure} list->vector l\n"
157 "Return a newly allocated vector composed of the\n"
158 "given arguments. Analogous to @code{list}.\n"
161 "(vector 'a 'b 'c) @result{} #(a b c)\n"
163 #define FUNC_NAME s_scm_vector
168 scm_t_array_handle handle
;
170 SCM_VALIDATE_LIST_COPYLEN (1, l
, len
);
172 res
= scm_c_make_vector (len
, SCM_UNSPECIFIED
);
173 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
175 while (scm_is_pair (l
) && i
< len
)
177 data
[i
] = SCM_CAR (l
);
182 scm_array_handle_release (&handle
);
188 SCM_GPROC (s_vector_ref
, "vector-ref", 2, 0, 0, scm_vector_ref
, g_vector_ref
);
191 "@var{k} must be a valid index of @var{vector}.\n"
192 "@samp{Vector-ref} returns the contents of element @var{k} of\n"
195 "(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8\n"
196 "(vector-ref '#(1 1 2 3 5 8 13 21)\n"
197 " (let ((i (round (* 2 (acos -1)))))\n"
198 " (if (inexact? i)\n"
199 " (inexact->exact i)\n"
200 " i))) @result{} 13\n"
205 scm_vector_ref (SCM v
, SCM k
)
206 #define FUNC_NAME s_vector_ref
208 return scm_c_vector_ref (v
, scm_to_size_t (k
));
213 scm_c_vector_ref (SCM v
, size_t k
)
215 if (SCM_I_IS_NONWEAK_VECTOR (v
))
219 if (k
>= SCM_I_VECTOR_LENGTH (v
))
220 scm_out_of_range (NULL
, scm_from_size_t (k
));
221 elt
= (SCM_I_VECTOR_ELTS(v
))[k
];
225 else if (SCM_I_WVECTP (v
))
227 scm_c_issue_deprecation_warning
228 ("Using vector-ref on weak vectors is deprecated. "
229 "Instead, use weak-vector-ref from (ice-9 weak-vectors).");
230 return scm_c_weak_vector_ref (v
, k
);
232 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
234 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
235 SCM vv
= SCM_I_ARRAY_V (v
);
236 if (SCM_I_IS_VECTOR (vv
))
240 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
241 scm_out_of_range (NULL
, scm_from_size_t (k
));
242 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
243 elt
= (SCM_I_VECTOR_ELTS (vv
))[k
];
245 if (SCM_UNPACK (elt
) == 0 && (SCM_I_WVECTP (vv
)))
247 scm_c_issue_deprecation_warning
248 ("Weak arrays are deprecated. Use weak vectors instead.");
249 /* ELT was a weak pointer and got nullified by the GC. */
255 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
258 SCM_WTA_DISPATCH_2 (g_vector_ref
, v
, scm_from_size_t (k
), 2, NULL
);
261 SCM_GPROC (s_vector_set_x
, "vector-set!", 3, 0, 0, scm_vector_set_x
, g_vector_set_x
);
263 /* "@var{k} must be a valid index of @var{vector}.\n"
264 "@code{Vector-set!} stores @var{obj} in element @var{k} of @var{vector}.\n"
265 "The value returned by @samp{vector-set!} is unspecified.\n"
267 "(let ((vec (vector 0 '(2 2 2 2) "Anna")))\n"
268 " (vector-set! vec 1 '("Sue" "Sue"))\n"
269 " vec) @result{} #(0 ("Sue" "Sue") "Anna")\n"
270 "(vector-set! '#(0 1 2) 1 "doe") @result{} @emph{error} ; constant vector\n"
275 scm_vector_set_x (SCM v
, SCM k
, SCM obj
)
276 #define FUNC_NAME s_vector_set_x
278 scm_c_vector_set_x (v
, scm_to_size_t (k
), obj
);
279 return SCM_UNSPECIFIED
;
284 scm_c_vector_set_x (SCM v
, size_t k
, SCM obj
)
286 if (SCM_I_IS_NONWEAK_VECTOR (v
))
288 if (k
>= SCM_I_VECTOR_LENGTH (v
))
289 scm_out_of_range (NULL
, scm_from_size_t (k
));
290 (SCM_I_VECTOR_WELTS(v
))[k
] = obj
;
292 else if (SCM_I_WVECTP (v
))
294 scm_c_issue_deprecation_warning
295 ("Using vector-set! on weak vectors is deprecated. "
296 "Instead, use weak-vector-set! from (ice-9 weak-vectors).");
297 scm_c_weak_vector_set_x (v
, k
, obj
);
299 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
301 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
302 SCM vv
= SCM_I_ARRAY_V (v
);
303 if (SCM_I_IS_VECTOR (vv
))
305 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
306 scm_out_of_range (NULL
, scm_from_size_t (k
));
307 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
308 (SCM_I_VECTOR_WELTS (vv
))[k
] = obj
;
310 if (SCM_I_WVECTP (vv
))
312 /* Make it a weak pointer. */
313 SCM
*link
= & SCM_I_VECTOR_WELTS (vv
)[k
];
314 SCM_I_REGISTER_DISAPPEARING_LINK ((void **) link
, SCM2PTR (obj
));
315 scm_c_issue_deprecation_warning
316 ("Weak arrays are deprecated. Use weak vectors instead.");
320 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
324 if (SCM_UNPACK (g_vector_set_x
))
325 scm_apply_generic (g_vector_set_x
,
326 scm_list_3 (v
, scm_from_size_t (k
), obj
));
328 scm_wrong_type_arg_msg (NULL
, 0, v
, "vector");
332 SCM_DEFINE (scm_make_vector
, "make-vector", 1, 1, 0,
334 "Return a newly allocated vector of @var{k} elements. If a\n"
335 "second argument is given, then each position is initialized to\n"
336 "@var{fill}. Otherwise the initial contents of each position is\n"
338 #define FUNC_NAME s_scm_make_vector
340 size_t l
= scm_to_unsigned_integer (k
, 0, VECTOR_MAX_LENGTH
);
342 if (SCM_UNBNDP (fill
))
343 fill
= SCM_UNSPECIFIED
;
345 return scm_c_make_vector (l
, fill
);
351 scm_c_make_vector (size_t k
, SCM fill
)
352 #define FUNC_NAME s_scm_make_vector
357 scm_gc_malloc ((k
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
),
365 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
367 base
= vector
+ SCM_I_VECTOR_HEADER_SIZE
;
368 for (j
= 0; j
!= k
; ++j
)
372 ((scm_t_bits
*) vector
)[0] = (k
<< 8) | scm_tc7_vector
;
373 ((scm_t_bits
*) vector
)[1] = 0;
375 return PTR2SCM (vector
);
379 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
381 "Return a copy of @var{vec}.")
382 #define FUNC_NAME s_scm_vector_copy
384 scm_t_array_handle handle
;
390 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
392 result
= scm_c_make_vector (len
, SCM_UNDEFINED
);
393 dst
= SCM_I_VECTOR_WELTS (result
);
394 for (i
= 0; i
< len
; i
++, src
+= inc
)
397 scm_array_handle_release (&handle
);
406 /* Allocate memory for the elements of a weak vector on behalf of the
409 make_weak_vector (scm_t_bits type
, size_t c_size
)
414 total_size
= (c_size
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
);
415 vector
= (SCM
*) scm_gc_malloc_pointerless (total_size
, "weak vector");
417 ((scm_t_bits
*) vector
)[0] = (c_size
<< 8) | scm_tc7_wvect
;
418 ((scm_t_bits
*) vector
)[1] = type
;
420 return PTR2SCM (vector
);
423 /* Return a new weak vector. The allocated vector will be of the given weak
424 vector subtype. It will contain SIZE elements which are initialized with
425 the FILL object, or, if FILL is undefined, with an unspecified object. */
427 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
432 if (SCM_UNBNDP (fill
))
433 fill
= SCM_UNSPECIFIED
;
435 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
436 wv
= make_weak_vector (type
, c_size
);
437 base
= SCM_I_WVECT_GC_WVELTS (wv
);
439 for (j
= 0; j
!= c_size
; ++j
)
445 /* Return a new weak vector with type TYPE and whose content are taken from
448 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
453 c_size
= scm_ilength (lst
);
454 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
456 wv
= make_weak_vector(type
, (size_t) c_size
);
458 for (elt
= SCM_I_WVECT_GC_WVELTS (wv
);
460 lst
= SCM_CDR (lst
), elt
++)
462 *elt
= SCM_CAR (lst
);
470 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
472 "Return a newly allocated list composed of the elements of @var{v}.\n"
475 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
476 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
478 #define FUNC_NAME s_scm_vector_to_list
482 scm_t_array_handle handle
;
483 size_t i
, count
, len
;
486 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
487 for (i
= (len
- 1) * inc
, count
= 0;
490 res
= scm_cons (data
[i
], res
);
492 scm_array_handle_release (&handle
);
498 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
500 "Store @var{fill} in every position of @var{vector}. The value\n"
501 "returned by @code{vector-fill!} is unspecified.")
502 #define FUNC_NAME s_scm_vector_fill_x
504 scm_t_array_handle handle
;
509 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
510 for (i
= 0; i
< len
; i
+= inc
)
512 scm_array_handle_release (&handle
);
513 return SCM_UNSPECIFIED
;
519 scm_i_vector_equal_p (SCM x
, SCM y
)
522 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
523 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
524 SCM_I_VECTOR_ELTS (y
)[i
])))
530 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
531 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
532 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
533 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
534 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
535 "@code{vector-move-left!} copies elements in leftmost order.\n"
536 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
537 "same vector, @code{vector-move-left!} is usually appropriate when\n"
538 "@var{start1} is greater than @var{start2}.")
539 #define FUNC_NAME s_scm_vector_move_left_x
541 scm_t_array_handle handle1
, handle2
;
548 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
549 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
551 i
= scm_to_unsigned_integer (start1
, 0, len1
);
552 e
= scm_to_unsigned_integer (end1
, i
, len1
);
553 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
554 j
= scm_to_unsigned_integer (start2
, 0, len2
);
555 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
560 for (; i
< e
; i
+= inc1
, j
+= inc2
)
563 scm_array_handle_release (&handle2
);
564 scm_array_handle_release (&handle1
);
566 return SCM_UNSPECIFIED
;
570 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
571 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
572 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
573 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
574 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
575 "@code{vector-move-right!} copies elements in rightmost order.\n"
576 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
577 "same vector, @code{vector-move-right!} is usually appropriate when\n"
578 "@var{start1} is less than @var{start2}.")
579 #define FUNC_NAME s_scm_vector_move_right_x
581 scm_t_array_handle handle1
, handle2
;
588 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
589 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
591 i
= scm_to_unsigned_integer (start1
, 0, len1
);
592 e
= scm_to_unsigned_integer (end1
, i
, len1
);
593 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
594 j
= scm_to_unsigned_integer (start2
, 0, len2
);
595 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
609 scm_array_handle_release (&handle2
);
610 scm_array_handle_release (&handle1
);
612 return SCM_UNSPECIFIED
;
618 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
620 if (idx
> h
->dims
[0].ubnd
)
621 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
622 return ((SCM
*)h
->elements
)[idx
];
626 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
628 if (idx
> h
->dims
[0].ubnd
)
629 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
630 ((SCM
*)h
->writable_elements
)[idx
] = val
;
634 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
640 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
642 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
643 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
646 /* the & ~2 allows catching scm_tc7_wvect as well. needs changing if you change
648 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
649 vector_handle_ref
, vector_handle_set
,
651 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
)
657 #include "libguile/vectors.x"