3 using System.Collections;
4 using System.Collections.Generic;
11 public enum MTextFormat
13 MTEXT_FORMAT_US_ASCII,
15 MTEXT_FORMAT_UTF_16BE,
16 MTEXT_FORMAT_UTF_16LE,
17 MTEXT_FORMAT_UTF_32BE,
18 MTEXT_FORMAT_UTF_32LE,
22 public class MTextProperty
28 internal enum Flag : byte
37 public MSymbol Key { get { return key; } }
38 public object Val { get { return val; } }
39 public bool FrontSticky
41 get { return (flags & Flag.FrontSticky) != Flag.None; }
43 public bool RearSticky
45 get { return (flags & Flag.RearSticky) != Flag.None; }
49 get { return (flags & Flag.Sensitive) != Flag.None; }
52 public MTextProperty (MSymbol key, object val)
58 public MTextProperty (MSymbol key, object val,
59 bool front_sticky, bool rear_sticky, bool sensitive)
64 flags |= Flag.FrontSticky;
66 flags |= Flag.RearSticky;
68 flags |= Flag.Sensitive;
71 public override string ToString ()
73 return key.ToString () + ":" + val;
77 public class MText : IEnumerable, IEquatable<MText>, IComparable<MText>
80 public enum MTextFormat format;
82 private StringBuilder sb;
84 private int cache_pos;
85 private int cache_idx;
86 private MPlist intervals;
87 private MPlist default_property;
88 private bool read_only;
90 private static UTF8Encoding utf8 = new UTF8Encoding ();
92 private static int count_chars (String str)
94 int len = str.Length, n = 0;
96 for (int i = 0; i < len; i++, n++)
97 if (surrogate_high_p (str[i]))
102 private static int count_chars (StringBuilder str)
104 int len = str.Length, n = 0;
106 for (int i = 0; i < len; i++, n++)
107 if (surrogate_high_p (str[i]))
114 sb = new StringBuilder ();
115 intervals = new MPlist ();
118 public MText (byte[] str)
120 sb = new StringBuilder (utf8.GetString (str));
121 nchars = count_chars (sb);
122 intervals = new MPlist ();
125 public MText (String str)
127 sb = new StringBuilder (str);
128 nchars = count_chars (str);
129 intervals = new MPlist ();
132 public MText (StringBuilder str)
135 nchars = count_chars (str);
136 intervals = new MPlist ();
139 public static MText operator+ (MText mt1, MText mt2)
141 MText mt = new MText ();
143 mt.sb.Append (mt1.sb);
144 mt.sb.Append (mt2.sb);
145 mt.nchars = mt1.nchars + mt2.nchars;
150 public bool ReadOnly { get { return read_only; } }
151 public int Length { get { return nchars; } }
155 // for IEnumerable interface
156 public IEnumerator GetEnumerator() { return new MTextEnum (this); }
158 // for IEquatable interface
159 public bool Equals (MText other) { return this.sb.Equals (other.sb); }
161 // for IComparable interface
162 public int CompareTo (MText other)
164 return this.sb.ToString ().CompareTo (other.sb.ToString ());
167 public override String ToString () { return "\"" + sb.ToString () + "\""; }
169 private static bool surrogate_high_p (char c)
171 return (c >= 0xD800 && c < 0xDC00);
174 private static bool surrogate_low_p (char c)
176 return (c >= 0xDC00 && c < 0xE000);
179 private static int inc_idx (StringBuilder sb, int i)
181 return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
184 private static int dec_idx (StringBuilder sb, int i)
186 return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
189 private static int pos_to_idx (MText mt, int pos)
191 if (pos == mt.cache_pos)
197 if (pos < mt.cache_pos)
199 if (mt.cache_pos == mt.cache_idx)
201 if (pos < mt.cache_pos - pos)
208 p = mt.cache_pos; i = mt.cache_idx;
214 if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
215 return (mt.cache_idx + pos - mt.cache_pos);
216 if (pos - mt.cache_pos < mt.nchars - pos)
218 p = mt.cache_pos; i = mt.cache_idx;
223 p = mt.nchars; i = mt.sb.Length;
228 for (; p < pos; i = inc_idx (mt.sb, i), p++);
230 for (; p > pos; i = dec_idx (mt.sb, i), p--);
236 private void check_pos (int pos, bool tail_ok)
238 if (pos < 0 || (tail_ok ? pos > nchars : pos >= nchars))
239 throw new Exception ("Invalid MText position:" + pos);
242 private bool check_range (int from, int to, bool zero_ok)
244 if (from < 0 || (zero_ok ? from > to : from >= to)
246 throw new Exception ("Invalid MText range");
250 private void insert (int pos, MText mt2, int from, int to)
252 check_pos (pos, true);
256 int pos_idx = pos_to_idx (this, pos);
257 int from_idx = pos_to_idx (mt2, from);
258 int to_idx = pos_to_idx (mt2, to);
260 sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
263 foreach (MPlist plist in mt2.intervals)
264 if (intervals.Find (plist.Key) == null)
265 intervals.Push (plist.Key, new MInterval (plist.Key, this));
266 foreach (MPlist plist in intervals)
268 MPlist p = mt2.intervals.Find (plist.Key);
272 interval = new MInterval (plist.Key, this, to - from);
274 interval = ((MInterval) p.Val).Copy (from, to);
275 ((MInterval) plist.Val).Insert (pos, interval);
279 private void insert (int pos, int c)
281 check_pos (pos, true);
283 int pos_idx = pos_to_idx (this, pos);
288 sb.Insert (pos_idx, ch);
292 char high = (char) (0xD800 + ((c - 0x10000) >> 10));
293 char low = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
294 sb.Insert (pos_idx, low);
295 sb.Insert (pos_idx, high);
298 foreach (MPlist plist in intervals)
299 ((MInterval) plist.Val).Insert (pos,
300 new MInterval (plist.Key, this, 1));
303 public int this[int i]
306 i = pos_to_idx (this, i);
309 if (surrogate_high_p (sb[i]))
311 sb[i] = (char) value;
315 char high = (char) (0xD800 + ((value - 0x10000) >> 10));
316 char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
318 if (! surrogate_high_p (sb[i]))
325 i = pos_to_idx (this, i);
326 return (surrogate_high_p (sb[i])
327 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
334 MText mt = new MText (sb.ToString ());
336 foreach (MPlist p in intervals)
337 mt.intervals.Add (p.Key, ((MInterval) p.Val).Copy (0, Length));
341 public MText Ins (int pos, int c)
347 public MText Ins (int pos, MText mt)
349 insert (pos, mt, 0, mt.nchars);
353 public MText Ins (int pos, MText mt, int from, int to)
355 insert (pos, mt, from, to);
359 public MText Cat (int c)
365 public MText Del (int from, int to)
367 if (check_range (from, to, true))
370 sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
374 foreach (MPlist plist in intervals)
375 ((MInterval) plist.Val).Delete (from, to);
377 intervals = new MPlist ();
381 public object GetProp (int pos, MSymbol key)
383 check_pos (pos, false);
385 MInterval i = (MInterval) intervals.Get (key);
389 MTextProperty prop = i.Get (pos);
390 return (prop != null ? prop.Val : null);
393 public object GetProp (int pos, MSymbol key, out MTextProperty prop)
395 check_pos (pos, false);
397 MInterval i = (MInterval) intervals.Get (key);
399 return (prop = null);
401 return (prop != null ? prop.Val : null);
404 public object GetProp (int pos, MSymbol key, out MTextProperty[] array)
406 check_pos (pos, false);
408 MInterval i = (MInterval) intervals.Get (key);
410 return (array = null);
411 MTextProperty prop = i.Get (pos, out array);
412 return (prop != null ? prop.Val : null);
415 public void PushProp (int from, int to, MSymbol key, object val)
417 if (! check_range (from, to, true))
418 PushProp (from, to, new MTextProperty (key, val));
421 public void PushProp (int from, int to, MTextProperty prop)
425 if (default_property == null)
426 default_property = new MPlist ();
427 default_property.Push (prop.key, prop.val);
431 if (check_range (from, to, true))
434 MPlist p = intervals.Find (prop.key);
439 root = new MInterval (prop.key, this);
440 intervals.Push (prop.key, root);
443 root = (MInterval) p.Val;
445 root.Push (from, to, prop);
449 public void PopProp (int from, int to, MSymbol key)
453 if (default_property == null)
455 MPlist p = default_property.Find (key);
462 if (check_range (from, to, true))
465 MPlist p = intervals.Find (key);
469 MInterval root = (MInterval) p.Val;
471 root.MergeAfterChange (from, to);
476 public void DumpProp ()
479 foreach (MPlist p in intervals)
480 ((MInterval) p.Val).Dump (true);
481 Console.WriteLine (")");
484 public void DumpPropNested ()
486 foreach (MPlist p in intervals)
487 ((MInterval) p.Val).DumpNested (true);
490 private class MInterval
492 // position: 0 1 2 3 4 5 6 7
493 // | A | B | C | D | E F | G |
494 // interval |---|---|---|<->|-------|---|
495 // |---|<->|---| |<----->|---|
499 // [3 (1 2)] [3 (4 6)]
500 // [1 (0 1)] [2 (2 3)] [1 (6 7)]
502 private static int count = 0;
505 private int From, To;
507 private MPlist Stack;
508 private MInterval Left, Right, Parent;
511 public MInterval (MSymbol key, MText mt, int length)
514 throw new Exception ("Invalid interval length");
518 Stack = new MPlist ();
522 public MInterval (MSymbol key, MText mt)
526 Length = mt.sb.Length;
529 Stack = new MPlist ();
533 public MTextProperty Get (int pos)
535 MInterval i = find (pos);
537 return (i.Stack.IsEmpty ? null : (MTextProperty) i.Stack.Val);
540 public MTextProperty Get (int pos, out MTextProperty[] array)
542 MInterval i = find (pos);
549 array = new MTextProperty[i.Stack.Count];
553 for (idx = 0, p = i.Stack; ! p.IsEmpty; idx++, p = p.Next)
554 array[idx] = (MTextProperty) p.Val;
558 private MInterval (MSymbol key, MText mt, int length, MPlist stack)
565 Stack = stack.Clone ();
569 private void update_from_to ()
574 To = Length - RightLength;
576 else if (Parent.Left == this)
578 From = Parent.From - Length + LeftLength;
579 To = Parent.From - RightLength;
583 From = Parent.To + LeftLength;
584 To = Parent.To + Length - RightLength;
588 private int LeftLength
590 get { return (Left == null ? 0 : Left.Length); }
593 private int RightLength
595 get { return (Right == null ? 0 : Right.Length); }
598 private MInterval LeftMost
603 Left.update_from_to ();
604 return Left.LeftMost;
608 private MInterval RightMost
613 Right.update_from_to ();
614 return Right.RightMost;
618 private MInterval Prev {
623 for (i = Left; i.Right != null; i = i.Right)
627 MInterval child = this;
628 for (i = Parent; i != null && i.Left == child;
629 child = i, i = i.Parent)
636 private MInterval Next {
641 for (i = Right; i.Left != null; i = i.Left)
645 MInterval child = this;
646 for (i = Parent; i != null && i.Right == child;
647 child = i, i = i.Parent)
654 private MInterval find (int pos)
658 return Left.find (pos);
660 return Right.find (pos);
664 private bool mergeable (MInterval i)
668 for (p1 = Stack, p2 = i.Stack; ! p1.IsEmpty && ! p2.IsEmpty;
669 p1 = p1.Next, p2 = p2.Next)
670 if (p1.Val != p2.Val)
672 return (p1.IsEmpty && p2.IsEmpty);
675 // p-. or .-p p-. or .-p
676 // .-this-. .-right-.
677 // left .-right-. -> .-this-. c2
679 private MInterval promote_right ()
681 int right_length = Right.Length;
685 mtext.intervals.Put (Key, Right);
686 else if (Parent.Left == this)
689 Parent.Right = Right;
690 Right.Parent = Parent;
696 Parent.Length += Length;
697 Length -= right_length;
701 Parent.Length -= c1.Length;
707 // p-. or .-p p-. or .-p
709 // .-left-. .-right-. -> c1 .-this-.
711 private MInterval promote_left ()
713 int left_length = Left.Length;
717 mtext.intervals.Put (Key, Left);
718 else if (Parent.Left == this)
722 Left.Parent = Parent;
728 Parent.Length += Length;
729 Length -= left_length;
733 Parent.Length -= c1.Length;
739 private MInterval balance ()
746 // .-left-. .-right-.
748 int diff = i.LeftLength - i.RightLength;
753 new_diff = (i.Length - i.LeftLength
754 + i.Left.RightLength - i.Left.LeftLength);
755 if (Math.Abs (new_diff) >= diff)
757 i = i.promote_left ();
762 new_diff = (i.Length - i.RightLength
763 + i.Right.LeftLength - i.Right.RightLength);
764 if (Math.Abs (new_diff) >= diff)
766 i = i.promote_right ();
773 public MInterval Copy (int start, int end)
775 MInterval copy, left_copy = null, right_copy = null;
782 return Left.Copy (start, end);
783 left_copy = Left.Copy (start, From);
788 return Right.Copy (start, end);
789 right_copy = Right.Copy (To, end);
792 copy = new MInterval (Key, null, end - start, Stack);
793 remove_properties (MTextProperty.Flag.Sensitive);
794 if (left_copy != null)
796 copy.Left = left_copy;
797 left_copy.Parent = copy;
799 if (right_copy != null)
801 copy.Right = right_copy;
802 right_copy.Parent = copy;
810 private MInterval divide_right (int pos)
812 MInterval interval = new MInterval (Key, mtext, To - pos, Stack);
814 M17N.DebugPrint ("divide-right({0}) at ", pos); DumpOne (false, true);
818 interval.Right = Right;
819 Right.Parent = interval;
820 interval.Length += Right.Length;
822 interval.Parent = this;
830 private MInterval divide_left (int pos)
832 MInterval interval = new MInterval (Key, mtext, pos - From, Stack);
834 M17N.DebugPrint ("divide-left({0}) at ", pos); DumpOne (false, true);
838 interval.Left = Left;
839 Left.Parent = interval;
840 interval.Length += Left.Length;
842 interval.Parent = this;
847 private void remove_properties (MTextProperty.Flag flags)
849 for (MPlist p = Stack; ! p.IsEmpty;)
851 MTextProperty prop = (MTextProperty) p.Val;
853 if ((prop.flags & flags) == flags)
860 private void inherit_front_properties (MPlist plist)
862 for (MInterval i = LeftMost; i != null; i = i.Next)
866 for (MPlist p = plist; ! p.IsEmpty; p = p.Next)
868 MTextProperty prop = (MTextProperty) p.Val;
870 if ((prop.flags & MTextProperty.Flag.RearSticky)
871 == MTextProperty.Flag.RearSticky)
872 i.Stack.Add (prop.key, prop);
877 private void inherit_rear_properties (MPlist plist)
879 for (MInterval i = RightMost; i != null; i = i.Prev)
883 for (MPlist p = plist; ! p.IsEmpty; p = p.Next)
885 MTextProperty prop = (MTextProperty) p.Val;
887 if ((prop.flags & MTextProperty.Flag.FrontSticky)
888 == MTextProperty.Flag.FrontSticky)
889 i.Stack.Add (prop.key, prop);
894 private MInterval delete_node_forward ()
898 int len = Length - RightLength;
900 for (MInterval i = Parent; i != null; i = i.Parent)
902 if (Parent.Left == this)
905 Parent.Right = Right;
910 Right.Parent = Parent;
911 return Right.LeftMost;
916 private MInterval delete_node_backward ()
920 int len = Length - RightLength;
922 for (MInterval i = Parent; i != null; i = i.Parent)
924 if (Parent.Left == this)
932 Left.Parent = Parent;
933 return Left.RightMost;
938 private void set_mtext (MText mt)
944 Right.set_mtext (mt);
947 private MInterval graft (MInterval interval, bool forward, out int len)
954 i = interval.LeftMost;
959 len += i.Length - i.RightLength;
960 i = i.delete_node_forward ();
965 i = interval.RightMost;
970 len += i.Length - i.LeftLength;
971 i = i.delete_node_backward ();
977 for (MInterval prev = this, ii = this.Parent; ii != null;
978 prev = ii, ii = ii.Parent)
988 while (i.Parent != null) i = i.Parent;
992 public void Insert (int pos, MInterval interval)
995 M17N.DebugPrint ("insert({0}) at {1} in ", interval.Length, pos);
996 DumpOne (false, false);
998 interval.set_mtext (mtext);
1001 Prev.Insert (pos, interval);
1002 else if (pos == From)
1004 MInterval prev = Prev;
1010 prev.Insert (pos, interval);
1013 prev.remove_properties
1014 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
1015 interval.inherit_front_properties (prev.Stack);
1018 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
1019 interval.inherit_rear_properties (Stack);
1022 interval = graft (interval, false, out len);
1023 if (interval != null && prev != null)
1024 interval = prev.graft (interval, true, out len);
1025 if (interval != null)
1031 // .-this-. ==> .-this-.
1043 interval.Parent = i;
1044 for (; i != null; i = i.Parent)
1045 i.Length += interval.Length;
1050 remove_properties (MTextProperty.Flag.Sensitive);
1053 interval = graft (interval, true, out len);
1055 if (interval != null)
1056 interval = graft (interval, false, out len);
1057 if (interval != null)
1060 Right.Left = interval;
1061 interval.Parent = Right;
1062 for (MInterval i = Right; i != null; i = i.Parent)
1063 i.Length += interval.Length;
1068 MInterval next = Next;
1074 next.Insert (pos, interval);
1077 next.remove_properties
1078 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
1079 interval.inherit_rear_properties (next.Stack);
1082 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
1083 interval.inherit_front_properties (Stack);
1086 interval = graft (interval, true, out len);
1087 if (interval != null && next != null)
1088 interval = next.graft (interval, false, out len);
1089 if (interval != null)
1095 // .-this-. ==> .-this-.
1108 interval.Parent = i;
1109 for (; i != null; i = i.Parent)
1110 i.Length += interval.Length;
1114 Next.Insert (pos, interval);
1115 M17N.DebugPrint (" done\n");
1118 private void vacate_node (MInterval interval)
1120 vacate_node (interval, null);
1123 private void vacate_node (MInterval interval, MInterval stop)
1125 if (interval != null)
1126 M17N.DebugPrint ("vacate #{0} to #{1}\n", ID, interval.ID);
1128 M17N.DebugPrint ("vacate #{0} to null\n", ID);
1129 if (interval != null)
1130 interval.Parent = Parent;
1134 mtext.intervals.Put (Key, interval);
1138 if (this == Parent.Right)
1139 Parent.Right = interval;
1141 Parent.Left = interval;
1144 if (interval != null)
1145 diff -= interval.Length;
1146 for (MInterval i = Parent; i != stop; i = i.Parent)
1151 public void Delete (int start, int end)
1154 M17N.DebugPrint ("delete({0} {1}) from ", start, end); DumpOne (false, true);
1159 Left.Delete (start, end);
1162 Left.Delete (start, From);
1164 end -= From - start;
1171 Right.Delete (start, end);
1174 Right.Delete (To, end);
1177 if (start == From && end == To)
1189 for (i = Right; i.Left != null; i = i.Left)
1190 i.Length += Left.Length;
1191 i.Length += Left.Length;
1195 vacate_node (Right);
1200 int len = end - start;
1202 for (MInterval i = this; i != null; i = i.Parent)
1207 public void Push (int start, int end, MTextProperty prop)
1210 M17N.DebugPrint ("push({0} {1}) at ", start, end); DumpOne (false, true);
1215 Left.Push (start, end, prop);
1218 Left.Push (start, From, prop);
1225 Right.Push (start, end, prop);
1228 Right.Push (To, end, prop);
1233 divide_left (start);
1236 Stack.Push (prop.key, prop);
1239 private static void merge_nodes (MInterval head, MInterval tail)
1241 M17N.DebugPrint ("merging "); head.DumpOne (true, false);
1242 M17N.DebugPrint (" through "); tail.DumpOne (true, false);
1244 int from = head.From;
1248 for (root = head; root.To + root.RightLength < to;
1249 root = root.Parent);
1251 M17N.DebugPrint (" common root is "); root.DumpOne (false, true);
1253 if (from < root.From)
1255 MInterval prev = root.Prev;
1259 M17N.DebugPrint ("merging "); prev.DumpOne (false, true);
1260 prev.vacate_node (prev.Left, root);
1263 if (prev.Left != null)
1264 prev = prev.Left.RightMost;
1271 MInterval next = root.Next;
1275 M17N.DebugPrint ("merging "); next.DumpOne (false, true);
1276 next.vacate_node (next.Right, root);
1279 if (next.Right != null)
1280 next = next.Right.LeftMost;
1287 public void MergeAfterChange (int start, int end)
1292 Prev.MergeAfterChange (start, end);
1296 MInterval head = this, tail = this, i;
1298 if (start == From && start > 0)
1304 while (tail.To < end)
1307 if (! tail.mergeable (i))
1310 merge_nodes (head, tail);
1318 if (i == null || ! tail.mergeable (i))
1323 merge_nodes (head, tail);
1326 public void Pop (int start, int end)
1329 M17N.DebugPrint ("pop({0} {1}) at ", start, end); DumpOne (false, true);
1334 Left.Pop (start, end);
1337 Left.Pop (start, From);
1344 Right.Pop (start, end);
1347 Right.Pop (To, end);
1351 if (! Stack.IsEmpty)
1354 divide_left (start);
1361 private void DumpOne (bool with_prop, bool newline)
1363 DumpOne (with_prop, newline, false);
1366 private void DumpOne (bool with_prop, bool newline, bool force)
1368 if (force || M17N.debug)
1370 Console.Write ("#{0}({1} {2} {3}", ID, Length, From, To);
1372 foreach (MPlist p in Stack)
1373 Console.Write (" " + p.Val);
1374 Console.Write (")");
1376 Console.WriteLine ();
1378 throw new Exception ("Invalid interval length");
1382 public void Dump () { Dump (false); }
1384 public void Dump (bool force)
1386 if (force || M17N.debug)
1393 Console.Write (" ");
1394 DumpOne (true, false, force);
1401 get { return (Parent == null ? 0 : Parent.Depth + 1); }
1404 public void DumpNested (bool force)
1406 DumpNested ("", force);
1409 public void DumpNested (string indent, bool force)
1411 if (force || M17N.debug)
1413 int indent_type = (Parent == null ? 1
1414 : Parent.Left == this ? 0 : 2);
1419 if (indent_type <= 1)
1420 Left.DumpNested (indent + " ", force);
1422 Left.DumpNested (indent + "| ", force);
1424 if (indent_type == 0)
1425 Console.Write (indent + ".-");
1426 else if (indent_type == 2)
1427 Console.Write (indent + "`-");
1428 DumpOne (true, true, true);
1431 if (indent_type >= 1)
1432 Right.DumpNested (indent + " ", force);
1434 Right.DumpNested (indent + "| ", force);
1440 private class MTextEnum : IEnumerator
1443 private int pos = -1;
1445 public MTextEnum (MText mt)
1450 public bool MoveNext ()
1453 return (pos < mt.nchars);
1456 public void Reset ()
1461 public object Current
1464 //if (pos < 0 || pos >= mt.nchars)
1465 //throw new InvalidOperationException ();