using System;
using System.Collections;
using System.Collections.Generic;
+using System.IO;
using M17N;
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 ((from == to)
+ ? String.Format ("[U+{0:X} {1}]", from,
+ value == null ? "null" : value)
+ : 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;
{
parent = null;
depth = 0;
- min_char = 0x110000;
- max_char = 0;
+ min_char = 0;
+ max_char = 0x10FFFF;
contents = new object[slots[0]];
}
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);
}
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 {
+ MCharRange.CheckChar (from);
- public MCharTableIT (int c, object value, MCharTable table)
- {
- this.c = c;
- this.value = value;
- this.table = table;
+ if (from == to)
+ Set (from, value);
+ else
+ {
+ MCharRange.CheckChar (to);
+ set_range (from, to, value);
+ }
}
+ }
- public override string ToString ()
- {
- return (String.Format ("<{0:X},{1}>", c, value));
- }
+ private void set_range (int from, int to, object value)
+ {
+ if (to > max_char)
+ to = max_char;
+ int i0 = index (from), i1 = index (to);
+
+ 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()
{
- private MCharTable table;
- private MCharTableIT it;
+ return GetEnumerator ();
+ }
- public MCharTableEnum (MCharTable table)
- {
- this.table = table;
- it = new MCharTableIT (-1, null, table);
- }
+ private class MCharTableEnum : IEnumerator<MCharRange>
+ {
+ MCharTable table;
+ private MCharRange range;
+
+ public MCharTableEnum (MCharTable table) {
+ this.table = table;
+ }
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 ()
+ public void Reset () { range = null; }
+
+ public MCharRange Current { get { return range; } }
+
+ object IEnumerator.Current { get { return Current; } }
+
+ public void Dispose () {}
+ }
+ }
+
+ public class MCharProp : MCharTable
+ {
+ private static Dictionary<MSymbol, MDatabase> char_prop
+ = new Dictionary<MSymbol, MDatabase> ();
+
+ public static void Define (MSymbol prop, MDatabase mdb)
{
- it.c = -1;
- it.table = table;
+ char_prop[prop] = mdb;
}
- public KeyValuePair<int, object> Current
+ public MCharProp (MSymbol prop)
{
- get { return new KeyValuePair<int, object> (it.c, it.value); }
+ MDatabase mdb;
+
+ if (! char_prop.TryGetValue (prop, out mdb))
+ throw new Exception ("Undefined character property: " + prop);
+ mdb.Load (this);
}
+ }
+
+ public partial class MDatabase : IComparable<MDatabase>
+ {
+ private bool read_range (MStreamReader mst, out int from, out int to)
+ {
+ if (! mst.ReadInteger (out from))
+ {
+ to = from;
+ return false;
+ }
+ to = mst.Read ();
+ if (to < 0)
+ return false;
+ if (to != '-')
+ {
+ to = from;
+ return true;
+ }
+ return mst.ReadInteger (out to);
+ }
+
+ private void load_char_table (MCharTable table)
+ {
+ MSymbol type = tag[1];
+
+ using (FileStream stream = FileInfo.OpenRead ())
+ {
+ MStreamReader mst = new MStreamReader (stream, ';', true);
+ int c, from, to;
+
+ while ((c = mst.Peek ()) >= 0)
+ {
+ if (c != '#'
+ && read_range (mst, out from, out to)
+ && mst.SkipSpace (out c))
+ {
+ object value = null;
+
+ if (type == MSymbol.integer)
+ {
+ int i;
+ if (mst.ReadInteger (out i))
+ value = i;
+ }
+ else if (type == MSymbol.symbol)
+ {
+ MSymbol sym;
+ if (mst.ReadSymbol (out sym, -1))
+ value = sym;
+ }
+ else if (type == MSymbol.mtext)
+ {
+ MText mt;
+ if (mst.ReadMText (out mt))
+ value = mt;
+ }
+ else if (type == MSymbol.plist)
+ {
+ value = new MPlist (mst);
+ }
+ else if (type == MSymbol.mstring)
+ {
+ string str;
+ if (mst.ReadString (out str))
+ value = str;
+ }
+ if (value != null)
+ table[from, to] = value;
+ }
+ mst.ForwardLine ();
+ }
+ }
+ }
+
+ public void Load (MCharTable table)
+ {
+ if (loader != null || Info.Format != Mchar_table)
+ throw new ArgumentException ("Not a database of CharTable type");
+ if (! update_status ())
+ throw new Exception ("Database invalid");
+ load_char_table (table);
}
}
}