2 * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
\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
13 /** An implementation of MCharBuffer that stores chars in an array with an insertion gap. */
\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
21 082296 jbr added check for 0-length iterator in replace
\r
24 package com.ibm.richtext.styledtext;
\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
31 import java.text.CharacterIterator;
\r
33 final class CharBuffer
\r
34 extends MCharBuffer implements Externalizable
\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
43 transient Validation fValidation = null;
\r
44 private char[] fArray;
\r
45 transient private int fArraySize;
\r
46 transient private int fGap;
\r
48 /** Create an empty char buffer. */
\r
53 /** Create a char buffer that can hold at least capacity chars. */
\r
55 public CharBuffer(int capacity)
\r
57 fArray = allocate(capacity);
\r
60 public void readExternal(ObjectInput in) throws IOException,
\r
61 ClassNotFoundException {
\r
63 if (in.readInt() != CURRENT_VERSION) {
\r
64 throw new IOException("Invalid version of CharBuffer");
\r
67 fArray = (char[]) in.readObject();
\r
68 if (fArray != null) {
\r
69 fArraySize = fArray.length;
\r
78 public void writeExternal(ObjectOutput out) throws IOException {
\r
81 out.writeInt(CURRENT_VERSION);
\r
82 out.writeObject(fArray);
\r
85 private void invalidate() {
\r
87 if (fValidation != null) {
\r
88 fValidation.invalidate();
\r
93 // not ThreadSafe - could end up with two Validations
\r
95 private Validation getValidation() {
\r
97 if (fValidation == null) {
\r
98 fValidation = new Validation();
\r
100 return fValidation;
\r
103 /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcBuffer. */
\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
108 public void replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)
\r
111 int dstLength = limit - start;
\r
112 int srcLength = srcLimit - srcStart;
\r
114 if (dstLength < 0 || srcLength < 0) {
\r
115 throw new IllegalArgumentException("replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)");
\r
119 if (srcChars == null) {
\r
120 gapAlloc = srcLength;
\r
124 int newSize = fArraySize - dstLength + srcLength;
\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
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
139 int newGap = start + srcLength;
\r
140 int gapLimit = fArray.length - fArraySize + fGap;
\r
142 if (newSize + gapAlloc > fArray.length) {
\r
143 char[] temp = allocate(newSize + gapAlloc);
\r
145 //move stuff at beginning that we aren't writing over
\r
147 at(0, start, temp, 0);
\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
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
157 // at(limit, fArraySize - limit, temp, temp.length - newSize + newGap);
\r
162 if (start > fGap) {
\r
163 System.arraycopy(fArray, gapLimit, fArray, fGap, start - fGap);
\r
165 if (limit < fGap) {
\r
166 System.arraycopy(fArray, limit, fArray, fArray.length - newSize + newGap, fGap - limit);
\r
168 if (srcLength > 0) {
\r
169 System.arraycopy(srcChars, srcStart, fArray, start, srcLength);
\r
173 fArraySize = newSize;
\r
178 /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcString. */
\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
183 public void replace(int start, int limit, String srcString, int srcStart, int srcLimit)
\r
186 int length = limit - start;
\r
187 int srcLength = srcLimit - srcStart;
\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
193 if (srcLength > 0) {
\r
194 fArray = allocate(srcLength);
\r
195 srcString.getChars(srcStart, srcLimit, fArray, 0);
\r
196 fArraySize = srcLength;
\r
200 if (start == fGap && fArray.length >= fArraySize - length + srcLength) {
\r
201 if (srcLimit > 0) {
\r
202 srcString.getChars(srcStart, srcLimit, fArray, fGap);
\r
205 fArraySize += srcLength - length;
\r
207 replace(start, limit, srcString != null ? srcString.toCharArray() : null, srcStart, srcLimit);
\r
212 public void replace(int start, int limit, MConstText srcText, int srcStart, int srcLimit)
\r
215 int length = limit - start;
\r
216 int srcLength = srcLimit - srcStart;
\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
222 if (srcLength > 0) {
\r
223 fArray = allocate(srcLength);
\r
224 srcText.extractChars(srcStart, srcLimit, fArray, 0);
\r
225 fArraySize = srcLength;
\r
229 if (start == fGap && fArray.length >= fArraySize - length + srcLength) {
\r
230 if (srcLimit > 0) {
\r
231 srcText.extractChars(srcStart, srcLimit, fArray, fGap);
\r
234 fArraySize += srcLength - length;
\r
236 char[] temp = srcLength == 0? null : new char[srcLength];
\r
237 if (temp != null) {
\r
238 srcText.extractChars(srcStart, srcLimit, temp, 0);
\r
240 replace(start, limit, temp, 0, srcLimit - srcStart);
\r
245 /** Replace the chars from start to limit with srcChar. */
\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
250 public void replace(int start, int limit, char srcChar)
\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
257 fArray = allocate(1);
\r
258 fArray[0] = srcChar;
\r
262 int length = limit - start;
\r
263 if (start == fGap && fArray.length > fArraySize - length) {
\r
264 fArray[fGap] = srcChar;
\r
266 fArraySize += 1 - length;
\r
268 replace(start, limit, new char[] { srcChar} , 0, 1);
\r
273 /** Return the char at pos. */
\r
275 public char at(int pos)
\r
277 if (pos < 0 || pos >= fArraySize) {
\r
278 throw new IllegalArgumentException();
\r
280 return pos < fGap ? fArray[pos] : fArray[fArray.length - fArraySize + pos];
\r
283 /** Copy the chars from start to limit to dst starting at dstStart. */
\r
285 public void at(int start, int limit, char[] dst, int dstStart)
\r
287 int length = limit - start;
\r
289 if (start < 0 || limit < start || limit > fArraySize) {
\r
290 throw new IllegalArgumentException();
\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
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
303 /** Return the number of chars in the buffer. */
\r
305 public final int length()
\r
310 /** Return the number of chars the buffer can hold before it must reallocate. */
\r
312 public final int capacity()
\r
314 return fArray != null ? fArray.length : 0;
\r
317 /** Reserve capacity chars at start. Utility to optimize a sequence of operations at start. */
\r
319 public void reserveCapacity(int start, int capacity)
\r
321 replace(start, start, (char[])null, 0, capacity);
\r
324 /** Minimize the storage used by the buffer. */
\r
326 public void compress()
\r
329 if (fArraySize == 0) {
\r
332 } else if (fArraySize != fArray.length) {
\r
333 char[] temp = new char[fArraySize];
\r
334 at(0, fArraySize, temp, 0);
\r
340 /** Display the buffer. */
\r
342 public String toString()
\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
353 return new String("The buffer is empty.");
\r
357 public CharacterIterator createCharacterIterator(int start, int limit) {
\r
359 Validation val = getValidation();
\r
360 return new CharBufferIterator(start, limit, fArray, fArraySize, fGap, val);
\r
363 /** The resizing algorithm. Return a value >= minSize. */
\r
365 protected int allocation(int minSize)
\r
367 // return (minSize + kGrowSize) & ~(kGrowSize - 1);
\r
368 return minSize < kGrowSize ? kGrowSize : (minSize * 2 + kGrowSize) & ~(kGrowSize - 1);
\r
371 /** Allocate a new character array of limit >= minSize. */
\r
373 protected char[] allocate(int minSize)
\r
375 return new char[allocation(minSize)];
\r