using System;
using System.Text;
+using System.Collections;
+using System.Collections.Generic;
using M17N.Core;
namespace M17N.Core
}
#endif
+ public class MTextProperty
+ {
+ internal MProperty prop;
+ internal bool front_sticky;
+ internal bool rear_sticky;
+ internal bool merginable;
+ public MProperty Prop { get { return prop; } }
+ public bool FrontSticky { get { return front_sticky; } }
+ public bool RearSticky { get { return rear_sticky; } }
+ public bool Merginable { get { return merginable; } }
+
+ public MTextProperty (bool front_sticky, bool rear_sticky)
+ {
+ this.front_sticky = front_sticky;
+ this.rear_sticky = rear_sticky;
+ }
+ public MTextProperty (bool front_sticky, bool rear_sticky, bool merginable)
+ {
+ this.front_sticky = front_sticky;
+ this.rear_sticky = rear_sticky;
+ this.merginable = merginable;
+ }
+ }
+
public class MText
{
#if false
public enum MTextFormat format;
#endif
- private class MTextPlist : MPlist
- {
- public class MInterval
- {
- MPlist stack;
- int nprops;
- public int start, end;
- public MInterval prev, next;
- }
-
- MInterval head, tail;
-
- public MTextPlist (MText mt)
- {
- head = tail = new MInterval ();
- head.start = 0;
- head.end = mt.sb.Length;
- }
- }
-
private StringBuilder sb;
private int nchars;
private int cache_pos;
private int cache_idx;
- private MTextPlist plist;
+ private MInterval root_interval;
private bool unmodifiable;
private static UTF8Encoding utf8 = new UTF8Encoding ();
return (new MText (sb.ToString ()));
}
- public MText ins (int pos, ref MText mt)
+ public MText ins (int pos, MText mt)
{
insert (pos, mt, 0, mt.nchars);
return this;
}
- public MText ins (int pos, ref MText mt, int from, int to)
+ public MText ins (int pos, MText mt, int from, int to)
{
insert (pos, mt, from, to);
return this;
nchars -= to - from;
return this;
}
- }
- public class MTextProperty
- {
+ private class MInterval
+ {
+ // Start and end positions of the MText covered of this interval
+ // and its children. The values are actually (4N +- 1), where N
+ // is a non-negative integer representing a position relative to
+ // the parent interval.
+ private int total_start, total_end;
+ // Stack of MTextProperty
+ private Stack<MTextProperty> stack;
+ // Number of child nodes
+ private int nodes;
+ private MInterval left, right, parent;
+
+ private int Start {
+ get {
+ return (left == null ? total_start : total_start + left.total_end);
+ }
+ }
+
+ private int End {
+ get {
+ return (right == null ? total_end : total_start + right.total_start);
+ }
+ }
+
+ private MInterval Left {
+ get {
+ MInterval interval;
+
+ if (left != null)
+ {
+ for (interval = left; interval.right != null;
+ interval = interval.right);
+ }
+ else
+ {
+ for (interval = parent;
+ interval != null && interval.total_start == total_start;
+ interval = interval.parent);
+ }
+ return interval;
+ }
+ }
+
+ private MInterval Right {
+ get {
+ MInterval interval;
+
+ if (right != null)
+ {
+ for (interval = right; interval.left != null;
+ interval = interval.left);
+ }
+ else
+ {
+ for (interval = parent;
+ interval != null && interval.total_end == total_end;
+ interval = interval.parent);
+ }
+ return interval;
+ }
+ }
+
+ private static int MakePosition (int pos, bool front_inclusive)
+ {
+ return (pos << 2) + (front_inclusive ? -1 : 1);
+ }
+
+ private MInterval (int start, int end)
+ {
+ if (start > end)
+ throw new Exception ("Invalid Interval Range");
+ this.total_start = (start << 2) + 1;
+ this.total_end = (end << 2) + -1;
+ this.stack = new Stack<MTextProperty> ();
+ this.nodes = 1;
+ }
+
+ public MInterval (int start, bool front_inclusive,
+ int end, bool rear_inclusive)
+ {
+ if (start > end)
+ throw new Exception ("Invalid Interval Range");
+ this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
+ this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
+ this.stack = new Stack<MTextProperty> ();
+ this.nodes = 1;
+ }
+
+ public void Push (MTextProperty prop, int start, int end)
+ {
+ start <<= 2;
+ if (prop.FrontSticky)
+ start--;
+ else
+ start++;
+ end <<= 2;
+ if (prop.RearSticky)
+ end++;
+ else
+ end--;
+ if (start >= end)
+ throw new Exception ("Invalid Text Property Range");
+
+ push (prop, start, end);
+ }
+
+ private MInterval divide_right (int pos)
+ {
+ MInterval interval = new MInterval (pos, End);
+
+ return interval;
+ }
+
+ private MInterval divide_left (int pos)
+ {
+ MInterval interval = new MInterval (Start, pos);
+
+ return interval;
+ }
+
+ private void push (MTextProperty prop, int start, int end)
+ {
+ int this_start = Start;
+ int this_end = End;
+
+ if (start < this_start)
+ {
+ if (end <= this_start)
+ Left.push (prop, start, end);
+ else
+ {
+ Left.push (prop, start, this_start);
+ if (end < this_end)
+ {
+ divide_right (end);
+ stack.Push (prop);
+ }
+ else
+ {
+ stack.Push (prop);
+ if (this_end < end)
+ Right.Push (prop, this_end, end);
+ }
+ }
+ }
+ else if (start < this_end)
+ {
+ divide_right (start).Push (prop, start, end);
+ }
+ else
+ Right.Push (prop, start, end);
+ }
+ }
}
}