* convert.c: include <string.h> for convert_i.c.
[bpt/guile.git] / srfi / srfi-14.c
index 7973e61..e16f233 100644 (file)
@@ -51,8 +51,9 @@
 #include "srfi-14.h"
 
 
-#define SCM_CHARSET_SET(cs, idx) (((long *) SCM_SMOB_DATA (cs))[(idx) / SCM_BITS_PER_LONG] |= (1 << ((idx) % SCM_BITS_PER_LONG)))
-
+#define SCM_CHARSET_SET(cs, idx) \
+  (((long *) SCM_SMOB_DATA (cs))[(idx) / SCM_BITS_PER_LONG] |= \
+    (1L << ((idx) % SCM_BITS_PER_LONG)))
 
 #define BYTES_PER_CHARSET (SCM_CHARSET_SIZE / 8)
 #define LONGS_PER_CHARSET (SCM_CHARSET_SIZE / SCM_BITS_PER_LONG)
@@ -98,7 +99,7 @@ make_char_set (const char * func_name)
 {
   long * p;
   
-  p = scm_must_malloc (BYTES_PER_CHARSET, func_name);
+  p = scm_gc_malloc (BYTES_PER_CHARSET, "character-set");
   memset (p, 0, BYTES_PER_CHARSET);
   SCM_RETURN_NEWSMOB (scm_tc16_charset, p);
 }
