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_NONWEAK_VECTOR (obj
))
52 if (SCM_I_WVECTP (obj
))
54 scm_c_issue_deprecation_warning
55 ("Expecting vector? to be true for weak vectors is deprecated. "
56 "Use weak-vector? instead.");
59 if (SCM_I_ARRAYP (obj
) && SCM_I_ARRAY_NDIM (obj
) == 1)
61 SCM v
= SCM_I_ARRAY_V (obj
);
62 if (SCM_I_IS_VECTOR (v
))
64 scm_c_issue_deprecation_warning
65 ("Expecting vector? to be true for rank-1 arrays is deprecated. "
66 "Use array?, array-rank, and array-type instead.");
75 scm_is_simple_vector (SCM obj
)
77 if (SCM_I_IS_NONWEAK_VECTOR (obj
))
79 if (SCM_I_WVECTP (obj
))
81 scm_c_issue_deprecation_warning
82 ("Expecting scm_is_simple_vector to be true for weak vectors is "
83 "deprecated. Use scm_is_weak_vector instead.");
90 scm_vector_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_elements (h
);
109 scm_vector_writable_elements (SCM vec
, scm_t_array_handle
*h
,
110 size_t *lenp
, ssize_t
*incp
)
112 if (SCM_I_WVECTP (vec
))
113 /* FIXME: We should check each (weak) element of the vector for NULL and
114 convert it to SCM_BOOL_F. */
117 scm_generalized_vector_get_handle (vec
, h
);
120 scm_t_array_dim
*dim
= scm_array_handle_dims (h
);
121 *lenp
= dim
->ubnd
- dim
->lbnd
+ 1;
124 return scm_array_handle_writable_elements (h
);
127 SCM_DEFINE (scm_vector_p
, "vector?", 1, 0, 0,
129 "Return @code{#t} if @var{obj} is a vector, otherwise return\n"
131 #define FUNC_NAME s_scm_vector_p
133 return scm_from_bool (scm_is_vector (obj
));
137 SCM_GPROC (s_vector_length
, "vector-length", 1, 0, 0, scm_vector_length
, g_vector_length
);
138 /* Returns the number of elements in @var{vector} as an exact integer. */
140 scm_vector_length (SCM v
)
142 if (SCM_I_IS_VECTOR (v
))
144 if (SCM_I_WVECTP (v
))
145 scm_c_issue_deprecation_warning
146 ("Using vector-length on weak vectors is deprecated. "
147 "Use weak-vector-length from (ice-9 weak-vectors) instead.");
148 return scm_from_size_t (SCM_I_VECTOR_LENGTH (v
));
150 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
152 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
153 scm_c_issue_deprecation_warning
154 ("Using vector-length on arrays is deprecated. "
155 "Use array-length instead.");
156 return scm_from_size_t (dim
->ubnd
- dim
->lbnd
+ 1);
158 else if (SCM_UNPACK (g_vector_length
))
160 scm_c_issue_deprecation_warning
161 ("Using vector-length as a primitive-generic is deprecated.");
162 return scm_call_generic_1 (g_vector_length
, v
);
166 scm_wrong_type_arg_msg ("vector-length", 1, v
, "vector");
167 return SCM_UNDEFINED
; /* not reached */
172 scm_c_vector_length (SCM v
)
174 if (SCM_I_IS_NONWEAK_VECTOR (v
))
175 return SCM_I_VECTOR_LENGTH (v
);
177 return scm_to_size_t (scm_vector_length (v
));
180 SCM_REGISTER_PROC (s_list_to_vector
, "list->vector", 1, 0, 0, scm_vector
);
182 "Return a newly created vector initialized to the elements of"
183 "the list @var{list}.\n\n"
185 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
186 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
189 SCM_DEFINE (scm_vector
, "vector", 0, 0, 1,
191 "@deffnx {Scheme Procedure} list->vector l\n"
192 "Return a newly allocated vector composed of the\n"
193 "given arguments. Analogous to @code{list}.\n"
196 "(vector 'a 'b 'c) @result{} #(a b c)\n"
198 #define FUNC_NAME s_scm_vector
203 scm_t_array_handle handle
;
205 SCM_VALIDATE_LIST_COPYLEN (1, l
, len
);
207 res
= scm_c_make_vector (len
, SCM_UNSPECIFIED
);
208 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
210 while (scm_is_pair (l
) && i
< len
)
212 data
[i
] = SCM_CAR (l
);
217 scm_array_handle_release (&handle
);
223 SCM_GPROC (s_vector_ref
, "vector-ref", 2, 0, 0, scm_vector_ref
, g_vector_ref
);
226 "@var{k} must be a valid index of @var{vector}.\n"
227 "@samp{Vector-ref} returns the contents of element @var{k} of\n"
230 "(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8\n"
231 "(vector-ref '#(1 1 2 3 5 8 13 21)\n"
232 " (let ((i (round (* 2 (acos -1)))))\n"
233 " (if (inexact? i)\n"
234 " (inexact->exact i)\n"
235 " i))) @result{} 13\n"
240 scm_vector_ref (SCM v
, SCM k
)
241 #define FUNC_NAME s_vector_ref
243 return scm_c_vector_ref (v
, scm_to_size_t (k
));
248 scm_c_vector_ref (SCM v
, size_t k
)
250 if (SCM_I_IS_NONWEAK_VECTOR (v
))
254 if (k
>= SCM_I_VECTOR_LENGTH (v
))
255 scm_out_of_range (NULL
, scm_from_size_t (k
));
256 elt
= (SCM_I_VECTOR_ELTS(v
))[k
];
260 else if (SCM_I_WVECTP (v
))
262 scm_c_issue_deprecation_warning
263 ("Using vector-ref on weak vectors is deprecated. "
264 "Instead, use weak-vector-ref from (ice-9 weak-vectors).");
265 return scm_c_weak_vector_ref (v
, k
);
267 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
269 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
270 SCM vv
= SCM_I_ARRAY_V (v
);
271 if (SCM_I_IS_VECTOR (vv
))
275 scm_c_issue_deprecation_warning
276 ("Using vector-ref on arrays is deprecated. "
277 "Use array-ref instead.");
279 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
280 scm_out_of_range (NULL
, scm_from_size_t (k
));
281 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
282 elt
= (SCM_I_VECTOR_ELTS (vv
))[k
];
284 if (SCM_UNPACK (elt
) == 0 && (SCM_I_WVECTP (vv
)))
286 scm_c_issue_deprecation_warning
287 ("Weak arrays are deprecated. Use weak vectors instead.");
288 /* ELT was a weak pointer and got nullified by the GC. */
294 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
296 else if (SCM_UNPACK (g_vector_ref
))
298 scm_c_issue_deprecation_warning
299 ("Using vector-ref as a primitive-generic is deprecated.");
300 return scm_call_generic_2 (g_vector_ref
, v
, scm_from_size_t (k
));
304 scm_wrong_type_arg_msg ("vector-ref", 1, v
, "vector");
305 return SCM_UNDEFINED
; /* not reached */
309 SCM_GPROC (s_vector_set_x
, "vector-set!", 3, 0, 0, scm_vector_set_x
, g_vector_set_x
);
311 /* "@var{k} must be a valid index of @var{vector}.\n"
312 "@code{Vector-set!} stores @var{obj} in element @var{k} of @var{vector}.\n"
313 "The value returned by @samp{vector-set!} is unspecified.\n"
315 "(let ((vec (vector 0 '(2 2 2 2) "Anna")))\n"
316 " (vector-set! vec 1 '("Sue" "Sue"))\n"
317 " vec) @result{} #(0 ("Sue" "Sue") "Anna")\n"
318 "(vector-set! '#(0 1 2) 1 "doe") @result{} @emph{error} ; constant vector\n"
323 scm_vector_set_x (SCM v
, SCM k
, SCM obj
)
324 #define FUNC_NAME s_vector_set_x
326 scm_c_vector_set_x (v
, scm_to_size_t (k
), obj
);
327 return SCM_UNSPECIFIED
;
332 scm_c_vector_set_x (SCM v
, size_t k
, SCM obj
)
334 if (SCM_I_IS_NONWEAK_VECTOR (v
))
336 if (k
>= SCM_I_VECTOR_LENGTH (v
))
337 scm_out_of_range (NULL
, scm_from_size_t (k
));
338 (SCM_I_VECTOR_WELTS(v
))[k
] = obj
;
340 else if (SCM_I_WVECTP (v
))
342 scm_c_issue_deprecation_warning
343 ("Using vector-set! on weak vectors is deprecated. "
344 "Instead, use weak-vector-set! from (ice-9 weak-vectors).");
345 scm_c_weak_vector_set_x (v
, k
, obj
);
347 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
349 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
350 SCM vv
= SCM_I_ARRAY_V (v
);
351 if (SCM_I_IS_VECTOR (vv
))
353 scm_c_issue_deprecation_warning
354 ("Using vector-set! on arrays is deprecated. "
355 "Use array-set! instead, but note the change in argument order.");
357 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
358 scm_out_of_range (NULL
, scm_from_size_t (k
));
359 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
360 (SCM_I_VECTOR_WELTS (vv
))[k
] = obj
;
362 if (SCM_I_WVECTP (vv
))
364 /* Make it a weak pointer. */
365 SCM
*link
= & SCM_I_VECTOR_WELTS (vv
)[k
];
366 SCM_I_REGISTER_DISAPPEARING_LINK ((void **) link
, SCM2PTR (obj
));
367 scm_c_issue_deprecation_warning
368 ("Weak arrays are deprecated. Use weak vectors instead.");
372 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
374 else if (SCM_UNPACK (g_vector_set_x
))
376 scm_c_issue_deprecation_warning
377 ("Using vector-set! as a primitive-generic is deprecated.");
378 scm_call_3 (g_vector_set_x
, v
, scm_from_size_t (k
), obj
);
381 scm_wrong_type_arg_msg ("vector-set!", 1, v
, "vector");
384 SCM_DEFINE (scm_make_vector
, "make-vector", 1, 1, 0,
386 "Return a newly allocated vector of @var{k} elements. If a\n"
387 "second argument is given, then each position is initialized to\n"
388 "@var{fill}. Otherwise the initial contents of each position is\n"
390 #define FUNC_NAME s_scm_make_vector
392 size_t l
= scm_to_unsigned_integer (k
, 0, VECTOR_MAX_LENGTH
);
394 if (SCM_UNBNDP (fill
))
395 fill
= SCM_UNSPECIFIED
;
397 return scm_c_make_vector (l
, fill
);
403 scm_c_make_vector (size_t k
, SCM fill
)
404 #define FUNC_NAME s_scm_make_vector
409 scm_gc_malloc ((k
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
),
417 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
419 base
= vector
+ SCM_I_VECTOR_HEADER_SIZE
;
420 for (j
= 0; j
!= k
; ++j
)
424 ((scm_t_bits
*) vector
)[0] = (k
<< 8) | scm_tc7_vector
;
425 ((scm_t_bits
*) vector
)[1] = 0;
427 return PTR2SCM (vector
);
431 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
433 "Return a copy of @var{vec}.")
434 #define FUNC_NAME s_scm_vector_copy
436 scm_t_array_handle handle
;
442 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
444 result
= scm_c_make_vector (len
, SCM_UNDEFINED
);
445 dst
= SCM_I_VECTOR_WELTS (result
);
446 for (i
= 0; i
< len
; i
++, src
+= inc
)
449 scm_array_handle_release (&handle
);
458 /* Allocate memory for the elements of a weak vector on behalf of the
461 make_weak_vector (scm_t_bits type
, size_t c_size
)
466 total_size
= (c_size
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
);
467 vector
= (SCM
*) scm_gc_malloc_pointerless (total_size
, "weak vector");
469 ((scm_t_bits
*) vector
)[0] = (c_size
<< 8) | scm_tc7_wvect
;
470 ((scm_t_bits
*) vector
)[1] = type
;
472 return PTR2SCM (vector
);
475 /* Return a new weak vector. The allocated vector will be of the given weak
476 vector subtype. It will contain SIZE elements which are initialized with
477 the FILL object, or, if FILL is undefined, with an unspecified object. */
479 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
484 if (SCM_UNBNDP (fill
))
485 fill
= SCM_UNSPECIFIED
;
487 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
488 wv
= make_weak_vector (type
, c_size
);
489 base
= SCM_I_WVECT_GC_WVELTS (wv
);
491 for (j
= 0; j
!= c_size
; ++j
)
497 /* Return a new weak vector with type TYPE and whose content are taken from
500 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
505 c_size
= scm_ilength (lst
);
506 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
508 wv
= make_weak_vector(type
, (size_t) c_size
);
510 for (elt
= SCM_I_WVECT_GC_WVELTS (wv
);
512 lst
= SCM_CDR (lst
), elt
++)
514 *elt
= SCM_CAR (lst
);
522 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
524 "Return a newly allocated list composed of the elements of @var{v}.\n"
527 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
528 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
530 #define FUNC_NAME s_scm_vector_to_list
534 scm_t_array_handle handle
;
535 size_t i
, count
, len
;
538 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
539 for (i
= (len
- 1) * inc
, count
= 0;
542 res
= scm_cons (data
[i
], res
);
544 scm_array_handle_release (&handle
);
550 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
552 "Store @var{fill} in every position of @var{vector}. The value\n"
553 "returned by @code{vector-fill!} is unspecified.")
554 #define FUNC_NAME s_scm_vector_fill_x
556 scm_t_array_handle handle
;
561 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
562 for (i
= 0; i
< len
; i
+= inc
)
564 scm_array_handle_release (&handle
);
565 return SCM_UNSPECIFIED
;
571 scm_i_vector_equal_p (SCM x
, SCM y
)
574 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
575 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
576 SCM_I_VECTOR_ELTS (y
)[i
])))
582 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
583 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
584 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
585 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
586 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
587 "@code{vector-move-left!} copies elements in leftmost order.\n"
588 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
589 "same vector, @code{vector-move-left!} is usually appropriate when\n"
590 "@var{start1} is greater than @var{start2}.")
591 #define FUNC_NAME s_scm_vector_move_left_x
593 scm_t_array_handle handle1
, handle2
;
600 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
601 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
603 i
= scm_to_unsigned_integer (start1
, 0, len1
);
604 e
= scm_to_unsigned_integer (end1
, i
, len1
);
605 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
606 j
= scm_to_unsigned_integer (start2
, 0, len2
);
607 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
612 for (; i
< e
; i
+= inc1
, j
+= inc2
)
615 scm_array_handle_release (&handle2
);
616 scm_array_handle_release (&handle1
);
618 return SCM_UNSPECIFIED
;
622 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
623 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
624 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
625 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
626 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
627 "@code{vector-move-right!} copies elements in rightmost order.\n"
628 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
629 "same vector, @code{vector-move-right!} is usually appropriate when\n"
630 "@var{start1} is less than @var{start2}.")
631 #define FUNC_NAME s_scm_vector_move_right_x
633 scm_t_array_handle handle1
, handle2
;
640 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
641 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
643 i
= scm_to_unsigned_integer (start1
, 0, len1
);
644 e
= scm_to_unsigned_integer (end1
, i
, len1
);
645 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
646 j
= scm_to_unsigned_integer (start2
, 0, len2
);
647 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
661 scm_array_handle_release (&handle2
);
662 scm_array_handle_release (&handle1
);
664 return SCM_UNSPECIFIED
;
670 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
672 if (idx
> h
->dims
[0].ubnd
)
673 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
674 return ((SCM
*)h
->elements
)[idx
];
678 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
680 if (idx
> h
->dims
[0].ubnd
)
681 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
682 ((SCM
*)h
->writable_elements
)[idx
] = val
;
686 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
692 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
694 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
695 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
698 /* the & ~2 allows catching scm_tc7_wvect as well. needs changing if you change
700 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
701 vector_handle_ref
, vector_handle_set
,
703 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
)
709 #include "libguile/vectors.x"