*** 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     private static bool surrogate_high_p (char c)
105     {
106       return (c >= 0xD800 && c < 0xDC00);
107     }
108
109     private static bool surrogate_low_p (char c)
110     {
111       return (c >= 0xDC00 && c < 0xE000);
112     }
113
114     private static int inc_idx (StringBuilder sb, int i)
115     {
116       return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
117     }
118
119     private static int dec_idx (StringBuilder sb, int i)
120     {
121       return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
122     }
123
124     private static int pos_to_idx (MText mt, int pos)
125     {
126       if (pos == mt.cache_pos)
127         return mt.cache_idx;
128
129       int p, i;
130       bool forward;
131
132       if (pos < mt.cache_pos)
133         {
134           if (mt.cache_pos == mt.cache_idx)
135             return mt.cache_idx;
136           if (pos < mt.cache_pos - pos)
137             {
138               p = i = 0;
139               forward = true;
140             }
141           else
142             {
143               p = mt.cache_pos; i = mt.cache_idx;
144               forward = false;
145             }
146         }
147       else
148         {
149           if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
150             return (mt.cache_idx + pos - mt.cache_pos);
151           if (pos - mt.cache_pos < mt.nchars - pos)
152             {
153               p = mt.cache_pos; i = mt.cache_idx;
154               forward = true;
155             }
156           else
157             {
158               p = mt.nchars; i = mt.sb.Length;
159               forward = false;
160             }
161         }
162       if (forward)
163         for (; p < pos; i = inc_idx (mt.sb, i), p++);
164       else
165         for (; p > pos; i = dec_idx (mt.sb, i), p--);
166       mt.cache_pos = p;
167       mt.cache_idx = i;
168       return i;
169     }
170
171     private void insert (int pos, MText mt2, int from, int to)
172     {
173       int pos_idx = pos_to_idx (this, pos);
174       int from_idx = pos_to_idx (mt2, from);
175       int to_idx = pos_to_idx (mt2, to);
176
177       sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
178       nchars += to - from;
179     }
180
181     public int this[int i]
182     {
183       set {
184         i = pos_to_idx (this, i);
185         if (value < 0x10000)
186           sb[i] = (char) value;
187         else
188           {
189             char high = (char) (0xD800 + ((i - 0x10000) >> 10));
190             char low = (char) (0xDC00 + ((i - 0x10000) & 0x3FF));
191
192             if (! surrogate_high_p (sb[i]))
193               sb.Insert (i, 0);
194             sb[i++] = high;
195             sb[i] = low;
196           }
197       }
198       get {
199         i = pos_to_idx (this, i);
200         return (surrogate_high_p (sb[i])
201                 ? i = ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
202                 : sb[i]);
203       }
204     }
205
206     public MText dup ()
207     {
208       return (new MText (this.sb));
209     }
210
211     public MText ins (int pos, ref MText mt)
212     {
213       insert (pos, mt, 0, mt.nchars);
214       return this;
215     }
216
217     public MText ins (int pos, ref MText mt, int from, int to)
218     {
219       insert (pos, mt, from, to);
220       return this;
221     }
222
223     public MText del (int from, int to)
224     {
225       sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
226       nchars -= to - from;
227       return this;
228     }
229   }
230
231   public class MTextProperty
232   {
233   }
234 }