*** empty log message ***
[m17n/m17n-lib-cs.git] / MText.cs
1 using System;
2 using System.Text;
3 using M17N.Core;
4
5 namespace M17N.Core
6 {
7 #if false
8   public enum MTextFormat
9   {
10     MTEXT_FORMAT_US_ASCII,
11     MTEXT_FORMAT_UTF_8,
12     MTEXT_FORMAT_UTF_16BE,
13     MTEXT_FORMAT_UTF_16LE,
14     MTEXT_FORMAT_UTF_32BE,
15     MTEXT_FORMAT_UTF_32LE,
16   }
17 #endif
18
19   public class MText
20   {
21 #if false
22     public enum MTextFormat format;
23 #endif
24
25     private class MTextPlist : MPlist
26     {
27       public class MInterval
28       {
29         MPlist stack;
30         int nprops;
31         public int start, end;
32         public MInterval prev, next;
33       }
34
35       MInterval head, tail;
36
37       public MTextPlist (MText mt)
38       {
39         head = tail = new MInterval ();
40         head.start = 0;
41         head.end = mt.sb.Length;
42       }
43     }
44
45     private StringBuilder sb;
46     private int nchars;
47     private int cache_pos;
48     private int cache_idx;
49     private MTextPlist plist;
50     private bool unmodifiable;
51
52     private static UTF8Encoding utf8 = new UTF8Encoding ();
53
54     private static int count_chars (String str)
55     {
56       int len = str.Length, n = 0;
57
58       for (int i = 0; i < len; i++) 
59         n += surrogate_high_p (str[i]) ? 2 : 1;
60       return n;
61     }
62
63     private static int count_chars (StringBuilder str)
64     {
65       int len = str.Length, n = 0;
66
67       for (int i = 0; i < len; i++) 
68         n += surrogate_high_p (str[i]) ? 2 : 1;
69       return n;
70     }
71
72     public MText ()
73     {
74       sb = new StringBuilder ();
75     }
76
77     public MText (byte[] str)
78     {
79       sb = new StringBuilder (utf8.GetString (str));
80       nchars = count_chars (sb);
81     }
82
83     public MText (String str)
84     {
85       sb = new StringBuilder (str);
86       nchars = count_chars (str);
87     }
88
89     public MText (StringBuilder str)
90     {
91       sb = str;
92       nchars = count_chars (str);
93     }
94
95     public static MText operator+ (MText mt1, MText mt2)
96     {
97       MText mt = new MText (mt1.sb);
98
99       mt.sb.Append (mt2.sb);
100       mt.nchars = mt1.nchars + mt2.nchars;
101       return mt;
102     }
103
104     public override string ToString ()
105     {
106       return sb.ToString ();
107     }
108
109     private static bool surrogate_high_p (char c)
110     {
111       return (c >= 0xD800 && c < 0xDC00);
112     }
113
114     private static bool surrogate_low_p (char c)
115     {
116       return (c >= 0xDC00 && c < 0xE000);
117     }
118
119     private static int inc_idx (StringBuilder sb, int i)
120     {
121       return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
122     }
123
124     private static int dec_idx (StringBuilder sb, int i)
125     {
126       return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
127     }
128
129     private static int pos_to_idx (MText mt, int pos)
130     {
131       if (pos == mt.cache_pos)
132         return mt.cache_idx;
133
134       int p, i;
135       bool forward;
136
137       if (pos < mt.cache_pos)
138         {
139           if (mt.cache_pos == mt.cache_idx)
140             return mt.cache_idx;
141           if (pos < mt.cache_pos - pos)
142             {
143               p = i = 0;
144               forward = true;
145             }
146           else
147             {
148               p = mt.cache_pos; i = mt.cache_idx;
149               forward = false;
150             }
151         }
152       else
153         {
154           if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
155             return (mt.cache_idx + pos - mt.cache_pos);
156           if (pos - mt.cache_pos < mt.nchars - pos)
157             {
158               p = mt.cache_pos; i = mt.cache_idx;
159               forward = true;
160             }
161           else
162             {
163               p = mt.nchars; i = mt.sb.Length;
164               forward = false;
165             }
166         }
167       if (forward)
168         for (; p < pos; i = inc_idx (mt.sb, i), p++);
169       else
170         for (; p > pos; i = dec_idx (mt.sb, i), p--);
171       mt.cache_pos = p;
172       mt.cache_idx = i;
173       return i;
174     }
175
176     private void insert (int pos, MText mt2, int from, int to)
177     {
178       int pos_idx = pos_to_idx (this, pos);
179       int from_idx = pos_to_idx (mt2, from);
180       int to_idx = pos_to_idx (mt2, to);
181
182       sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
183       nchars += to - from;
184     }
185
186     public int this[int i]
187     {
188       set {
189         i = pos_to_idx (this, i);
190         if (value < 0x10000)
191           {
192             if (surrogate_high_p (sb[i]))
193               sb.Remove (i, 1);
194             sb[i] = (char) value;
195           }
196         else
197           {
198             char high = (char) (0xD800 + ((value - 0x10000) >> 10));
199             char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
200
201             if (! surrogate_high_p (sb[i]))
202               sb.Insert (i, 0);
203             sb[i] = high;
204             sb[i + 1] = low;
205           }
206       }
207       get {
208         i = pos_to_idx (this, i);
209         return (surrogate_high_p (sb[i])
210                 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
211                 : sb[i]);
212       }
213     }
214
215     public MText dup ()
216     {
217       return (new MText (sb.ToString ()));
218     }
219
220     public MText ins (int pos, ref MText mt)
221     {
222       insert (pos, mt, 0, mt.nchars);
223       return this;
224     }
225
226     public MText ins (int pos, ref MText mt, int from, int to)
227     {
228       insert (pos, mt, from, to);
229       return this;
230     }
231
232     public MText del (int from, int to)
233     {
234       sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
235       nchars -= to - from;
236       return this;
237     }
238   }
239
240   public class MTextProperty
241   {
242   }
243 }