3 using System.Collections;
4 using System.Collections.Generic;
10 public enum MTextFormat
12 MTEXT_FORMAT_US_ASCII,
14 MTEXT_FORMAT_UTF_16BE,
15 MTEXT_FORMAT_UTF_16LE,
16 MTEXT_FORMAT_UTF_32BE,
17 MTEXT_FORMAT_UTF_32LE,
21 public class MTextProperty
27 internal enum Flag : byte
36 public MSymbol Key { get { return key; } }
37 public object Val { get { return val; } }
38 public bool FrontSticky
40 get { return (flags & Flag.FrontSticky) != Flag.None; }
42 public bool RearSticky
44 get { return (flags & Flag.RearSticky) != Flag.None; }
48 get { return (flags & Flag.Sensitive) != Flag.None; }
51 public MTextProperty (MSymbol key, object val)
55 flags |= Flag.RearSticky;
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;
72 public class MText : IEnumerable, IEquatable<MText>, IComparable<MText>
75 public enum MTextFormat format;
77 private StringBuilder sb;
79 private int cache_pos;
80 private int cache_idx;
81 private MPlist intervals;
82 private MPlist default_property;
83 private bool read_only;
85 private static UTF8Encoding utf8 = new UTF8Encoding ();
87 private static int count_chars (String str)
89 int len = str.Length, n = 0;
91 for (int i = 0; i < len; i++, n++)
92 if (surrogate_high_p (str[i]))
97 private static int count_chars (StringBuilder str)
99 int len = str.Length, n = 0;
101 for (int i = 0; i < len; i++, n++)
102 if (surrogate_high_p (str[i]))
109 sb = new StringBuilder ();
110 intervals = new MPlist ();
113 public MText (byte[] str)
115 sb = new StringBuilder (utf8.GetString (str));
116 nchars = count_chars (sb);
117 intervals = new MPlist ();
120 public MText (String str)
122 sb = new StringBuilder (str);
123 nchars = count_chars (str);
124 intervals = new MPlist ();
127 public MText (StringBuilder str)
130 nchars = count_chars (str);
131 intervals = new MPlist ();
134 public static MText operator+ (MText mt1, MText mt2)
136 MText mt = new MText ();
138 mt.sb.Append (mt1.sb);
139 mt.sb.Append (mt2.sb);
140 mt.nchars = mt1.nchars + mt2.nchars;
145 public bool ReadOnly { get { return read_only; } }
146 public int Length { get { return nchars; } }
150 // for IEnumerable interface
151 public IEnumerator GetEnumerator() { return new MTextEnum (this); }
153 // for IEquatable interface
154 public bool Equals (MText other) { return this.sb.Equals (other.sb); }
156 // for IComparable interface
157 public int CompareTo (MText other)
159 return this.sb.ToString ().CompareTo (other.sb.ToString ());
162 public override String ToString () { return "\"" + sb.ToString () + "\""; }
164 private static bool surrogate_high_p (char c)
166 return (c >= 0xD800 && c < 0xDC00);
169 private static bool surrogate_low_p (char c)
171 return (c >= 0xDC00 && c < 0xE000);
174 private static int inc_idx (StringBuilder sb, int i)
176 return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
179 private static int dec_idx (StringBuilder sb, int i)
181 return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
184 private static int pos_to_idx (MText mt, int pos)
186 if (pos == mt.cache_pos)
192 if (pos < mt.cache_pos)
194 if (mt.cache_pos == mt.cache_idx)
196 if (pos < mt.cache_pos - pos)
203 p = mt.cache_pos; i = mt.cache_idx;
209 if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
210 return (mt.cache_idx + pos - mt.cache_pos);
211 if (pos - mt.cache_pos < mt.nchars - pos)
213 p = mt.cache_pos; i = mt.cache_idx;
218 p = mt.nchars; i = mt.sb.Length;
223 for (; p < pos; i = inc_idx (mt.sb, i), p++);
225 for (; p > pos; i = dec_idx (mt.sb, i), p--);
231 private void insert (int pos, MText mt2, int from, int to)
233 int pos_idx = pos_to_idx (this, pos);
234 int from_idx = pos_to_idx (mt2, from);
235 int to_idx = pos_to_idx (mt2, to);
237 sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
240 foreach (MPlist plist in mt2.intervals)
241 if (intervals.Find (plist.Key) == null)
242 intervals.Push (plist.Key, new MInterval (plist.Key, this));
243 foreach (MPlist plist in intervals)
245 MPlist p = mt2.intervals.Find (plist.Key);
249 interval = new MInterval (plist.Key, to - from);
251 interval = ((MInterval) p.Val).copy (from, to);
252 ((MInterval) plist.Val).insert (pos, interval);
256 public int this[int i]
259 i = pos_to_idx (this, i);
262 if (surrogate_high_p (sb[i]))
264 sb[i] = (char) value;
268 char high = (char) (0xD800 + ((value - 0x10000) >> 10));
269 char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
271 if (! surrogate_high_p (sb[i]))
278 i = pos_to_idx (this, i);
279 return (surrogate_high_p (sb[i])
280 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
287 return (new MText (sb.ToString ()));
290 public MText Ins (int pos, MText mt)
292 insert (pos, mt, 0, mt.nchars);
296 public MText Ins (int pos, MText mt, int from, int to)
298 insert (pos, mt, from, to);
302 public MText Del (int from, int to)
304 sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
307 foreach (MPlist plist in intervals)
308 ((MInterval) plist.Val).Delete (from, to);
312 public object GetProp (int pos, MSymbol key)
314 MInterval i = (MInterval) intervals.Find (key).Val;
319 MTextProperty prop = i.Get (pos);
320 return (prop != null ? prop.Val : null);
323 public object GetProp (int pos, MSymbol key, out MTextProperty prop)
325 MInterval i = (MInterval) intervals.Find (key).Val;
328 return (prop = null);
330 return (prop != null ? prop.Val : null);
333 public object GetProp (int pos, MSymbol key, out MTextProperty[] array)
335 MInterval i = (MInterval) intervals.Find (key).Val;
338 return (array = null);
339 MTextProperty prop = i.Get (pos, out array);
340 return (prop != null ? prop.Val : null);
343 public void PushProp (int from, int to, MSymbol key, object val)
345 PushProp (from, to, new MTextProperty (key, val));
348 public void PushProp (int from, int to, MTextProperty prop)
352 if (default_property == null)
353 default_property = new MPlist ();
354 default_property.Push (prop.key, prop.val);
358 MInterval root = (MInterval) intervals.Find (prop.key).Val;
362 root = new MInterval (prop.key, this);
363 intervals.Push (prop.key, root);
365 root.Push (from, to, prop);
369 public void DumpProp ()
371 foreach (MPlist p in intervals)
372 ((MInterval) p.Val).Dump ();
375 private class MInterval
377 // position: 0 1 2 3 4 5 6 7
378 // | A | B | C | D | E F | G |
379 // interval |---|---|---|<->|-------|---|
380 // |---|<->|---| |<----->|---|
384 // [3 (1 2)] [3 (4 6)]
385 // [1 (0 1)] [2 (2 3)] [1 (6 7)]
386 private int total_length;
387 private int from, to;
389 private MPlist stack;
390 private MInterval left, right, parent;
393 public MInterval (MSymbol key, int length)
396 throw new Exception ("Invalid interval length");
398 total_length = length;
399 stack = new MPlist ();
402 public MInterval (MSymbol key, MText mt)
406 total_length = mt.sb.Length;
409 stack = new MPlist ();
412 public MTextProperty Get (int pos)
414 MInterval i = find (pos);
416 return (i.stack.IsEmpty ? null : (MTextProperty) i.stack.Val);
419 public MTextProperty Get (int pos, out MTextProperty[] array)
421 MInterval i = find (pos);
428 array = new MTextProperty[i.stack.Count];
432 for (idx = 0, p = i.stack; ! p.IsEmpty; idx++, p = p.Next)
433 array[idx] = (MTextProperty) p.Val;
434 return array[idx - 1];
437 private MInterval (MSymbol key, int length, MPlist stack)
440 total_length = length;
443 this.stack = stack.Clone ();
446 private void update_from_to ()
450 from = parent.from - total_length + LeftLength;
451 to = parent.from - RightLength;
455 private int LeftLength
457 get { return (left == null ? 0 : left.total_length); }
460 private int RightLength
462 get { return (right == null ? 0 : right.total_length); }
465 private MInterval left_most_node
467 get { return (left == null ? this : left.left_most_node); }
470 private MInterval right_most_node
472 get { return (right == null ? this : right.right_most_node); }
475 private MInterval prev {
480 for (i = left; i.right != null; i = i.right);
482 for (i = parent; i != null && i.left == null; i = i.parent);
487 private MInterval next {
492 for (i = right; i.left != null; i = i.left);
494 for (i = parent; i != null && i.right == null; i = i.parent);
499 private MInterval find (int pos)
503 return left.find (pos);
505 return right.find (pos);
509 // p-. or .-p p-. or .-p
510 // .-this-. .-right-.
511 // left .-right-. -> .-this-. c2
513 private MInterval promote_right ()
515 int right_length = right.total_length;
519 mtext.intervals.Put (key, right);
520 else if (parent.left == this)
523 parent.right = right;
524 right.parent = parent;
530 parent.total_length += total_length;
531 total_length -= right_length;
535 parent.total_length -= c1.total_length;
536 total_length += c1.total_length;
541 // p-. or .-p p-. or .-p
543 // .-left-. .-right-. -> c1 .-this-.
545 private MInterval promote_left ()
547 int left_length = left.total_length;
551 mtext.intervals.Put (key, left);
552 else if (parent.left == this)
556 left.parent = parent;
562 parent.total_length += total_length;
563 total_length -= left_length;
567 parent.total_length -= c1.total_length;
568 total_length += c1.total_length;
573 private MInterval balance ()
580 // .-left-. .-right-.
582 int diff = i.LeftLength - i.RightLength;
587 new_diff = (i.total_length - i.LeftLength
588 + i.left.RightLength - i.left.LeftLength);
589 if (Math.Abs (new_diff) >= diff)
591 i = i.promote_left ();
596 new_diff = (i.total_length - i.RightLength
597 + i.right.LeftLength - i.right.RightLength);
598 if (Math.Abs (new_diff) >= diff)
600 i = i.promote_right ();
607 public MInterval copy (int start, int end)
609 MInterval this_copy, left_copy = null, right_copy = null;
615 return left.copy (start, end);
616 left_copy = left.copy (start, from);
621 return right.copy (start, end);
622 right_copy = right.copy (to, end);
624 this_copy = new MInterval (key, end - start, stack);
625 this_copy.left = left_copy;
626 this_copy.right = right_copy;
634 private MInterval divide_right (int pos)
638 MInterval interval = new MInterval (key, to - pos, stack);
640 total_length -= to - pos;
644 right.parent = interval;
645 interval.total_length += right.total_length;
647 interval.parent = this;
655 private MInterval divide_left (int pos)
659 MInterval interval = new MInterval (key, to - pos, stack);
661 total_length -= to - pos;
665 left.parent = interval;
666 interval.total_length += left.total_length;
668 interval.parent = this;
673 private void remove_properties (MTextProperty.Flag flags)
675 for (MPlist p = stack; ! p.IsEmpty;)
677 MTextProperty prop = (MTextProperty) p.Val;
679 if ((prop.flags & flags) == flags)
686 private void merge_properties (MPlist plist, MTextProperty.Flag flags)
689 left.merge_properties (plist, flags);
691 right.merge_properties (plist, flags);
692 for (MPlist p = plist; ! p.IsEmpty; p = p.Next)
694 MTextProperty prop = (MTextProperty) p.Val;
696 if ((prop.flags & flags) == flags
697 && stack.Get (prop.Key) == null)
698 stack.Push (prop.key, prop);
702 public void insert (int pos, MInterval interval)
705 if (pos < from || (pos == from && left == null && pos > 0))
707 prev.insert (pos, interval);
710 if (pos > to || (pos == to && right == null && next != null))
712 next.insert (pos, interval);
715 if (pos > from && pos < to)
717 remove_properties (MTextProperty.Flag.Sensitive);
718 divide_right (pos).insert (pos, interval);
725 prev.remove_properties
726 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
727 interval.merge_properties
728 (prev.stack, MTextProperty.Flag.RearSticky);
731 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
732 interval.merge_properties
733 (stack, MTextProperty.Flag.FrontSticky);
735 // INTERVAL is ready to insert.
737 // .-this-. ==> .-this-.
744 MInterval i = left.right_most_node;
748 for (; i != null; i = i.parent)
749 i.total_length += interval.total_length;
755 for (MInterval i = this; i != null; i = i.parent)
756 i.total_length += interval.total_length;
763 MInterval left_most = right.left_most_node;
765 left_most.remove_properties
766 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
767 interval.merge_properties
768 (stack, MTextProperty.Flag.FrontSticky);
771 (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
772 interval.merge_properties
773 (stack, MTextProperty.Flag.RearSticky);
775 // INTERVAL is ready to insert.
777 // .-this-. ==> .-this-.
784 MInterval i = right.left_most_node;
788 for (; i != null; i = i.parent)
789 i.total_length += interval.total_length;
795 for (MInterval i = this; i != null; i = i.parent)
796 i.total_length += interval.total_length;
801 private void update_parent (MInterval i)
804 mtext.intervals.Put (key, i);
809 if (parent.right == i)
811 diff = parent.right.total_length - i.total_length;
816 diff = parent.left.total_length - i.total_length;
819 for (i = parent; i != null; i = i.parent)
820 i.total_length += diff;
824 public void Delete (int start, int end)
831 left.Delete (start, end);
834 left.Delete (start, from);
841 right.Delete (start, end);
844 right.Delete (to, end);
847 if (start == from && end == to)
850 update_parent (right);
851 else if (right == null)
852 update_parent (left);
857 for (i = right; i.left != null; i = i.left)
858 i.total_length += left.total_length;
859 i.total_length += left.total_length;
861 update_parent (right);
866 int len = end - start;
868 for (MInterval i = this; i != null; i = i.parent)
869 i.total_length -= len;
873 public MTextProperty Push (int start, int end, MTextProperty prop)
878 left.Push (start, end, prop);
885 right.Push (start, end, prop);
895 stack.Push (prop.key, prop);
896 Console.WriteLine ("push({0},{1})", from, to);
907 Console.WriteLine ("({0} {1})", from, to);
909 Console.WriteLine ("({0} {1} {2})", from, to, stack.Val);
915 private class MTextEnum : IEnumerator
918 private int pos = -1;
920 public MTextEnum (MText mt)
925 public bool MoveNext ()
928 return (pos < mt.nchars);
936 public object Current
939 //if (pos < 0 || pos >= mt.nchars)
940 //throw new InvalidOperationException ();