1 /* Copyright (C) 1995,1996,1998,1999,2000,2001, 2006, 2008, 2009 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * 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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include "libguile/_scm.h"
26 #include "libguile/eq.h"
27 #include "libguile/root.h"
28 #include "libguile/strings.h"
29 #include "libguile/lang.h"
31 #include "libguile/validate.h"
32 #include "libguile/vectors.h"
33 #include "libguile/generalized-vectors.h"
34 #include "libguile/arrays.h"
35 #include "libguile/bitvectors.h"
36 #include "libguile/bytevectors.h"
37 #include "libguile/array-map.h"
38 #include "libguile/srfi-4.h"
39 #include "libguile/strings.h"
40 #include "libguile/srfi-13.h"
41 #include "libguile/dynwind.h"
42 #include "libguile/deprecation.h"
44 #include "libguile/bdw-gc.h"
49 #define VECTOR_MAX_LENGTH (SCM_T_BITS_MAX >> 8)
52 scm_is_vector (SCM obj
)
54 if (SCM_I_IS_VECTOR (obj
))
56 if (SCM_I_ARRAYP (obj
) && SCM_I_ARRAY_NDIM (obj
) == 1)
58 SCM v
= SCM_I_ARRAY_V (obj
);
59 return SCM_I_IS_VECTOR (v
);
65 scm_is_simple_vector (SCM obj
)
67 return SCM_I_IS_VECTOR (obj
);
71 scm_vector_elements (SCM vec
, scm_t_array_handle
*h
,
72 size_t *lenp
, ssize_t
*incp
)
74 if (SCM_I_WVECTP (vec
))
75 /* FIXME: We should check each (weak) element of the vector for NULL and
76 convert it to SCM_BOOL_F. */
79 scm_generalized_vector_get_handle (vec
, h
);
82 scm_t_array_dim
*dim
= scm_array_handle_dims (h
);
83 *lenp
= dim
->ubnd
- dim
->lbnd
+ 1;
86 return scm_array_handle_elements (h
);
90 scm_vector_writable_elements (SCM vec
, scm_t_array_handle
*h
,
91 size_t *lenp
, ssize_t
*incp
)
93 if (SCM_I_WVECTP (vec
))
94 /* FIXME: We should check each (weak) element of the vector for NULL and
95 convert it to SCM_BOOL_F. */
98 scm_generalized_vector_get_handle (vec
, h
);
101 scm_t_array_dim
*dim
= scm_array_handle_dims (h
);
102 *lenp
= dim
->ubnd
- dim
->lbnd
+ 1;
105 return scm_array_handle_writable_elements (h
);
108 SCM_DEFINE (scm_vector_p
, "vector?", 1, 0, 0,
110 "Return @code{#t} if @var{obj} is a vector, otherwise return\n"
112 #define FUNC_NAME s_scm_vector_p
114 return scm_from_bool (scm_is_vector (obj
));
118 SCM_GPROC (s_vector_length
, "vector-length", 1, 0, 0, scm_vector_length
, g_vector_length
);
119 /* Returns the number of elements in @var{vector} as an exact integer. */
121 scm_vector_length (SCM v
)
123 if (SCM_I_IS_VECTOR (v
))
124 return scm_from_size_t (SCM_I_VECTOR_LENGTH (v
));
125 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
127 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
128 return scm_from_size_t (dim
->ubnd
- dim
->lbnd
+ 1);
131 SCM_WTA_DISPATCH_1 (g_vector_length
, v
, 1, NULL
);
135 scm_c_vector_length (SCM v
)
137 if (SCM_I_IS_VECTOR (v
))
138 return SCM_I_VECTOR_LENGTH (v
);
140 return scm_to_size_t (scm_vector_length (v
));
143 SCM_REGISTER_PROC (s_list_to_vector
, "list->vector", 1, 0, 0, scm_vector
);
145 "Return a newly created vector initialized to the elements of"
146 "the list @var{list}.\n\n"
148 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
149 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
152 SCM_DEFINE (scm_vector
, "vector", 0, 0, 1,
154 "@deffnx {Scheme Procedure} list->vector l\n"
155 "Return a newly allocated vector composed of the\n"
156 "given arguments. Analogous to @code{list}.\n"
159 "(vector 'a 'b 'c) @result{} #(a b c)\n"
161 #define FUNC_NAME s_scm_vector
166 scm_t_array_handle handle
;
168 SCM_VALIDATE_LIST_COPYLEN (1, l
, len
);
170 res
= scm_c_make_vector (len
, SCM_UNSPECIFIED
);
171 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
173 while (scm_is_pair (l
) && i
< len
)
175 data
[i
] = SCM_CAR (l
);
180 scm_array_handle_release (&handle
);
186 SCM_GPROC (s_vector_ref
, "vector-ref", 2, 0, 0, scm_vector_ref
, g_vector_ref
);
189 "@var{k} must be a valid index of @var{vector}.\n"
190 "@samp{Vector-ref} returns the contents of element @var{k} of\n"
193 "(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8\n"
194 "(vector-ref '#(1 1 2 3 5 8 13 21)\n"
195 " (let ((i (round (* 2 (acos -1)))))\n"
196 " (if (inexact? i)\n"
197 " (inexact->exact i)\n"
198 " i))) @result{} 13\n"
203 scm_vector_ref (SCM v
, SCM k
)
204 #define FUNC_NAME s_vector_ref
206 return scm_c_vector_ref (v
, scm_to_size_t (k
));
211 scm_c_vector_ref (SCM v
, size_t k
)
213 if (SCM_I_IS_VECTOR (v
))
217 if (k
>= SCM_I_VECTOR_LENGTH (v
))
218 scm_out_of_range (NULL
, scm_from_size_t (k
));
219 elt
= (SCM_I_VECTOR_ELTS(v
))[k
];
221 if ((elt
== SCM_PACK (NULL
)) && SCM_I_WVECTP (v
))
222 /* ELT was a weak pointer and got nullified by the GC. */
227 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
229 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
230 SCM vv
= SCM_I_ARRAY_V (v
);
231 if (SCM_I_IS_VECTOR (vv
))
235 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
236 scm_out_of_range (NULL
, scm_from_size_t (k
));
237 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
238 elt
= (SCM_I_VECTOR_ELTS (vv
))[k
];
240 if ((elt
== SCM_PACK (NULL
)) && (SCM_I_WVECTP (vv
)))
241 /* ELT was a weak pointer and got nullified by the GC. */
246 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
249 SCM_WTA_DISPATCH_2 (g_vector_ref
, v
, scm_from_size_t (k
), 2, NULL
);
252 SCM_GPROC (s_vector_set_x
, "vector-set!", 3, 0, 0, scm_vector_set_x
, g_vector_set_x
);
254 /* "@var{k} must be a valid index of @var{vector}.\n"
255 "@code{Vector-set!} stores @var{obj} in element @var{k} of @var{vector}.\n"
256 "The value returned by @samp{vector-set!} is unspecified.\n"
258 "(let ((vec (vector 0 '(2 2 2 2) "Anna")))\n"
259 " (vector-set! vec 1 '("Sue" "Sue"))\n"
260 " vec) @result{} #(0 ("Sue" "Sue") "Anna")\n"
261 "(vector-set! '#(0 1 2) 1 "doe") @result{} @emph{error} ; constant vector\n"
266 scm_vector_set_x (SCM v
, SCM k
, SCM obj
)
267 #define FUNC_NAME s_vector_set_x
269 scm_c_vector_set_x (v
, scm_to_size_t (k
), obj
);
270 return SCM_UNSPECIFIED
;
275 scm_c_vector_set_x (SCM v
, size_t k
, SCM obj
)
277 if (SCM_I_IS_VECTOR (v
))
279 if (k
>= SCM_I_VECTOR_LENGTH (v
))
280 scm_out_of_range (NULL
, scm_from_size_t (k
));
281 (SCM_I_VECTOR_WELTS(v
))[k
] = obj
;
282 if (SCM_I_WVECTP (v
))
284 /* Make it a weak pointer. */
285 GC_PTR link
= (GC_PTR
) & ((SCM_I_VECTOR_WELTS (v
))[k
]);
286 SCM_I_REGISTER_DISAPPEARING_LINK (link
, obj
);
289 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
291 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
292 SCM vv
= SCM_I_ARRAY_V (v
);
293 if (SCM_I_IS_VECTOR (vv
))
295 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
296 scm_out_of_range (NULL
, scm_from_size_t (k
));
297 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
298 (SCM_I_VECTOR_WELTS (vv
))[k
] = obj
;
300 if (SCM_I_WVECTP (vv
))
302 /* Make it a weak pointer. */
303 GC_PTR link
= (GC_PTR
) & ((SCM_I_VECTOR_WELTS (vv
))[k
]);
304 SCM_I_REGISTER_DISAPPEARING_LINK (link
, obj
);
308 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
312 if (SCM_UNPACK (g_vector_set_x
))
313 scm_apply_generic (g_vector_set_x
,
314 scm_list_3 (v
, scm_from_size_t (k
), obj
));
316 scm_wrong_type_arg_msg (NULL
, 0, v
, "vector");
320 SCM_DEFINE (scm_make_vector
, "make-vector", 1, 1, 0,
322 "Return a newly allocated vector of @var{k} elements. If a\n"
323 "second argument is given, then each position is initialized to\n"
324 "@var{fill}. Otherwise the initial contents of each position is\n"
326 #define FUNC_NAME s_scm_make_vector
328 size_t l
= scm_to_unsigned_integer (k
, 0, VECTOR_MAX_LENGTH
);
330 if (SCM_UNBNDP (fill
))
331 fill
= SCM_UNSPECIFIED
;
333 return scm_c_make_vector (l
, fill
);
339 scm_c_make_vector (size_t k
, SCM fill
)
340 #define FUNC_NAME s_scm_make_vector
345 scm_gc_malloc ((k
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
),
353 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
355 base
= vector
+ SCM_I_VECTOR_HEADER_SIZE
;
356 for (j
= 0; j
!= k
; ++j
)
360 ((scm_t_bits
*) vector
)[0] = (k
<< 8) | scm_tc7_vector
;
361 ((scm_t_bits
*) vector
)[1] = 0;
363 return PTR2SCM (vector
);
367 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
369 "Return a copy of @var{vec}.")
370 #define FUNC_NAME s_scm_vector_copy
372 scm_t_array_handle handle
;
378 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
380 result
= scm_c_make_vector (len
, SCM_UNDEFINED
);
381 dst
= SCM_I_VECTOR_WELTS (result
);
382 for (i
= 0; i
< len
; i
++, src
+= inc
)
385 scm_array_handle_release (&handle
);
394 /* Allocate memory for the elements of a weak vector on behalf of the
397 make_weak_vector (scm_t_bits type
, size_t c_size
)
402 total_size
= (c_size
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
);
403 vector
= (SCM
*) scm_gc_malloc_pointerless (total_size
, "weak vector");
405 ((scm_t_bits
*) vector
)[0] = (c_size
<< 8) | scm_tc7_wvect
;
406 ((scm_t_bits
*) vector
)[1] = type
;
408 return PTR2SCM (vector
);
411 /* Return a new weak vector. The allocated vector will be of the given weak
412 vector subtype. It will contain SIZE elements which are initialized with
413 the FILL object, or, if FILL is undefined, with an unspecified object. */
415 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
420 if (SCM_UNBNDP (fill
))
421 fill
= SCM_UNSPECIFIED
;
423 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
424 wv
= make_weak_vector (type
, c_size
);
425 base
= SCM_I_WVECT_GC_WVELTS (wv
);
427 for (j
= 0; j
!= c_size
; ++j
)
433 /* Return a new weak vector with type TYPE and whose content are taken from
436 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
441 c_size
= scm_ilength (lst
);
442 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
444 wv
= make_weak_vector(type
, (size_t) c_size
);
446 for (elt
= SCM_I_WVECT_GC_WVELTS (wv
);
448 lst
= SCM_CDR (lst
), elt
++)
450 *elt
= SCM_CAR (lst
);
458 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
460 "Return a newly allocated list composed of the elements of @var{v}.\n"
463 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
464 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
466 #define FUNC_NAME s_scm_vector_to_list
470 scm_t_array_handle handle
;
471 size_t i
, count
, len
;
474 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
475 for (i
= (len
- 1) * inc
, count
= 0;
478 res
= scm_cons (data
[i
], res
);
480 scm_array_handle_release (&handle
);
486 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
488 "Store @var{fill} in every position of @var{vector}. The value\n"
489 "returned by @code{vector-fill!} is unspecified.")
490 #define FUNC_NAME s_scm_vector_fill_x
492 scm_t_array_handle handle
;
497 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
498 for (i
= 0; i
< len
; i
+= inc
)
500 scm_array_handle_release (&handle
);
501 return SCM_UNSPECIFIED
;
507 scm_i_vector_equal_p (SCM x
, SCM y
)
510 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
511 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
512 SCM_I_VECTOR_ELTS (y
)[i
])))
518 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
519 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
520 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
521 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
522 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
523 "@code{vector-move-left!} copies elements in leftmost order.\n"
524 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
525 "same vector, @code{vector-move-left!} is usually appropriate when\n"
526 "@var{start1} is greater than @var{start2}.")
527 #define FUNC_NAME s_scm_vector_move_left_x
529 scm_t_array_handle handle1
, handle2
;
536 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
537 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
539 i
= scm_to_unsigned_integer (start1
, 0, len1
);
540 e
= scm_to_unsigned_integer (end1
, i
, len1
);
541 j
= scm_to_unsigned_integer (start2
, 0, len2
- (i
-e
));
546 for (; i
< e
; i
+= inc1
, j
+= inc2
)
549 scm_array_handle_release (&handle2
);
550 scm_array_handle_release (&handle1
);
552 return SCM_UNSPECIFIED
;
556 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
557 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
558 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
559 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
560 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
561 "@code{vector-move-right!} copies elements in rightmost order.\n"
562 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
563 "same vector, @code{vector-move-right!} is usually appropriate when\n"
564 "@var{start1} is less than @var{start2}.")
565 #define FUNC_NAME s_scm_vector_move_right_x
567 scm_t_array_handle handle1
, handle2
;
574 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
575 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
577 i
= scm_to_unsigned_integer (start1
, 0, len1
);
578 e
= scm_to_unsigned_integer (end1
, i
, len1
);
579 j
= scm_to_unsigned_integer (start2
, 0, len2
- (i
-e
));
591 scm_array_handle_release (&handle2
);
592 scm_array_handle_release (&handle1
);
594 return SCM_UNSPECIFIED
;
600 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
602 if (idx
> h
->dims
[0].ubnd
)
603 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
604 return ((SCM
*)h
->elements
)[idx
];
608 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
610 if (idx
> h
->dims
[0].ubnd
)
611 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
612 ((SCM
*)h
->writable_elements
)[idx
] = val
;
616 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
622 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
624 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
625 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
628 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
629 vector_handle_ref
, vector_handle_set
,
631 SCM_ARRAY_IMPLEMENTATION (scm_tc7_wvect
, 0x7f & ~2,
632 vector_handle_ref
, vector_handle_set
,
634 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
);
640 #include "libguile/vectors.x"