int to_idx = pos_to_idx (mt2, to);
sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
-#if false
+ nchars += to - from;
if (root_interval != null)
{
- MInterval interval;
-
- if (mt2.root_interval != null)
- interval = mt2.root_interval.Copy (from, to);
+ MInterval interval = (mt2.root_interval == null
+ ? new MInterval (0, false, to - from, false)
+ : mt2.root_interval.CopyTree (from, to));
root_interval.Insert (pos, interval);
}
-#endif
- nchars += to - from;
}
public int this[int i]
public void PushProp (int from, int to, MTextProperty prop)
{
if (root_interval == null)
- root_interval = new MInterval (0, true, sb.Length, true);
+ root_interval = new MInterval (this);
root_interval.Push (from, to, prop);
}
private class MInterval
{
+ // position: 0 1 2 3
+ // index: -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+ // | | A | | B | | C | |
+ // interval |<--------->|<--->|<--------------->|<------
+ //
+ // [-1 99 (9 89)]
+ // [0 10 (-1 9)] [-10 0 (89 99)]
+ // [0 4 (-1 3)] [-4 0 (5 9)] [0 4 (89 93)] [-2 0 (97 99)]
+ //
// Start and end positions of this interval and its children.
// If this is the left node, the values are relative to the
// parent's total_start. Otherwise, the values are relatie to
private int total_start, total_end;
// Stack of MTextProperty
private Stack<MTextProperty> stack;
- private int depth;
private MInterval left, right, parent;
+ private MText mt;
private static int adjust_position (int pos, bool front_inclusive)
{
return (pos << 2) + (front_inclusive ? -1 : 1);
}
+ private static bool before_point_p (int pos)
+ {
+ return ((pos + 1) % 4) == 0;
+ }
+
public MInterval (int start, bool front_inclusive,
int end, bool rear_inclusive)
{
this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
this.stack = new Stack<MTextProperty> ();
- this.depth = 1;
}
+ public MInterval (MText mt)
+ {
+ this.mt = mt;
+ this.total_start = -1;
+ this.total_end = (mt.sb.Length << 2) + 1;
+ this.stack = new Stack<MTextProperty> ();
+ }
+
+ private MInterval () { }
+
private MInterval (int start, int end, Stack<MTextProperty> stack)
{
this.total_start = start;
this.total_end = end;
this.stack = new Stack<MTextProperty> (stack);
- this.depth = 1;
}
- private MInterval find (int pos)
+ private MInterval find (int pos, out int offset)
{
if (pos < total_start || total_end < pos)
- return null;
+ {
+ offset = 0;
+ return null;
+ }
if (pos < Start)
- return left.find (pos);
+ return left.find (pos, out offset);
if (End < pos)
- return right.find (pos);
+ return right.find (pos - total_end, out offset);
+ offset = pos - Start;
return this;
}
- public MInterval Copy (int start, int end)
+ // p-. or .-p p-. or .-p
+ // .-this-. .-right-.
+ // left .-right-. -> .-this-. c2
+ // c1 c2 left c1
+ private MInterval promote_right ()
+ {
+ int right_length = - right.total_start;
+ MInterval c1;
+
+ if (parent == null)
+ mt.root_interval = right;
+ else if (total_start == 0)
+ parent.left = right;
+ else
+ parent.right = right;
+ right.parent = parent;
+ c1 = right.left;
+ right.left = this;
+
+ parent = right;
+ right = c1;
+ if (c1 != null)
+ c1.parent = this;
+
+ parent.total_start = total_start;
+ parent.total_end = total_end;
+ total_start = 0;
+ total_end -= right_length - (c1 == null ? 0 : c1.total_end);
+
+ if (c1 != null)
+ {
+ c1.total_end = - c1.total_start;
+ c1.total_start = 0;
+ }
+ return parent;
+ }
+
+ // p-. or .-p p-. or .-p
+ // .-this-. .-left-.
+ // .-left-. .-right-. -> c1 .-this-.
+ // c1 c2 c2 right
+ private MInterval promote_left ()
+ {
+ int left_length = left.total_end;
+ MInterval c2;
+
+ if (parent == null)
+ mt.root_interval = left;
+ else if (total_start == 0)
+ parent.left = left;
+ else
+ parent.right = left;
+ left.parent = parent;
+ c2 = left.right;
+ left.right = this;
+
+ parent = left;
+ left = c2;
+ if (c2 != null)
+ c2.parent = this;
+
+ parent.total_start = total_start;
+ parent.total_end = total_end;
+ total_start -= left_length + (c2 == null ? 0 : c2.total_end);;
+ total_end = 0;
+
+ if (c2 != null)
+ {
+ c2.total_start = - c2.total_end;
+ c2.total_end = 0;
+ }
+ return parent;
+ }
+
+ private MInterval balance ()
{
- MInterval interval_start = find (start);
- MInterval interval_end = find (end);
- MInterval interval;
+ MInterval interval = this;
- start = adjust_position (start, true);
- end = adjust_position (end, true);
- interval = new MInterval (start, end, stack);
+ while (true)
+ {
+ int this_start = interval.Start;
+ int this_end = interval.End;
+ int diff = ((this_start - interval.total_start)
+ - (interval.total_end - this_end));
+ int abs = Math.Abs (diff);
+
+ if (abs < this_end - this_start)
+ break;
+ if (diff < 0)
+ {
+ interval = interval.promote_right ();
+ interval.left.balance ();
+ }
+ else
+ {
+ interval = interval.promote_left ();
+ interval.right.balance ();
+ }
+ }
return interval;
}
- private MInterval Copy ()
+ public MInterval CopyTree (int start, int end)
+ {
+ MInterval interval_start, interval_end, interval;
+ int offset_start, offset_end;
+
+ start <<= 2;
+ end <<= 2;
+ interval_start = find (start, out offset_start);
+ interval_end = find (end, out offset_end);
+
+ interval = new MInterval ();
+ interval.total_start = 0;
+ interval.total_end = end - start;
+ interval.stack = new Stack<MTextProperty> (interval_start.stack);
+ interval = interval.divide_right (offset_start);
+ while (interval_start != interval_end)
+ {
+ interval_start = interval_start.Right;
+ interval = interval.divide_right (interval_start.End
+ - interval_start.Start);
+ }
+ return interval;
+ }
+
+ private MInterval CopyNode ()
{
return new MInterval (total_start, total_end, stack);
}
push (start, end, prop);
}
- public void Insert (int start, int end, MInterval interval)
+ public void Insert (int pos, MInterval interval)
{
+ if (pos < Start)
+ Left.Insert (pos - total_start, interval);
+ else if (pos > End)
+ Right.Insert (pos - total_end, interval);
+ else
+ {
+ // position: 0 1 2 3
+ // index: -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+ // this |<----------<-------------->->|
+ // |<--------->| |<>|
+ //
+ // interval |<->----->->|
+ //
+ // new |<----------<----->----->-->------------>->|
+ // |<--------->| |<---->-->------------>->|
+ // |<----------->->|
+ // |<>|
+ int len = interval.total_end - interval.total_start;
+ MInterval temp;
+
+ total_end += len;
+ for (temp = this; temp.parent != null;
+ temp = temp.parent)
+ temp.parent.total_end += len;
+ if (End - pos < interval.End)
+ {
+
+
+ }
+
+ temp = divide_right (Start + 2);
+ temp.left = interval;
+ right = interval;
+ }
+
+
}
private MInterval divide_right (int pos)
{
- MInterval interval = Copy ();
+ MInterval interval = CopyNode ();
int this_start = Start;
int this_end = End;
- if (left == null || (right != null && left.depth < right.depth))
+ if (left == null
+ || (right != null && left.total_end < - right.total_start))
{
interval.left = this;
interval.right = right;
else
parent.right = interval;
}
- interval.depth = depth;
- if (right == null)
- interval.depth++;
total_start = 0;
total_end = pos - this_start;
}
private MInterval divide_left (int pos)
{
- MInterval interval = Copy ();
+ MInterval interval = CopyNode ();
int this_start = Start;
int this_end = End;
- if (left == null || (right != null && left.depth < right.depth))
+ if (left == null
+ || (right != null && left.total_end < - right.total_start))
{
interval.total_start = 0;
interval.total_end = pos - this_start;
else
parent.right = interval;
}
- interval.depth = depth;
- if (left == null)
- interval.depth++;
total_start = pos - this_end;
total_end = 0;
}