*** empty log message ***
authorhanda <handa>
Tue, 14 Jul 2009 11:17:53 +0000 (11:17 +0000)
committerhanda <handa>
Tue, 14 Jul 2009 11:17:53 +0000 (11:17 +0000)
MCharTable.cs
chartab.cs [new file with mode: 0644]

index 6845767..35685d7 100644 (file)
@@ -6,18 +6,99 @@ using M17N.Core;
 
 namespace M17N.Core
 {
-  public class MCharTable : IEnumerable
+  public class MCharRange
+  {
+    internal int from;
+    internal int to;
+    internal object value;
+    internal MCharTable from_table;
+    internal MCharTable to_table;
+
+    public int From { get { return from; } }
+    public int To { get { return to; } }
+    public object Value { get { return value; } }
+
+    internal static void CheckChar (int c)
+    {
+      if (c < 0 || c > 0x10FFFF)
+       throw new ArgumentException ("Invalid Unicode character: " + c);
+    }
+    
+    public MCharRange (int c, MCharTable table)
+    {
+      CheckChar (c);
+      value = table.Get (c, out table);
+      if (c == 0)
+       {
+         from = c;
+         from_table = table;
+       }
+      else
+       from = table.PrevBoundary (c - 1, value, out from_table) + 1;
+      if (c == 0x10FFFF)
+       {
+         to = c;
+         to_table = table;
+       }
+      else
+       to = table.NextBoundary (c + 1, value, out to_table) - 1;
+    }
+
+    public bool Prev ()
+    {
+      if (from == 0)
+       return false;
+      to = from - 1;
+      value = from_table.Get (to, out to_table);
+      if (to == 0)
+       {
+         from = to;
+         from_table = to_table;
+       }
+      else
+       from = to_table.PrevBoundary (to - 1, value, out from_table) + 1;
+      return true;
+    }
+
+    public bool Next ()
+    {
+      if (to == 0x10FFFF)
+       return false;
+      from = to + 1;
+      value = to_table.Get (from, out from_table);
+      if (from == 0x10FFFF)
+       {
+         to = from;
+         to_table = from_table;
+       }
+      else
+       to = from_table.NextBoundary (from + 1, value, out to_table) - 1;
+      return true;
+    }
+
+    public override string ToString ()
+    {
+      return String.Format ("[U+{0:X}..U+{1:X} {2}]", from, to,
+                           value == null ? "null" : value);
+    }
+  }
+
+  public class MCharTable : IEnumerable<MCharRange>
   {
     private static readonly int[] nchars
       = new int[] { 0x110000, 0x10000, 0x1000, 0x80 };
     private static readonly int[] slots
       = new int[] { 17, 16, 32, 128 };
-    private static readonly int[] mask
-      = new int[] { 0x11FFFF, 0xFFFF, 0xFFF, 0x7F };
     private static readonly int[] shift
       = new int[] { 16, 12, 7, 0 };
 
-    private int index (int c) { return ((c & mask[depth]) >> shift[depth]); }
+    private static bool IsSubCharTable (object obj)
+      {
+       return (obj is MCharTable
+               && ((MCharTable) obj).depth > 0);
+      }
+
+    private int index (int c) { return ((c - min_char) >> shift[depth]); }
 
     private MCharTable parent;
     private int depth;
@@ -28,8 +109,8 @@ namespace M17N.Core
       {
        parent = null;
        depth = 0;
-       min_char = 0x110000;
-       max_char = 0;
+       min_char = 0;
+       max_char = 0x10FFFF;
        contents = new object[slots[0]];
       }
 
@@ -47,22 +128,32 @@ namespace M17N.Core
     private object Get (int c)
     {
       object slot = contents[index (c)];
-      if (slot is MCharTable)
+      if (IsSubCharTable (slot))
        return ((MCharTable) slot).Get (c);
       return slot;
     }
 
+    internal object Get (int c, out MCharTable table)
+    {
+      if (c < min_char || c > max_char)
+       return parent.Get (c, out table);
+      object slot = contents[index (c)];
+      if (IsSubCharTable (slot))
+       return ((MCharTable) slot).Get (c, out table);
+      table = this;
+      return slot;
+    }
+
     private void Set (int c, object value)
     {
+      int i = index (c);
+
       if (depth == 3)
-       contents[c & mask[3]] = value;
+       contents[i] = value;
       else
        {
-         int i = index (c);
-         int offset = depth == 0 ? 0 : min_char;
-
-         if (! (contents[i] is MCharTable))
-           contents[i] = new MCharTable (this, offset + i << shift[depth],
+         if (! IsSubCharTable (contents[i]))
+           contents[i] = new MCharTable (this, min_char + (i << shift[depth]),
                                          contents[i]);
          ((MCharTable) contents[i]).Set (c, value);
        }
@@ -71,97 +162,137 @@ namespace M17N.Core
     public object this[int c]
     {
       get {
-       if (c < 0 || c > 0x10FFFF)
-         throw new ArgumentException ("Invalid character: " + c);
-       if (min_char > c || max_char < c)
-         return null;
+       MCharRange.CheckChar (c);
        return Get (c);
       }
 
       set {
-       if (c < 0 || c > 0x10FFFF)
-         throw new ArgumentException ("Invalid character: " + c);
-       if (value is MCharTable)
-         throw new ArgumentException ("Invalid value type: MCharTable");
-       if (min_char > c)
-         min_char = c;
-       if (max_char < c)
-         max_char = c;
+       MCharRange.CheckChar (c);
        Set (c, value);
       }
     }
 
-    private class MCharTableIT
+    public object this[int from, int to]
     {
-      public int c;
-      public object value;
-      public MCharTable table;
+      set { set_range (from, to, value); }
+    }
 
-      public MCharTableIT (int c, object value, MCharTable table)
-      {
-       this.c = c;
-       this.value = value;
-       this.table = table;
-      }
+    private void set_range (int from, int to, object value)
+    {
+      if (to > max_char)
+       to = max_char;
+      int i0 = index (from), i1 = index (to);
 
-      public override string ToString ()
-      {
-       return (String.Format ("<{0:X},{1}>", c, value));
-      }
+      if (depth == 3)
+       {
+         for (; i0 <= i1; i0++)
+           contents[i0] = value;
+       }
+      else
+       {
+         int min0 = min_char + (i0 << shift[depth]);
+         int min1 = min_char + (i1 << shift[depth]);
+
+         if (min0 < from)
+           {
+             if (contents[i0] != value)
+               {
+                 if (! IsSubCharTable (contents[i0]))
+                   contents[i0] = new MCharTable (this, min0, contents[i0]);
+                 ((MCharTable) contents[i0]).set_range (from, to, value);
+               }
+             from = min0 + nchars[depth + 1];
+             if (from >= to)
+               return;
+             i0++;
+           }
+         for (; i0 < i1; i0++)
+           contents[i0] = value;
+         if (to == min1 + nchars[depth + 1] - 1)
+           contents[i1] = value;
+         else if (contents[i1] != value)
+           {
+             if (! IsSubCharTable (contents[i1]))
+               contents[i1] = new MCharTable (this, min1, contents[i1]);
+             ((MCharTable) contents[i1]).set_range (min1, to, value);
+           }
+       }
     }
 
-    private bool Next (MCharTableIT it)
+    internal int NextBoundary (int c, object value, out MCharTable table)
     {
-      Console.WriteLine ("Depth:{0} ({1:X}-{2:X}) IT:{3}", depth, min_char, max_char, it);
-      if (it.c > max_char)
-       return (parent != null ? parent.Next (it) : false);
+      table = this;
+      for (int i = index (c); i < slots[depth];
+          i++, c = min_char + (i << shift[depth]))
+       if (contents[i] != value)
+         return (IsSubCharTable (contents[i])
+                 ? ((MCharTable) contents[i]).NextBoundary (c, value,
+                                                            out table)
+                 : c);
+      return (depth == 0
+             ? c : parent.NextBoundary (c, value, out table));
+    }
 
-      object value = null;
-      for (int i = index (it.c);
-          i < slots[depth] && (value = contents[i]) == null;
-          i++, it.c = min_char + i << shift[depth]);
-      Console.WriteLine ("IT:{1}", depth, it);
-      if (value == null)
-       return (parent != null ? parent.Next (it) : false);
-      if (value is MCharTable)
-       return ((MCharTable) value).Next (it);
-      it.table = this;
-      it.value = value;
-      return true;
+    internal int PrevBoundary (int c, object value, out MCharTable table)
+    {
+      table = this;
+      for (int i = index (c); i >= 0;
+          c = min_char + (i << shift[depth]) - 1, i--)
+       if (contents[i] != value)
+         return (IsSubCharTable (contents[i])
+                 ? ((MCharTable) contents[i]).PrevBoundary (c, value,
+                                                            out table)
+                 : c);
+      return (depth == 0
+             ? c : parent.PrevBoundary (c, value, out table));
     }
 
     // for IEnumerable interface
-    public IEnumerator GetEnumerator()
+    public IEnumerator<MCharRange> GetEnumerator()
     {
       return new MCharTableEnum (this);
     }
 
-    private class MCharTableEnum : IEnumerator
+    IEnumerator IEnumerable.GetEnumerator()
+    {
+      return GetEnumerator ();
+    }
+
+    private class MCharTableEnum : IEnumerator<MCharRange>
     {
-      private MCharTable table;
-      private MCharTableIT it;
+      MCharTable table;
+      private MCharRange range;
 
       public MCharTableEnum (MCharTable table)
        {
          this.table = table;
-         it = new MCharTableIT (-1, null, table);
        }
 
+      public void Dispose () {}
+
       public bool MoveNext ()
       {
-       it.c++;
-       return it.table.Next (it);
+       if (range == null)
+         {
+           range = new MCharRange (0, table);
+           return true;
+         }
+       return range.Next ();
       }
 
       public void Reset ()
       {
-       it.c = -1;
-       it.table = table;
+       range = null;
+      }
+
+      public MCharRange Current
+      {
+       get { return range; }
       }
 
-      public KeyValuePair<int, object> Current
+      object IEnumerator.Current
       {
-        get { return new KeyValuePair<int, object> (it.c, it.value); }
+       get { return Current; }
       }
     }
   }
diff --git a/chartab.cs b/chartab.cs
new file mode 100644 (file)
index 0000000..78e2a29
--- /dev/null
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using M17N;
+using M17N.Core;
+
+public class Test
+{
+  public static void Main()
+  {
+    MCharTable tbl = new MCharTable ();
+
+    tbl[0x100] = MSymbol.Of ("test-100");
+    tbl[0x101] = MSymbol.Of ("test-101");
+    tbl[0xFFF] = MSymbol.Of ("test-FFF");
+    tbl[0x1000] = MSymbol.Of ("test-1000");
+
+    tbl[0x2070, 0x4001] = MSymbol.t;
+
+    Console.WriteLine ("# Direct access by tbl[CHAR]");
+    Console.WriteLine ("0x100:{0}, 0x1000:{1}", tbl[0x100], tbl[0x1000]);
+    Console.WriteLine ("0x206F:{0}, 0x2070:{1}, 0x4001:{2}, 0x4002:{3}",
+                      tbl[0x206F], tbl[0x2070], tbl[0x4001], tbl[0x4002]);
+
+    Console.WriteLine ("# Enumerate on tbl");
+    foreach (MCharRange range in tbl)
+      Console.WriteLine (range);
+
+    Console.WriteLine ("# Using CharRange from U+3000 to U+0");
+    MCharRange r = new MCharRange (0x3000, tbl);
+    do {
+      Console.WriteLine (r);
+    } while (r.Prev ());
+  }
+}