namespace M17N.Core
{
+ public struct MProperty
+ {
+ internal MSymbol key;
+ internal object val;
+
+ public MSymbol Key { get { return this.key;} }
+ public object Val { get { return this.val; } }
+
+ public MProperty (MSymbol key, object val)
+ {
+ this.key = key;
+ this.val = val;
+ }
+ }
+
public class MPlist
{
- private MSymbol key;
- private object val;
+ private MProperty prop;
private MPlist next;
public MPlist ()
{
- key = null;
- val = null;
- next = null;
+ prop = new MProperty (MSymbol.nil, null);
}
- public bool tailp { get { return (object) key == null; } }
+ public bool tailp { get { return prop.key == MSymbol.nil; } }
public new string ToString ()
{
for (MPlist p = this; ! p.tailp; p = p.next)
{
- str += (p == this ? "(" : " ") + p.key.ToString () + ":";
- if (p.val is MSymbol)
- str += ((MSymbol) p.val).ToString ();
- else if (p.val is MPlist)
- str += ((MPlist) p.val).ToString ();
+ str += (p == this ? "(" : " ") + p.prop.key.ToString () + ":";
+ if (p.prop.val is MSymbol)
+ str += ((MSymbol) p.prop.val).ToString ();
+ else if (p.prop.val is MPlist)
+ str += ((MPlist) p.prop.val).ToString ();
}
return str + ")";
}
if ((object) key == null)
return null;
for (MPlist p = this; ! p.tailp; p = p.next)
- if (p.key == key)
- return p.val;
+ if (p.prop.key == key)
+ return p.prop.val;
return null;
}
MPlist p;
for (p = this; ! p.tailp; p = p.next)
- if (p.key == key)
+ if (p.prop.key == key)
{
if (val != null)
- p.val = val;
+ p.prop.val = val;
else
p.pop ();
return val;
}
if (val != null)
{
- p.key = key;
- p.val = val;
+ p.prop.key = key;
+ p.prop.val = val;
p.next = new MPlist ();
}
return val;
{
MPlist p = new MPlist ();
- p.key = this.key;
- p.val = this.val;
+ p.prop.key = this.prop.key;
+ p.prop.val = this.prop.val;
p.next = this.next;
- this.key = key;
- this.val = val;
+ this.prop.key = key;
+ this.prop.val = val;
this.next = p;
return val;
if (tailp)
return null;
- object val = this.val;
+ object val = this.prop.val;
- this.key = this.next.key;
- this.val = this.next.val;
+ this.prop.key = this.next.prop.key;
+ this.prop.val = this.next.prop.val;
this.next = this.next.next;
return val;
}
for (p = this; ! p.tailp; p = p.next);
if (val != null)
{
- p.key = key;
- p.val = val;
+ p.prop.key = key;
+ p.prop.val = val;
p.next = new MPlist ();
}
return val;
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);
+ }
+ }
}
}