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/boehm-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 GC_GENERAL_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 GC_GENERAL_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
349 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
351 base
= scm_gc_malloc (k
* sizeof (SCM
), "vector");
352 for (j
= 0; j
!= k
; ++j
)
358 v
= scm_immutable_cell ((k
<< 8) | scm_tc7_vector
, (scm_t_bits
) base
);
359 scm_remember_upto_here_1 (fill
);
365 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
367 "Return a copy of @var{vec}.")
368 #define FUNC_NAME s_scm_vector_copy
370 scm_t_array_handle handle
;
376 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
377 dst
= scm_gc_malloc (len
* sizeof (SCM
), "vector");
378 for (i
= 0; i
< len
; i
++, src
+= inc
)
380 scm_array_handle_release (&handle
);
382 return scm_cell ((len
<< 8) | scm_tc7_vector
, (scm_t_bits
) dst
);
387 scm_i_vector_free (SCM vec
)
389 scm_gc_free (SCM_I_VECTOR_WELTS (vec
),
390 SCM_I_VECTOR_LENGTH (vec
) * sizeof(SCM
),
398 /* Initialize RET as a weak vector of type TYPE of SIZE elements pointed to
400 #define MAKE_WEAK_VECTOR(_ret, _type, _size, _base) \
401 (_ret) = scm_double_cell ((_size << 8) | scm_tc7_wvect, \
402 (scm_t_bits) (_base), \
404 SCM_UNPACK (SCM_EOL));
407 /* Allocate memory for the elements of a weak vector on behalf of the
410 allocate_weak_vector (scm_t_bits type
, size_t c_size
)
415 /* The base itself should not be scanned for pointers otherwise those
416 pointers will always be reachable. */
417 base
= scm_gc_malloc_pointerless (c_size
* sizeof (SCM
), "weak vector");
424 /* Return a new weak vector. The allocated vector will be of the given weak
425 vector subtype. It will contain SIZE elements which are initialized with
426 the FILL object, or, if FILL is undefined, with an unspecified object. */
428 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
433 if (SCM_UNBNDP (fill
))
434 fill
= SCM_UNSPECIFIED
;
436 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
437 base
= allocate_weak_vector (type
, c_size
);
439 for (j
= 0; j
!= c_size
; ++j
)
442 MAKE_WEAK_VECTOR (wv
, type
, c_size
, base
);
447 /* Return a new weak vector with type TYPE and whose content are taken from
450 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
455 c_size
= scm_ilength (lst
);
456 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
458 base
= allocate_weak_vector (type
, (size_t)c_size
);
461 lst
= SCM_CDR (lst
), elt
++)
463 *elt
= SCM_CAR (lst
);
466 MAKE_WEAK_VECTOR (wv
, type
, (size_t)c_size
, base
);
473 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
475 "Return a newly allocated list composed of the elements of @var{v}.\n"
478 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
479 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
481 #define FUNC_NAME s_scm_vector_to_list
485 scm_t_array_handle handle
;
486 size_t i
, count
, len
;
489 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
490 for (i
= (len
- 1) * inc
, count
= 0;
493 res
= scm_cons (data
[i
], res
);
495 scm_array_handle_release (&handle
);
501 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
503 "Store @var{fill} in every position of @var{vector}. The value\n"
504 "returned by @code{vector-fill!} is unspecified.")
505 #define FUNC_NAME s_scm_vector_fill_x
507 scm_t_array_handle handle
;
512 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
513 for (i
= 0; i
< len
; i
+= inc
)
515 scm_array_handle_release (&handle
);
516 return SCM_UNSPECIFIED
;
522 scm_i_vector_equal_p (SCM x
, SCM y
)
525 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
526 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
527 SCM_I_VECTOR_ELTS (y
)[i
])))
533 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
534 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
535 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
536 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
537 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
538 "@code{vector-move-left!} copies elements in leftmost order.\n"
539 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
540 "same vector, @code{vector-move-left!} is usually appropriate when\n"
541 "@var{start1} is greater than @var{start2}.")
542 #define FUNC_NAME s_scm_vector_move_left_x
544 scm_t_array_handle handle1
, handle2
;
551 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
552 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
554 i
= scm_to_unsigned_integer (start1
, 0, len1
);
555 e
= scm_to_unsigned_integer (end1
, i
, len1
);
556 j
= scm_to_unsigned_integer (start2
, 0, len2
- (i
-e
));
561 for (; i
< e
; i
+= inc1
, j
+= inc2
)
564 scm_array_handle_release (&handle2
);
565 scm_array_handle_release (&handle1
);
567 return SCM_UNSPECIFIED
;
571 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
572 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
573 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
574 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
575 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
576 "@code{vector-move-right!} copies elements in rightmost order.\n"
577 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
578 "same vector, @code{vector-move-right!} is usually appropriate when\n"
579 "@var{start1} is less than @var{start2}.")
580 #define FUNC_NAME s_scm_vector_move_right_x
582 scm_t_array_handle handle1
, handle2
;
589 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
590 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
592 i
= scm_to_unsigned_integer (start1
, 0, len1
);
593 e
= scm_to_unsigned_integer (end1
, i
, len1
);
594 j
= scm_to_unsigned_integer (start2
, 0, len2
- (i
-e
));
606 scm_array_handle_release (&handle2
);
607 scm_array_handle_release (&handle1
);
609 return SCM_UNSPECIFIED
;
615 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
617 if (idx
> h
->dims
[0].ubnd
)
618 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
619 return ((SCM
*)h
->elements
)[idx
];
623 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
625 if (idx
> h
->dims
[0].ubnd
)
626 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
627 ((SCM
*)h
->writable_elements
)[idx
] = val
;
631 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
637 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
639 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
640 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
643 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
644 vector_handle_ref
, vector_handle_set
,
646 SCM_ARRAY_IMPLEMENTATION (scm_tc7_wvect
, 0x7f & ~2,
647 vector_handle_ref
, vector_handle_set
,
649 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
);
655 scm_nullvect
= scm_c_make_vector (0, SCM_UNDEFINED
);
657 #include "libguile/vectors.x"