Bytevectors Section 2.3: "Operations on Integers of Arbitrary Size"
[guile-r6rs-libs.git] / src / bytevector.c
blob794de9f82b28a947c90b3765b1bd4a95eaeaf3c6
1 /* Guile-R6RS-Libs --- Implementation of R6RS standard libraries.
2 Copyright (C) 2007 Ludovic Courtès <ludovic.courtes@laas.fr>
4 Guile-R6RS-Libs is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 Guile-R6RS-Libs is distributed in the hope that it will be useful,
10 but 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 Guile-R6RS-Libs; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18 #include "config.h"
20 #include <libguile.h>
21 #include <gmp.h>
23 #ifdef HAVE_BYTESWAP_H
24 # include <byteswap.h>
25 #endif
26 #ifdef HAVE_LIMITS_H
27 # include <limits.h>
28 #else
29 /* Assuming 32-bit longs. */
30 # define ULONG_MAX 4294967295UL
31 #endif
33 #include <string.h>
36 /* Utilities. */
38 #ifdef __GNUC__
39 # define EXPECT __builtin_expect
40 #else
41 # define EXPECT(_expr, _value) (_expr)
42 #endif
44 #define EXPECT_TRUE(_expr) EXPECT ((_expr), 1)
45 #define EXPECT_FALSE(_expr) EXPECT ((_expr), 0)
49 /* Bytevector type. */
51 SCM_SMOB (scm_tc16_r6rs_bytevector, "r6rs-bytevector", 0);
53 #define SCM_VALIDATE_R6RS_BYTEVECTOR(_pos, _obj) \
54 SCM_VALIDATE_SMOB ((_pos), (_obj), r6rs_bytevector);
57 static inline SCM
58 make_bytevector (unsigned len, signed char *contents)
60 SCM_RETURN_NEWSMOB2 (scm_tc16_r6rs_bytevector, len, contents);
63 #define SCM_R6RS_BYTEVECTOR_LENGTH(_bv) \
64 ((unsigned) SCM_SMOB_DATA (_bv))
65 #define SCM_R6RS_BYTEVECTOR_CONTENTS(_bv) \
66 ((signed char *) SCM_SMOB_DATA_2 (_bv))
68 #define SCM_GC_BYTEVECTOR "r6rs-bytevector"
70 SCM_SMOB_FREE (scm_tc16_r6rs_bytevector, free_bytevector, bv)
72 unsigned c_len;
73 signed char *c_bv;
75 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
76 c_bv = SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
78 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
80 return 0;
85 /* General operations. */
87 SCM_SYMBOL (scm_sym_big, "big");
88 SCM_SYMBOL (scm_sym_little, "little");
90 /* Host endianness (a symbol). */
91 static SCM native_endianness = SCM_UNSPECIFIED;
93 /* Byte-swapping. */
94 #ifdef HAVE_BYTESWAP_H
95 # define non_native_byteswap_16 bswap_16
96 # define non_native_byteswap_32 bswap_32
97 #else
98 # error "No byteswap function available."
99 #endif
102 SCM_DEFINE (scm_r6rs_native_endianness, "native-endianness", 0, 0, 0,
103 (void),
104 "Return a symbol denoting the machine's native endianness.")
105 #define FUNC_NAME s_scm_r6rs_native_endianness
107 return native_endianness;
109 #undef FUNC_NAME
111 SCM_DEFINE (scm_r6rs_bytevector_p, "bytevector?", 1, 0, 0,
112 (SCM obj),
113 "Return true if @var{obj} is a bytevector.")
114 #define FUNC_NAME s_scm_r6rs_bytevector_p
116 return (scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_r6rs_bytevector,
117 obj)));
119 #undef FUNC_NAME
121 SCM_DEFINE (scm_r6rs_make_bytevector, "make-bytevector", 1, 1, 0,
122 (SCM len, SCM fill),
123 "Return a newly allocated bytevector of @var{len} bytes, "
124 "optionally filled with @var{fill}.")
125 #define FUNC_NAME s_scm_r6rs_make_bytevector
127 unsigned c_len;
128 signed char c_fill;
129 signed char *contents;
131 SCM_VALIDATE_UINT_COPY (1, len, c_len);
132 if (fill != SCM_UNDEFINED)
134 int value;
136 value = scm_to_int (fill);
137 if (EXPECT_FALSE ((value < -128) || (value > 255)))
138 scm_out_of_range (FUNC_NAME, fill);
139 c_fill = (signed char) value;
142 contents = (signed char *) scm_gc_malloc (c_len, SCM_GC_BYTEVECTOR);
143 if (fill != SCM_UNDEFINED)
145 unsigned i;
147 for (i = 0; i < c_len; i++)
148 contents[i] = c_fill;
151 return (make_bytevector (c_len, contents));
153 #undef FUNC_NAME
155 SCM_DEFINE (scm_r6rs_bytevector_length, "bytevector-length", 1, 0, 0,
156 (SCM bv),
157 "Return the length (in bytes) of @var{bv}.")
158 #define FUNC_NAME s_scm_r6rs_bytevector_length
160 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv);
162 return (scm_from_uint (SCM_R6RS_BYTEVECTOR_LENGTH (bv)));
164 #undef FUNC_NAME
166 SCM_DEFINE (scm_r6rs_bytevector_eq_p, "bytevector=?", 2, 0, 0,
167 (SCM bv1, SCM bv2),
168 "Return is @var{bv1} equals to @var{bv2}---i.e., if they "
169 "have the same length and contents.")
170 #define FUNC_NAME s_scm_r6rs_bytevector_eq_p
172 SCM result = SCM_BOOL_F;
173 unsigned c_len1, c_len2;
175 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv1);
176 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv2);
178 c_len1 = SCM_R6RS_BYTEVECTOR_LENGTH (bv1);
179 c_len2 = SCM_R6RS_BYTEVECTOR_LENGTH (bv2);
181 if (c_len1 == c_len2)
183 signed char *c_bv1, *c_bv2;
185 c_bv1 = SCM_R6RS_BYTEVECTOR_CONTENTS (bv1);
186 c_bv2 = SCM_R6RS_BYTEVECTOR_CONTENTS (bv2);
188 result = scm_from_bool (!memcmp (c_bv1, c_bv2, c_len1));
191 return result;
193 #undef FUNC_NAME
195 SCM_DEFINE (scm_r6rs_bytevector_fill_x, "bytevector-fill!", 2, 0, 0,
196 (SCM bv, SCM fill),
197 "Fill bytevector @var{bv} with @var{fill}, a byte.")
198 #define FUNC_NAME s_scm_r6rs_bytevector_fill_x
200 unsigned c_len, i;
201 signed char *c_bv, c_fill;
203 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv);
204 c_fill = scm_to_int8 (fill);
206 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
207 c_bv = SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
209 for (i = 0; i < c_len; i++)
210 c_bv[i] = c_fill;
212 return SCM_UNSPECIFIED;
214 #undef FUNC_NAME
216 SCM_DEFINE (scm_r6rs_bytevector_copy_x, "bytevector-copy!", 5, 0, 0,
217 (SCM source, SCM source_start, SCM target, SCM target_start,
218 SCM len),
219 "Copy @var{len} bytes from @var{source} into @var{target}, "
220 "starting reading from @var{source_start} (a positive index "
221 "within @var{source}) and start writing at "
222 "@var{target_start}.")
223 #define FUNC_NAME s_scm_r6rs_bytevector_copy_x
225 unsigned c_len, c_source_len, c_target_len;
226 unsigned c_source_start, c_target_start;
227 signed char *c_source, *c_target;
229 SCM_VALIDATE_R6RS_BYTEVECTOR (1, source);
230 SCM_VALIDATE_R6RS_BYTEVECTOR (3, target);
232 c_len = scm_to_uint (len);
233 c_source_start = scm_to_uint (source_start);
234 c_target_start = scm_to_uint (target_start);
236 c_source = SCM_R6RS_BYTEVECTOR_CONTENTS (source);
237 c_target = SCM_R6RS_BYTEVECTOR_CONTENTS (target);
238 c_source_len = SCM_R6RS_BYTEVECTOR_LENGTH (source);
239 c_target_len = SCM_R6RS_BYTEVECTOR_LENGTH (target);
241 if (EXPECT_FALSE (c_source_start + c_len > c_source_len))
242 scm_out_of_range (FUNC_NAME, source_start);
243 if (EXPECT_FALSE (c_target_start + c_len > c_target_len))
244 scm_out_of_range (FUNC_NAME, target_start);
246 memcpy (c_target + c_target_start,
247 c_source + c_source_start,
248 c_len);
250 return SCM_UNSPECIFIED;
252 #undef FUNC_NAME
254 SCM_DEFINE (scm_r6rs_bytevector_copy, "bytevector-copy", 1, 0, 0,
255 (SCM bv),
256 "Return a newly allocated copy of @var{bv}.")
257 #define FUNC_NAME s_scm_r6rs_bytevector_copy
259 unsigned c_len;
260 signed char *c_bv, *c_copy;
262 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv);
264 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
265 c_bv = SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
267 c_copy = scm_gc_malloc (c_len, SCM_GC_BYTEVECTOR);
268 memcpy (c_copy, c_bv, c_len);
270 return (make_bytevector (c_len, c_copy));
272 #undef FUNC_NAME
275 /* Operations on bytes and octets. */
277 #define OCTET_ACCESSOR_PROLOGUE(_sign) \
278 unsigned c_len, c_index; \
279 _sign char *c_bv; \
281 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
282 c_index = scm_to_uint (index); \
284 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
285 c_bv = (_sign char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
287 if (EXPECT_FALSE (c_index >= c_len)) \
288 scm_out_of_range (FUNC_NAME, index);
291 SCM_DEFINE (scm_r6rs_bytevector_u8_ref, "bytevector-u8-ref", 2, 0, 0,
292 (SCM bv, SCM index),
293 "Return the octet located at @var{index} in @var{bv}.")
294 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
296 OCTET_ACCESSOR_PROLOGUE (unsigned);
298 return (SCM_I_MAKINUM (c_bv[c_index]));
300 #undef FUNC_NAME
302 SCM_DEFINE (scm_r6rs_bytevector_s8_ref, "bytevector-s8-ref", 2, 0, 0,
303 (SCM bv, SCM index),
304 "Return the byte located at @var{index} in @var{bv}.")
305 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
307 OCTET_ACCESSOR_PROLOGUE (signed);
309 return (SCM_I_MAKINUM (c_bv[c_index]));
311 #undef FUNC_NAME
313 SCM_DEFINE (scm_r6rs_bytevector_u8_set_x, "bytevector-u8-set!", 3, 0, 0,
314 (SCM bv, SCM index, SCM value),
315 "Return the octet located at @var{index} in @var{bv}.")
316 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
318 unsigned char c_value;
320 OCTET_ACCESSOR_PROLOGUE (unsigned);
321 c_value = scm_to_uint8 (value);
323 c_bv[c_index] = c_value;
325 return SCM_UNSPECIFIED;
327 #undef FUNC_NAME
329 SCM_DEFINE (scm_r6rs_bytevector_s8_set_x, "bytevector-s8-set!", 3, 0, 0,
330 (SCM bv, SCM index, SCM value),
331 "Return the octet located at @var{index} in @var{bv}.")
332 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
334 unsigned char c_value;
336 OCTET_ACCESSOR_PROLOGUE (signed);
337 c_value = scm_to_int8 (value);
339 c_bv[c_index] = c_value;
341 return SCM_UNSPECIFIED;
343 #undef FUNC_NAME
345 #undef OCTET_ACCESSOR_PROLOGUE
348 SCM_DEFINE (scm_r6rs_bytevector_to_u8_list, "bytevector->u8-list", 1, 0, 0,
349 (SCM bv),
350 "Return a newly allocated list of octets containing the "
351 "contents of @var{bv}.")
352 #define FUNC_NAME s_scm_r6rs_bytevector_to_u8_list
354 SCM lst, pair;
355 unsigned c_len, i;
356 unsigned char *c_bv;
358 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv);
360 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv);
361 c_bv = (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv);
363 lst = scm_make_list (scm_from_uint (c_len), SCM_UNSPECIFIED);
364 for (i = 0, pair = lst;
365 i < c_len;
366 i++, pair = SCM_CDR (pair))
368 SCM_SETCAR (pair, SCM_I_MAKINUM (c_bv[i]));
371 return lst;
373 #undef FUNC_NAME
375 SCM_DEFINE (scm_r6rs_u8_list_to_bytevector, "u8-list->bytevector", 1, 0, 0,
376 (SCM lst),
377 "Turn @var{lst}, a list of octets, into a bytevector.")
378 #define FUNC_NAME s_scm_r6rs_u8_list_to_bytevector
380 SCM item;
381 unsigned c_len, i;
382 unsigned char *c_bv;
384 SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len);
386 c_bv = scm_gc_malloc (c_len, SCM_GC_BYTEVECTOR);
387 for (i = 0; i < c_len; lst = SCM_CDR (lst), i++)
389 item = SCM_CAR (lst);
391 if (EXPECT_TRUE (SCM_I_INUMP (item)))
393 long c_item;
395 c_item = SCM_I_INUM (item);
396 if (EXPECT_TRUE ((c_item >= 0) && (c_item < 256)))
397 c_bv[i] = (unsigned char) c_item;
398 else
399 goto type_error;
401 else
402 goto type_error;
405 return (make_bytevector (c_len, (signed char *) c_bv));
407 type_error:
408 scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
409 scm_wrong_type_arg (FUNC_NAME, 1, item);
411 return SCM_BOOL_F;
413 #undef FUNC_NAME
415 /* Compute the two's complement of VALUE (a positive integer) on SIZE octets
416 using (2^(SIZE * 8) - VALUE). */
417 static inline void
418 twos_complement (mpz_t value, size_t size)
420 unsigned long bit_count;
422 /* We expect BIT_COUNT to fit in a unsigned long thanks to the range
423 checking on SIZE performed earlier. */
424 bit_count = (unsigned long) size << 3UL;
426 if (EXPECT_TRUE (bit_count < sizeof (unsigned long)))
427 mpz_ui_sub (value, 1UL << bit_count, value);
428 else
430 mpz_t max;
432 mpz_init (max);
433 mpz_ui_pow_ui (max, 2, bit_count);
434 mpz_sub (value, max, value);
435 mpz_clear (max);
439 static inline SCM
440 bytevector_large_ref (const char *c_bv, size_t c_size, int signed_p,
441 SCM endianness)
443 SCM result;
444 mpz_t c_mpz;
445 int c_endianness, negative_p = 0;
447 if (signed_p)
449 if (scm_is_eq (endianness, scm_sym_big))
450 negative_p = c_bv[0] & 0x80;
451 else
452 negative_p = c_bv[c_size - 1] & 0x80;
455 c_endianness = scm_is_eq (endianness, scm_sym_big) ? 1 : -1;
457 mpz_init (c_mpz);
458 mpz_import (c_mpz, 1 /* 1 word */, 1 /* word order doesn't matter */,
459 c_size /* word is C_SIZE-byte long */,
460 c_endianness,
461 0 /* nails */, c_bv);
463 if (signed_p && negative_p)
465 twos_complement (c_mpz, c_size);
466 mpz_neg (c_mpz, c_mpz);
469 result = scm_from_mpz (c_mpz);
470 mpz_clear (c_mpz); /* FIXME: Needed? */
472 return result;
475 static inline int
476 bytevector_large_set (char *c_bv, size_t c_size, int signed_p,
477 SCM value, SCM endianness)
479 size_t word_count, value_size;
480 mpz_t c_mpz;
481 int c_endianness, err = 0;
483 c_endianness = scm_is_eq (endianness, scm_sym_big) ? 1 : -1;
485 mpz_init (c_mpz);
486 scm_to_mpz (value, c_mpz);
487 if (mpz_sgn (c_mpz) < 0)
489 if (EXPECT_TRUE (signed_p))
491 mpz_neg (c_mpz, c_mpz);
492 twos_complement (c_mpz, c_size);
494 else
496 err = -1;
497 goto finish;
501 value_size = (mpz_sizeinbase (c_mpz, 2) + (8 * c_size)) / (8 * c_size);
502 if (EXPECT_FALSE (value_size > c_size))
504 err = -2;
505 goto finish;
508 mpz_export (c_bv, &word_count, 1 /* word order doesn't matter */,
509 c_size, c_endianness,
510 0 /* nails */, c_mpz);
511 if (EXPECT_FALSE (word_count != 1))
512 abort ();
514 finish:
515 mpz_clear (c_mpz);
517 return err;
520 #define INTEGER_ACCESSOR_PROLOGUE(_sign) \
521 unsigned c_len, c_index, c_size; \
522 _sign char *c_bv; \
524 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
525 c_index = scm_to_uint (index); \
526 c_size = scm_to_uint (size); \
528 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
529 c_bv = (_sign char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
531 /* C_SIZE must have its 3 higher bits set to zero so that \
532 multiplying it by 8 yields a number that fits in an \
533 unsigned long. */ \
534 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
535 scm_out_of_range (FUNC_NAME, size); \
536 if (EXPECT_FALSE (c_index + c_size > c_len)) \
537 scm_out_of_range (FUNC_NAME, index);
540 #define BV_SIGNED_signed 1
541 #define BV_SIGNED_unsigned 0
542 #define INT16_T_signed scm_t_int16
543 #define INT16_T_unsigned scm_t_uint16
545 #define is_signed_int8(_x) (((_x) >= -128L) && ((_x) <= 127L))
546 #define is_unsigned_int8(_x) ((_x) <= 255UL)
547 #define is_signed_int16(_x) (((_x) >= -32768L) && ((_x) <= 32767L))
548 #define is_unsigned_int16(_x) ((_x) <= 65535UL)
550 /* Template of an integer reference function. */
551 #define INTEGER_REF(_sign) \
552 SCM result; \
554 if (c_size < 3) \
556 int swap; \
557 _sign int value; \
559 swap = !scm_is_eq (endianness, native_endianness); \
560 switch (c_size) \
562 case 1: \
563 value = *(_sign char *) c_bv; \
564 break; \
565 case 2: \
566 value = *(INT16_T_ ## _sign *) c_bv; \
567 if (swap) \
568 value = (INT16_T_ ## _sign) non_native_byteswap_16 (value); \
569 break; \
570 default: \
571 abort (); \
574 result = SCM_I_MAKINUM ((_sign int) value); \
576 else \
577 result = bytevector_large_ref ((char *) c_bv, \
578 c_size, \
579 BV_SIGNED_ ## _sign, endianness); \
581 return result;
583 static inline SCM
584 bytevector_signed_ref (const char *c_bv, size_t c_size, SCM endianness)
586 INTEGER_REF (signed);
589 static inline SCM
590 bytevector_unsigned_ref (const char *c_bv, size_t c_size, SCM endianness)
592 INTEGER_REF (unsigned);
596 /* Template of an integer assignment function. */
597 #define INTEGER_SET(_sign) \
598 if (c_size < 3) \
600 _sign int c_value; \
602 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
603 goto range_error; \
605 c_value = SCM_I_INUM (value); \
606 switch (c_size) \
608 case 1: \
609 if (EXPECT_TRUE (is_ ## _sign ## _int8 (c_value))) \
610 * (_sign char *) c_bv = (_sign char) c_value; \
611 else \
612 goto range_error; \
613 break; \
615 case 2: \
616 if (EXPECT_TRUE (is_ ## _sign ## _int16 (c_value))) \
618 int swap; \
619 INT16_T_ ## _sign c_value16; \
621 swap = !scm_is_eq (endianness, native_endianness); \
623 c_value16 = \
624 swap ? non_native_byteswap_16 (c_value) : c_value; \
625 *(INT16_T_ ## _sign *) c_bv = c_value16; \
627 else \
628 goto range_error; \
629 break; \
631 default: \
632 abort (); \
635 else \
637 int err; \
639 err = bytevector_large_set (c_bv, c_size, \
640 BV_SIGNED_ ## _sign, \
641 value, endianness); \
642 if (err) \
643 goto range_error; \
646 return; \
648 range_error: \
649 scm_out_of_range (FUNC_NAME, value); \
650 return;
652 static inline void
653 bytevector_signed_set (char *c_bv, size_t c_size,
654 SCM value, SCM endianness,
655 const char *func_name)
656 #define FUNC_NAME func_name
658 INTEGER_SET (signed);
660 #undef FUNC_NAME
662 static inline void
663 bytevector_unsigned_set (char *c_bv, size_t c_size,
664 SCM value, SCM endianness,
665 const char *func_name)
666 #define FUNC_NAME func_name
668 INTEGER_SET (unsigned);
670 #undef FUNC_NAME
672 #undef INTEGER_SET
673 #undef INTEGER_REF
674 #undef is_signed_int16
675 #undef is_unsigned_int16
676 #undef is_signed_int8
677 #undef is_unsigned_int8
678 #undef INT16_T_signed
679 #undef INT16_T_unsigned
680 #undef BV_SIGNED_unsigned
681 #undef BV_SIGNED_signed
684 SCM_DEFINE (scm_r6rs_bytevector_uint_ref, "bytevector-uint-ref", 4, 0, 0,
685 (SCM bv, SCM index, SCM endianness, SCM size),
686 "Return the @var{size}-octet long unsigned integer at index "
687 "@var{index} in @var{bv}.")
688 #define FUNC_NAME s_scm_r6rs_bytevector_uint_ref
690 INTEGER_ACCESSOR_PROLOGUE ();
692 return (bytevector_unsigned_ref (&c_bv[c_index], c_size, endianness));
694 #undef FUNC_NAME
696 SCM_DEFINE (scm_r6rs_bytevector_sint_ref, "bytevector-sint-ref", 4, 0, 0,
697 (SCM bv, SCM index, SCM endianness, SCM size),
698 "Return the @var{size}-octet long unsigned integer at index "
699 "@var{index} in @var{bv}.")
700 #define FUNC_NAME s_scm_r6rs_bytevector_sint_ref
702 INTEGER_ACCESSOR_PROLOGUE ();
704 return (bytevector_signed_ref (&c_bv[c_index], c_size, endianness));
706 #undef FUNC_NAME
708 SCM_DEFINE (scm_r6rs_bytevector_uint_set_x, "bytevector-uint-set!", 5, 0, 0,
709 (SCM bv, SCM index, SCM value, SCM endianness, SCM size),
710 "Set the @var{size}-octet long unsigned integer at @var{index} "
711 "to @var{value}.")
712 #define FUNC_NAME s_scm_r6rs_bytevector_uint_set_x
714 INTEGER_ACCESSOR_PROLOGUE ();
716 bytevector_unsigned_set (&c_bv[c_index], c_size, value, endianness,
717 FUNC_NAME);
719 return SCM_UNSPECIFIED;
721 #undef FUNC_NAME
723 SCM_DEFINE (scm_r6rs_bytevector_sint_set_x, "bytevector-sint-set!", 5, 0, 0,
724 (SCM bv, SCM index, SCM value, SCM endianness, SCM size),
725 "Set the @var{size}-octet long signed integer at @var{index} "
726 "to @var{value}.")
727 #define FUNC_NAME s_scm_r6rs_bytevector_sint_set_x
729 INTEGER_ACCESSOR_PROLOGUE ();
731 bytevector_signed_set (&c_bv[c_index], c_size, value, endianness,
732 FUNC_NAME);
734 return SCM_UNSPECIFIED;
736 #undef FUNC_NAME
740 /* Operations on integers of arbitrary size. */
742 #define INTEGERS_TO_LIST(_sign) \
743 SCM lst, pair; \
744 const char *c_bv; \
745 size_t i, c_len, c_size; \
747 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
748 SCM_VALIDATE_SYMBOL (2, endianness); \
749 c_size = scm_to_uint (size); \
751 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
752 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
754 lst = scm_make_list (scm_from_uint (c_len / c_size), SCM_UNSPECIFIED); \
755 for (i = 0, pair = lst; \
756 i <= c_len - c_size; \
757 i += c_size, c_bv += c_size, pair = SCM_CDR (pair)) \
759 SCM_SETCAR (pair, \
760 bytevector_ ## _sign ## _ref (c_bv, c_size, \
761 endianness)); \
764 return lst;
766 SCM_DEFINE (scm_r6rs_bytevector_to_sint_list, "bytevector->sint-list",
767 3, 0, 0,
768 (SCM bv, SCM endianness, SCM size),
769 "Return a list of signed integers of @var{size} octets "
770 "representing the contents of @var{bv}.")
771 #define FUNC_NAME s_scm_r6rs_bytevector_to_sint_list
773 INTEGERS_TO_LIST (signed);
775 #undef FUNC_NAME
777 SCM_DEFINE (scm_r6rs_bytevector_to_uint_list, "bytevector->uint-list",
778 3, 0, 0,
779 (SCM bv, SCM endianness, SCM size),
780 "Return a list of unsigned integers of @var{size} octets "
781 "representing the contents of @var{bv}.")
782 #define FUNC_NAME s_scm_r6rs_bytevector_to_sint_list
784 INTEGERS_TO_LIST (unsigned);
786 #undef FUNC_NAME
788 #undef INTEGER_TO_LIST
791 #define INTEGER_LIST_TO_BYTEVECTOR(_sign) \
792 SCM result; \
793 size_t c_len, c_size; \
794 char *c_bv, *c_bv_ptr; \
796 SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len); \
797 SCM_VALIDATE_SYMBOL (2, endianness); \
798 c_size = scm_to_uint (size); \
800 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
801 scm_out_of_range (FUNC_NAME, size); \
803 c_bv = scm_gc_malloc (c_len * c_size, SCM_GC_BYTEVECTOR); \
805 /* FIXME: We leak C_BV here if one of the elements in LST is incorrect \
806 but `scm_dynwind_free ()' isn't appropriate. */ \
808 for (c_bv_ptr = c_bv; \
809 !scm_is_null (lst); \
810 lst = SCM_CDR (lst), c_bv_ptr += c_size) \
812 bytevector_ ## _sign ## _set (c_bv_ptr, c_size, \
813 SCM_CAR (lst), endianness, \
814 FUNC_NAME); \
817 result = make_bytevector (c_len * c_size, (signed char *) c_bv); \
819 return result;
822 SCM_DEFINE (scm_r6rs_uint_list_to_bytevector, "uint-list->bytevector",
823 3, 0, 0,
824 (SCM lst, SCM endianness, SCM size),
825 "Return a bytevector containing the unsigned integers "
826 "listed in @var{lst} and encoded on @var{size} octets "
827 "according to @var{endianness}.")
828 #define FUNC_NAME s_scm_r6rs_uint_list_to_bytevector
830 INTEGER_LIST_TO_BYTEVECTOR (unsigned);
832 #undef FUNC_NAME
834 SCM_DEFINE (scm_r6rs_sint_list_to_bytevector, "sint-list->bytevector",
835 3, 0, 0,
836 (SCM lst, SCM endianness, SCM size),
837 "Return a bytevector containing the signed integers "
838 "listed in @var{lst} and encoded on @var{size} octets "
839 "according to @var{endianness}.")
840 #define FUNC_NAME s_scm_r6rs_sint_list_to_bytevector
842 INTEGER_LIST_TO_BYTEVECTOR (signed);
844 #undef FUNC_NAME
846 #undef INTEGER_LIST_TO_BYTEVECTOR
849 /* FIXME: Unfinished! */
852 /* Initialization. */
854 void
855 scm_init_r6rs_bytevector (void)
857 #include "bytevector.c.x"
859 #ifdef WORDS_BIGENDIAN
860 native_endianness = scm_sym_big;
861 #else
862 native_endianness = scm_sym_little;
863 #endif
866 /* arch-tag: e5a30664-90fc-40d7-8036-ee767aea5fb6