Avoid unpacking symbols in GOOPS
[bpt/guile.git] / libguile / unif.c
index ff6cc32..cf39d05 100644 (file)
@@ -1,18 +1,19 @@
-/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,2000,2001,2002,2003,2004, 2005, 2006, 2009 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 as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  */
 
 
@@ -25,7 +26,7 @@
 */
 \f
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
 
@@ -46,6 +47,7 @@
 #include "libguile/srfi-13.h"
 #include "libguile/srfi-4.h"
 #include "libguile/vectors.h"
+#include "libguile/bytevectors.h"
 #include "libguile/list.h"
 #include "libguile/deprecation.h"
 #include "libguile/dynwind.h"
@@ -108,6 +110,7 @@ struct {
   { "f64", SCM_UNSPECIFIED, scm_make_f64vector },
   { "c32", SCM_UNSPECIFIED, scm_make_c32vector },
   { "c64", SCM_UNSPECIFIED, scm_make_c64vector },
+  { "vu8", SCM_UNSPECIFIED, scm_make_bytevector },
   { NULL }
 };
 
@@ -312,6 +315,12 @@ bitvector_ref (scm_t_array_handle *h, ssize_t pos)
     scm_from_bool (((scm_t_uint32 *)h->elements)[pos/32] & (1l << (pos % 32)));
 }
 
+static SCM
+bytevector_ref (scm_t_array_handle *h, ssize_t pos)
+{
+  return scm_from_uint8 (((scm_t_uint8 *) h->elements)[pos]);
+}
+
 static SCM
 memoize_ref (scm_t_array_handle *h, ssize_t pos)
 {
@@ -345,6 +354,11 @@ memoize_ref (scm_t_array_handle *h, ssize_t pos)
       h->elements = scm_array_handle_bit_elements (h);
       h->ref = bitvector_ref;
     }
+  else if (scm_is_bytevector (v))
+    {
+      h->elements = scm_array_handle_uniform_elements (h);
+      h->ref = bytevector_ref;
+    }
   else
     scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (h->array));
 
@@ -368,9 +382,9 @@ string_set (scm_t_array_handle *h, ssize_t pos, SCM val)
 {
   pos += h->base;
   if (SCM_I_ARRAYP (h->array))
-    return scm_c_string_set_x (SCM_I_ARRAY_V (h->array), pos, val);
+    scm_c_string_set_x (SCM_I_ARRAY_V (h->array), pos, val);
   else
-    return scm_c_string_set_x (h->array, pos, val);
+    scm_c_string_set_x (h->array, pos, val);
 }
 
 static void
@@ -380,9 +394,20 @@ bitvector_set (scm_t_array_handle *h, ssize_t pos, SCM val)
   pos += scm_array_handle_bit_elements_offset (h);
   mask = 1l << (pos % 32);
   if (scm_to_bool (val))
-    ((scm_t_uint32 *)h->elements)[pos/32] |= mask;
+    ((scm_t_uint32 *)h->writable_elements)[pos/32] |= mask;
   else
-    ((scm_t_uint32 *)h->elements)[pos/32] &= ~mask;
+    ((scm_t_uint32 *)h->writable_elements)[pos/32] &= ~mask;
+}
+
+static void
+bytevector_set (scm_t_array_handle *h, ssize_t pos, SCM val)
+{
+  scm_t_uint8 c_value;
+  scm_t_uint8 *elements;
+
+  c_value = scm_to_uint8 (val);
+  elements = (scm_t_uint8 *) h->elements;
+  elements[pos] = (scm_t_uint8) c_value;
 }
 
 static void
@@ -419,6 +444,11 @@ memoize_set (scm_t_array_handle *h, ssize_t pos, SCM val)
       h->writable_elements = scm_array_handle_bit_writable_elements (h);
       h->set = bitvector_set;
     }
+  else if (scm_is_bytevector (v))
+    {
+      h->elements = scm_array_handle_uniform_writable_elements (h);
+      h->set = bytevector_set;
+    }
   else
     scm_misc_error (NULL, "unknown array type: ~a", scm_list_1 (h->array));
 
@@ -770,6 +800,53 @@ SCM_DEFINE (scm_make_typed_array, "make-typed-array", 2, 0, 1,
 }
 #undef FUNC_NAME
 
