X-Git-Url: http://git.chise.org/gitweb/?p=m17n%2Fm17n-lib-cs.git;a=blobdiff_plain;f=MText.cs;h=14a0696c76691d54cc2e66f6449de490ebfbbf0f;hp=986bad09e397c896831ea9634ca17526bc3d7075;hb=HEAD;hpb=d1ae89066a7547f370cde297ed52c83a697ccd5c diff --git a/MText.cs b/MText.cs index 986bad0..14a0696 100644 --- a/MText.cs +++ b/MText.cs @@ -25,28 +25,52 @@ namespace M17N.Core public enum Flags { None = 0x00, - /// A text inserted before a character that has this property - /// inherits this property. If the text already has properties - /// of the same key, they are deleted. - FrontSticky = 0x01, - /// A text inserted after a character that has this property - /// inherits this property. If the text already has properties - /// of the same key, they are deleted. - RearSticky = 0x02, + + /// On inserting a text in between two characters, if the + /// preceding and following characters have Sticky properties of + /// the same key with same values, the inserted text inherits + /// those properties. In that case, properties of the inserted + /// text are overriden. + Sticky = 0x01, // 00000001 + + /// On inserting a text before a character, if the character has + /// FrontSticky properties, the inserted text inherits those + /// properties. + FrontSticky = 0x03, // 00000011 + + /// On inserting a text after a character, if the character has + /// RearSticky properties, the inserted text inherits those + /// properties. + RearSticky = 0x05, // 00000101 + + /// Like RearSticky, but if the inserted text inherits no + /// properties from the preceding character, it inherits + /// BothSticky properties from the following character if any. + BothSticky = 0x07, // 00000111 + /// This property is deleted from a span of text if the span is - /// modified (i.e. a character is changed, a text is inserted, - /// some part is deleted). This propery is also deleted if a - /// property of the same key is added, which means that this - /// property is not stackable. - Sensitive = 0x04, + /// modified (i.e. one of a character is changed, a text is + /// inserted, some part is deleted). Here, "span" means a + /// sequence of characters that has this property with the same + /// value. This property is also deleted if a property of the + /// same key is added, which means that this property is not + /// stackable. In addition this property is never merged with + /// the same value of preceding or following property. At last, + /// this property can't be sticky in any way. + Sensitive = 0x10, // 00010000 + /// Like Sensitive but also this property is deleted from a span - /// of text if a text just before the span is modified, + /// of text if a characeter just before the span is modified, /// inserted, or deleted. - FrontSensitive = 0x08, + FrontSensitive = 0x30, // 00110000 + /// Like Sensitive but also this property is deleted from a span - /// of text if a text just after the span is modified, inserted, - /// or deleted. - RearSensitive = 0x10 + /// of text if a character just after the span is modified, + /// inserted, or deleted. + RearSensitive = 0x50, // 01010000 + + /// Same as (FrontSensitive | RearSensitive). + BothSensitive = 0x70, // 01110000 }; internal MSymbol key; @@ -71,7 +95,7 @@ namespace M17N.Core public static bool HasFlags (MSymbol key, Flags flags) { - return ((key.flags & flags) != Flags.None); + return ((key.flags & flags) == flags); } public override string ToString () @@ -91,7 +115,7 @@ namespace M17N.Core private int cache_idx; private MPlist intervals; private MPlist default_property; - private bool read_only; + private bool read_only = false; private static UTF8Encoding utf8 = new UTF8Encoding (); @@ -100,7 +124,7 @@ namespace M17N.Core int len = str.Length, n = 0; for (int i = 0; i < len; i++, n++) - if (surrogate_high_p (str[i])) + if (Char.IsHighSurrogate (str[i])) i++; return n; } @@ -110,7 +134,7 @@ namespace M17N.Core int len = str.Length, n = 0; for (int i = 0; i < len; i++, n++) - if (surrogate_high_p (str[i])) + if (Char.IsHighSurrogate (str[i])) i++; return n; } @@ -128,6 +152,13 @@ namespace M17N.Core intervals = new MPlist (); } + public MText (byte[] str, int offset, int length) + { + sb = new StringBuilder (utf8.GetString (str, offset, length)); + nchars = count_chars (sb); + intervals = new MPlist (); + } + public MText (String str) { sb = new StringBuilder (str); @@ -142,6 +173,14 @@ namespace M17N.Core intervals = new MPlist (); } + public MText (int c, int len) : this () + { + while (len-- > 0) + this.Cat (c); + } + + public MText (int c) : this (c, 1) { } + public static MText operator+ (object obj, MText mt) { if (obj is string) @@ -188,24 +227,24 @@ namespace M17N.Core public override string ToString () { return sb.ToString (); } - private static bool surrogate_high_p (char c) + public static implicit operator MText (string str) { - return (c >= 0xD800 && c < 0xDC00); + return new MText (str); } - private static bool surrogate_low_p (char c) + public static explicit operator string (MText mt) { - return (c >= 0xDC00 && c < 0xE000); + return mt.ToString (); } private static int inc_idx (StringBuilder sb, int i) { - return (i + (surrogate_high_p (sb[i]) ? 2 : 1)); + return (i + (Char.IsHighSurrogate (sb[i]) ? 2 : 1)); } private static int dec_idx (StringBuilder sb, int i) { - return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1)); + return (i - (Char.IsLowSurrogate (sb[i - 1]) ? 2 : 1)); } private static int pos_to_idx (MText mt, int pos) @@ -219,7 +258,7 @@ namespace M17N.Core if (pos < mt.cache_pos) { if (mt.cache_pos == mt.cache_idx) - return mt.cache_idx; + return pos; if (pos < mt.cache_pos - pos) { p = i = 0; @@ -340,7 +379,7 @@ namespace M17N.Core i = pos_to_idx (this, i); if (value < 0x10000) { - if (surrogate_high_p (sb[i])) + if (Char.IsHighSurrogate (sb[i])) sb.Remove (i, 1); sb[i] = (char) value; } @@ -349,20 +388,32 @@ namespace M17N.Core char high = (char) (0xD800 + ((value - 0x10000) >> 10)); char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF)); - if (! surrogate_high_p (sb[i])) + if (! Char.IsHighSurrogate (sb[i])) sb.Insert (i, 0); sb[i] = high; sb[i + 1] = low; } + PopProp (i, i + 1); } get { i = pos_to_idx (this, i); - return (surrogate_high_p (sb[i]) + return (Char.IsHighSurrogate (sb[i]) ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000 : sb[i]); } } + public MText this[int from, int to] + { + set { + if (from < to) + Del (from, to); + if (value != null) + Ins (from, value); + } + get { return Dup (from, to); } + } + public MText Dup () { MText mt = new MText (sb.ToString ()); @@ -409,14 +460,29 @@ namespace M17N.Core return this; } + public MText Cat (MText mt) + { + insert (nchars, mt, 0, mt.Length); + return this; + } + + public MText Cat (MText mt, int from, int to) + { + insert (nchars, mt, from, to); + return this; + } + + public MText Del () + { + return Del (0, Length); + } + public MText Del (int from, int to) { if (check_range (from, to, true)) return this; - sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from)); nchars -= to - from; - if (nchars > 0) foreach (MPlist plist in intervals) { @@ -494,16 +560,46 @@ namespace M17N.Core intervals.Push (prop.key, root); } else - root = (MInterval) p.Val; - - if (root.isSensitive) - root.PopSensitive (from, to); + { + root = (MInterval) p.Val; + if (root.isSensitive) + { + root.PopSensitive (from, to); + root.MergeAfterChange (from, to); + root = (MInterval) p.Val; + if (M17n.debug) + DumpPropNested (); + } + } root.Push (from, to, prop); root.MergeAfterChange (from, to); root.Balance (); } } + public void PopProp (int from, int to) + { + if (from < 0) + { + default_property = null; + } + else + { + if (check_range (from, to, true)) + return; + for (MPlist p = intervals; ! p.IsEmpty; p = p.next) + { + MInterval root = (MInterval) p.Val; + root.PopAll (from, to); + root = (MInterval) p.Val; + if (M17n.debug) + DumpPropNested (); + root.MergeAfterChange (from, to); + root.Balance (); + } + } + } + public void PopProp (int from, int to, MSymbol key) { if (from < 0) @@ -538,6 +634,19 @@ namespace M17N.Core } } + public object FindProp (MSymbol key, int pos, out int from, out int to) + { + from = 0; + to = Length; + check_pos (pos, false); + + MInterval i = (MInterval) intervals.Get (key); + if (i != null + && (i = i.Find (pos, out from, out to)) != null) + return GetProp (from, key); + return null; + } + public void DumpProp () { Console.Write ("("); @@ -663,14 +772,6 @@ namespace M17N.Core MProperty.Flags.RearSensitive) ; } } - public bool isAnySensitive - { - get { return MProperty.HasFlags (Key, - (MProperty.Flags.Sensitive - | MProperty.Flags.RearSensitive - | MProperty.Flags.FrontSensitive)) ; } - } - private void update_from_to () { if (Parent == null) @@ -784,6 +885,10 @@ namespace M17N.Core { MPlist p1, p2; + if (Stack.IsEmpty && i.Stack.IsEmpty) + return true; + if (isSensitive) + return false; for (p1 = Stack, p2 = i.Stack; ! p1.IsEmpty && ! p2.IsEmpty; p1 = p1.Next, p2 = p2.Next) if (p1.Val != p2.Val) @@ -859,6 +964,21 @@ namespace M17N.Core return Parent; } + public MInterval Find (int pos, out int from, out int to) + { + MInterval i = find_head (pos); + + from = to = pos; + if (i.Stack.IsEmpty) + i = i.Next; + if (i != null) + { + from = i.From; + to = i.To; + } + return i; + } + public MInterval Balance () { MInterval i = this; @@ -942,21 +1062,25 @@ namespace M17N.Core MInterval head = find_head (start); MInterval tail = find_tail (end); + M17n.DebugPrint ("Copying: {0}", copy); + if (! head.Stack.IsEmpty - && (isAnySensitive && head.From < start - || isFrontSensitive && ! first)) + && (isSensitive && head.From < start + || (isFrontSensitive && ! first))) { + M17n.DebugPrint (" clear head"); head = copy.find_head (0); head.Stack.Clear (); } if (! tail.Stack.IsEmpty - && (isAnySensitive && end < head.To - || isRearSensitive && ! last)) + && (isSensitive && end < tail.To + || (isRearSensitive && ! last))) { + M17n.DebugPrint (" clear tail"); tail = copy.find_tail (copy.Length); tail.Stack.Clear (); } - M17n.DebugPrint ("Copied: {0}\n", copy); + M17n.DebugPrint ("\n"); return copy; } @@ -1039,10 +1163,9 @@ namespace M17N.Core len = 0; if (Stack.IsEmpty - && (isFrontSensitive - || ((isSensitive || isRearSensitive) && i.From < start))) + && (isFrontSensitive || (isSensitive && i.From < start))) { - M17n.DebugPrint (" grafting {0}", i); + M17n.DebugPrint (" forward grafting {0}", i); if (i.To < end) len = i.To - start; else @@ -1051,7 +1174,7 @@ namespace M17N.Core } while (i != null && i.From < end && mergeable (i)) { - M17n.DebugPrint (" grafting {0}", i); + M17n.DebugPrint (" forward grafting {0}", i); len += i.To - i.From; if (i.From < start) len -= start - i.From; @@ -1084,10 +1207,9 @@ namespace M17N.Core len = 0; if (Stack.IsEmpty - && (isRearSensitive - || ((isSensitive || isFrontSensitive) && end < i.To))) + && (isRearSensitive || (isSensitive && end < i.To))) { - M17n.DebugPrint (" grafting {0}", i); + M17n.DebugPrint (" backward grafting {0}", i); if (i.From <= start) len = end - start; else @@ -1096,7 +1218,7 @@ namespace M17N.Core } while (i != null && i.To <= start && mergeable (i)) { - M17n.DebugPrint (" grafting {0}", i); + M17n.DebugPrint (" backward grafting {0}", i); len += i.To - i.From; if (end < i.To) len -= i.To - end; @@ -1135,11 +1257,13 @@ namespace M17N.Core if (prev != null && isRearSticky && ! prev.Stack.IsEmpty) { prev.enlarge (end - start); + M17n.DebugPrint (" done\n"); return; } if (isFrontSticky && ! Stack.IsEmpty) { enlarge (end - start); + M17n.DebugPrint (" done\n"); return; } bool front_grafted = false, rear_grafted = false; @@ -1149,14 +1273,20 @@ namespace M17N.Core { start += grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } front_grafted = true; } if ((grafted = graft_backward (interval, start, end)) > 0) { end -= grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } rear_grafted = true; } @@ -1191,7 +1321,7 @@ namespace M17N.Core { if (! Stack.IsEmpty) { - if (isSensitive || isFrontSensitive || isRearSensitive) + if (isSensitive) Stack.Clear (); else if (isFrontSticky || isRearSticky) { @@ -1205,7 +1335,10 @@ namespace M17N.Core { start += grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } front_grafted = true; pos += grafted; } @@ -1213,7 +1346,10 @@ namespace M17N.Core { end -= grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } rear_grafted = true; } if (interval != null) @@ -1239,11 +1375,14 @@ namespace M17N.Core if (isRearSticky && ! Stack.IsEmpty) { enlarge (end - start); + M17n.DebugPrint (" done by enlarging this\n"); return; } if (next != null && isFrontSticky && ! next.Stack.IsEmpty) { + M17n.DebugPrint (" next is {0}\n", next); next.enlarge (end - start); + M17n.DebugPrint (" done by enlarging next\n"); return; } bool front_grafted = false, rear_grafted = false; @@ -1253,21 +1392,27 @@ namespace M17N.Core { end -= grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } rear_grafted = true; } if ((grafted = graft_forward (interval, start, end)) > 0) { start += grafted; if (start == end) - return; + { + M17n.DebugPrint (" done\n"); + return; + } front_grafted = true; } if (interval != null) interval = interval.Copy (mtext, start, end, front_grafted, (rear_grafted - || (next == null && end < interval.mtext.Length))); + || (next == null && end == interval.mtext.Length))); else interval = new MInterval (Key, mtext, end - start, null); @@ -1346,7 +1491,7 @@ namespace M17N.Core Left.Delete (start, end); return; } - if (isSensitive || isFrontSensitive) + if (isSensitive) Stack.Clear (); Left.Delete (start, From); To -= From - start; @@ -1363,7 +1508,7 @@ namespace M17N.Core Right.Delete (start, end); return; } - if (isSensitive || isRearSensitive) + if (isSensitive) Stack.Clear (); Right.Delete (To, end); end = To; @@ -1404,7 +1549,7 @@ namespace M17N.Core { int len = end - start; - if (isAnySensitive) + if (isSensitive) Stack.Clear (); for (MInterval i = this; i != null; i = i.Parent) i.Length -= len; @@ -1436,7 +1581,7 @@ namespace M17N.Core end = To; } - if (! Stack.IsEmpty && isAnySensitive) + if (! Stack.IsEmpty && isSensitive) Stack.Clear (); if (start > From) divide_left (start); @@ -1560,7 +1705,7 @@ namespace M17N.Core if (! Stack.IsEmpty) { - if (isAnySensitive) + if (isSensitive) Stack.Clear (); else { @@ -1578,23 +1723,47 @@ namespace M17N.Core update_from_to (); MInterval head = find_head (start); MInterval tail = find_tail (end); - while (! head.Stack.IsEmpty && head.From > 0) - { - MInterval prev = head.Prev; + Pop (head.From, tail.To); + } - if (prev.Stack.IsEmpty || head.Stack.Val != prev.Stack.Val) - break; - head = head.Prev; + public void PopAll (int start, int end) + { + update_from_to (); + M17n.DebugPrint ("popall({0} {1}) at {2}\n", start, end, this); + if (start < From) + { + if (end <= From) + { + Left.PopAll (start, end); + return; + } + Left.PopAll (start, From); + start = From; } - while (! tail.Stack.IsEmpty && tail.To < mtext.Length) + if (end > To) { - MInterval next = tail.Next; + if (start >= To) + { + Right.PopAll (start, end); + return; + } + Right.PopAll (To, end); + end = To; + } - if (next.Stack.IsEmpty || tail.Stack.Val != next.Stack.Val) - break; - tail = tail.Next; + if (! Stack.IsEmpty) + { + if (isSensitive) + Stack.Clear (); + else + { + if (start > From) + divide_left (start); + if (end < To) + divide_right (end); + Stack.Clear (); + } } - Pop (head.From, tail.To); } public override string ToString () @@ -1661,7 +1830,7 @@ namespace M17N.Core public void DumpNested (bool force) { - DumpNested (Key.ToString () + ":", force); + DumpNested (" " + Key.ToString () + ":", force); } public void DumpNested (string indent, bool force)