@@ -191,7 +192,7 @@ SCM_DEFINE (scm_char_set_hash, "char-set-hash", 1, 1, 0,
   const int default_bnd = 871;
   int bnd;
   long * p;
-  unsigned val = 0;
+  unsigned long val = 0;
   int k;
 
   SCM_VALIDATE_SMOB (1, cs, charset);
@@ -316,11 +317,11 @@ SCM_DEFINE (scm_char_set_unfold, "char-set-unfold", 4, 1, 0,
            (SCM p, SCM f, SCM g, SCM seed, SCM base_cs),
            "This is a fundamental constructor for character sets.\n"
            "@itemize @bullet\n"
-           "@item @var{g} is used to generate a series of ``seed'' values \n"
+           "@item @var{g} is used to generate a series of ``seed'' values\n"
            "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
            "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
            "@item @var{p} tells us when to stop -- when it returns true\n"
-           "when applied to one of the seed values. \n"
+           "when applied to one of the seed values.\n"
            "@item @var{f} maps each seed value to a character. These\n"
            "characters are added to the base character set @var{base_cs} to\n"
            "form the result; @var{base_cs} defaults to the empty set.\n"
@@ -361,10 +362,10 @@ SCM_DEFINE (scm_char_set_unfold_x, "char-set-unfold!", 5, 0, 0,
            "This is a fundamental constructor for character sets.\n"
            "@itemize @bullet\n"
            "@item @var{g} is used to generate a series of ``seed'' values\n"
-           "from the initial seed: @var{seed}, (@var{g} @var{seed}), \n"
+           "from the initial seed: @var{seed}, (@var{g} @var{seed}),\n"
            "(@var{g}^2 @var{seed}), (@var{g}^3 @var{seed}), @dots{}\n"
            "@item @var{p} tells us when to stop -- when it returns true\n"
-           "when applied to one of the seed values. \n"
+           "when applied to one of the seed values.\n"
            "@item @var{f} maps each seed value to a character. These\n"
            "characters are added to the base character set @var{base_cs} to\n"
            "form the result; @var{base_cs} defaults to the empty set.\n"
@@ -479,7 +480,7 @@ SCM_DEFINE (scm_char_set, "char-set", 0, 0, 1,
       SCM_VALIDATE_CHAR_COPY (argnum, SCM_CAR (rest), c);
       argnum++;
       rest = SCM_CDR (rest);
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return cs;
 }
@@ -513,7 +514,7 @@ SCM_DEFINE (scm_list_to_char_set, "list->char-set", 1, 1, 0,
       SCM_VALIDATE_CHAR_COPY (0, chr, c);
       list = SCM_CDR (list);
 
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return cs;
 }
@@ -525,7 +526,7 @@ SCM_DEFINE (scm_list_to_char_set_x, "list->char-set!", 2, 0, 0,
            "Convert the character list @var{list} to a character set.  The\n"
            "characters are added to @var{base_cs} and @var{base_cs} is\n"
            "returned.")
-#define FUNC_NAME s_scm_list_to_char_set
+#define FUNC_NAME s_scm_list_to_char_set_x
 {
   long * p;
 
@@ -540,7 +541,7 @@ SCM_DEFINE (scm_list_to_char_set_x, "list->char-set!", 2, 0, 0,
       SCM_VALIDATE_CHAR_COPY (0, chr, c);
       list = SCM_CDR (list);
 
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return base_cs;
 }
@@ -557,7 +558,7 @@ SCM_DEFINE (scm_string_to_char_set, "string->char-set", 1, 1, 0,
   SCM cs;
   long * p;
   char * s;
-  int k = 0;
+  size_t k = 0;
 
   SCM_VALIDATE_STRING (1, str);
   if (SCM_UNBNDP (base_cs))
@@ -572,7 +573,7 @@ SCM_DEFINE (scm_string_to_char_set, "string->char-set", 1, 1, 0,
   while (k < SCM_STRING_LENGTH (str))
     {
       int c = s[k++];
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return cs;
 }
@@ -588,7 +589,7 @@ SCM_DEFINE (scm_string_to_char_set_x, "string->char-set!", 2, 0, 0,
 {
   long * p;
   char * s;
-  int k = 0;
+  size_t k = 0;
 
   SCM_VALIDATE_STRING (1, str);
   SCM_VALIDATE_SMOB (2, base_cs, charset);
@@ -597,7 +598,7 @@ SCM_DEFINE (scm_string_to_char_set_x, "string->char-set!", 2, 0, 0,
   while (k < SCM_STRING_LENGTH (str))
     {
       int c = s[k++];
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return base_cs;
 }
@@ -632,7 +633,7 @@ SCM_DEFINE (scm_char_set_filter, "char-set-filter", 2, 1, 0,
          SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
 
          if (!SCM_FALSEP (res))
-           p[k / SCM_BITS_PER_LONG] |= 1 << (k % SCM_BITS_PER_LONG);
+           p[k / SCM_BITS_PER_LONG] |= 1L << (k % SCM_BITS_PER_LONG);
        }
     }
   return ret;
@@ -661,7 +662,7 @@ SCM_DEFINE (scm_char_set_filter_x, "char-set-filter!", 3, 0, 0,
          SCM res = scm_call_1 (pred, SCM_MAKE_CHAR (k));
 
          if (!SCM_FALSEP (res))
-           p[k / SCM_BITS_PER_LONG] |= 1 << (k % SCM_BITS_PER_LONG);
+           p[k / SCM_BITS_PER_LONG] |= 1L << (k % SCM_BITS_PER_LONG);
        }
     }
   return base_cs;
@@ -715,7 +716,7 @@ SCM_DEFINE (scm_ucs_range_to_char_set, "ucs-range->char-set", 2, 2, 0,
   p = (long *) SCM_SMOB_DATA (cs);
   while (clower < cupper)
     {
-      p[clower / SCM_BITS_PER_LONG] |= 1 << (clower % SCM_BITS_PER_LONG);
+      p[clower / SCM_BITS_PER_LONG] |= 1L << (clower % SCM_BITS_PER_LONG);
       clower++;
     }
   return cs;
@@ -758,7 +759,7 @@ SCM_DEFINE (scm_ucs_range_to_char_set_x, "ucs-range->char-set!", 4, 0, 0,
   p = (long *) SCM_SMOB_DATA (base_cs);
   while (clower < cupper)
     {
-      p[clower / SCM_BITS_PER_LONG] |= 1 << (clower % SCM_BITS_PER_LONG);
+      p[clower / SCM_BITS_PER_LONG] |= 1L << (clower % SCM_BITS_PER_LONG);
       clower++;
     }
   return base_cs;
@@ -931,7 +932,7 @@ SCM_DEFINE (scm_char_set_adjoin, "char-set-adjoin", 1, 0, 1,
       SCM_VALIDATE_CHAR_COPY (1, chr, c);
       rest = SCM_CDR (rest);
 
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return cs;
 }
@@ -959,7 +960,7 @@ SCM_DEFINE (scm_char_set_delete, "char-set-delete", 1, 0, 1,
       SCM_VALIDATE_CHAR_COPY (1, chr, c);
       rest = SCM_CDR (rest);
 
-      p[c / SCM_BITS_PER_LONG] &= ~(1 << (c % SCM_BITS_PER_LONG));
+      p[c / SCM_BITS_PER_LONG] &= ~(1L << (c % SCM_BITS_PER_LONG));
     }
   return cs;
 }
@@ -986,7 +987,7 @@ SCM_DEFINE (scm_char_set_adjoin_x, "char-set-adjoin!", 1, 0, 1,
       SCM_VALIDATE_CHAR_COPY (1, chr, c);
       rest = SCM_CDR (rest);
 
-      p[c / SCM_BITS_PER_LONG] |= 1 << (c % SCM_BITS_PER_LONG);
+      p[c / SCM_BITS_PER_LONG] |= 1L << (c % SCM_BITS_PER_LONG);
     }
   return cs;
 }
@@ -1013,7 +1014,7 @@ SCM_DEFINE (scm_char_set_delete_x, "char-set-delete!", 1, 0, 1,
       SCM_VALIDATE_CHAR_COPY (1, chr, c);
       rest = SCM_CDR (rest);
 
-      p[c / SCM_BITS_PER_LONG] &= ~(1 << (c % SCM_BITS_PER_LONG));
+      p[c / SCM_BITS_PER_LONG] &= ~(1L << (c % SCM_BITS_PER_LONG));
     }
   return cs;
 }
@@ -1070,31 +1071,41 @@ SCM_DEFINE (scm_char_set_union, "char-set-union", 0, 0, 1,
 #undef FUNC_NAME
 
 
-SCM_DEFINE (scm_char_set_intersection, "char-set-intersection", 1, 0, 1,
-           (SCM cs1, SCM rest),
+SCM_DEFINE (scm_char_set_intersection, "char-set-intersection", 0, 0, 1,
+           (SCM rest),
            "Return the intersection of all argument character sets.")
 #define FUNC_NAME s_scm_char_set_intersection
 {
-  int c = 2;
   SCM res;
-  long * p;
 
-  SCM_VALIDATE_SMOB (1, cs1, charset);
   SCM_VALIDATE_REST_ARGUMENT (rest);
 
-  res = scm_char_set_copy (cs1);
-  p = (long *) SCM_SMOB_DATA (res);
-  while (!SCM_NULLP (rest))
+  if (SCM_NULLP (rest))
+    res = make_char_set (FUNC_NAME);
+  else
     {
-      int k;
-      SCM cs = SCM_CAR (rest);
-      SCM_VALIDATE_SMOB (c, cs, charset);
-      c++;
+      long *p;
+      int argnum = 2;
+
+      res = scm_char_set_copy (SCM_CAR (rest));
+      p = (long *) SCM_SMOB_DATA (res);
       rest = SCM_CDR (rest);
 
-      for (k = 0; k < LONGS_PER_CHARSET; k++)
-       p[k] &= ((long *) SCM_SMOB_DATA (cs))[k];
+      while (SCM_CONSP (rest))
+       {
+         int k;
+         SCM cs = SCM_CAR (rest);
+         long *cs_data;
+
+         SCM_VALIDATE_SMOB (argnum, cs, charset);
+         argnum++;
+         cs_data = (long *) SCM_SMOB_DATA (cs);
+         rest = SCM_CDR (rest);
+         for (k = 0; k < LONGS_PER_CHARSET; k++)
+           p[k] &= cs_data[k];
+       }
     }
+
   return res;
 }
 #undef FUNC_NAME
@@ -1130,30 +1141,40 @@ SCM_DEFINE (scm_char_set_difference, "char-set-difference", 1, 0, 1,
 #undef FUNC_NAME
 
 
-SCM_DEFINE (scm_char_set_xor, "char-set-xor", 1, 0, 1,
-           (SCM cs1, SCM rest),
+SCM_DEFINE (scm_char_set_xor, "char-set-xor", 0, 0, 1,
+           (SCM rest),
            "Return the exclusive-or of all argument character sets.")
 #define FUNC_NAME s_scm_char_set_xor
 {
-  int c = 2;
   SCM res;
-  long * p;
 
-  SCM_VALIDATE_SMOB (1, cs1, charset);
   SCM_VALIDATE_REST_ARGUMENT (rest);
 
-  res = scm_char_set_copy (cs1);
-  p = (long *) SCM_SMOB_DATA (res);
-  while (!SCM_NULLP (rest))
+  if (SCM_NULLP (rest))
+    res = make_char_set (FUNC_NAME);
+  else
     {
-      int k;
-      SCM cs = SCM_CAR (rest);
-      SCM_VALIDATE_SMOB (c, cs, charset);
-      c++;
+      int argnum = 2;
+      long * p;
+
+      res = scm_char_set_copy (SCM_CAR (rest));
+      p = (long *) SCM_SMOB_DATA (res);
       rest = SCM_CDR (rest);
 
-      for (k = 0; k < LONGS_PER_CHARSET; k++)
-       p[k] ^= ((long *) SCM_SMOB_DATA (cs))[k];
+      while (SCM_CONSP (rest))
+       {
+         SCM cs = SCM_CAR (rest);
+         long *cs_data;
+         int k;
+
+         SCM_VALIDATE_SMOB (argnum, cs, charset);
+         argnum++;
+         cs_data = (long *) SCM_SMOB_DATA (cs);
+         rest = SCM_CDR (rest);
+
+         for (k = 0; k < LONGS_PER_CHARSET; k++)
+           p[k] ^= cs_data[k];
+       }
     }
   return res;
 }
@@ -1174,22 +1195,25 @@ SCM_DEFINE (scm_char_set_diff_plus_intersection, "char-set-diff+intersection", 1
   SCM_VALIDATE_REST_ARGUMENT (rest);
 
   res1 = scm_char_set_copy (cs1);
-  res2 = scm_char_set_copy (cs1);
+  res2 = make_char_set (FUNC_NAME);
   p = (long *) SCM_SMOB_DATA (res1);
   q = (long *) SCM_SMOB_DATA (res2);
   while (!SCM_NULLP (rest))
     {
       int k;
       SCM cs = SCM_CAR (rest);
+      long *r;
+
       SCM_VALIDATE_SMOB (c, cs, charset);
       c++;
-      rest = SCM_CDR (rest);
+      r = (long *) SCM_SMOB_DATA (cs);
 
       for (k = 0; k < LONGS_PER_CHARSET; k++)
        {
-         p[k] &= ~((long *) SCM_SMOB_DATA (cs))[k];
-         q[k] &= ((long *) SCM_SMOB_DATA (cs))[k];
+         q[k] |= p[k] & r[k];
+         p[k] &= ~r[k];
        }
+      rest = SCM_CDR (rest);
     }
   return scm_values (scm_list_2 (res1, res2));
 }
@@ -1302,6 +1326,15 @@ SCM_DEFINE (scm_char_set_xor_x, "char-set-xor!", 1, 0, 1,
            "Return the exclusive-or of all argument character sets.")
 #define FUNC_NAME s_scm_char_set_xor_x
 {
+  /* a side-effecting variant should presumably give consistent results:
+     (define a (char-set #\a))
+     (char-set-xor a a a) -> char set #\a
+     (char-set-xor! a a a) -> char set #\a
+  */
+  return scm_char_set_xor (scm_cons (cs1, rest));
+
+#if 0
+  /* this would give (char-set-xor! a a a) -> empty char set.  */
   int c = 2;
   long * p;
 
@@ -1321,41 +1354,58 @@ SCM_DEFINE (scm_char_set_xor_x, "char-set-xor!", 1, 0, 1,
        p[k] ^= ((long *) SCM_SMOB_DATA (cs))[k];
     }
   return cs1;
+#endif
 }
 #undef FUNC_NAME
 
 
-SCM_DEFINE (scm_char_set_diff_plus_intersection_x, "char-set-diff+intersection!", 1, 0, 1,
-           (SCM cs1, SCM rest),
+SCM_DEFINE (scm_char_set_diff_plus_intersection_x, "char-set-diff+intersection!", 2, 0, 1,
+           (SCM cs1, SCM cs2, SCM rest),
            "Return the difference and the intersection of all argument\n"
            "character sets.")
 #define FUNC_NAME s_scm_char_set_diff_plus_intersection_x
 {
-  int c = 2;
-  SCM res2;
+  int c = 3;
   long * p, * q;
+  int k;
 
   SCM_VALIDATE_SMOB (1, cs1, charset);
+  SCM_VALIDATE_SMOB (2, cs2, charset);
   SCM_VALIDATE_REST_ARGUMENT (rest);
 
-  res2 = scm_char_set_copy (cs1);
   p = (long *) SCM_SMOB_DATA (cs1);
-  q = (long *) SCM_SMOB_DATA (res2);
+  q = (long *) SCM_SMOB_DATA (cs2);
+  if (p == q)
+    {
+      /* (char-set-diff+intersection! a a ...): can't share storage,
+        but we know the answer without checking for further
+        arguments.  */
+      return scm_values (scm_list_2 (make_char_set (FUNC_NAME), cs1));
+    }
+  for (k = 0; k < LONGS_PER_CHARSET; k++)
+    {
+      long t = p[k];
+
+      p[k] &= ~q[k];
+      q[k] = t & q[k];
+    }
   while (!SCM_NULLP (rest))
     {
-      int k;
       SCM cs = SCM_CAR (rest);
+      long *r;
+
       SCM_VALIDATE_SMOB (c, cs, charset);
       c++;
-      rest = SCM_CDR (rest);
+      r = (long *) SCM_SMOB_DATA (cs);
 
       for (k = 0; k < LONGS_PER_CHARSET; k++)
        {
-         p[k] &= ~((long *) SCM_SMOB_DATA (cs))[k];
-         q[k] &= ((long *) SCM_SMOB_DATA (cs))[k];
+         q[k] |= p[k] & r[k];
+         p[k] &= ~r[k];
        }
+      rest = SCM_CDR (rest);
     }
-  return scm_values (scm_list_2 (cs1, res2));
+  return scm_values (scm_list_2 (cs1, cs2));
 }
 #undef FUNC_NAME