changeset 90966:d563fa5ce200

(map_sub_char_table): Make it work for the top-level char-table. Fix handling of parent char-table. (map_char_table): Adjusted for the above change.
author Kenichi Handa <handa@m17n.org>
date Mon, 25 Jun 2007 10:25:21 +0000
parents 77d6accc7a63
children 33eea7233b42
files src/chartab.c
diffstat 1 files changed, 102 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/chartab.c	Sun Jun 24 20:49:39 2007 +0000
+++ b/src/chartab.c	Mon Jun 25 10:25:21 2007 +0000
@@ -705,34 +705,104 @@
 }
 
 
+/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table),
+   calling it for each character or group of characters that share a
+   value.  RANGE is a cons (FROM . TO) specifying the range of target
+   characters, VAL is a value of FROM in TABLE, DEFAULT_VAL is the
+   default value of the char-table, PARENT is the parent of the
+   char-table.
+
+   ARG is passed to C_FUNCTION when that is called.
+
+   It returns the value of last character covered by TABLE (not the
+   value inheritted from the parent), and by side-effect, the car part
+   of RANGE is updated to the minimum character C where C and all the
+   following characters in TABLE have the same value.  */
+
 static Lisp_Object
 map_sub_char_table (c_function, function, table, arg, val, range,
 		    default_val, parent)
      void (*c_function) P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
      Lisp_Object function, table, arg, val, range, default_val, parent;
 {
-  struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
-  int depth = XINT (tbl->depth);
+  /* Pointer to the elements of TABLE. */
+  Lisp_Object *contents;
+  /* Depth of TABLE.  */
+  int depth;
+  /* Minimum and maxinum characters covered by TABLE. */
+  int min_char, max_char;
+  /* Number of characters covered by one element of TABLE.  */
+  int chars_in_block;
+  int from = XINT (XCAR (range)), to = XINT (XCDR (range));
   int i, c;
 
-  for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth];
-       i++, c += chartab_chars[depth])
+  if (SUB_CHAR_TABLE_P (table))
     {
-      Lisp_Object this;
+      struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
+
+      depth = XINT (tbl->depth);
+      contents = tbl->contents;
+      min_char = XINT (tbl->min_char);
+      max_char = min_char + chartab_chars[depth - 1] - 1;
+    }
+  else
+    {
+      depth = 0;
+      contents = XCHAR_TABLE (table)->contents;
+      min_char = 0;
+      max_char = MAX_CHAR;
+    }
+  chars_in_block = chartab_chars[depth];
 
-      this = tbl->contents[i];
+  if (to < max_char)
+    max_char = to;
+  /* Set I to the index of the first element to check.  */
+  if (from <= min_char)
+    i = 0;
+  else
+    i = (from - min_char) / chars_in_block;
+  for (c = min_char + chars_in_block * i; c <= max_char;
+       i++, c += chars_in_block)
+    {
+      Lisp_Object this = contents[i];
+      int nextc = c + chars_in_block;
+
       if (SUB_CHAR_TABLE_P (this))
-	val = map_sub_char_table (c_function, function, this, arg, val, range,
-				  default_val, parent);
+	{
+	  if (to >= nextc)
+	    XSETCDR (range, make_number (nextc - 1));
+	  val = map_sub_char_table (c_function, function, this, arg,
+				    val, range, default_val, parent);
+	}
       else
 	{
 	  if (NILP (this))
 	    this = default_val;
-	  if (NILP (this) && ! NILP (parent))
-	    this = CHAR_TABLE_REF (parent, c);
 	  if (NILP (Fequal (val, this)))
 	    {
-	      if (! NILP (val))
+	      int different_value = 1;
+
+	      if (NILP (val))
+		{
+		  if (! NILP (parent))
+		    {
+		      Lisp_Object temp = XCHAR_TABLE (parent)->parent;
+
+		      /* This is to get a value of FROM in PARENT
+			 without checking the parent of PARENT.  */
+		      XCHAR_TABLE (parent)->parent = Qnil;
+		      val = CHAR_TABLE_REF (parent, from);
+		      XCHAR_TABLE (parent)->parent = temp;
+		      XSETCDR (range, make_number (c - 1));
+		      val = map_sub_char_table (c_function, function,
+						parent, arg, val, range,
+						XCHAR_TABLE (parent)->defalt,
+						XCHAR_TABLE (parent)->parent);
+		      if (! NILP (Fequal (val, this)))
+			different_value = 0;
+		    }
+		}
+	      if (! NILP (val) && different_value)
 		{
 		  XSETCDR (range, make_number (c - 1));
 		  if (depth == 3
@@ -752,9 +822,11 @@
 		    }
 		}
 	      val = this;
+	      from = c;
 	      XSETCAR (range, make_number (c));
 	    }
 	}
+      XSETCDR (range, make_number (to));
     }
   return val;
 }
@@ -774,46 +846,35 @@
   int c, i;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
-  range = Fcons (make_number (0), Qnil);
+  range = Fcons (make_number (0), make_number (MAX_CHAR));
   GCPRO3 (table, arg, range);
   val = XCHAR_TABLE (table)->ascii;
   if (SUB_CHAR_TABLE_P (val))
     val = XSUB_CHAR_TABLE (val)->contents[0];
-
-  for (i = 0, c = 0; i < chartab_size[0]; i++, c += chartab_chars[0])
+  val = map_sub_char_table (c_function, function, table, arg, val, range,
+			    XCHAR_TABLE (table)->defalt,
+			    XCHAR_TABLE (table)->parent);
+  /* If VAL is nil and TABLE has a parent, we must consult the parent
+     recursively.  */
+  while (NILP (val) && ! NILP (XCHAR_TABLE (table)->parent))
     {
-      Lisp_Object this;
+      Lisp_Object parent = XCHAR_TABLE (table)->parent;
+      Lisp_Object temp = XCHAR_TABLE (parent)->parent;
+      int from = XINT (XCAR (range));
 
-      this = XCHAR_TABLE (table)->contents[i];
-      if (SUB_CHAR_TABLE_P (this))
-	val = map_sub_char_table (c_function, function, this, arg, val, range,
-				  XCHAR_TABLE (table)->defalt,
-				  XCHAR_TABLE (table)->parent);
-      else
-	{
-	  if (NILP (this))
-	    this = XCHAR_TABLE (table)->defalt;
-	  if (NILP (this) && ! NILP (XCHAR_TABLE (table)->parent))
-	    this = CHAR_TABLE_REF (XCHAR_TABLE (table)->parent, c);
-	  if (NILP (Fequal (val, this)))
-	    {
-	      if (! NILP (val))
-		{
-		  XSETCDR (range, make_number (c - 1));
-		  if (c_function)
-		    (*c_function) (arg, range, val);
-		  else
-		    call2 (function, range, val);
-		}
-	      val = this;
-	      XSETCAR (range, make_number (c));
-	    }
-	}
+      /* This is to get a value of FROM in PARENT without checking the
+	 parent of PARENT.  */
+      XCHAR_TABLE (parent)->parent = Qnil;
+      val = CHAR_TABLE_REF (parent, from);
+      XCHAR_TABLE (parent)->parent = temp;
+      val = map_sub_char_table (c_function, function, parent, arg, val, range,
+				XCHAR_TABLE (parent)->defalt,
+				XCHAR_TABLE (parent)->parent);
+      table = parent;
     }
 
   if (! NILP (val))
     {
-      XSETCDR (range, make_number (c - 1));
       if (c_function)
 	(*c_function) (arg, range, val);
       else