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 */
23 #include "bytevector.h"
32 /* Assuming 32-bit longs. */
33 # define ULONG_MAX 4294967295UL
42 /* Convenience macros. These are used by the various templates (macros) that
43 are parameterized by integer signedness. */
44 #define INT8_T_signed scm_t_int8
45 #define INT8_T_unsigned scm_t_uint8
46 #define INT16_T_signed scm_t_int16
47 #define INT16_T_unsigned scm_t_uint16
48 #define is_signed_int8(_x) (((_x) >= -128L) && ((_x) <= 127L))
49 #define is_unsigned_int8(_x) ((_x) <= 255UL)
50 #define is_signed_int16(_x) (((_x) >= -32768L) && ((_x) <= 32767L))
51 #define is_unsigned_int16(_x) ((_x) <= 65535UL)
52 #define SIGNEDNESS_signed 1
53 #define SIGNEDNESS_unsigned 0
55 #define INT_TYPE(_size, _sign) INT ## _size ## _T_ ## _sign
56 #define INT_SWAP(_size) bswap_ ## _size
57 #define INT_VALID_P(_size, _sign) is_ ## _sign ## _int ## _size
58 #define SIGNEDNESS(_sign) SIGNEDNESS_ ## _sign
61 #define INTEGER_ACCESSOR_PROLOGUE(_len, _sign) \
62 unsigned c_len, c_index; \
65 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
66 c_index = scm_to_uint (index); \
68 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
69 c_bv = (_sign char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
71 if (EXPECT_FALSE (c_index + ((_len) >> 3UL) - 1 >= c_len)) \
72 scm_out_of_range (FUNC_NAME, index);
74 /* Template for fixed-size integer access (only 8, 16 or 32-bit). */
75 #define INTEGER_REF(_len, _sign) \
78 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
79 SCM_VALIDATE_SYMBOL (3, endianness); \
82 INT_TYPE (_len, _sign) c_result; \
84 memcpy (&c_result, &c_bv[c_index], (_len) / 8); \
85 if (!scm_is_eq (endianness, native_endianness)) \
86 c_result = INT_SWAP (_len) (c_result); \
88 result = SCM_I_MAKINUM (c_result); \
93 /* Template for fixed-size integer access using the native endianness. */
94 #define INTEGER_NATIVE_REF(_len, _sign) \
97 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
100 INT_TYPE (_len, _sign) c_result; \
102 memcpy (&c_result, &c_bv[c_index], (_len) / 8); \
103 result = SCM_I_MAKINUM (c_result); \
108 /* Template for fixed-size integer modification (only 8, 16 or 32-bit). */
109 #define INTEGER_SET(_len, _sign) \
110 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
111 SCM_VALIDATE_SYMBOL (3, endianness); \
114 _sign long c_value; \
115 INT_TYPE (_len, _sign) c_value_short; \
117 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
118 scm_wrong_type_arg (FUNC_NAME, 3, value); \
120 c_value = SCM_I_INUM (value); \
121 if (EXPECT_FALSE (!INT_VALID_P (_len, _sign) (c_value))) \
122 scm_out_of_range (FUNC_NAME, value); \
124 c_value_short = (INT_TYPE (_len, _sign)) c_value; \
125 if (!scm_is_eq (endianness, native_endianness)) \
126 c_value_short = INT_SWAP (_len) (c_value_short); \
128 memcpy (&c_bv[c_index], &c_value_short, (_len) / 8); \
131 return SCM_UNSPECIFIED;
133 /* Template for fixed-size integer modification using the native
135 #define INTEGER_NATIVE_SET(_len, _sign) \
136 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
139 _sign long c_value; \
140 INT_TYPE (_len, _sign) c_value_short; \
142 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
143 scm_wrong_type_arg (FUNC_NAME, 3, value); \
145 c_value = SCM_I_INUM (value); \
146 if (EXPECT_FALSE (!INT_VALID_P (_len, _sign) (c_value))) \
147 scm_out_of_range (FUNC_NAME, value); \
149 c_value_short = (INT_TYPE (_len, _sign)) c_value; \
151 memcpy (&c_bv[c_index], &c_value_short, (_len) / 8); \
154 return SCM_UNSPECIFIED;
158 /* Bytevector type. */
160 SCM_GLOBAL_SMOB (scm_tc16_r6rs_bytevector
, "r6rs-bytevector", 0);
162 #define SCM_R6RS_BYTEVECTOR_SET_LENGTH(_bv, _len) \
163 SCM_SET_SMOB_DATA ((_bv), (scm_t_bits) (_len))
164 #define SCM_R6RS_BYTEVECTOR_SET_CONTENTS(_bv, _buf) \
165 SCM_SET_SMOB_DATA_2 ((_bv), (scm_t_bits) (_buf))
167 /* The empty bytevector. */
168 SCM scm_r6rs_null_bytevector
= SCM_UNSPECIFIED
;
172 make_bytevector_from_buffer (unsigned len
, signed char *contents
)
174 /* Assuming LEN > SCM_R6RS_BYTEVECTOR_INLINE_THRESHOLD. */
175 SCM_RETURN_NEWSMOB2 (scm_tc16_r6rs_bytevector
, len
, contents
);
179 make_bytevector (unsigned len
)
183 if (EXPECT_FALSE (len
== 0))
184 bv
= scm_r6rs_null_bytevector
;
187 signed char *contents
= NULL
;
189 if (!SCM_R6RS_BYTEVECTOR_INLINEABLE_SIZE_P (len
))
190 contents
= (signed char *) scm_gc_malloc (len
, SCM_GC_BYTEVECTOR
);
192 bv
= make_bytevector_from_buffer (len
, contents
);
198 /* Return a new bytevector of size LEN octets. */
200 scm_r6rs_c_make_bytevector (unsigned len
)
202 return (make_bytevector (len
));
205 /* Return a bytevector of size LEN made up of CONTENTS. The area pointed to
206 by CONTENTS must have been allocated using `scm_gc_malloc ()'. */
208 scm_r6rs_c_take_bytevector (signed char *contents
, unsigned len
)
212 if (EXPECT_FALSE (SCM_R6RS_BYTEVECTOR_INLINEABLE_SIZE_P (len
)))
214 /* Copy CONTENTS into an "in-line" buffer, then free CONTENTS. */
217 bv
= make_bytevector (len
);
218 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
219 memcpy (c_bv
, contents
, len
);
220 scm_gc_free (contents
, len
, SCM_GC_BYTEVECTOR
);
223 bv
= make_bytevector_from_buffer (len
, contents
);
228 /* Shrink BV to C_NEW_LEN (which is assumed to be smaller than its current
229 size) and return BV. */
231 scm_r6rs_i_shrink_bytevector (SCM bv
, unsigned c_new_len
)
233 if (!SCM_R6RS_BYTEVECTOR_INLINE_P (bv
))
236 signed char *c_bv
, *c_new_bv
;
238 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
239 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
241 SCM_R6RS_BYTEVECTOR_SET_LENGTH (bv
, c_new_len
);
243 if (SCM_R6RS_BYTEVECTOR_INLINEABLE_SIZE_P (c_new_len
))
245 /* Copy to the in-line buffer and free the current buffer. */
246 c_new_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
247 memcpy (c_new_bv
, c_bv
, c_new_len
);
248 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
252 /* Resize the existing buffer. */
253 c_new_bv
= scm_gc_realloc (c_bv
, c_len
, c_new_len
,
255 SCM_R6RS_BYTEVECTOR_SET_CONTENTS (bv
, c_new_bv
);
262 SCM_SMOB_PRINT (scm_tc16_r6rs_bytevector
, print_bytevector
,
268 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
269 c_bv
= (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
271 scm_puts ("#vu8(", port
);
272 for (i
= 0; i
< c_len
; i
++)
275 scm_putc (' ', port
);
277 scm_uintprint (c_bv
[i
], 10, port
);
280 scm_putc (')', port
);
285 SCM_SMOB_FREE (scm_tc16_r6rs_bytevector
, free_bytevector
, bv
)
288 if (!SCM_R6RS_BYTEVECTOR_INLINE_P (bv
))
293 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
294 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
296 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
304 /* General operations. */
306 SCM_SYMBOL (scm_sym_big
, "big");
307 SCM_SYMBOL (scm_sym_little
, "little");
309 /* Host endianness (a symbol). */
310 static SCM native_endianness
= SCM_UNSPECIFIED
;
314 # define bswap_24(_x) \
315 ((((_x) & 0xff0000) >> 16) | \
316 (((_x) & 0x00ff00)) | \
317 (((_x) & 0x0000ff) << 16))
321 SCM_DEFINE (scm_r6rs_native_endianness
, "native-endianness", 0, 0, 0,
323 "Return a symbol denoting the machine's native endianness.")
324 #define FUNC_NAME s_scm_r6rs_native_endianness
326 return native_endianness
;
330 SCM_DEFINE (scm_r6rs_bytevector_p
, "bytevector?", 1, 0, 0,
332 "Return true if @var{obj} is a bytevector.")
333 #define FUNC_NAME s_scm_r6rs_bytevector_p
335 return (scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_r6rs_bytevector
,
340 SCM_DEFINE (scm_r6rs_make_bytevector
, "make-bytevector", 1, 1, 0,
342 "Return a newly allocated bytevector of @var{len} bytes, "
343 "optionally filled with @var{fill}.")
344 #define FUNC_NAME s_scm_r6rs_make_bytevector
348 signed char c_fill
= '\0';
350 SCM_VALIDATE_UINT_COPY (1, len
, c_len
);
351 if (fill
!= SCM_UNDEFINED
)
355 value
= scm_to_int (fill
);
356 if (EXPECT_FALSE ((value
< -128) || (value
> 255)))
357 scm_out_of_range (FUNC_NAME
, fill
);
358 c_fill
= (signed char) value
;
361 bv
= make_bytevector (c_len
);
362 if (fill
!= SCM_UNDEFINED
)
365 signed char *contents
;
367 contents
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
368 for (i
= 0; i
< c_len
; i
++)
369 contents
[i
] = c_fill
;
376 SCM_DEFINE (scm_r6rs_bytevector_length
, "bytevector-length", 1, 0, 0,
378 "Return the length (in bytes) of @var{bv}.")
379 #define FUNC_NAME s_scm_r6rs_bytevector_length
381 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
383 return (scm_from_uint (SCM_R6RS_BYTEVECTOR_LENGTH (bv
)));
387 SCM_DEFINE (scm_r6rs_bytevector_eq_p
, "bytevector=?", 2, 0, 0,
389 "Return is @var{bv1} equals to @var{bv2}---i.e., if they "
390 "have the same length and contents.")
391 #define FUNC_NAME s_scm_r6rs_bytevector_eq_p
393 SCM result
= SCM_BOOL_F
;
394 unsigned c_len1
, c_len2
;
396 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv1
);
397 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv2
);
399 c_len1
= SCM_R6RS_BYTEVECTOR_LENGTH (bv1
);
400 c_len2
= SCM_R6RS_BYTEVECTOR_LENGTH (bv2
);
402 if (c_len1
== c_len2
)
404 signed char *c_bv1
, *c_bv2
;
406 c_bv1
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv1
);
407 c_bv2
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv2
);
409 result
= scm_from_bool (!memcmp (c_bv1
, c_bv2
, c_len1
));
416 SCM_DEFINE (scm_r6rs_bytevector_fill_x
, "bytevector-fill!", 2, 0, 0,
418 "Fill bytevector @var{bv} with @var{fill}, a byte.")
419 #define FUNC_NAME s_scm_r6rs_bytevector_fill_x
422 signed char *c_bv
, c_fill
;
424 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
425 c_fill
= scm_to_int8 (fill
);
427 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
428 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
430 for (i
= 0; i
< c_len
; i
++)
433 return SCM_UNSPECIFIED
;
437 SCM_DEFINE (scm_r6rs_bytevector_copy_x
, "bytevector-copy!", 5, 0, 0,
438 (SCM source
, SCM source_start
, SCM target
, SCM target_start
,
440 "Copy @var{len} bytes from @var{source} into @var{target}, "
441 "starting reading from @var{source_start} (a positive index "
442 "within @var{source}) and start writing at "
443 "@var{target_start}.")
444 #define FUNC_NAME s_scm_r6rs_bytevector_copy_x
446 unsigned c_len
, c_source_len
, c_target_len
;
447 unsigned c_source_start
, c_target_start
;
448 signed char *c_source
, *c_target
;
450 SCM_VALIDATE_R6RS_BYTEVECTOR (1, source
);
451 SCM_VALIDATE_R6RS_BYTEVECTOR (3, target
);
453 c_len
= scm_to_uint (len
);
454 c_source_start
= scm_to_uint (source_start
);
455 c_target_start
= scm_to_uint (target_start
);
457 c_source
= SCM_R6RS_BYTEVECTOR_CONTENTS (source
);
458 c_target
= SCM_R6RS_BYTEVECTOR_CONTENTS (target
);
459 c_source_len
= SCM_R6RS_BYTEVECTOR_LENGTH (source
);
460 c_target_len
= SCM_R6RS_BYTEVECTOR_LENGTH (target
);
462 if (EXPECT_FALSE (c_source_start
+ c_len
> c_source_len
))
463 scm_out_of_range (FUNC_NAME
, source_start
);
464 if (EXPECT_FALSE (c_target_start
+ c_len
> c_target_len
))
465 scm_out_of_range (FUNC_NAME
, target_start
);
467 memcpy (c_target
+ c_target_start
,
468 c_source
+ c_source_start
,
471 return SCM_UNSPECIFIED
;
475 SCM_DEFINE (scm_r6rs_bytevector_copy
, "bytevector-copy", 1, 0, 0,
477 "Return a newly allocated copy of @var{bv}.")
478 #define FUNC_NAME s_scm_r6rs_bytevector_copy
482 signed char *c_bv
, *c_copy
;
484 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
486 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
487 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
489 copy
= make_bytevector (c_len
);
490 c_copy
= SCM_R6RS_BYTEVECTOR_CONTENTS (copy
);
491 memcpy (c_copy
, c_bv
, c_len
);
498 /* Operations on bytes and octets. */
500 SCM_DEFINE (scm_r6rs_bytevector_u8_ref
, "bytevector-u8-ref", 2, 0, 0,
502 "Return the octet located at @var{index} in @var{bv}.")
503 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
505 INTEGER_NATIVE_REF (8, unsigned);
509 SCM_DEFINE (scm_r6rs_bytevector_s8_ref
, "bytevector-s8-ref", 2, 0, 0,
511 "Return the byte located at @var{index} in @var{bv}.")
512 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
514 INTEGER_NATIVE_REF (8, signed);
518 SCM_DEFINE (scm_r6rs_bytevector_u8_set_x
, "bytevector-u8-set!", 3, 0, 0,
519 (SCM bv
, SCM index
, SCM value
),
520 "Return the octet located at @var{index} in @var{bv}.")
521 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
523 INTEGER_NATIVE_SET (8, unsigned);
527 SCM_DEFINE (scm_r6rs_bytevector_s8_set_x
, "bytevector-s8-set!", 3, 0, 0,
528 (SCM bv
, SCM index
, SCM value
),
529 "Return the octet located at @var{index} in @var{bv}.")
530 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
532 INTEGER_NATIVE_SET (8, signed);
536 #undef OCTET_ACCESSOR_PROLOGUE
539 SCM_DEFINE (scm_r6rs_bytevector_to_u8_list
, "bytevector->u8-list", 1, 0, 0,
541 "Return a newly allocated list of octets containing the "
542 "contents of @var{bv}.")
543 #define FUNC_NAME s_scm_r6rs_bytevector_to_u8_list
549 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
551 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
552 c_bv
= (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
554 lst
= scm_make_list (scm_from_uint (c_len
), SCM_UNSPECIFIED
);
555 for (i
= 0, pair
= lst
;
557 i
++, pair
= SCM_CDR (pair
))
559 SCM_SETCAR (pair
, SCM_I_MAKINUM (c_bv
[i
]));
566 SCM_DEFINE (scm_r6rs_u8_list_to_bytevector
, "u8-list->bytevector", 1, 0, 0,
568 "Turn @var{lst}, a list of octets, into a bytevector.")
569 #define FUNC_NAME s_scm_r6rs_u8_list_to_bytevector
575 SCM_VALIDATE_LIST_COPYLEN (1, lst
, c_len
);
577 bv
= make_bytevector (c_len
);
578 c_bv
= (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
580 for (i
= 0; i
< c_len
; lst
= SCM_CDR (lst
), i
++)
582 item
= SCM_CAR (lst
);
584 if (EXPECT_TRUE (SCM_I_INUMP (item
)))
588 c_item
= SCM_I_INUM (item
);
589 if (EXPECT_TRUE ((c_item
>= 0) && (c_item
< 256)))
590 c_bv
[i
] = (unsigned char) c_item
;
601 scm_wrong_type_arg (FUNC_NAME
, 1, item
);
607 /* Compute the two's complement of VALUE (a positive integer) on SIZE octets
608 using (2^(SIZE * 8) - VALUE). */
610 twos_complement (mpz_t value
, size_t size
)
612 unsigned long bit_count
;
614 /* We expect BIT_COUNT to fit in a unsigned long thanks to the range
615 checking on SIZE performed earlier. */
616 bit_count
= (unsigned long) size
<< 3UL;
618 if (EXPECT_TRUE (bit_count
< sizeof (unsigned long)))
619 mpz_ui_sub (value
, 1UL << bit_count
, value
);
625 mpz_ui_pow_ui (max
, 2, bit_count
);
626 mpz_sub (value
, max
, value
);
632 bytevector_large_ref (const char *c_bv
, size_t c_size
, int signed_p
,
637 int c_endianness
, negative_p
= 0;
641 if (scm_is_eq (endianness
, scm_sym_big
))
642 negative_p
= c_bv
[0] & 0x80;
644 negative_p
= c_bv
[c_size
- 1] & 0x80;
647 c_endianness
= scm_is_eq (endianness
, scm_sym_big
) ? 1 : -1;
650 mpz_import (c_mpz
, 1 /* 1 word */, 1 /* word order doesn't matter */,
651 c_size
/* word is C_SIZE-byte long */,
653 0 /* nails */, c_bv
);
655 if (signed_p
&& negative_p
)
657 twos_complement (c_mpz
, c_size
);
658 mpz_neg (c_mpz
, c_mpz
);
661 result
= scm_from_mpz (c_mpz
);
662 mpz_clear (c_mpz
); /* FIXME: Needed? */
668 bytevector_large_set (char *c_bv
, size_t c_size
, int signed_p
,
669 SCM value
, SCM endianness
)
672 int c_endianness
, c_sign
, err
= 0;
674 c_endianness
= scm_is_eq (endianness
, scm_sym_big
) ? 1 : -1;
677 scm_to_mpz (value
, c_mpz
);
679 c_sign
= mpz_sgn (c_mpz
);
682 if (EXPECT_TRUE (signed_p
))
684 mpz_neg (c_mpz
, c_mpz
);
685 twos_complement (c_mpz
, c_size
);
696 memset (c_bv
, 0, c_size
);
699 size_t word_count
, value_size
;
701 value_size
= (mpz_sizeinbase (c_mpz
, 2) + (8 * c_size
)) / (8 * c_size
);
702 if (EXPECT_FALSE (value_size
> c_size
))
709 mpz_export (c_bv
, &word_count
, 1 /* word order doesn't matter */,
710 c_size
, c_endianness
,
711 0 /* nails */, c_mpz
);
712 if (EXPECT_FALSE (word_count
!= 1))
713 /* Shouldn't happen since we already checked with VALUE_SIZE. */
723 #define GENERIC_INTEGER_ACCESSOR_PROLOGUE(_sign) \
724 unsigned c_len, c_index, c_size; \
727 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
728 c_index = scm_to_uint (index); \
729 c_size = scm_to_uint (size); \
731 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
732 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
734 /* C_SIZE must have its 3 higher bits set to zero so that \
735 multiplying it by 8 yields a number that fits in an \
737 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
738 scm_out_of_range (FUNC_NAME, size); \
739 if (EXPECT_FALSE (c_index + c_size > c_len)) \
740 scm_out_of_range (FUNC_NAME, index);
743 /* Template of an integer reference function. */
744 #define GENERIC_INTEGER_REF(_sign) \
752 swap = !scm_is_eq (endianness, native_endianness); \
757 _sign char c_value8; \
758 memcpy (&c_value8, c_bv, 1); \
764 INT_TYPE (16, _sign) c_value16; \
765 memcpy (&c_value16, c_bv, 2); \
767 value = (INT_TYPE (16, _sign)) bswap_16 (c_value16); \
776 result = SCM_I_MAKINUM ((_sign int) value); \
779 result = bytevector_large_ref ((char *) c_bv, \
780 c_size, SIGNEDNESS (_sign), \
786 bytevector_signed_ref (const char *c_bv
, size_t c_size
, SCM endianness
)
788 GENERIC_INTEGER_REF (signed);
792 bytevector_unsigned_ref (const char *c_bv
, size_t c_size
, SCM endianness
)
794 GENERIC_INTEGER_REF (unsigned);
798 /* Template of an integer assignment function. */
799 #define GENERIC_INTEGER_SET(_sign) \
804 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
807 c_value = SCM_I_INUM (value); \
811 if (EXPECT_TRUE (INT_VALID_P (8, _sign) (c_value))) \
813 _sign char c_value8; \
814 c_value8 = (_sign char) c_value; \
815 memcpy (c_bv, &c_value8, 1); \
822 if (EXPECT_TRUE (INT_VALID_P (16, _sign) (c_value))) \
825 INT_TYPE (16, _sign) c_value16; \
827 swap = !scm_is_eq (endianness, native_endianness); \
830 swap ? bswap_16 (c_value) : c_value; \
831 memcpy (c_bv, &c_value16, 2); \
845 err = bytevector_large_set (c_bv, c_size, \
846 SIGNEDNESS (_sign), \
847 value, endianness); \
855 scm_out_of_range (FUNC_NAME, value); \
859 bytevector_signed_set (char *c_bv
, size_t c_size
,
860 SCM value
, SCM endianness
,
861 const char *func_name
)
862 #define FUNC_NAME func_name
864 GENERIC_INTEGER_SET (signed);
869 bytevector_unsigned_set (char *c_bv
, size_t c_size
,
870 SCM value
, SCM endianness
,
871 const char *func_name
)
872 #define FUNC_NAME func_name
874 GENERIC_INTEGER_SET (unsigned);
878 #undef GENERIC_INTEGER_SET
879 #undef GENERIC_INTEGER_REF
882 SCM_DEFINE (scm_r6rs_bytevector_uint_ref
, "bytevector-uint-ref", 4, 0, 0,
883 (SCM bv
, SCM index
, SCM endianness
, SCM size
),
884 "Return the @var{size}-octet long unsigned integer at index "
885 "@var{index} in @var{bv}.")
886 #define FUNC_NAME s_scm_r6rs_bytevector_uint_ref
888 GENERIC_INTEGER_ACCESSOR_PROLOGUE (unsigned);
890 return (bytevector_unsigned_ref (&c_bv
[c_index
], c_size
, endianness
));
894 SCM_DEFINE (scm_r6rs_bytevector_sint_ref
, "bytevector-sint-ref", 4, 0, 0,
895 (SCM bv
, SCM index
, SCM endianness
, SCM size
),
896 "Return the @var{size}-octet long unsigned integer at index "
897 "@var{index} in @var{bv}.")
898 #define FUNC_NAME s_scm_r6rs_bytevector_sint_ref
900 GENERIC_INTEGER_ACCESSOR_PROLOGUE (signed);
902 return (bytevector_signed_ref (&c_bv
[c_index
], c_size
, endianness
));
906 SCM_DEFINE (scm_r6rs_bytevector_uint_set_x
, "bytevector-uint-set!", 5, 0, 0,
907 (SCM bv
, SCM index
, SCM value
, SCM endianness
, SCM size
),
908 "Set the @var{size}-octet long unsigned integer at @var{index} "
910 #define FUNC_NAME s_scm_r6rs_bytevector_uint_set_x
912 GENERIC_INTEGER_ACCESSOR_PROLOGUE (unsigned);
914 bytevector_unsigned_set (&c_bv
[c_index
], c_size
, value
, endianness
,
917 return SCM_UNSPECIFIED
;
921 SCM_DEFINE (scm_r6rs_bytevector_sint_set_x
, "bytevector-sint-set!", 5, 0, 0,
922 (SCM bv
, SCM index
, SCM value
, SCM endianness
, SCM size
),
923 "Set the @var{size}-octet long signed integer at @var{index} "
925 #define FUNC_NAME s_scm_r6rs_bytevector_sint_set_x
927 GENERIC_INTEGER_ACCESSOR_PROLOGUE (signed);
929 bytevector_signed_set (&c_bv
[c_index
], c_size
, value
, endianness
,
932 return SCM_UNSPECIFIED
;
938 /* Operations on integers of arbitrary size. */
940 #define INTEGERS_TO_LIST(_sign) \
942 size_t i, c_len, c_size; \
944 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
945 SCM_VALIDATE_SYMBOL (2, endianness); \
946 c_size = scm_to_uint (size); \
948 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
955 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
957 lst = scm_make_list (scm_from_uint (c_len / c_size), \
959 for (i = 0, pair = lst; \
960 i <= c_len - c_size; \
961 i += c_size, c_bv += c_size, pair = SCM_CDR (pair)) \
964 bytevector_ ## _sign ## _ref (c_bv, c_size, \
971 SCM_DEFINE (scm_r6rs_bytevector_to_sint_list
, "bytevector->sint-list",
973 (SCM bv
, SCM endianness
, SCM size
),
974 "Return a list of signed integers of @var{size} octets "
975 "representing the contents of @var{bv}.")
976 #define FUNC_NAME s_scm_r6rs_bytevector_to_sint_list
978 INTEGERS_TO_LIST (signed);
982 SCM_DEFINE (scm_r6rs_bytevector_to_uint_list
, "bytevector->uint-list",
984 (SCM bv
, SCM endianness
, SCM size
),
985 "Return a list of unsigned integers of @var{size} octets "
986 "representing the contents of @var{bv}.")
987 #define FUNC_NAME s_scm_r6rs_bytevector_to_uint_list
989 INTEGERS_TO_LIST (unsigned);
993 #undef INTEGER_TO_LIST
996 #define INTEGER_LIST_TO_BYTEVECTOR(_sign) \
998 size_t c_len, c_size; \
999 char *c_bv, *c_bv_ptr; \
1001 SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len); \
1002 SCM_VALIDATE_SYMBOL (2, endianness); \
1003 c_size = scm_to_uint (size); \
1005 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
1006 scm_out_of_range (FUNC_NAME, size); \
1008 bv = make_bytevector (c_len * c_size); \
1009 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
1011 for (c_bv_ptr = c_bv; \
1012 !scm_is_null (lst); \
1013 lst = SCM_CDR (lst), c_bv_ptr += c_size) \
1015 bytevector_ ## _sign ## _set (c_bv_ptr, c_size, \
1016 SCM_CAR (lst), endianness, \
1023 SCM_DEFINE (scm_r6rs_uint_list_to_bytevector
, "uint-list->bytevector",
1025 (SCM lst
, SCM endianness
, SCM size
),
1026 "Return a bytevector containing the unsigned integers "
1027 "listed in @var{lst} and encoded on @var{size} octets "
1028 "according to @var{endianness}.")
1029 #define FUNC_NAME s_scm_r6rs_uint_list_to_bytevector
1031 INTEGER_LIST_TO_BYTEVECTOR (unsigned);
1035 SCM_DEFINE (scm_r6rs_sint_list_to_bytevector
, "sint-list->bytevector",
1037 (SCM lst
, SCM endianness
, SCM size
),
1038 "Return a bytevector containing the signed integers "
1039 "listed in @var{lst} and encoded on @var{size} octets "
1040 "according to @var{endianness}.")
1041 #define FUNC_NAME s_scm_r6rs_sint_list_to_bytevector
1043 INTEGER_LIST_TO_BYTEVECTOR (signed);
1047 #undef INTEGER_LIST_TO_BYTEVECTOR
1051 /* Operations on 16-bit integers. */
1053 SCM_DEFINE (scm_r6rs_bytevector_u16_ref
, "bytevector-u16-ref",
1055 (SCM bv
, SCM index
, SCM endianness
),
1056 "Return the unsigned 16-bit integer from @var{bv} at "
1058 #define FUNC_NAME s_scm_r6rs_bytevector_u16_ref
1060 INTEGER_REF (16, unsigned);
1064 SCM_DEFINE (scm_r6rs_bytevector_s16_ref
, "bytevector-s16-ref",
1066 (SCM bv
, SCM index
, SCM endianness
),
1067 "Return the signed 16-bit integer from @var{bv} at "
1069 #define FUNC_NAME s_scm_r6rs_bytevector_s16_ref
1071 INTEGER_REF (16, signed);
1075 SCM_DEFINE (scm_r6rs_bytevector_u16_native_ref
, "bytevector-u16-native-ref",
1077 (SCM bv
, SCM index
),
1078 "Return the unsigned 16-bit integer from @var{bv} at "
1079 "@var{index} using the native endianness.")
1080 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_ref
1082 INTEGER_NATIVE_REF (16, unsigned);
1086 SCM_DEFINE (scm_r6rs_bytevector_s16_native_ref
, "bytevector-s16-native-ref",
1088 (SCM bv
, SCM index
),
1089 "Return the unsigned 16-bit integer from @var{bv} at "
1090 "@var{index} using the native endianness.")
1091 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_ref
1093 INTEGER_NATIVE_REF (16, signed);
1097 SCM_DEFINE (scm_r6rs_bytevector_u16_set_x
, "bytevector-u16-set!",
1099 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1100 "Store @var{value} in @var{bv} at @var{index} according to "
1101 "@var{endianness}.")
1102 #define FUNC_NAME s_scm_r6rs_bytevector_u16_set_x
1104 INTEGER_SET (16, unsigned);
1108 SCM_DEFINE (scm_r6rs_bytevector_s16_set_x
, "bytevector-s16-set!",
1110 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1111 "Store @var{value} in @var{bv} at @var{index} according to "
1112 "@var{endianness}.")
1113 #define FUNC_NAME s_scm_r6rs_bytevector_s16_set_x
1115 INTEGER_SET (16, signed);
1119 SCM_DEFINE (scm_r6rs_bytevector_u16_native_set_x
, "bytevector-u16-native-set!",
1121 (SCM bv
, SCM index
, SCM value
),
1122 "Store the unsigned integer @var{value} at index @var{index} "
1123 "of @var{bv} using the native endianness.")
1124 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_set_x
1126 INTEGER_NATIVE_SET (16, unsigned);
1130 SCM_DEFINE (scm_r6rs_bytevector_s16_native_set_x
, "bytevector-s16-native-set!",
1132 (SCM bv
, SCM index
, SCM value
),
1133 "Store the signed integer @var{value} at index @var{index} "
1134 "of @var{bv} using the native endianness.")
1135 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_set_x
1137 INTEGER_NATIVE_SET (16, signed);
1143 /* Operations on 32-bit integers. */
1145 /* Unfortunately, on 32-bit machines `SCM' is not large enough to hold
1146 arbitrary 32-bit integers. Thus we fall back to using the
1147 `large_{ref,set}' variants on 32-bit machines. */
1149 #define LARGE_INTEGER_REF(_len, _sign) \
1150 INTEGER_ACCESSOR_PROLOGUE(_len, _sign); \
1151 SCM_VALIDATE_SYMBOL (3, endianness); \
1153 return (bytevector_large_ref ((char *) c_bv + c_index, _len / 8, \
1154 SIGNEDNESS (_sign), endianness));
1156 #define LARGE_INTEGER_SET(_len, _sign) \
1158 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
1159 SCM_VALIDATE_SYMBOL (4, endianness); \
1161 err = bytevector_large_set ((char *) c_bv + c_index, _len / 8, \
1162 SIGNEDNESS (_sign), value, endianness); \
1163 if (EXPECT_FALSE (err)) \
1164 scm_out_of_range (FUNC_NAME, value); \
1166 return SCM_UNSPECIFIED;
1168 #define LARGE_INTEGER_NATIVE_REF(_len, _sign) \
1169 INTEGER_ACCESSOR_PROLOGUE(_len, _sign); \
1170 return (bytevector_large_ref ((char *) c_bv + c_index, _len / 8, \
1171 SIGNEDNESS (_sign), native_endianness));
1173 #define LARGE_INTEGER_NATIVE_SET(_len, _sign) \
1175 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
1177 err = bytevector_large_set ((char *) c_bv + c_index, _len / 8, \
1178 SIGNEDNESS (_sign), value, \
1179 native_endianness); \
1180 if (EXPECT_FALSE (err)) \
1181 scm_out_of_range (FUNC_NAME, value); \
1183 return SCM_UNSPECIFIED;
1186 SCM_DEFINE (scm_r6rs_bytevector_u32_ref
, "bytevector-u32-ref",
1188 (SCM bv
, SCM index
, SCM endianness
),
1189 "Return the unsigned 32-bit integer from @var{bv} at "
1191 #define FUNC_NAME s_scm_r6rs_bytevector_u32_ref
1193 #if SIZEOF_VOID_P > 4
1194 INTEGER_REF (32, unsigned);
1196 LARGE_INTEGER_REF (32, unsigned);
1201 SCM_DEFINE (scm_r6rs_bytevector_s32_ref
, "bytevector-s32-ref",
1203 (SCM bv
, SCM index
, SCM endianness
),
1204 "Return the signed 32-bit integer from @var{bv} at "
1206 #define FUNC_NAME s_scm_r6rs_bytevector_s32_ref
1208 #if SIZEOF_VOID_P > 4
1209 INTEGER_REF (32, signed);
1211 LARGE_INTEGER_REF (32, signed);
1216 SCM_DEFINE (scm_r6rs_bytevector_u32_native_ref
, "bytevector-u32-native-ref",
1218 (SCM bv
, SCM index
),
1219 "Return the unsigned 32-bit integer from @var{bv} at "
1220 "@var{index} using the native endianness.")
1221 #define FUNC_NAME s_scm_r6rs_bytevector_u32_native_ref
1223 #if SIZEOF_VOID_P > 4
1224 INTEGER_NATIVE_REF (32, unsigned);
1226 LARGE_INTEGER_NATIVE_REF (32, unsigned);
1231 SCM_DEFINE (scm_r6rs_bytevector_s32_native_ref
, "bytevector-s32-native-ref",
1233 (SCM bv
, SCM index
),
1234 "Return the unsigned 32-bit integer from @var{bv} at "
1235 "@var{index} using the native endianness.")
1236 #define FUNC_NAME s_scm_r6rs_bytevector_u32_native_ref
1238 #if SIZEOF_VOID_P > 4
1239 INTEGER_NATIVE_REF (32, signed);
1241 LARGE_INTEGER_NATIVE_REF (32, signed);
1246 SCM_DEFINE (scm_r6rs_bytevector_u32_set_x
, "bytevector-u32-set!",
1248 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1249 "Store @var{value} in @var{bv} at @var{index} according to "
1250 "@var{endianness}.")
1251 #define FUNC_NAME s_scm_r6rs_bytevector_u32_set_x
1253 #if SIZEOF_VOID_P > 4
1254 INTEGER_SET (32, unsigned);
1256 LARGE_INTEGER_SET (32, unsigned);
1261 SCM_DEFINE (scm_r6rs_bytevector_s32_set_x
, "bytevector-s32-set!",
1263 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1264 "Store @var{value} in @var{bv} at @var{index} according to "
1265 "@var{endianness}.")
1266 #define FUNC_NAME s_scm_r6rs_bytevector_s32_set_x
1268 #if SIZEOF_VOID_P > 4
1269 INTEGER_SET (32, signed);
1271 LARGE_INTEGER_SET (32, signed);
1276 SCM_DEFINE (scm_r6rs_bytevector_u32_native_set_x
, "bytevector-u32-native-set!",
1278 (SCM bv
, SCM index
, SCM value
),
1279 "Store the unsigned integer @var{value} at index @var{index} "
1280 "of @var{bv} using the native endianness.")
1281 #define FUNC_NAME s_scm_r6rs_bytevector_u32_native_set_x
1283 #if SIZEOF_VOID_P > 4
1284 INTEGER_NATIVE_SET (32, unsigned);
1286 LARGE_INTEGER_NATIVE_SET (32, unsigned);
1291 SCM_DEFINE (scm_r6rs_bytevector_s32_native_set_x
, "bytevector-s32-native-set!",
1293 (SCM bv
, SCM index
, SCM value
),
1294 "Store the signed integer @var{value} at index @var{index} "
1295 "of @var{bv} using the native endianness.")
1296 #define FUNC_NAME s_scm_r6rs_bytevector_u32_native_set_x
1298 #if SIZEOF_VOID_P > 4
1299 INTEGER_NATIVE_SET (32, signed);
1301 LARGE_INTEGER_NATIVE_SET (32, signed);
1308 /* Operations on 64-bit integers. */
1310 /* For 64-bit integers, we use only the `large_{ref,set}' variant. */
1312 SCM_DEFINE (scm_r6rs_bytevector_u64_ref
, "bytevector-u64-ref",
1314 (SCM bv
, SCM index
, SCM endianness
),
1315 "Return the unsigned 64-bit integer from @var{bv} at "
1317 #define FUNC_NAME s_scm_r6rs_bytevector_u64_ref
1319 LARGE_INTEGER_REF (64, unsigned);
1323 SCM_DEFINE (scm_r6rs_bytevector_s64_ref
, "bytevector-s64-ref",
1325 (SCM bv
, SCM index
, SCM endianness
),
1326 "Return the signed 64-bit integer from @var{bv} at "
1328 #define FUNC_NAME s_scm_r6rs_bytevector_s64_ref
1330 LARGE_INTEGER_REF (64, signed);
1334 SCM_DEFINE (scm_r6rs_bytevector_u64_native_ref
, "bytevector-u64-native-ref",
1336 (SCM bv
, SCM index
),
1337 "Return the unsigned 64-bit integer from @var{bv} at "
1338 "@var{index} using the native endianness.")
1339 #define FUNC_NAME s_scm_r6rs_bytevector_u64_native_ref
1341 LARGE_INTEGER_NATIVE_REF (64, unsigned);
1345 SCM_DEFINE (scm_r6rs_bytevector_s64_native_ref
, "bytevector-s64-native-ref",
1347 (SCM bv
, SCM index
),
1348 "Return the unsigned 64-bit integer from @var{bv} at "
1349 "@var{index} using the native endianness.")
1350 #define FUNC_NAME s_scm_r6rs_bytevector_u64_native_ref
1352 LARGE_INTEGER_NATIVE_REF (64, signed);
1356 SCM_DEFINE (scm_r6rs_bytevector_u64_set_x
, "bytevector-u64-set!",
1358 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1359 "Store @var{value} in @var{bv} at @var{index} according to "
1360 "@var{endianness}.")
1361 #define FUNC_NAME s_scm_r6rs_bytevector_u64_set_x
1363 LARGE_INTEGER_SET (64, unsigned);
1367 SCM_DEFINE (scm_r6rs_bytevector_s64_set_x
, "bytevector-s64-set!",
1369 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1370 "Store @var{value} in @var{bv} at @var{index} according to "
1371 "@var{endianness}.")
1372 #define FUNC_NAME s_scm_r6rs_bytevector_s64_set_x
1374 LARGE_INTEGER_SET (64, signed);
1378 SCM_DEFINE (scm_r6rs_bytevector_u64_native_set_x
, "bytevector-u64-native-set!",
1380 (SCM bv
, SCM index
, SCM value
),
1381 "Store the unsigned integer @var{value} at index @var{index} "
1382 "of @var{bv} using the native endianness.")
1383 #define FUNC_NAME s_scm_r6rs_bytevector_u64_native_set_x
1385 LARGE_INTEGER_NATIVE_SET (64, unsigned);
1389 SCM_DEFINE (scm_r6rs_bytevector_s64_native_set_x
, "bytevector-s64-native-set!",
1391 (SCM bv
, SCM index
, SCM value
),
1392 "Store the signed integer @var{value} at index @var{index} "
1393 "of @var{bv} using the native endianness.")
1394 #define FUNC_NAME s_scm_r6rs_bytevector_u64_native_set_x
1396 LARGE_INTEGER_NATIVE_SET (64, signed);
1402 /* Operations on IEEE-754 numbers. */
1404 /* XXX: There are not only two encodings (big and little endian), as implied
1405 by the API, but rather three (in the case of little endian, there are two
1406 possible word endians, as visible in glibc's <ieee754.h>). When the
1407 endianness is `little', we assume little endian for both the byte order
1408 and the word order. */
1410 /* Convert to/from a floating-point number with different endianness. This
1411 method is probably not the most efficient but it should be portable. */
1414 float_to_foreign_endianness (union scm_r6rs_ieee754_float
*target
,
1417 union scm_r6rs_ieee754_float src
;
1421 #ifdef WORDS_BIGENDIAN
1422 /* Assuming little endian for both byte and word order. */
1423 target
->little_endian
.negative
= src
.big_endian
.negative
;
1424 target
->little_endian
.exponent
= src
.big_endian
.exponent
;
1425 target
->little_endian
.mantissa
= src
.big_endian
.mantissa
;
1427 target
->big_endian
.negative
= src
.little_endian
.negative
;
1428 target
->big_endian
.exponent
= src
.little_endian
.exponent
;
1429 target
->big_endian
.mantissa
= src
.little_endian
.mantissa
;
1434 float_from_foreign_endianness (const union scm_r6rs_ieee754_float
*source
)
1436 union scm_r6rs_ieee754_float result
;
1438 #ifdef WORDS_BIGENDIAN
1439 /* Assuming little endian for both byte and word order. */
1440 result
.big_endian
.negative
= source
->little_endian
.negative
;
1441 result
.big_endian
.exponent
= source
->little_endian
.exponent
;
1442 result
.big_endian
.mantissa
= source
->little_endian
.mantissa
;
1444 result
.little_endian
.negative
= source
->big_endian
.negative
;
1445 result
.little_endian
.exponent
= source
->big_endian
.exponent
;
1446 result
.little_endian
.mantissa
= source
->big_endian
.mantissa
;
1453 double_to_foreign_endianness (union scm_r6rs_ieee754_double
*target
,
1456 union scm_r6rs_ieee754_double src
;
1460 #ifdef WORDS_BIGENDIAN
1461 /* Assuming little endian for both byte and word order. */
1462 target
->little_little_endian
.negative
= src
.big_endian
.negative
;
1463 target
->little_little_endian
.exponent
= src
.big_endian
.exponent
;
1464 target
->little_little_endian
.mantissa0
= src
.big_endian
.mantissa0
;
1465 target
->little_little_endian
.mantissa1
= src
.big_endian
.mantissa1
;
1467 target
->big_endian
.negative
= src
.little_little_endian
.negative
;
1468 target
->big_endian
.exponent
= src
.little_little_endian
.exponent
;
1469 target
->big_endian
.mantissa0
= src
.little_little_endian
.mantissa0
;
1470 target
->big_endian
.mantissa1
= src
.little_little_endian
.mantissa1
;
1474 static inline double
1475 double_from_foreign_endianness (const union scm_r6rs_ieee754_double
*source
)
1477 union scm_r6rs_ieee754_double result
;
1479 #ifdef WORDS_BIGENDIAN
1480 /* Assuming little endian for both byte and word order. */
1481 result
.big_endian
.negative
= source
->little_little_endian
.negative
;
1482 result
.big_endian
.exponent
= source
->little_little_endian
.exponent
;
1483 result
.big_endian
.mantissa0
= source
->little_little_endian
.mantissa0
;
1484 result
.big_endian
.mantissa1
= source
->little_little_endian
.mantissa1
;
1486 result
.little_little_endian
.negative
= source
->big_endian
.negative
;
1487 result
.little_little_endian
.exponent
= source
->big_endian
.exponent
;
1488 result
.little_little_endian
.mantissa0
= source
->big_endian
.mantissa0
;
1489 result
.little_little_endian
.mantissa1
= source
->big_endian
.mantissa1
;
1495 /* Template macros to abstract over doubles and floats.
1496 XXX: Guile can only convert to/from doubles. */
1497 #define IEEE754_UNION(_c_type) union scm_r6rs_ieee754_ ## _c_type
1498 #define IEEE754_TO_SCM(_c_type) scm_from_double
1499 #define IEEE754_FROM_SCM(_c_type) scm_to_double
1500 #define IEEE754_FROM_FOREIGN_ENDIANNESS(_c_type) \
1501 _c_type ## _from_foreign_endianness
1502 #define IEEE754_TO_FOREIGN_ENDIANNESS(_c_type) \
1503 _c_type ## _to_foreign_endianness
1506 /* Templace getters and setters. */
1508 #define IEEE754_ACCESSOR_PROLOGUE(_type) \
1509 INTEGER_ACCESSOR_PROLOGUE (sizeof (_type) << 3UL, signed);
1511 #define IEEE754_REF(_type) \
1514 IEEE754_ACCESSOR_PROLOGUE (_type); \
1515 SCM_VALIDATE_SYMBOL (3, endianness); \
1517 if (scm_is_eq (endianness, native_endianness)) \
1518 memcpy (&c_result, &c_bv[c_index], sizeof (c_result)); \
1521 IEEE754_UNION (_type) c_raw; \
1523 memcpy (&c_raw, &c_bv[c_index], sizeof (c_raw)); \
1525 IEEE754_FROM_FOREIGN_ENDIANNESS (_type) (&c_raw); \
1528 return (IEEE754_TO_SCM (_type) (c_result));
1530 #define IEEE754_NATIVE_REF(_type) \
1533 IEEE754_ACCESSOR_PROLOGUE (_type); \
1535 memcpy (&c_result, &c_bv[c_index], sizeof (c_result)); \
1536 return (IEEE754_TO_SCM (_type) (c_result));
1538 #define IEEE754_SET(_type) \
1541 IEEE754_ACCESSOR_PROLOGUE (_type); \
1542 SCM_VALIDATE_REAL (3, value); \
1543 SCM_VALIDATE_SYMBOL (4, endianness); \
1544 c_value = IEEE754_FROM_SCM (_type) (value); \
1546 if (scm_is_eq (endianness, native_endianness)) \
1547 memcpy (&c_bv[c_index], &c_value, sizeof (c_value)); \
1550 IEEE754_UNION (_type) c_raw; \
1552 IEEE754_TO_FOREIGN_ENDIANNESS (_type) (&c_raw, c_value); \
1553 memcpy (&c_bv[c_index], &c_raw, sizeof (c_raw)); \
1556 return SCM_UNSPECIFIED;
1558 #define IEEE754_NATIVE_SET(_type) \
1561 IEEE754_ACCESSOR_PROLOGUE (_type); \
1562 SCM_VALIDATE_REAL (3, value); \
1563 c_value = IEEE754_FROM_SCM (_type) (value); \
1565 memcpy (&c_bv[c_index], &c_value, sizeof (c_value)); \
1566 return SCM_UNSPECIFIED;
1569 /* Single precision. */
1571 SCM_DEFINE (scm_r6rs_bytevector_ieee_single_ref
,
1572 "bytevector-ieee-single-ref",
1574 (SCM bv
, SCM index
, SCM endianness
),
1575 "Return the IEEE-754 single from @var{bv} at "
1577 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_single_ref
1579 IEEE754_REF (float);
1583 SCM_DEFINE (scm_r6rs_bytevector_ieee_single_native_ref
,
1584 "bytevector-ieee-single-native-ref",
1586 (SCM bv
, SCM index
),
1587 "Return the IEEE-754 single from @var{bv} at "
1588 "@var{index} using the native endianness.")
1589 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_single_native_ref
1591 IEEE754_NATIVE_REF (float);
1595 SCM_DEFINE (scm_r6rs_bytevector_ieee_single_set_x
,
1596 "bytevector-ieee-single-set!",
1598 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1599 "Store real @var{value} in @var{bv} at @var{index} according to "
1600 "@var{endianness}.")
1601 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_single_set_x
1603 IEEE754_SET (float);
1607 SCM_DEFINE (scm_r6rs_bytevector_ieee_single_native_set_x
,
1608 "bytevector-ieee-single-native-set!",
1610 (SCM bv
, SCM index
, SCM value
),
1611 "Store the real @var{value} at index @var{index} "
1612 "of @var{bv} using the native endianness.")
1613 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_single_native_set_x
1615 IEEE754_NATIVE_SET (float);
1620 /* Double precision. */
1622 SCM_DEFINE (scm_r6rs_bytevector_ieee_double_ref
,
1623 "bytevector-ieee-double-ref",
1625 (SCM bv
, SCM index
, SCM endianness
),
1626 "Return the IEEE-754 double from @var{bv} at "
1628 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_double_ref
1630 IEEE754_REF (double);
1634 SCM_DEFINE (scm_r6rs_bytevector_ieee_double_native_ref
,
1635 "bytevector-ieee-double-native-ref",
1637 (SCM bv
, SCM index
),
1638 "Return the IEEE-754 double from @var{bv} at "
1639 "@var{index} using the native endianness.")
1640 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_double_native_ref
1642 IEEE754_NATIVE_REF (double);
1646 SCM_DEFINE (scm_r6rs_bytevector_ieee_double_set_x
,
1647 "bytevector-ieee-double-set!",
1649 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
1650 "Store real @var{value} in @var{bv} at @var{index} according to "
1651 "@var{endianness}.")
1652 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_double_set_x
1654 IEEE754_SET (double);
1658 SCM_DEFINE (scm_r6rs_bytevector_ieee_double_native_set_x
,
1659 "bytevector-ieee-double-native-set!",
1661 (SCM bv
, SCM index
, SCM value
),
1662 "Store the real @var{value} at index @var{index} "
1663 "of @var{bv} using the native endianness.")
1664 #define FUNC_NAME s_scm_r6rs_bytevector_ieee_double_native_set_x
1666 IEEE754_NATIVE_SET (double);
1671 #undef IEEE754_UNION
1672 #undef IEEE754_TO_SCM
1673 #undef IEEE754_FROM_SCM
1674 #undef IEEE754_FROM_FOREIGN_ENDIANNESS
1675 #undef IEEE754_TO_FOREIGN_ENDIANNESS
1677 #undef IEEE754_NATIVE_REF
1679 #undef IEEE754_NATIVE_SET
1682 /* Initialization. */
1685 scm_init_r6rs_bytevector (void)
1687 #include "bytevector.x"
1689 #ifdef WORDS_BIGENDIAN
1690 native_endianness
= scm_sym_big
;
1692 native_endianness
= scm_sym_little
;
1695 scm_r6rs_null_bytevector
=
1696 scm_gc_protect_object (make_bytevector_from_buffer (0, NULL
));
1699 /* arch-tag: e5a30664-90fc-40d7-8036-ee767aea5fb6