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 : IEnumerable
{
- private MProperty prop;
+ public MSymbol Key;
+ public object Val;
private MPlist next;
public MPlist ()
{
- prop = new MProperty (MSymbol.nil, null);
+ Key = MSymbol.nil;
+ Val = null;
}
- public bool tailp { get { return prop.key == MSymbol.nil; } }
+ private MPlist (MSymbol key, object val)
+ {
+ Key = key;
+ Val = val;
+ }
+
+ public bool IsEmpty { get { return next == null; } }
public new string ToString ()
{
string str = "";
- for (MPlist p = this; ! p.tailp; p = p.next)
+ for (MPlist p = this; ! p.IsEmpty; p = p.next)
{
- 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 ();
+ 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 ();
}
return str + ")";
}
+ public MPlist find (MSymbol key)
+ {
+ MPlist p;
+
+ for (p = this; ! p.IsEmpty; p = p.next)
+ if (p.Key == key)
+ break;
+ return p;
+ }
+
public object get (MSymbol key)
{
- if ((object) key == null)
- return null;
- for (MPlist p = this; ! p.tailp; p = p.next)
- if (p.prop.key == key)
- return p.prop.val;
- return null;
+ return find (key).Val;
}
- public object put (MSymbol key, object val)
+ public MPlist put (MSymbol key, object val)
{
- MPlist p;
+ MPlist p = find (key);
- for (p = this; ! p.tailp; p = p.next)
- if (p.prop.key == key)
- {
- if (val != null)
- p.prop.val = val;
- else
- p.pop ();
- return val;
- }
- if (val != null)
- {
- p.prop.key = key;
- p.prop.val = val;
- p.next = new MPlist ();
- }
- return val;
+ if (p.IsEmpty)
+ return p.push (key, val);
+ p.Val = val;
+ return p;
}
- public object push (MSymbol key, object val)
+ public MPlist push (MSymbol key, object val)
{
- MPlist p = new MPlist ();
+ MPlist p = new MPlist (Key, Val);
- p.prop.key = this.prop.key;
- p.prop.val = this.prop.val;
p.next = this.next;
- this.prop.key = key;
- this.prop.val = val;
- this.next = p;
-
- return val;
+ Key = key;
+ Val = val;
+ next = p;
+ return this;
}
public object pop ()
{
- if (tailp)
+ if (IsEmpty)
return null;
- object val = this.prop.val;
+ object val = Val;
- this.prop.key = this.next.prop.key;
- this.prop.val = this.next.prop.val;
- this.next = this.next.next;
+ Key = next.Key;
+ Val = next.Val;
+ next = next.next;
return val;
}
- public object add (MSymbol key, object val)
+ public MPlist add (MSymbol key, object val)
{
MPlist p;
- for (p = this; ! p.tailp; p = p.next);
- if (val != null)
- {
- p.prop.key = key;
- p.prop.val = val;
- p.next = new MPlist ();
- }
- return val;
- }
-
- public MPlist find (MSymbol key)
- {
- for (MPlist p = this; ! p.tailp; p = p.next)
- if (p.prop.key == key)
- return p;
- return null;
+ for (p = this; ! p.IsEmpty; p = p.next);
+ return p.push (key, val);
}
// Implement IEnumerable interface.
public object Current
{
get {
- if (current == null || current.tailp)
+ if (current == null || current.IsEmpty)
throw new InvalidOperationException ();
return current;
}
{
if (current == null)
current = plist;
- else if (current.tailp)
+ else if (current.IsEmpty)
return false;
else
current = current.next;
public class MTextProperty
{
- private MProperty prop;
+ internal MSymbol key;
+ internal object val;
private bool front_sticky;
private bool rear_sticky;
- private MText mtext;
- public MProperty Prop { get { return prop; } }
+ public MSymbol Key { get { return key; } }
+ public object Val { get { return val; } }
public bool FrontSticky { get { return front_sticky; } }
public bool RearSticky { get { return rear_sticky; } }
- public MText Mtext { get { return mtext; } }
- public MTextProperty (MProperty prop, bool front_sticky, bool rear_sticky)
+ public MTextProperty (MSymbol key, object val)
{
- this.prop = prop;
+ this.key = key;
+ this.val = val;
+ }
+
+ public MTextProperty (MSymbol key, object val,
+ bool front_sticky, bool rear_sticky)
+ {
+ this.key = key;
+ this.val = val;
this.front_sticky = front_sticky;
this.rear_sticky = rear_sticky;
}
private int cache_pos;
private int cache_idx;
private MPlist intervals;
- private MProperty default_property;
+ private MPlist default_property;
private bool read_only;
private static UTF8Encoding utf8 = new UTF8Encoding ();
public MText ()
{
sb = new StringBuilder ();
+ intervals = new MPlist ();
}
public MText (byte[] str)
{
sb = new StringBuilder (utf8.GetString (str));
nchars = count_chars (sb);
+ intervals = new MPlist ();
}
public MText (String str)
{
sb = new StringBuilder (str);
nchars = count_chars (str);
+ intervals = new MPlist ();
}
public MText (StringBuilder str)
{
sb = str;
nchars = count_chars (str);
+ intervals = new MPlist ();
}
public static MText operator+ (MText mt1, MText mt2)
sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
nchars += to - from;
- if (mt2.intervals != null
- && ! mt2.intervals.tailp)
+ foreach (MPlist plist in mt2.intervals)
+ if (intervals.find (plist.Key) == null)
+ intervals.push (plist.Key, new MInterval (plist.Key, this));
+ foreach (MPlist plist in intervals)
{
- if (intervals == null)
- intervals = new MPlist ();
- foreach (MInterval interval in mt2.intervals)
- if (intervals.find (interval.key) == null)
- intervals.push (interval.key, new MInterval (interval.key, mt));
- }
+ MPlist p = mt2.intervals.find (plist.Key);
+ MInterval interval;
- if (intervals != null)
- {
- foreach (MInterval root in intervals)
- {
- MInterval interval;
-
- if (mt2.intervals != null
- && ! mt2.intervals.tailp)
- {
- interval = mt2.intervals.find (root.key);
- if (interval != null)
- interval = interval.CopyTree (from, to);
- }
- if (interval == null)
- interval = new MInterval (root.key, to - from);
- root.Insert (pos, interval);
+ if (p.IsEmpty)
+ interval = new MInterval (plist.Key, to - from);
+ else
+ interval = ((MInterval) p.Val).copy (from, to);
+ ((MInterval) plist.Val).insert (pos, interval);
}
}
{
sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
nchars -= to - from;
+
+ foreach (MPlist plist in intervals)
+ ((MInterval) plist.Val).delete (from, to);
return this;
}
- public void PushProp (int from, int to, MTextProperty prop)
+ public object get_prop (int pos, MSymbol key)
{
- MInterval root;
+ MInterval i = (MInterval) intervals.find (key).Val;
+
+ if (i == null)
+ return null;
+
+ MTextProperty prop = i.get (pos);
+ return (prop != null ? prop.Val : null);
+ }
- if (intervals == null
- || (root = intervals.find (prop.key)) )
- intervals = new MPlist (prop.key, new MInterval (prop.key, this));
+ public object get_prop (int pos, MSymbol key, out MTextProperty prop)
+ {
+ MInterval i = (MInterval) intervals.find (key).Val;
+
+ if (i == null)
+ return (prop = null);
+ prop = i.get (pos);
+ return (prop != null ? prop.Val : null);
+ }
+
+ public object get_prop (int pos, MSymbol key, out MTextProperty[] array)
+ {
+ MInterval i = (MInterval) intervals.find (key).Val;
+
+ if (i == null)
+ return (array = null);
+ MTextProperty prop = i.get (pos, out array);
+ return (prop != null ? prop.Val : null);
+ }
+
+ public void push_prop (int from, int to, MSymbol key, object val)
+ {
+ push_prop (from, to, new MTextProperty (key, val));
+ }
+
+ public void push_prop (int from, int to, MTextProperty prop)
+ {
+ if (from < 0)
+ {
+ if (default_property == null)
+ default_property = new MPlist ();
+ default_property.push (prop.key, prop.val);
+ }
+ else
+ {
+ MInterval root = (MInterval) intervals.find (prop.key).Val;
- root_interval.Push (from, to, prop);
+ if (root == null)
+ {
+ root = new MInterval (prop.key, this);
+ intervals.push (prop.key, root);
+ }
+ root.Push (from, to, prop);
+ }
}
private class MInterval
{
- // position: 0 1 2 3
- // | A | B | C |
- // interval |<--------->|<--------->|<--------->|
+ // position: 0 1 2 3 4 5 6 7
+ // | A | B | C | D | E F | G |
+ // interval |---|---|---|<->|-------|---|
+ // |---|<->|---| |<----->|---|
+ // |<->| |<->| |<->|
//
- // [3 (1 2)]
- // [1 (0 1)] [1 (2 3)]
+ // [7 (3 4)]
+ // [3 (1 2)] [3 (4 6)]
+ // [1 (0 1)] [2 (2 3)] [1 (6 7)]
private int total_length;
private int from, to;
private MSymbol key;
stack = new Stack<MTextProperty> ();
}
- private MInterval (MSymbol key, int length, Stack<MTextProperty> stack)
+ public MInterval (MSymbol key, MText mt)
{
this.key = key;
- total_length = length;
+ mtext = mt;
+ total_length = mt.sb.Length;
from = 0;
to = total_length;
- stack = new Stack<MTextProperty> (stack);
+ stack = new Stack<MTextProperty> ();
}
- public MInterval (MSymbol key, MText mt)
+ public MTextProperty get (int pos)
+ {
+ MInterval i = find (pos);
+
+ return (i.stack.Count > 0 ? i.stack.Peek () : null);
+ }
+
+ public MTextProperty get (int pos, out MTextProperty[] array)
+ {
+ MInterval i = find (pos);
+
+ if (i.stack.Count == 0)
+ {
+ array = null;
+ return null;
+ }
+ array = i.stack.ToArray ();
+ return i.stack.Peek ();
+ }
+
+ private MInterval (MSymbol key, int length, Stack<MTextProperty> stack)
{
this.key = key;
- mtext = mt;
- total_length = mt.sb.Length;
+ total_length = length;
from = 0;
to = total_length;
- stack = new Stack<MTextProperty> ();
+ stack = new Stack<MTextProperty> (stack);
}
+
private void update_from_to ()
{
if (parent != null)
MInterval c1;
if (parent == null)
- mtext.root_intervals.put (key, right);
+ mtext.intervals.put (key, right);
else if (parent.left == this)
parent.left = right;
else
MInterval c1;
if (parent == null)
- mtext.update_root_interval (key, left);
+ mtext.intervals.put (key, left);
else if (parent.left == this)
parent.left = left;
else
private MInterval balance ()
{
- MInteval i = this;
+ MInterval i = this;
while (true)
{
i.left.balance ();
}
}
- return interval;
+ return i;
}
- public MInterval CopyTree (int start, int end)
+ public MInterval copy (int start, int end)
{
- MInterval this_copy, left_copy, right_copy;
+ MInterval this_copy, left_copy = null, right_copy = null;
update_from_to ();
if (start < from)
{
if (end <= from)
- return left.CopyTree (start, end);
- left_copy = left.CopyTree (start, from);
+ return left.copy (start, end);
+ left_copy = left.copy (start, from);
}
else if (end > to)
{
if (start >= to)
- return right.CopyTree (start, end);
- right_copy = right.CopyTree (to, end);
+ return right.copy (start, end);
+ right_copy = right.copy (to, end);
}
- this_copy = MInteval (key, end - start, stack);
+ this_copy = new MInterval (key, end - start, stack);
this_copy.left = left_copy;
this_copy.right = right_copy;
// right
private MInterval divide_right (int pos)
{
- MInterval interval;
-
update_from_to ();
- interval = new MInterval (key, to - pos, stack);
+
+ MInterval interval = new MInterval (key, to - pos, stack);
total_length -= to - pos;
if (right != null)
{
- right->parent = interval;
- interval.total_length += right->total_length;
+ right.parent = interval;
+ interval.total_length += right.total_length;
}
- interval->parent = this;
+ interval.parent = this;
right = interval;
return interval;
}
// left
private MInterval divide_left (int pos)
{
- MInterval interval = CopyNode ();
- int this_start = Start;
- int this_end = End;
+ update_from_to ();
- if (left == null
- || (right != null && left.total_end < - right.total_start))
- {
- interval.total_start = 0;
- interval.total_end = pos - this_start;
- if (left != null)
- left.parent = interval;
- left = interval;
- }
- else
+ MInterval interval = new MInterval (key, to - pos, stack);
+
+ total_length -= to - pos;
+ if (left != null)
{
- interval.right = this;
- interval.left = left;
- interval.parent = parent;
- if (parent != null)
- {
- if (total_start == 0)
- parent.left = interval;
- else
- parent.right = interval;
- }
- total_start = pos - this_end;
- total_end = 0;
+ left.parent = interval;
+ interval.total_length += left.total_length;
}
-
+ interval.parent = this;
+ left = interval;
return interval;
}
- public void Insert (int pos, MInterval interval)
+ public void insert (int pos, MInterval interval)
{
update_from_to ();
if (pos < from)
{
- LeftNode.Insert (pos, interval);
+ LeftNode.insert (pos, interval);
return;
}
if (pos >= to)
{
- RightNode.Insert (pos, interval);
+ RightNode.insert (pos, interval);
return;
}
if (pos > from)
{
- divide_right (pos).Insert (pos, interval);
+ divide_right (pos).insert (pos, interval);
return;
}
s.Push (p);
if (s.Count > 0)
{
- for (MInterval i = interval.LeftMost;
+ for (MInterval i = interval.LeftMostNode;
i != null && i.stack.Count == 0;
i = i.LeftNode)
foreach (MTextProperty p in s)
// child interval
// child
- if (left)
+ if (left != null)
{
MInterval i = left.RightMostNode;
i.left = interval;
- interval->parent = i;
+ interval.parent = i;
for (; i != null; i = i.parent)
i.total_length += interval.total_length;
}
}
}
+ private void update_parent (MInterval i)
+ {
+ if (parent == null)
+ mtext.intervals.put (key, i);
+ else
+ {
+ int diff;
+
+ if (parent.right == i)
+ {
+ diff = parent.right.total_length - i.total_length;
+ parent.right = i;
+ }
+ else
+ {
+ diff = parent.left.total_length - i.total_length;
+ parent.left = i;
+ }
+ for (i = parent; i != null; i = i.parent)
+ i.total_length += diff;
+ }
+ }
+
+ public void delete (int start, int end)
+ {
+ update_from_to ();
+ if (start < from)
+ {
+ if (end <= from)
+ {
+ left.delete (start, end);
+ return;
+ }
+ left.delete (start, from);
+ start = from;
+ }
+ else if (end > to)
+ {
+ if (start >= to)
+ {
+ right.delete (start, end);
+ return;
+ }
+ right.delete (to, end);
+ end = to;
+ }
+ if (start == from && end == to)
+ {
+ if (left == null)
+ update_parent (right);
+ else if (right == null)
+ update_parent (left);
+ else
+ {
+ MInterval i;
+
+ for (i = right; i.left != null; i = i.left)
+ i.total_length += left.total_length;
+ i.total_length += left.total_length;
+ i.left = left;
+ update_parent (right);
+ }
+ }
+ else
+ {
+ int len = end - start;
+
+ for (MInterval i = this; i != null; i = i.parent)
+ i.total_length -= len;
+ }
+ }
+
public MTextProperty Push (int start, int end, MTextProperty prop)
{
update_from_to ();