+SCM
+scm_from_contiguous_typed_array (SCM type, SCM bounds, const void *bytes,
+                                 size_t byte_len)
+#define FUNC_NAME "scm_from_contiguous_typed_array"
+{
+  size_t k, rlen = 1;
+  scm_t_array_dim *s;
+  creator_proc *creator;
+  SCM ra;
+  scm_t_array_handle h;
+  void *base;
+  size_t sz;
+  
+  creator = type_to_creator (type);
+  ra = scm_i_shap2ra (bounds);
+  SCM_SET_ARRAY_CONTIGUOUS_FLAG (ra);
+  s = SCM_I_ARRAY_DIMS (ra);
+  k = SCM_I_ARRAY_NDIM (ra);
+
+  while (k--)
+    {
+      s[k].inc = rlen;
+      SCM_ASSERT_RANGE (1, bounds, s[k].lbnd <= s[k].ubnd + 1);
+      rlen = (s[k].ubnd - s[k].lbnd + 1) * s[k].inc;
+    }
+  SCM_I_ARRAY_V (ra) = creator (scm_from_size_t (rlen), SCM_UNDEFINED);
+
+
+  scm_array_get_handle (ra, &h);
+  base = scm_array_handle_uniform_writable_elements (&h);
+  sz = scm_array_handle_uniform_element_size (&h);
+  scm_array_handle_release (&h);
+
+  if (byte_len % sz)
+    SCM_MISC_ERROR ("byte length not a multiple of the unit size", SCM_EOL);
+  if (byte_len / sz != rlen)
+    SCM_MISC_ERROR ("byte length and dimensions do not match", SCM_EOL);
+
+  memcpy (base, bytes, byte_len);
+
+  if (1 == SCM_I_ARRAY_NDIM (ra) && 0 == SCM_I_ARRAY_BASE (ra))
+    if (s->ubnd < s->lbnd || (0 == s->lbnd && 1 == s->inc))
+      return SCM_I_ARRAY_V (ra);
+  return ra;
+}
+#undef FUNC_NAME
+
 SCM_DEFINE (scm_make_array, "make-array", 1, 0, 1,
            (SCM fill, SCM bounds),
            "Create and return an array.")
@@ -796,6 +873,18 @@ SCM_DEFINE (scm_dimensions_to_uniform_array, "dimensions->uniform-array", 2, 1,
 
   if (scm_is_integer (dims))
     dims = scm_list_1 (dims);
+
+  if (SCM_UNBNDP (fill))
+    {
+      /* Using #\nul as the prototype yields a s8 array, but numeric
+        arrays can't store characters, so we have to special case this.
+      */
+      if (scm_is_eq (prot, SCM_MAKE_CHAR (0)))
+       fill = scm_from_int (0);
+      else
+       fill = prot;
+    }
+
   return scm_make_typed_array (prototype_to_type (prot), fill, dims);
 }
 #undef FUNC_NAME
@@ -849,7 +938,7 @@ SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
   SCM imap;
   size_t k;
   ssize_t i;
-  long old_min, new_min, old_max, new_max;
+  long old_base, old_min, new_min, old_max, new_max;
   scm_t_array_dim *s;
 
   SCM_VALIDATE_REST_ARGUMENT (dims);
