add SCM_{PACK,UNPACK}_POINTER
[bpt/guile.git] / libguile / bytevectors.c
index 45dae1c..96b9ab6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
   SCM_VALIDATE_SYMBOL (3, endianness);                         \
                                                                \
   {                                                            \
-    _sign long c_value;                                                \
+    scm_t_signed_bits c_value;                                 \
     INT_TYPE (_len, _sign) c_value_short;                      \
                                                                \
     if (SCM_UNLIKELY (!SCM_I_INUMP (value)))                   \
   INTEGER_ACCESSOR_PROLOGUE (_len, _sign);                     \
                                                                \
   {                                                            \
-    _sign long c_value;                                                \
+    scm_t_signed_bits c_value;                                 \
     INT_TYPE (_len, _sign) c_value_short;                      \
                                                                \
     if (SCM_UNLIKELY (!SCM_I_INUMP (value)))                   \
 /* Bytevector type.  */
 
 #define SCM_BYTEVECTOR_HEADER_BYTES            \
-  (SCM_BYTEVECTOR_HEADER_SIZE * sizeof (SCM))
+  (SCM_BYTEVECTOR_HEADER_SIZE * sizeof (scm_t_bits))
 
 #define SCM_BYTEVECTOR_SET_LENGTH(_bv, _len)            \
   SCM_SET_CELL_WORD_1 ((_bv), (scm_t_bits) (_len))
   SCM_SET_BYTEVECTOR_FLAGS ((bv),                                      \
                             (hint)                                     \
                             | (SCM_BYTEVECTOR_CONTIGUOUS_P (bv) << 8UL))
+#define SCM_BYTEVECTOR_SET_PARENT(_bv, _parent)        \
+  SCM_SET_CELL_OBJECT_3 ((_bv), (_parent))
+
 #define SCM_BYTEVECTOR_TYPE_SIZE(var)                           \
   (scm_i_array_element_type_sizes[SCM_BYTEVECTOR_ELEMENT_TYPE (var)]/8)
 #define SCM_BYTEVECTOR_TYPED_LENGTH(var)                        \
@@ -210,7 +213,7 @@ make_bytevector (size_t len, scm_t_array_element_type element_type)
 
   if (SCM_UNLIKELY (element_type > SCM_ARRAY_ELEMENT_TYPE_LAST
                     || scm_i_array_element_type_sizes[element_type] < 8
-                    || len >= (SCM_I_SIZE_MAX
+                    || len >= (((size_t) -1)
                                / (scm_i_array_element_type_sizes[element_type]/8))))
     /* This would be an internal Guile programming error */
     abort ();
@@ -226,13 +229,14 @@ make_bytevector (size_t len, scm_t_array_element_type element_type)
 
       contents = scm_gc_malloc_pointerless (SCM_BYTEVECTOR_HEADER_BYTES + c_len,
                                            SCM_GC_BYTEVECTOR);
-      ret = PTR2SCM (contents);
+      ret = SCM_PACK_POINTER (contents);
       contents += SCM_BYTEVECTOR_HEADER_BYTES;
 
       SCM_BYTEVECTOR_SET_LENGTH (ret, c_len);
       SCM_BYTEVECTOR_SET_CONTENTS (ret, contents);
       SCM_BYTEVECTOR_SET_CONTIGUOUS_P (ret, 1);
       SCM_BYTEVECTOR_SET_ELEMENT_TYPE (ret, element_type);
+      SCM_BYTEVECTOR_SET_PARENT (ret, SCM_BOOL_F);
     }
 
   return ret;
@@ -253,7 +257,7 @@ make_bytevector_from_buffer (size_t len, void *contents,
     {
       size_t c_len;
 
-      ret = PTR2SCM (scm_gc_malloc (SCM_BYTEVECTOR_HEADER_BYTES,
+      ret = SCM_PACK_POINTER (scm_gc_malloc (SCM_BYTEVECTOR_HEADER_BYTES,
                                    SCM_GC_BYTEVECTOR));
 
       c_len = len * (scm_i_array_element_type_sizes[element_type] / 8);
@@ -262,6 +266,7 @@ make_bytevector_from_buffer (size_t len, void *contents,
       SCM_BYTEVECTOR_SET_CONTENTS (ret, contents);
       SCM_BYTEVECTOR_SET_CONTIGUOUS_P (ret, 0);
       SCM_BYTEVECTOR_SET_ELEMENT_TYPE (ret, element_type);
+      SCM_BYTEVECTOR_SET_PARENT (ret, SCM_BOOL_F);
     }
 
   return ret;
@@ -282,19 +287,31 @@ scm_i_make_typed_bytevector (size_t len, scm_t_array_element_type element_type)
   return make_bytevector (len, element_type);
 }
 
-/* Return a bytevector of size LEN made up of CONTENTS.  The area pointed to
-   by CONTENTS must have been allocated using `scm_gc_malloc ()'.  */
+/* Return a bytevector of size LEN made up of CONTENTS.  The area
+   pointed to by CONTENTS must be protected from GC somehow: either
+   because it was allocated using `scm_gc_malloc ()', or because it is
+   part of PARENT.  */
 SCM
-scm_c_take_bytevector (signed char *contents, size_t len)
+scm_c_take_gc_bytevector (signed char *contents, size_t len, SCM parent)
 {
-  return make_bytevector_from_buffer (len, contents, SCM_ARRAY_ELEMENT_TYPE_VU8);
+  SCM ret;
+
+  ret = make_bytevector_from_buffer (len, contents, SCM_ARRAY_ELEMENT_TYPE_VU8);
+  SCM_BYTEVECTOR_SET_PARENT (ret, parent);
+
+  return ret;
 }
 
 SCM
 scm_c_take_typed_bytevector (signed char *contents, size_t len,
-                             scm_t_array_element_type element_type)
+                             scm_t_array_element_type element_type, SCM parent)
 {
-  return make_bytevector_from_buffer (len, contents, element_type);
+  SCM ret;
+
+  ret = make_bytevector_from_buffer (len, contents, element_type);
+  SCM_BYTEVECTOR_SET_PARENT (ret, parent);
+
+  return ret;
 }
 
 /* Shrink BV to C_NEW_LEN (which is assumed to be smaller than its current
@@ -462,7 +479,7 @@ SCM_DEFINE (scm_make_bytevector, "make-bytevector", 1, 1, 0,
   signed char c_fill = '\0';
 
   SCM_VALIDATE_UINT_COPY (1, len, c_len);
-  if (fill != SCM_UNDEFINED)
+  if (!scm_is_eq (fill, SCM_UNDEFINED))
     {
       int value;
 
@@ -473,7 +490,7 @@ SCM_DEFINE (scm_make_bytevector, "make-bytevector", 1, 1, 0,
     }
 
   bv = make_bytevector (c_len, SCM_ARRAY_ELEMENT_TYPE_VU8);
-  if (fill != SCM_UNDEFINED)
+  if (!scm_is_eq (fill, SCM_UNDEFINED))
     {
       unsigned i;
       signed char *contents;
@@ -482,6 +499,8 @@ SCM_DEFINE (scm_make_bytevector, "make-bytevector", 1, 1, 0,
       for (i = 0; i < c_len; i++)
        contents[i] = c_fill;
     }
+  else
+    memset (SCM_BYTEVECTOR_CONTENTS (bv), 0, c_len);
 
   return bv;
 }
@@ -511,7 +530,8 @@ SCM_DEFINE (scm_bytevector_eq_p, "bytevector=?", 2, 0, 0,
   c_len1 = SCM_BYTEVECTOR_LENGTH (bv1);
   c_len2 = SCM_BYTEVECTOR_LENGTH (bv2);
 
-  if (c_len1 == c_len2)
+  if (c_len1 == c_len2 && (SCM_BYTEVECTOR_ELEMENT_TYPE (bv1)
+                           == SCM_BYTEVECTOR_ELEMENT_TYPE (bv2)))
     {
       signed char *c_bv1, *c_bv2;
 
@@ -734,7 +754,7 @@ SCM_DEFINE (scm_u8_list_to_bytevector, "u8-list->bytevector", 1, 0, 0,
 
       if (SCM_LIKELY (SCM_I_INUMP (item)))
        {
-         long c_item;
+         scm_t_signed_bits c_item;
 
          c_item = SCM_I_INUM (item);
          if (SCM_LIKELY ((c_item >= 0) && (c_item < 256)))
@@ -950,7 +970,7 @@ bytevector_unsigned_ref (const char *c_bv, size_t c_size, SCM endianness)
 #define GENERIC_INTEGER_SET(_sign)                                     \
   if (c_size < 3)                                                      \
     {                                                                  \
-      _sign int c_value;                                               \
+      scm_t_signed_bits c_value;                                       \
                                                                        \
       if (SCM_UNLIKELY (!SCM_I_INUMP (value)))                         \
        goto range_error;                                               \
@@ -1664,7 +1684,7 @@ double_from_foreign_endianness (const union scm_ieee754_double *source)
 /* FIXME: SCM_VALIDATE_REAL rejects integers, etc. grrr */
 #define VALIDATE_REAL(pos, v) \
   do { \
-    SCM_ASSERT_TYPE (scm_is_true (scm_rational_p (v)), v, pos, FUNC_NAME, "real"); \
+    SCM_ASSERT_TYPE (scm_is_real (v), v, pos, FUNC_NAME, "real"); \
   } while (0)
 
 /* Templace getters and setters.  */
@@ -1904,7 +1924,7 @@ utf_encoding_name (char *name, size_t utf_width, SCM endianness)
   size_t c_strlen, c_utf_len = 0;                                       \
                                                                         \
   SCM_VALIDATE_STRING (1, str);                                         \
-  if (endianness == SCM_UNDEFINED)                                      \
+  if (scm_is_eq (endianness, SCM_UNDEFINED))                            \
     endianness = scm_sym_big;                                           \
   else                                                                  \
     SCM_VALIDATE_SYMBOL (2, endianness);                                \
@@ -2017,7 +2037,7 @@ SCM_DEFINE (scm_string_to_utf32, "string->utf32",
   size_t c_strlen = 0, c_utf_len = 0;                                  \
                                                                        \
   SCM_VALIDATE_BYTEVECTOR (1, utf);                                    \
-  if (endianness == SCM_UNDEFINED)                                     \
+  if (scm_is_eq (endianness, SCM_UNDEFINED))                            \
     endianness = scm_sym_big;                                          \
   else                                                                 \
     SCM_VALIDATE_SYMBOL (2, endianness);                               \
@@ -2089,26 +2109,56 @@ SCM_DEFINE (scm_utf32_to_string, "utf32->string",
 \f
 /* Bytevectors as generalized vectors & arrays.  */
 
+#define COMPLEX_ACCESSOR_PROLOGUE(_type)                       \
+  size_t c_len, c_index;                                       \
+  char *c_bv;                                                  \
+                                                               \
+  SCM_VALIDATE_BYTEVECTOR (1, bv);                             \
+  c_index = scm_to_size_t (index);                             \
+                                                               \
+  c_len = SCM_BYTEVECTOR_LENGTH (bv);                          \
+  c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);                        \
+                                                               \
+  if (SCM_UNLIKELY (c_index + 2 * sizeof (_type) - 1 >= c_len))        \
+    scm_out_of_range (FUNC_NAME, index);
+
+/* Template for native access to complex numbers of type TYPE.  */
+#define COMPLEX_NATIVE_REF(_type)                                      \
+  SCM result;                                                          \
+                                                                       \
+  COMPLEX_ACCESSOR_PROLOGUE (_type);                                   \
+                                                                       \
+  {                                                                    \
+    _type real, imag;                                                  \
+                                                                       \
+    memcpy (&real, &c_bv[c_index], sizeof (_type));                    \
+    memcpy (&imag, &c_bv[c_index + sizeof (_type)], sizeof (_type));   \
+                                                                       \
+    result = scm_c_make_rectangular (real, imag);                      \
+  }                                                                    \
+                                                                       \
+  return result;
 
 static SCM
-bytevector_ref_c32 (SCM bv, SCM idx)
-{ /* FIXME add some checks */
-  const float *contents = (const float*)SCM_BYTEVECTOR_CONTENTS (bv);
-  size_t i = scm_to_size_t (idx);
-  return scm_c_make_rectangular (contents[i/4], contents[i/4 + 1]);
+bytevector_ref_c32 (SCM bv, SCM index)
+#define FUNC_NAME "bytevector_ref_c32"
+{
+  COMPLEX_NATIVE_REF (float);
 }
+#undef FUNC_NAME
 
 static SCM
-bytevector_ref_c64 (SCM bv, SCM idx)
-{ /* FIXME add some checks */
-  const double *contents = (const double*)SCM_BYTEVECTOR_CONTENTS (bv);
-  size_t i = scm_to_size_t (idx);
-  return scm_c_make_rectangular (contents[i/8], contents[i/8 + 1]);
+bytevector_ref_c64 (SCM bv, SCM index)
+#define FUNC_NAME "bytevector_ref_c64"
+{
+  COMPLEX_NATIVE_REF (double);
 }
+#undef FUNC_NAME
 
 typedef SCM (*scm_t_bytevector_ref_fn)(SCM, SCM);
 
-const scm_t_bytevector_ref_fn bytevector_ref_fns[SCM_ARRAY_ELEMENT_TYPE_LAST + 1] = 
+static const scm_t_bytevector_ref_fn
+bytevector_ref_fns[SCM_ARRAY_ELEMENT_TYPE_LAST + 1] =
 {
   NULL, /* SCM */
   NULL, /* CHAR */
@@ -2140,24 +2190,36 @@ bv_handle_ref (scm_t_array_handle *h, size_t index)
   return ref_fn (h->array, byte_index);
 }
 
-/* FIXME add checks!!! */
-static SCM
-bytevector_set_c32 (SCM bv, SCM idx, SCM val)
-{ float *contents = (float*)SCM_BYTEVECTOR_CONTENTS (bv);
-  size_t i = scm_to_size_t (idx);
-  contents[i/4] = scm_c_real_part (val);
-  contents[i/4 + 1] = scm_c_imag_part (val);
+/* Template for native modification of complex numbers of type TYPE.  */
+#define COMPLEX_NATIVE_SET(_type)                                      \
+  COMPLEX_ACCESSOR_PROLOGUE (_type);                                   \
+                                                                       \
+  {                                                                    \
+    _type real, imag;                                                  \
+    real = scm_c_real_part (value);                                    \
+    imag = scm_c_imag_part (value);                                    \
+                                                                       \
+    memcpy (&c_bv[c_index], &real, sizeof (_type));                    \
+    memcpy (&c_bv[c_index + sizeof (_type)], &imag, sizeof (_type));   \
+  }                                                                    \
+                                                                       \
   return SCM_UNSPECIFIED;
+
+static SCM
+bytevector_set_c32 (SCM bv, SCM index, SCM value)
+#define FUNC_NAME "bytevector_set_c32"
+{
+  COMPLEX_NATIVE_SET (float);
 }
+#undef FUNC_NAME
 
 static SCM
-bytevector_set_c64 (SCM bv, SCM idx, SCM val)
-{ double *contents = (double*)SCM_BYTEVECTOR_CONTENTS (bv);
-  size_t i = scm_to_size_t (idx);
-  contents[i/8] = scm_c_real_part (val);
-  contents[i/8 + 1] = scm_c_imag_part (val);
-  return SCM_UNSPECIFIED;
+bytevector_set_c64 (SCM bv, SCM index, SCM value)
+#define FUNC_NAME "bytevector_set_c64"
+{
+  COMPLEX_NATIVE_SET (double);
 }
+#undef FUNC_NAME
 
 typedef SCM (*scm_t_bytevector_set_fn)(SCM, SCM, SCM);
 
@@ -2213,17 +2275,18 @@ void
 scm_bootstrap_bytevectors (void)
 {
   /* This must be instantiated here because the generalized-vector API may
-     want to access bytevectors even though `(rnrs bytevector)' hasn't been
+     want to access bytevectors even though `(rnrs bytevectors)' hasn't been
      loaded.  */
   scm_null_bytevector = make_bytevector (0, SCM_ARRAY_ELEMENT_TYPE_VU8);
 
 #ifdef WORDS_BIGENDIAN
-  scm_i_native_endianness = scm_from_locale_symbol ("big");
+  scm_i_native_endianness = scm_from_latin1_symbol ("big");
 #else
-  scm_i_native_endianness = scm_from_locale_symbol ("little");
+  scm_i_native_endianness = scm_from_latin1_symbol ("little");
 #endif
 
-  scm_c_register_extension ("libguile", "scm_init_bytevectors",
+  scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
+                            "scm_init_bytevectors",
                            (scm_t_extension_init_func) scm_init_bytevectors,
                            NULL);