001: /*
002: * (C) Copyright IBM Corp. 1998-2004. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013: /** An implementation of MCharBuffer that stores chars in an array with an insertion gap. */package com.ibm.richtext.styledtext;
014:
015: import java.io.Externalizable;
016: import java.io.ObjectInput;
017: import java.io.ObjectOutput;
018: import java.io.IOException;
019:
020: import java.text.CharacterIterator;
021:
022: final class CharBuffer extends MCharBuffer implements Externalizable {
023:
024: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
025: private static final int kGrowSize = 0x80; // small size for testing
026: private static final int CURRENT_VERSION = 1; // version code for streaming
027: private static final long serialVersionUID = 563174;
028:
029: transient Validation fValidation = null;
030: private char[] fArray;
031: transient private int fArraySize;
032: transient private int fGap;
033:
034: /** Create an empty char buffer. */
035: public CharBuffer() {
036: }
037:
038: /** Create a char buffer that can hold at least capacity chars. */
039:
040: public CharBuffer(int capacity) {
041: fArray = allocate(capacity);
042: }
043:
044: public void readExternal(ObjectInput in) throws IOException,
045: ClassNotFoundException {
046:
047: if (in.readInt() != CURRENT_VERSION) {
048: throw new IOException("Invalid version of CharBuffer");
049: }
050:
051: fArray = (char[]) in.readObject();
052: if (fArray != null) {
053: fArraySize = fArray.length;
054: fGap = fArraySize;
055: } else {
056: fArraySize = 0;
057: fGap = 0;
058: }
059: }
060:
061: public void writeExternal(ObjectOutput out) throws IOException {
062:
063: compress();
064: out.writeInt(CURRENT_VERSION);
065: out.writeObject(fArray);
066: }
067:
068: private void invalidate() {
069:
070: if (fValidation != null) {
071: fValidation.invalidate();
072: fValidation = null;
073: }
074: }
075:
076: // not ThreadSafe - could end up with two Validations
077: // being generated
078: private Validation getValidation() {
079:
080: if (fValidation == null) {
081: fValidation = new Validation();
082: }
083: return fValidation;
084: }
085:
086: /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcBuffer. */
087:
088: /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcChars.
089: * This is the core routine for manipulating the buffer.
090: */
091: public void replace(int start, int limit, char[] srcChars,
092: int srcStart, int srcLimit) {
093: invalidate();
094: int dstLength = limit - start;
095: int srcLength = srcLimit - srcStart;
096:
097: if (dstLength < 0 || srcLength < 0) {
098: throw new IllegalArgumentException(
099: "replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)");
100: }
101:
102: int gapAlloc = 0;
103: if (srcChars == null) {
104: gapAlloc = srcLength;
105: srcLength = 0;
106: }
107:
108: int newSize = fArraySize - dstLength + srcLength;
109:
110: if (fArray == null) {
111: if (start != 0 || limit != 0) {
112: throw new IllegalArgumentException(
113: "replace(int start, int limit, char[] srcChars, int srcStart, int srcLimit)");
114: }
115: if (newSize + gapAlloc > 0) {
116: fArray = allocate(newSize + gapAlloc);
117: if (srcLength > 0) {
118: System.arraycopy(srcChars, srcStart, fArray, 0,
119: srcLength);
120: fArraySize = srcLength;
121: fGap = srcLength;
122: }
123: }
124: } else {
125: int newGap = start + srcLength;
126: int gapLimit = fArray.length - fArraySize + fGap;
127:
128: if (newSize + gapAlloc > fArray.length) {
129: char[] temp = allocate(newSize + gapAlloc);
130:
131: //move stuff at beginning that we aren't writing over
132: if (start > 0) {
133: at(0, start, temp, 0);
134: }
135: //move stuff from src array that we are copying
136: if (srcLength > 0) {
137: System.arraycopy(srcChars, srcStart, temp, start,
138: srcLength);
139: }
140: //move stuff at end that we aren't copying over
141: if (limit < fArraySize) {
142: at(limit, fArraySize, temp, temp.length - newSize
143: + newGap);
144: //change 7-23-96
145: // at(limit, fArraySize - limit, temp, temp.length - newSize + newGap);
146: }
147:
148: fArray = temp;
149: } else {
150: if (start > fGap) {
151: System.arraycopy(fArray, gapLimit, fArray, fGap,
152: start - fGap);
153: }
154: if (limit < fGap) {
155: System.arraycopy(fArray, limit, fArray,
156: fArray.length - newSize + newGap, fGap
157: - limit);
158: }
159: if (srcLength > 0) {
160: System.arraycopy(srcChars, srcStart, fArray, start,
161: srcLength);
162: }
163: }
164:
165: fArraySize = newSize;
166: fGap = newGap;
167: }
168: }
169:
170: /** Replace the chars from start to limit with the chars from srcStart to srcLimit in srcString. */
171:
172: /* This implements optimizations for null text or inserting text that fits at the gap,
173: and defaults to call the core replace routine if these optimizations fail. */
174:
175: public void replace(int start, int limit, String srcString,
176: int srcStart, int srcLimit) {
177: invalidate();
178: int length = limit - start;
179: int srcLength = srcLimit - srcStart;
180:
181: if (fArray == null) {
182: if (start != 0 || limit != 0) {
183: throw new IllegalArgumentException(
184: "replace(int start, int limit, String srcString, int srcStart, int srcLimit)");
185: }
186: if (srcLength > 0) {
187: fArray = allocate(srcLength);
188: srcString.getChars(srcStart, srcLimit, fArray, 0);
189: fArraySize = srcLength;
190: fGap = srcLength;
191: }
192: } else {
193: if (start == fGap
194: && fArray.length >= fArraySize - length + srcLength) {
195: if (srcLimit > 0) {
196: srcString
197: .getChars(srcStart, srcLimit, fArray, fGap);
198: fGap += srcLength;
199: }
200: fArraySize += srcLength - length;
201: } else {
202: replace(start, limit, srcString != null ? srcString
203: .toCharArray() : null, srcStart, srcLimit);
204: }
205: }
206: }
207:
208: public void replace(int start, int limit, MConstText srcText,
209: int srcStart, int srcLimit) {
210: invalidate();
211: int length = limit - start;
212: int srcLength = srcLimit - srcStart;
213:
214: if (fArray == null) {
215: if (start != 0 || limit != 0) {
216: throw new IllegalArgumentException(
217: "replace(int start, int limit, String srcString, int srcStart, int srcLimit)");
218: }
219: if (srcLength > 0) {
220: fArray = allocate(srcLength);
221: srcText.extractChars(srcStart, srcLimit, fArray, 0);
222: fArraySize = srcLength;
223: fGap = srcLength;
224: }
225: } else {
226: if (start == fGap
227: && fArray.length >= fArraySize - length + srcLength) {
228: if (srcLimit > 0) {
229: srcText.extractChars(srcStart, srcLimit, fArray,
230: fGap);
231: fGap += srcLength;
232: }
233: fArraySize += srcLength - length;
234: } else {
235: char[] temp = srcLength == 0 ? null
236: : new char[srcLength];
237: if (temp != null) {
238: srcText.extractChars(srcStart, srcLimit, temp, 0);
239: }
240: replace(start, limit, temp, 0, srcLimit - srcStart);
241: }
242: }
243: }
244:
245: /** Replace the chars from start to limit with srcChar. */
246:
247: /* This implements optimizations for null text or replacing a character that fits into the gap,
248: and defaults to call the core replace routine if these optimizations fail. */
249:
250: public void replace(int start, int limit, char srcChar) {
251: invalidate();
252: if (fArray == null) {
253: if (start != 0 || limit != 0) {
254: throw new IllegalArgumentException(
255: "replace(int start, int limit, char srcChar)");
256: }
257: fArray = allocate(1);
258: fArray[0] = srcChar;
259: fArraySize = 1;
260: fGap = 1;
261: } else {
262: int length = limit - start;
263: if (start == fGap && fArray.length > fArraySize - length) {
264: fArray[fGap] = srcChar;
265: fGap += 1;
266: fArraySize += 1 - length;
267: } else {
268: replace(start, limit, new char[] { srcChar }, 0, 1);
269: }
270: }
271: }
272:
273: /** Return the char at pos. */
274:
275: public char at(int pos) {
276: if (pos < 0 || pos >= fArraySize) {
277: throw new IllegalArgumentException();
278: }
279: return pos < fGap ? fArray[pos] : fArray[fArray.length
280: - fArraySize + pos];
281: }
282:
283: /** Copy the chars from start to limit to dst starting at dstStart. */
284:
285: public void at(int start, int limit, char[] dst, int dstStart) {
286: int length = limit - start;
287:
288: if (start < 0 || limit < start || limit > fArraySize) {
289: throw new IllegalArgumentException();
290: }
291:
292: if (limit <= fGap) {
293: System.arraycopy(fArray, start, dst, dstStart, length);
294: } else if (start >= fGap) {
295: System.arraycopy(fArray,
296: fArray.length - fArraySize + start, dst, dstStart,
297: length);
298: } else {
299: System
300: .arraycopy(fArray, start, dst, dstStart, fGap
301: - start);
302: System.arraycopy(fArray, fArray.length - fArraySize + fGap,
303: dst, dstStart + fGap - start, limit - fGap);
304: }
305: }
306:
307: /** Return the number of chars in the buffer. */
308:
309: public final int length() {
310: return fArraySize;
311: }
312:
313: /** Return the number of chars the buffer can hold before it must reallocate. */
314:
315: public final int capacity() {
316: return fArray != null ? fArray.length : 0;
317: }
318:
319: /** Reserve capacity chars at start. Utility to optimize a sequence of operations at start. */
320:
321: public void reserveCapacity(int start, int capacity) {
322: replace(start, start, (char[]) null, 0, capacity);
323: }
324:
325: /** Minimize the storage used by the buffer. */
326:
327: public void compress() {
328: invalidate();
329: if (fArraySize == 0) {
330: fArray = null;
331: fGap = 0;
332: } else if (fArraySize != fArray.length) {
333: char[] temp = new char[fArraySize];
334: at(0, fArraySize, temp, 0);
335: fArray = temp;
336: fGap = fArraySize;
337: }
338: }
339:
340: /** Display the buffer. */
341:
342: public String toString() {
343: if (fArray != null) {
344: return new StringBuffer().append("limit: ").append(
345: fArray.length).append(", size: ")
346: .append(fArraySize).append(", gap: ").append(fGap)
347: .append(", ").append(fArray, 0, fGap).append(
348: fArray, fArray.length - fArraySize + fGap,
349: fArraySize - fGap).toString();
350: } else {
351: return new String("The buffer is empty.");
352: }
353: }
354:
355: public CharacterIterator createCharacterIterator(int start,
356: int limit) {
357:
358: Validation val = getValidation();
359: return new CharBufferIterator(start, limit, fArray, fArraySize,
360: fGap, val);
361: }
362:
363: /** The resizing algorithm. Return a value >= minSize. */
364:
365: protected int allocation(int minSize) {
366: // return (minSize + kGrowSize) & ~(kGrowSize - 1);
367: return minSize < kGrowSize ? kGrowSize
368: : (minSize * 2 + kGrowSize) & ~(kGrowSize - 1);
369: }
370:
371: /** Allocate a new character array of limit >= minSize. */
372:
373: protected char[] allocate(int minSize) {
374: return new char[allocation(minSize)];
375: }
376: }
|