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);
132 else if (SCM_UNPACK (g_vector_length
))
134 scm_c_issue_deprecation_warning
135 ("Using vector-length as a primitive-generic is deprecated.");
136 return scm_call_generic_1 (g_vector_length
, v
);
140 scm_wrong_type_arg_msg ("vector-length", 1, v
, "vector");
141 return SCM_UNDEFINED
; /* not reached */
146 scm_c_vector_length (SCM v
)
148 if (SCM_I_IS_NONWEAK_VECTOR (v
))
149 return SCM_I_VECTOR_LENGTH (v
);
151 return scm_to_size_t (scm_vector_length (v
));
154 SCM_REGISTER_PROC (s_list_to_vector
, "list->vector", 1, 0, 0, scm_vector
);
156 "Return a newly created vector initialized to the elements of"
157 "the list @var{list}.\n\n"
159 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
160 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
163 SCM_DEFINE (scm_vector
, "vector", 0, 0, 1,
165 "@deffnx {Scheme Procedure} list->vector l\n"
166 "Return a newly allocated vector composed of the\n"
167 "given arguments. Analogous to @code{list}.\n"
170 "(vector 'a 'b 'c) @result{} #(a b c)\n"
172 #define FUNC_NAME s_scm_vector
177 scm_t_array_handle handle
;
179 SCM_VALIDATE_LIST_COPYLEN (1, l
, len
);
181 res
= scm_c_make_vector (len
, SCM_UNSPECIFIED
);
182 data
= scm_vector_writable_elements (res
, &handle
, NULL
, NULL
);
184 while (scm_is_pair (l
) && i
< len
)
186 data
[i
] = SCM_CAR (l
);
191 scm_array_handle_release (&handle
);
197 SCM_GPROC (s_vector_ref
, "vector-ref", 2, 0, 0, scm_vector_ref
, g_vector_ref
);
200 "@var{k} must be a valid index of @var{vector}.\n"
201 "@samp{Vector-ref} returns the contents of element @var{k} of\n"
204 "(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8\n"
205 "(vector-ref '#(1 1 2 3 5 8 13 21)\n"
206 " (let ((i (round (* 2 (acos -1)))))\n"
207 " (if (inexact? i)\n"
208 " (inexact->exact i)\n"
209 " i))) @result{} 13\n"
214 scm_vector_ref (SCM v
, SCM k
)
215 #define FUNC_NAME s_vector_ref
217 return scm_c_vector_ref (v
, scm_to_size_t (k
));
222 scm_c_vector_ref (SCM v
, size_t k
)
224 if (SCM_I_IS_NONWEAK_VECTOR (v
))
228 if (k
>= SCM_I_VECTOR_LENGTH (v
))
229 scm_out_of_range (NULL
, scm_from_size_t (k
));
230 elt
= (SCM_I_VECTOR_ELTS(v
))[k
];
234 else if (SCM_I_WVECTP (v
))
236 scm_c_issue_deprecation_warning
237 ("Using vector-ref on weak vectors is deprecated. "
238 "Instead, use weak-vector-ref from (ice-9 weak-vectors).");
239 return scm_c_weak_vector_ref (v
, k
);
241 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
243 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
244 SCM vv
= SCM_I_ARRAY_V (v
);
245 if (SCM_I_IS_VECTOR (vv
))
249 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
250 scm_out_of_range (NULL
, scm_from_size_t (k
));
251 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
252 elt
= (SCM_I_VECTOR_ELTS (vv
))[k
];
254 if (SCM_UNPACK (elt
) == 0 && (SCM_I_WVECTP (vv
)))
256 scm_c_issue_deprecation_warning
257 ("Weak arrays are deprecated. Use weak vectors instead.");
258 /* ELT was a weak pointer and got nullified by the GC. */
264 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
266 else if (SCM_UNPACK (g_vector_ref
))
268 scm_c_issue_deprecation_warning
269 ("Using vector-ref as a primitive-generic is deprecated.");
270 return scm_call_generic_2 (g_vector_ref
, v
, scm_from_size_t (k
));
274 scm_wrong_type_arg_msg ("vector-ref", 1, v
, "vector");
275 return SCM_UNDEFINED
; /* not reached */
279 SCM_GPROC (s_vector_set_x
, "vector-set!", 3, 0, 0, scm_vector_set_x
, g_vector_set_x
);
281 /* "@var{k} must be a valid index of @var{vector}.\n"
282 "@code{Vector-set!} stores @var{obj} in element @var{k} of @var{vector}.\n"
283 "The value returned by @samp{vector-set!} is unspecified.\n"
285 "(let ((vec (vector 0 '(2 2 2 2) "Anna")))\n"
286 " (vector-set! vec 1 '("Sue" "Sue"))\n"
287 " vec) @result{} #(0 ("Sue" "Sue") "Anna")\n"
288 "(vector-set! '#(0 1 2) 1 "doe") @result{} @emph{error} ; constant vector\n"
293 scm_vector_set_x (SCM v
, SCM k
, SCM obj
)
294 #define FUNC_NAME s_vector_set_x
296 scm_c_vector_set_x (v
, scm_to_size_t (k
), obj
);
297 return SCM_UNSPECIFIED
;
302 scm_c_vector_set_x (SCM v
, size_t k
, SCM obj
)
304 if (SCM_I_IS_NONWEAK_VECTOR (v
))
306 if (k
>= SCM_I_VECTOR_LENGTH (v
))
307 scm_out_of_range (NULL
, scm_from_size_t (k
));
308 (SCM_I_VECTOR_WELTS(v
))[k
] = obj
;
310 else if (SCM_I_WVECTP (v
))
312 scm_c_issue_deprecation_warning
313 ("Using vector-set! on weak vectors is deprecated. "
314 "Instead, use weak-vector-set! from (ice-9 weak-vectors).");
315 scm_c_weak_vector_set_x (v
, k
, obj
);
317 else if (SCM_I_ARRAYP (v
) && SCM_I_ARRAY_NDIM (v
) == 1)
319 scm_t_array_dim
*dim
= SCM_I_ARRAY_DIMS (v
);
320 SCM vv
= SCM_I_ARRAY_V (v
);
321 if (SCM_I_IS_VECTOR (vv
))
323 if (k
>= dim
->ubnd
- dim
->lbnd
+ 1)
324 scm_out_of_range (NULL
, scm_from_size_t (k
));
325 k
= SCM_I_ARRAY_BASE (v
) + k
*dim
->inc
;
326 (SCM_I_VECTOR_WELTS (vv
))[k
] = obj
;
328 if (SCM_I_WVECTP (vv
))
330 /* Make it a weak pointer. */
331 SCM
*link
= & SCM_I_VECTOR_WELTS (vv
)[k
];
332 SCM_I_REGISTER_DISAPPEARING_LINK ((void **) link
, SCM2PTR (obj
));
333 scm_c_issue_deprecation_warning
334 ("Weak arrays are deprecated. Use weak vectors instead.");
338 scm_wrong_type_arg_msg (NULL
, 0, v
, "non-uniform vector");
340 else if (SCM_UNPACK (g_vector_set_x
))
342 scm_c_issue_deprecation_warning
343 ("Using vector-set! as a primitive-generic is deprecated.");
344 return scm_call_3 (g_vector_set_x
, v
, scm_from_size_t (k
), obj
);
348 scm_wrong_type_arg_msg ("vector-set!", 1, v
, "vector");
349 return SCM_UNDEFINED
; /* not reached */
353 SCM_DEFINE (scm_make_vector
, "make-vector", 1, 1, 0,
355 "Return a newly allocated vector of @var{k} elements. If a\n"
356 "second argument is given, then each position is initialized to\n"
357 "@var{fill}. Otherwise the initial contents of each position is\n"
359 #define FUNC_NAME s_scm_make_vector
361 size_t l
= scm_to_unsigned_integer (k
, 0, VECTOR_MAX_LENGTH
);
363 if (SCM_UNBNDP (fill
))
364 fill
= SCM_UNSPECIFIED
;
366 return scm_c_make_vector (l
, fill
);
372 scm_c_make_vector (size_t k
, SCM fill
)
373 #define FUNC_NAME s_scm_make_vector
378 scm_gc_malloc ((k
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
),
386 SCM_ASSERT_RANGE (1, scm_from_ulong (k
), k
<= VECTOR_MAX_LENGTH
);
388 base
= vector
+ SCM_I_VECTOR_HEADER_SIZE
;
389 for (j
= 0; j
!= k
; ++j
)
393 ((scm_t_bits
*) vector
)[0] = (k
<< 8) | scm_tc7_vector
;
394 ((scm_t_bits
*) vector
)[1] = 0;
396 return PTR2SCM (vector
);
400 SCM_DEFINE (scm_vector_copy
, "vector-copy", 1, 0, 0,
402 "Return a copy of @var{vec}.")
403 #define FUNC_NAME s_scm_vector_copy
405 scm_t_array_handle handle
;
411 src
= scm_vector_elements (vec
, &handle
, &len
, &inc
);
413 result
= scm_c_make_vector (len
, SCM_UNDEFINED
);
414 dst
= SCM_I_VECTOR_WELTS (result
);
415 for (i
= 0; i
< len
; i
++, src
+= inc
)
418 scm_array_handle_release (&handle
);
427 /* Allocate memory for the elements of a weak vector on behalf of the
430 make_weak_vector (scm_t_bits type
, size_t c_size
)
435 total_size
= (c_size
+ SCM_I_VECTOR_HEADER_SIZE
) * sizeof (SCM
);
436 vector
= (SCM
*) scm_gc_malloc_pointerless (total_size
, "weak vector");
438 ((scm_t_bits
*) vector
)[0] = (c_size
<< 8) | scm_tc7_wvect
;
439 ((scm_t_bits
*) vector
)[1] = type
;
441 return PTR2SCM (vector
);
444 /* Return a new weak vector. The allocated vector will be of the given weak
445 vector subtype. It will contain SIZE elements which are initialized with
446 the FILL object, or, if FILL is undefined, with an unspecified object. */
448 scm_i_make_weak_vector (scm_t_bits type
, SCM size
, SCM fill
)
453 if (SCM_UNBNDP (fill
))
454 fill
= SCM_UNSPECIFIED
;
456 c_size
= scm_to_unsigned_integer (size
, 0, VECTOR_MAX_LENGTH
);
457 wv
= make_weak_vector (type
, c_size
);
458 base
= SCM_I_WVECT_GC_WVELTS (wv
);
460 for (j
= 0; j
!= c_size
; ++j
)
466 /* Return a new weak vector with type TYPE and whose content are taken from
469 scm_i_make_weak_vector_from_list (scm_t_bits type
, SCM lst
)
474 c_size
= scm_ilength (lst
);
475 SCM_ASSERT (c_size
>= 0, lst
, SCM_ARG2
, "scm_i_make_weak_vector_from_list");
477 wv
= make_weak_vector(type
, (size_t) c_size
);
479 for (elt
= SCM_I_WVECT_GC_WVELTS (wv
);
481 lst
= SCM_CDR (lst
), elt
++)
483 *elt
= SCM_CAR (lst
);
491 SCM_DEFINE (scm_vector_to_list
, "vector->list", 1, 0, 0,
493 "Return a newly allocated list composed of the elements of @var{v}.\n"
496 "(vector->list '#(dah dah didah)) @result{} (dah dah didah)\n"
497 "(list->vector '(dididit dah)) @result{} #(dididit dah)\n"
499 #define FUNC_NAME s_scm_vector_to_list
503 scm_t_array_handle handle
;
504 size_t i
, count
, len
;
507 data
= scm_vector_elements (v
, &handle
, &len
, &inc
);
508 for (i
= (len
- 1) * inc
, count
= 0;
511 res
= scm_cons (data
[i
], res
);
513 scm_array_handle_release (&handle
);
519 SCM_DEFINE (scm_vector_fill_x
, "vector-fill!", 2, 0, 0,
521 "Store @var{fill} in every position of @var{vector}. The value\n"
522 "returned by @code{vector-fill!} is unspecified.")
523 #define FUNC_NAME s_scm_vector_fill_x
525 scm_t_array_handle handle
;
530 data
= scm_vector_writable_elements (v
, &handle
, &len
, &inc
);
531 for (i
= 0; i
< len
; i
+= inc
)
533 scm_array_handle_release (&handle
);
534 return SCM_UNSPECIFIED
;
540 scm_i_vector_equal_p (SCM x
, SCM y
)
543 for (i
= SCM_I_VECTOR_LENGTH (x
) - 1; i
>= 0; i
--)
544 if (scm_is_false (scm_equal_p (SCM_I_VECTOR_ELTS (x
)[i
],
545 SCM_I_VECTOR_ELTS (y
)[i
])))
551 SCM_DEFINE (scm_vector_move_left_x
, "vector-move-left!", 5, 0, 0,
552 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
553 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
554 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
555 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
556 "@code{vector-move-left!} copies elements in leftmost order.\n"
557 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
558 "same vector, @code{vector-move-left!} is usually appropriate when\n"
559 "@var{start1} is greater than @var{start2}.")
560 #define FUNC_NAME s_scm_vector_move_left_x
562 scm_t_array_handle handle1
, handle2
;
569 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
570 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
572 i
= scm_to_unsigned_integer (start1
, 0, len1
);
573 e
= scm_to_unsigned_integer (end1
, i
, len1
);
574 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
575 j
= scm_to_unsigned_integer (start2
, 0, len2
);
576 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
581 for (; i
< e
; i
+= inc1
, j
+= inc2
)
584 scm_array_handle_release (&handle2
);
585 scm_array_handle_release (&handle1
);
587 return SCM_UNSPECIFIED
;
591 SCM_DEFINE (scm_vector_move_right_x
, "vector-move-right!", 5, 0, 0,
592 (SCM vec1
, SCM start1
, SCM end1
, SCM vec2
, SCM start2
),
593 "Copy elements from @var{vec1}, positions @var{start1} to @var{end1},\n"
594 "to @var{vec2} starting at position @var{start2}. @var{start1} and\n"
595 "@var{start2} are inclusive indices; @var{end1} is exclusive.\n\n"
596 "@code{vector-move-right!} copies elements in rightmost order.\n"
597 "Therefore, in the case where @var{vec1} and @var{vec2} refer to the\n"
598 "same vector, @code{vector-move-right!} is usually appropriate when\n"
599 "@var{start1} is less than @var{start2}.")
600 #define FUNC_NAME s_scm_vector_move_right_x
602 scm_t_array_handle handle1
, handle2
;
609 elts1
= scm_vector_elements (vec1
, &handle1
, &len1
, &inc1
);
610 elts2
= scm_vector_writable_elements (vec2
, &handle2
, &len2
, &inc2
);
612 i
= scm_to_unsigned_integer (start1
, 0, len1
);
613 e
= scm_to_unsigned_integer (end1
, i
, len1
);
614 SCM_ASSERT_RANGE (SCM_ARG3
, end1
, (e
-i
) <= len2
);
615 j
= scm_to_unsigned_integer (start2
, 0, len2
);
616 SCM_ASSERT_RANGE (SCM_ARG5
, start2
, j
<= len2
- (e
- i
));
630 scm_array_handle_release (&handle2
);
631 scm_array_handle_release (&handle1
);
633 return SCM_UNSPECIFIED
;
639 vector_handle_ref (scm_t_array_handle
*h
, size_t idx
)
641 if (idx
> h
->dims
[0].ubnd
)
642 scm_out_of_range ("vector-handle-ref", scm_from_size_t (idx
));
643 return ((SCM
*)h
->elements
)[idx
];
647 vector_handle_set (scm_t_array_handle
*h
, size_t idx
, SCM val
)
649 if (idx
> h
->dims
[0].ubnd
)
650 scm_out_of_range ("vector-handle-set!", scm_from_size_t (idx
));
651 ((SCM
*)h
->writable_elements
)[idx
] = val
;
655 vector_get_handle (SCM v
, scm_t_array_handle
*h
)
661 h
->dim0
.ubnd
= SCM_I_VECTOR_LENGTH (v
) - 1;
663 h
->element_type
= SCM_ARRAY_ELEMENT_TYPE_SCM
;
664 h
->elements
= h
->writable_elements
= SCM_I_VECTOR_WELTS (v
);
667 /* the & ~2 allows catching scm_tc7_wvect as well. needs changing if you change
669 SCM_ARRAY_IMPLEMENTATION (scm_tc7_vector
, 0x7f & ~2,
670 vector_handle_ref
, vector_handle_set
,
672 SCM_VECTOR_IMPLEMENTATION (SCM_ARRAY_ELEMENT_TYPE_SCM
, scm_make_vector
)
678 #include "libguile/vectors.x"