]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/richtext/styledtext/CharBuffer.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / richtext / styledtext / CharBuffer.java
1 /*\r
2  * (C) Copyright IBM Corp. 1998-2004.  All Rights Reserved.\r
3  *\r
4  * The program is provided "as is" without any warranty express or\r
5  * implied, including the warranty of non-infringement and the implied\r
6  * warranties of merchantibility and fitness for a particular purpose.\r
7  * IBM will not be liable for any damages suffered by you as a result\r
8  * of using the Program. In no event will IBM be liable for any\r
9  * special, indirect or consequential damages or lost profits even if\r
10  * IBM has been advised of the possibility of their occurrence. IBM\r
11  * will not be liable for any third party claims against you.\r
12  */\r
13 /** An implementation of MCharBuffer that stores chars in an array with an insertion gap. */\r
14 /*\r
15     Change history\r
16     072396 jf   - fixed a bug in replace(int, int, char[], int, int) so that it correctly\r
17                 inserted into the middle of the buffer.\r
18     080296 jf   - added timestamp.  This is strictly a debugging device to help catch\r
19                 stale iterators.\r
20 \r
21     082296 jbr  added check for 0-length iterator in replace\r
22 */\r
23 \r
24 package com.ibm.richtext.styledtext;\r
25 \r
26 import java.io.Externalizable;\r
27 import java.io.ObjectInput;\r
28 import java.io.ObjectOutput;\r
29 import java.io.IOException;\r
30 \r
31 import java.text.CharacterIterator;\r
32 \r
33 final class CharBuffer\r
34     extends MCharBuffer implements Externalizable\r
35 {\r
36 \r
37     static final String COPYRIGHT =\r
38                 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";\r
39   private static final int kGrowSize = 0x80; // small size for testing\r
40   private static final int CURRENT_VERSION = 1; // version code for streaming\r
41   private static final long serialVersionUID = 563174;\r
42 \r
43   transient Validation fValidation = null;\r
44   private char[] fArray;\r
45   transient private int fArraySize;\r
46   transient private int fGap;\r
47 \r
48   /** Create an empty char buffer. */\r
49   public CharBuffer()\r
50   {\r
51   }\r
52 \r
53   /** Create a char buffer that can hold at least capacity chars. */\r
54 \r
55   public CharBuffer(int capacity)\r
56   {\r
57     fArray = allocate(capacity);\r
58   }\r
59 \r
60   public void readExternal(ObjectInput in) throws IOException,\r
61                                             ClassNotFoundException {\r
62 \r
63     if (in.readInt() != CURRENT_VERSION) {\r
64         throw new IOException("Invalid version of CharBuffer");\r
65     }\r
66 \r
67     fArray = (char[]) in.readObject();\r
68     if (fArray != null) {\r
69         fArraySize = fArray.length;\r
70         fGap = fArraySize;\r
71     }\r
72     else {\r
73         fArraySize = 0;\r
74         fGap = 0;\r
75     }\r
76   }\r
77 \r
78   public void writeExternal(ObjectOutput out) throws IOException {\r
79 \r
80     compress();\r
81     out.writeInt(CURRENT_VERSION);\r
82     out.writeObject(fArray);\r
83   }\r
84 \r
85   private void invalidate() {\r
86 \r
87     if (fValidation != null) {\r
88         fValidation.invalidate();\r
89         fValidation = null;\r
90     }\r
91   }\r
92 \r
93   // not ThreadSafe - could end up with two Validations\r
94   // being generated\r
95   private Validation getValidation() {\r
96 \r
97     if (fValidation == null) {\r
98         fValidation = new Validation();\r
99     }\r
100     return fValidation;\r
101   }\r
102 \r
103   /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcBuffer. */\r
104 \r
105   /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcChars.\r
106   * This is the core routine for manipulating the buffer.\r
107   */\r
108   public void replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)\r
109   {\r
110     invalidate();\r
111     int dstLength = limit - start;\r
112     int srcLength = srcLimit - srcStart;\r
113 \r
114     if (dstLength < 0 || srcLength < 0) {\r
115         throw new IllegalArgumentException("replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)");\r
116     }\r
117 \r
118     int gapAlloc = 0;\r
119     if (srcChars == null) {\r
120         gapAlloc = srcLength;\r
121         srcLength = 0;\r
122     }\r
123 \r
124     int newSize = fArraySize - dstLength + srcLength;\r
125 \r
126     if (fArray == null) {\r
127         if (start != 0 || limit != 0) {\r
128             throw new IllegalArgumentException("replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)");\r
129         }\r
130         if (newSize + gapAlloc > 0) {\r
131             fArray = allocate(newSize + gapAlloc);\r
132             if (srcLength > 0) {\r
133                 System.arraycopy(srcChars, srcStart, fArray, 0, srcLength);\r
134                 fArraySize = srcLength;\r
135                 fGap = srcLength;\r
136             }\r
137         }\r
138     } else {\r
139         int newGap = start + srcLength;\r
140         int gapLimit = fArray.length - fArraySize + fGap;\r
141 \r
142         if (newSize + gapAlloc > fArray.length) {\r
143             char[] temp = allocate(newSize + gapAlloc);\r
144 \r
145             //move stuff at beginning that we aren't writing over\r
146             if (start > 0) {\r
147                 at(0, start, temp, 0);\r
148             }\r
149             //move stuff from src array that we are copying\r
150             if (srcLength > 0) {\r
151                 System.arraycopy(srcChars, srcStart, temp, start, srcLength);\r
152             }\r
153             //move stuff at end that we aren't copying over\r
154             if (limit < fArraySize) {\r
155                 at(limit, fArraySize, temp, temp.length - newSize + newGap);\r
156             //change 7-23-96\r
157             //    at(limit, fArraySize - limit, temp, temp.length - newSize + newGap);\r
158             }\r
159 \r
160             fArray = temp;\r
161         } else {\r
162             if (start > fGap) {\r
163                 System.arraycopy(fArray, gapLimit, fArray, fGap, start - fGap);\r
164             }\r
165             if (limit < fGap) {\r
166                 System.arraycopy(fArray, limit, fArray, fArray.length - newSize + newGap, fGap - limit);\r
167             }\r
168             if (srcLength > 0) {\r
169                 System.arraycopy(srcChars, srcStart, fArray, start, srcLength);\r
170             }\r
171         }\r
172 \r
173         fArraySize = newSize;\r
174         fGap = newGap;\r
175     }\r
176   }\r
177 \r
178   /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcString. */\r
179 \r
180   /* This implements optimizations for null text or inserting text that fits at the gap,\r
181      and defaults to call the core replace routine if these optimizations fail. */\r
182 \r
183   public void replace(int start, int limit, String srcString, int srcStart, int srcLimit)\r
184   {\r
185     invalidate();\r
186     int length = limit - start;\r
187     int srcLength = srcLimit - srcStart;\r
188 \r
189     if (fArray == null) {\r
190         if (start != 0 || limit != 0) {\r
191             throw new IllegalArgumentException("replace(int start, int limit, String srcString, int srcStart, int srcLimit)");\r
192         }\r
193         if (srcLength > 0) {\r
194             fArray = allocate(srcLength);\r
195             srcString.getChars(srcStart, srcLimit, fArray, 0);\r
196             fArraySize = srcLength;\r
197             fGap = srcLength;\r
198         }\r
199     } else {\r
200         if (start == fGap && fArray.length >= fArraySize - length + srcLength) {\r
201             if (srcLimit > 0) {\r
202                 srcString.getChars(srcStart, srcLimit, fArray, fGap);\r
203                 fGap += srcLength;\r
204             }\r
205             fArraySize += srcLength - length;\r
206         } else {\r
207             replace(start, limit, srcString != null ? srcString.toCharArray() : null, srcStart, srcLimit);\r
208         }\r
209     }\r
210   }\r
211 \r
212   public void replace(int start, int limit, MConstText srcText, int srcStart, int srcLimit)\r
213   {\r
214     invalidate();\r
215     int length = limit - start;\r
216     int srcLength = srcLimit - srcStart;\r
217 \r
218     if (fArray == null) {\r
219         if (start != 0 || limit != 0) {\r
220             throw new IllegalArgumentException("replace(int start, int limit, String srcString, int srcStart, int srcLimit)");\r
221         }\r
222         if (srcLength > 0) {\r
223             fArray = allocate(srcLength);\r
224             srcText.extractChars(srcStart, srcLimit, fArray, 0);\r
225             fArraySize = srcLength;\r
226             fGap = srcLength;\r
227         }\r
228     } else {\r
229         if (start == fGap && fArray.length >= fArraySize - length + srcLength) {\r
230             if (srcLimit > 0) {\r
231                 srcText.extractChars(srcStart, srcLimit, fArray, fGap);\r
232                 fGap += srcLength;\r
233             }\r
234             fArraySize += srcLength - length;\r
235         } else {\r
236             char[] temp = srcLength == 0? null : new char[srcLength];\r
237             if (temp != null) {\r
238                 srcText.extractChars(srcStart, srcLimit, temp, 0);\r
239             }\r
240             replace(start, limit, temp, 0, srcLimit - srcStart);\r
241         }\r
242     }\r
243   }\r
244 \r
245   /** Replace the chars from start to limit with srcChar. */\r
246 \r
247   /* This implements optimizations for null text or replacing a character that fits into the gap,\r
248      and defaults to call the core replace routine if these optimizations fail. */\r
249 \r
250   public void replace(int start, int limit, char srcChar)\r
251   {\r
252     invalidate();\r
253     if (fArray == null) {\r
254         if (start != 0 || limit != 0) {\r
255             throw new IllegalArgumentException("replace(int start, int limit, char srcChar)");\r
256         }\r
257         fArray = allocate(1);\r
258         fArray[0] = srcChar;\r
259         fArraySize = 1;\r
260         fGap = 1;\r
261     } else {\r
262         int length = limit - start;\r
263         if (start == fGap && fArray.length > fArraySize - length) {\r
264             fArray[fGap] = srcChar;\r
265             fGap += 1;\r
266             fArraySize += 1 - length;\r
267         } else {\r
268             replace(start, limit, new char[] { srcChar} , 0, 1);\r
269         }\r
270     }\r
271   }\r
272 \r
273   /** Return the char at pos. */\r
274 \r
275   public char at(int pos)\r
276   {\r
277     if (pos < 0 || pos >= fArraySize) {\r
278       throw new IllegalArgumentException();\r
279     }\r
280     return pos < fGap ? fArray[pos] : fArray[fArray.length - fArraySize + pos];\r
281   }\r
282 \r
283   /** Copy the chars from start to limit to dst starting at dstStart. */\r
284 \r
285   public void at(int start, int limit, char[] dst, int dstStart)\r
286   {\r
287     int length = limit - start;\r
288 \r
289     if (start < 0 || limit < start || limit > fArraySize) {\r
290         throw new IllegalArgumentException();\r
291     }\r
292 \r
293     if (limit <= fGap) {\r
294         System.arraycopy(fArray, start, dst, dstStart, length);\r
295     } else if (start >= fGap) {\r
296         System.arraycopy(fArray, fArray.length - fArraySize + start, dst, dstStart, length);\r
297     } else {\r
298         System.arraycopy(fArray, start, dst, dstStart, fGap - start);\r
299         System.arraycopy(fArray, fArray.length - fArraySize + fGap, dst, dstStart + fGap - start, limit - fGap);\r
300     }\r
301   }\r
302 \r
303   /** Return the number of chars in the buffer. */\r
304 \r
305   public final int length()\r
306   {\r
307     return fArraySize;\r
308   }\r
309 \r
310   /** Return the number of chars the buffer can hold before it must reallocate. */\r
311 \r
312   public final int capacity()\r
313   {\r
314     return fArray != null ? fArray.length : 0;\r
315   }\r
316 \r
317   /** Reserve capacity chars at start. Utility to optimize a sequence of operations at start. */\r
318 \r
319   public void reserveCapacity(int start, int capacity)\r
320   {\r
321     replace(start, start, (char[])null, 0, capacity);\r
322   }\r
323 \r
324   /** Minimize the storage used by the buffer. */\r
325 \r
326   public void compress()\r
327   {\r
328     invalidate();\r
329     if (fArraySize == 0) {\r
330         fArray = null;\r
331         fGap = 0;\r
332     } else if (fArraySize != fArray.length) {\r
333         char[] temp = new char[fArraySize];\r
334         at(0, fArraySize, temp, 0);\r
335         fArray = temp;\r
336         fGap = fArraySize;\r
337     }\r
338   }\r
339 \r
340   /** Display the buffer. */\r
341 \r
342   public String toString()\r
343   {\r
344     if (fArray != null) {\r
345         return new StringBuffer()\r
346         .append("limit: ").append(fArray.length)\r
347         .append(", size: ").append(fArraySize)\r
348         .append(", gap: ").append(fGap)\r
349         .append(", ").append(fArray, 0, fGap)\r
350         .append(fArray, fArray.length - fArraySize + fGap, fArraySize - fGap)\r
351         .toString();\r
352     } else {\r
353         return new String("The buffer is empty.");\r
354     }\r
355   }\r
356 \r
357   public CharacterIterator createCharacterIterator(int start, int limit) {\r
358 \r
359     Validation val = getValidation();\r
360     return new CharBufferIterator(start, limit, fArray, fArraySize, fGap, val);\r
361   }\r
362 \r
363   /** The resizing algorithm. Return a value >= minSize. */\r
364 \r
365   protected int allocation(int minSize)\r
366   {\r
367     //    return (minSize + kGrowSize) & ~(kGrowSize - 1);\r
368     return minSize < kGrowSize ? kGrowSize : (minSize * 2 + kGrowSize) & ~(kGrowSize - 1);\r
369   }\r
370 \r
371   /** Allocate a new character array of limit >= minSize. */\r
372 \r
373   protected char[] allocate(int minSize)\r
374   {\r
375     return new char[allocation(minSize)];\r
376   }\r
377 }\r