2 using System.Collections;
3 using System.Collections.Generic;
10 public class MCharRange
14 internal object value;
15 internal MCharTable from_table;
16 internal MCharTable to_table;
18 public int From { get { return from; } }
19 public int To { get { return to; } }
20 public object Value { get { return value; } }
22 internal static void CheckChar (int c)
24 if (c < 0 || c > 0x10FFFF)
25 throw new ArgumentException ("Invalid Unicode character: " + c);
28 public MCharRange (int c, MCharTable table)
31 value = table.Get (c, out table);
38 from = table.PrevBoundary (c - 1, value, out from_table) + 1;
45 to = table.NextBoundary (c + 1, value, out to_table) - 1;
53 value = from_table.Get (to, out to_table);
57 from_table = to_table;
60 from = to_table.PrevBoundary (to - 1, value, out from_table) + 1;
69 value = to_table.Get (from, out from_table);
73 to_table = from_table;
76 to = from_table.NextBoundary (from + 1, value, out to_table) - 1;
80 public override string ToString ()
83 ? String.Format ("[U+{0:X} {1}]", from,
84 value == null ? "null" : value)
85 : String.Format ("[U+{0:X}..U+{1:X} {2}]", from, to,
86 value == null ? "null" : value));
90 public class MCharTable : IEnumerable<MCharRange>
92 private static readonly int[] nchars
93 = new int[] { 0x110000, 0x10000, 0x1000, 0x80 };
94 private static readonly int[] slots
95 = new int[] { 17, 16, 32, 128 };
96 private static readonly int[] shift
97 = new int[] { 16, 12, 7, 0 };
99 private static bool IsSubCharTable (object obj)
101 return (obj is MCharTable
102 && ((MCharTable) obj).depth > 0);
105 private int index (int c) { return ((c - min_char) >> shift[depth]); }
107 private MCharTable parent;
109 private int min_char, max_char;
110 private object[] contents;
118 contents = new object[slots[0]];
121 private MCharTable (MCharTable parent, int min_char, object value)
123 this.parent = parent;
124 this.min_char = min_char;
125 depth = parent.depth + 1;
126 max_char = min_char + nchars[depth] - 1;
127 contents = new object[slots[depth]];
128 for (int i = 0; i < slots[depth]; i++)
132 private object Get (int c)
134 object slot = contents[index (c)];
135 if (IsSubCharTable (slot))
136 return ((MCharTable) slot).Get (c);
140 internal object Get (int c, out MCharTable table)
142 if (c < min_char || c > max_char)
143 return parent.Get (c, out table);
144 object slot = contents[index (c)];
145 if (IsSubCharTable (slot))
146 return ((MCharTable) slot).Get (c, out table);
151 private void Set (int c, object value)
159 if (! IsSubCharTable (contents[i]))
160 contents[i] = new MCharTable (this, min_char + (i << shift[depth]),
162 ((MCharTable) contents[i]).Set (c, value);
166 public object this[int c]
169 MCharRange.CheckChar (c);
174 MCharRange.CheckChar (c);
179 public object this[int from, int to]
182 MCharRange.CheckChar (from);
188 MCharRange.CheckChar (to);
189 set_range (from, to, value);
194 private void set_range (int from, int to, object value)
198 int i0 = index (from), i1 = index (to);
202 for (; i0 <= i1; i0++)
203 contents[i0] = value;
207 int min0 = min_char + (i0 << shift[depth]);
208 int min1 = min_char + (i1 << shift[depth]);
212 if (contents[i0] != value)
214 if (! IsSubCharTable (contents[i0]))
215 contents[i0] = new MCharTable (this, min0, contents[i0]);
216 ((MCharTable) contents[i0]).set_range (from, to, value);
218 from = min0 + nchars[depth + 1];
223 for (; i0 < i1; i0++)
224 contents[i0] = value;
225 if (to == min1 + nchars[depth + 1] - 1)
226 contents[i1] = value;
227 else if (contents[i1] != value)
229 if (! IsSubCharTable (contents[i1]))
230 contents[i1] = new MCharTable (this, min1, contents[i1]);
231 ((MCharTable) contents[i1]).set_range (min1, to, value);
236 internal int NextBoundary (int c, object value, out MCharTable table)
239 for (int i = index (c); i < slots[depth];
240 i++, c = min_char + (i << shift[depth]))
241 if (contents[i] != value)
242 return (IsSubCharTable (contents[i])
243 ? ((MCharTable) contents[i]).NextBoundary (c, value,
247 ? c : parent.NextBoundary (c, value, out table));
250 internal int PrevBoundary (int c, object value, out MCharTable table)
253 for (int i = index (c); i >= 0;
254 c = min_char + (i << shift[depth]) - 1, i--)
255 if (contents[i] != value)
256 return (IsSubCharTable (contents[i])
257 ? ((MCharTable) contents[i]).PrevBoundary (c, value,
261 ? c : parent.PrevBoundary (c, value, out table));
264 // for IEnumerable interface
265 public IEnumerator<MCharRange> GetEnumerator()
267 return new MCharTableEnum (this);
270 IEnumerator IEnumerable.GetEnumerator()
272 return GetEnumerator ();
275 private class MCharTableEnum : IEnumerator<MCharRange>
278 private MCharRange range;
280 public MCharTableEnum (MCharTable table) {
284 public bool MoveNext ()
288 range = new MCharRange (0, table);
291 return range.Next ();
294 public void Reset () { range = null; }
296 public MCharRange Current { get { return range; } }
298 object IEnumerator.Current { get { return Current; } }
300 public void Dispose () {}
304 public class MCharProp : MCharTable
306 private static Dictionary<MSymbol, MDatabase> char_prop
307 = new Dictionary<MSymbol, MDatabase> ();
309 public static void Define (MSymbol prop, MDatabase mdb)
311 char_prop[prop] = mdb;
314 public MCharProp (MSymbol prop)
318 if (! char_prop.TryGetValue (prop, out mdb))
319 throw new Exception ("Undefined character property: " + prop);
324 public partial class MDatabase : IComparable<MDatabase>
326 private bool read_range (MStreamReader mst, out int from, out int to)
328 if (! mst.ReadInteger (out from))
341 return mst.ReadInteger (out to);
344 private MCharTable load_char_table (MCharTable table)
346 MSymbol type = tag[1];
348 using (FileStream stream = FileInfo.OpenRead ())
350 MStreamReader mst = new MStreamReader (stream, ';', true);
353 while ((c = mst.Peek ()) >= 0)
356 && read_range (mst, out from, out to)
357 && mst.SkipSpace (out c))
361 if (type == MSymbol.integer)
364 if (mst.ReadInteger (out i))
367 else if (type == MSymbol.symbol)
370 if (mst.ReadSymbol (out sym, -1))
373 else if (type == MSymbol.mtext)
376 if (mst.ReadMText (out mt))
379 else if (type == MSymbol.plist)
381 value = new MPlist (mst);
383 else if (type == MSymbol.mstring)
386 if (mst.ReadString (out str))
390 table[from, to] = value;
398 public object Load (MCharTable table)
400 if (loader != null || Info.Format != Mchar_table)
401 throw new ArgumentException ("Not a database of CharTable type");
402 if (! update_status ())
403 throw new Exception ("Database invalid");
404 return load_char_table (table);