001: // Copyright (c) 2001, 2003, 2005 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.lists;
005:
006: /** Editable character sequence using a a buffer-gap implementstion and
007: * self-adjusting position.
008: * Can implement (the text part of) an Emacs buffer, or a
009: * javax.swing.text.AbstractDocument.Content
010: */
011:
012: public class CharBuffer extends StableVector implements CharSeq,
013: java.io.Serializable {
014: // Same as super.base but pre-cast to FString.
015: private FString string;
016:
017: public CharBuffer(FString str) {
018: super (str);
019: string = str;
020: }
021:
022: public CharBuffer(int initialSize) {
023: this (new FString(initialSize));
024: }
025:
026: protected CharBuffer() {
027: }
028:
029: public int length() {
030: return size();
031: }
032:
033: public char charAt(int index) {
034: // If index is out of bounds, the base.get will catch that.
035: if (index >= gapStart)
036: index += gapEnd - gapStart;
037: return string.charAt(index);
038: }
039:
040: /** Copy characters into a destination buffer.
041: * Same interface as java.lang.String's getChars. */
042: public void getChars(int srcBegin, int srcEnd, char[] dst,
043: int dstBegin) {
044: char[] array = string.data;
045: int count;
046: if (srcBegin < gapStart) {
047: count = (srcEnd < gapStart ? srcEnd : gapStart) - srcBegin;
048: if (count > 0) {
049: System.arraycopy(array, srcBegin, dst, dstBegin, count);
050: srcBegin += count;
051: dstBegin += count;
052: }
053: }
054: int gapSize = gapEnd - gapStart;
055: srcBegin += gapSize;
056: srcEnd += gapSize;
057: count = srcEnd - srcBegin;
058: if (count > 0)
059: System.arraycopy(array, srcBegin, dst, dstBegin, count);
060: }
061:
062: public void setCharAt(int index, char value) {
063: // If index is out of bounds, the base.get will catch that.
064: if (index >= gapStart)
065: index += gapEnd - gapStart;
066: string.setCharAt(index, value);
067: }
068:
069: /* #ifdef use:java.lang.CharSequence */
070: public CharSequence subSequence(int start, int end) {
071: int sz = size();
072: if (start < 0 || end < start || end > sz)
073: throw new IndexOutOfBoundsException();
074: return new SubCharSeq(this , base.createPos(start, false), base
075: .createPos(end, true));
076: }
077:
078: /* #endif */
079:
080: public void fill(int fromIndex, int toIndex, char value) {
081: char[] array = string.data;
082: int i = fromIndex;
083: int limit = gapStart < toIndex ? gapStart : toIndex;
084: for (; i < limit; i++)
085: array[i] = value;
086: int gapSize = gapEnd - gapStart;
087: i = limit + gapSize;
088: limit += toIndex;
089: for (; i < limit; i++)
090: array[i] = value;
091: }
092:
093: /** Set all the elements to a given character. */
094: public final void fill(char value) {
095: char[] array = string.data;
096: for (int i = array.length; --i >= gapEnd;)
097: array[i] = value;
098: for (int i = gapStart; --i >= 0;)
099: array[i] = value;
100: }
101:
102: public char[] getArray() {
103: return (char[]) base.getBuffer();
104: }
105:
106: public void delete(int where, int count) {
107: int ipos = createPos(where, false);
108: removePos(ipos, count);
109: releasePos(ipos);
110: }
111:
112: public void insert(int where, String str, boolean beforeMarkers/*ignored*/) {
113: int len = str.length();
114: gapReserve(where, len);
115: str.getChars(0, len, string.data, where);
116: gapStart += len;
117: }
118:
119: public void consume(int start, int count, Consumer dest) {
120: char[] array = string.data;
121: if (start < gapStart) {
122: int count0 = gapStart - start;
123: if (count0 > count)
124: count0 = count;
125: dest.write(array, start, count0);
126: count -= count0;
127: start += count;
128: }
129: if (count > 0) {
130: start += gapEnd - gapStart;
131: dest.write(array, start, count);
132: }
133: }
134:
135: public String toString() {
136: int len = size();
137: int start = getSegment(0, len);
138: return new String(getArray(), start, len);
139: }
140:
141: /* #ifdef JAVA5 */
142: // public void writeTo(int start, int count, Appendable dest)
143: // throws java.io.IOException
144: // {
145: // if (dest instanceof java.io.Writer)
146: // writeTo(start, count, (java.io.Writer) dest);
147: // else
148: // dest.append(this, start, start+count);
149: // }
150: // public void writeTo(Appendable dest)
151: // throws java.io.IOException
152: // {
153: // writeTo(0, size(), dest);
154: // }
155: /* #endif */
156:
157: public void writeTo(int start, int count, java.io.Writer dest)
158: throws java.io.IOException {
159: char[] array = string.data;
160: if (start < gapStart) {
161: int count0 = gapStart - start;
162: if (count0 > count)
163: count0 = count;
164: dest.write(array, start, count0);
165: count -= count0;
166: start += count;
167: }
168: if (count > 0) {
169: start += gapEnd - gapStart;
170: dest.write(array, start, count);
171: }
172: }
173:
174: public void writeTo(java.io.Writer dest) throws java.io.IOException {
175: char[] array = string.data;
176: dest.write(array, 0, gapStart);
177: dest.write(array, gapEnd, array.length - gapEnd);
178: }
179:
180: public void dump() {
181: System.err.println("Buffer Content dump. size:" + size()
182: + " buffer:" + getArray().length);
183: System.err.print("before gap: \"");
184: System.err.print(new String(getArray(), 0, gapStart));
185: System.err.println("\" (gapStart:" + gapStart + " gapEnd:"
186: + gapEnd + ')');
187: System.err.print("after gap: \"");
188: System.err.print(new String(getArray(), gapEnd,
189: getArray().length - gapEnd));
190: System.err.println("\"");
191: int poslen = positions == null ? 0 : positions.length;
192: System.err.println("Positions (size: " + poslen + " free:"
193: + free + "):");
194: boolean[] isFree = null;
195: if (free != -2) {
196: isFree = new boolean[positions.length];
197: for (int i = free; i >= 0; i = positions[i])
198: isFree[i] = true;
199: }
200: for (int i = 0; i < poslen; i++) {
201: int pos = positions[i];
202: if (free == -2 ? pos != FREE_POSITION : !isFree[i])
203: System.err.println("position#" + i + ": " + (pos >> 1)
204: + " isAfter:" + (pos & 1));
205: }
206: }
207: }
|