@@ -861,7 +950,7 @@ SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
   if (SCM_I_ARRAYP (oldra))
     {
       SCM_I_ARRAY_V (ra) = SCM_I_ARRAY_V (oldra);
-      old_min = old_max = SCM_I_ARRAY_BASE (oldra);
+      old_base = old_min = old_max = SCM_I_ARRAY_BASE (oldra);
       s = scm_array_handle_dims (&old_handle);
       k = scm_array_handle_rank (&old_handle);
       while (k--)
@@ -875,7 +964,7 @@ SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
   else
     {
       SCM_I_ARRAY_V (ra) = oldra;
-      old_min = 0;
+      old_base = old_min = 0;
       old_max = scm_c_generalized_vector_length (oldra) - 1;
     }
 
@@ -897,7 +986,7 @@ SCM_DEFINE (scm_make_shared_array, "make-shared-array", 2, 0, 1,
 
   imap = scm_apply_0 (mapfunc, scm_reverse (inds));
   i = scm_array_handle_pos (&old_handle, imap);
-  SCM_I_ARRAY_BASE (ra) = new_min = new_max = i;
+  SCM_I_ARRAY_BASE (ra) = new_min = new_max = i + old_base;
   indptr = inds;
   k = SCM_I_ARRAY_NDIM (ra);
   while (k--)
@@ -1060,7 +1149,6 @@ SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
 #define FUNC_NAME s_scm_enclose_array
 {
   SCM axv, res, ra_inr;
-  const char *c_axv;
   scm_t_array_dim vdim, *s = &vdim;
   int ndim, j, k, ninr, noutr;
 
@@ -1108,10 +1196,9 @@ SCM_DEFINE (scm_enclose_array, "enclose-array", 1, 0, 1,
       SCM_I_ARRAY_DIMS (ra_inr)[k].inc = s[j].inc;
       scm_c_string_set_x (axv, j, SCM_MAKE_CHAR (1));
     }
-  c_axv = scm_i_string_chars (axv);
   for (j = 0, k = 0; k < noutr; k++, j++)
     {
-      while (c_axv[j])
+      while (!scm_i_string_ref (axv, j) == '\0')
        j++;
       SCM_I_ARRAY_DIMS (res)[k].lbnd = s[j].lbnd;
       SCM_I_ARRAY_DIMS (res)[k].ubnd = s[j].ubnd;
@@ -1136,23 +1223,12 @@ SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
 
   SCM_VALIDATE_REST_ARGUMENT (args);
 
-  if (scm_is_generalized_vector (v))
-    {
-      long ind;
-
-      if (!scm_is_pair (args))
-       SCM_WRONG_NUM_ARGS ();
-      ind = scm_to_long (SCM_CAR (args));
-      args = SCM_CDR (args);
-      res = scm_from_bool (ind >= 0
-                          && ind < scm_c_generalized_vector_length (v));
-    }
-  else if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
+  if (SCM_I_ARRAYP (v) || SCM_I_ENCLOSED_ARRAYP (v))
     {
-      size_t k = SCM_I_ARRAY_NDIM (v);
+      size_t k, ndim = SCM_I_ARRAY_NDIM (v);
       scm_t_array_dim *s = SCM_I_ARRAY_DIMS (v);
 
-      while (k > 0)
+      for (k = 0; k < ndim; k++)
        {
          long ind;
 
@@ -1160,9 +1236,8 @@ SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
            SCM_WRONG_NUM_ARGS ();
          ind = scm_to_long (SCM_CAR (args));
          args = SCM_CDR (args);
-         k -= 1;
 
-         if (ind < s->lbnd || ind > s->ubnd)
+         if (ind < s[k].lbnd || ind > s[k].ubnd)
            {
              res = SCM_BOOL_F;
              /* We do not stop the checking after finding a violation
@@ -1172,6 +1247,21 @@ SCM_DEFINE (scm_array_in_bounds_p, "array-in-bounds?", 1, 0, 1,
            }
        }
     }
+  else if (scm_is_generalized_vector (v))
+    {
+      /* Since real arrays have been covered above, all generalized
+        vectors are guaranteed to be zero-origin here.
+      */
+
+      long ind;
+
+      if (!scm_is_pair (args))
+       SCM_WRONG_NUM_ARGS ();
+      ind = scm_to_long (SCM_CAR (args));
+      args = SCM_CDR (args);
+      res = scm_from_bool (ind >= 0
+                          && ind < scm_c_generalized_vector_length (v));
+    }
   else
     scm_wrong_type_arg_msg (NULL, 0, v, "array");
 
@@ -2237,13 +2327,12 @@ scm_istr2bve (SCM str)
   SCM res = vec;
 
   scm_t_uint32 mask;
-  size_t k, j;
-  const char *c_str;
+  size_t k, j, p;
   scm_t_uint32 *data;
 
   data = scm_bitvector_writable_elements (vec, &handle, NULL, NULL, NULL);
-  c_str = scm_i_string_chars (str);
 
+  p = 0;
   for (k = 0; k < (len + 31) / 32; k++)
     {
       data[k] = 0L;
@@ -2251,7 +2340,7 @@ scm_istr2bve (SCM str)
       if (j > 32)
        j = 32;
       for (mask = 1L; j--; mask <<= 1)
-       switch (*c_str++)
+       switch (scm_i_string_ref (str, p++))
          {
          case '0':
            break;
@@ -2653,7 +2742,7 @@ read_decimal_integer (SCM port, int c, ssize_t *resp)
     }
 
   if (got_it)
-    *resp = res;
+    *resp = sign * res;
   return c;
 }
 
@@ -2737,6 +2826,11 @@ scm_i_read_array (SCM port, int c)
            {
              c = scm_getc (port);
              c = read_decimal_integer (port, c, &len);
+             if (len < 0)
+               scm_i_input_error (NULL, port,
+                                  "array length must be non-negative",
+                                  SCM_EOL);
+
              s = scm_list_2 (s, scm_from_ssize_t (lbnd+len-1));
            }
 
@@ -2885,7 +2979,7 @@ scm_aind (SCM ra, SCM args, const char *what)
     args = scm_list_1 (args);
   
   scm_array_get_handle (ra, &handle);
-  pos = scm_array_handle_pos (&handle, args);
+  pos = scm_array_handle_pos (&handle, args) + SCM_I_ARRAY_BASE (ra);
   scm_array_handle_release (&handle);
   return pos;
 }