001: /*
002: * TclList.java
003: *
004: * Copyright (c) 1997 Sun Microsystems, Inc.
005: *
006: * See the file "license.terms" for information on usage and
007: * redistribution of this file, and for a DISCLAIMER OF ALL
008: * WARRANTIES.
009: *
010: * RCS: @(#) $Id: TclString.java,v 1.12 2006/06/08 07:44:51 mdejong Exp $
011: *
012: */
013:
014: package tcl.lang;
015:
016: // This class implements the string object type in Tcl.
017:
018: public class TclString implements InternalRep {
019:
020: // This dummy field is used as the internal rep for every
021: // TclString that has not been modified via an append
022: // operation. The most common case is for a TclString
023: // to be created but never be appended to. This field
024: // makes it possible to avoid allocating an internal
025: // rep instance until a string is actually modified.
026:
027: private static TclString dummy = new TclString();
028:
029: // Used to perform "append" operations. After an append op,
030: // sbuf.toString() will contain the latest value of the string and
031: // tobj.stringRep will be set to null. This field is not private
032: // since it will need to be accessed directly by Jacl's IO code.
033:
034: StringBuffer sbuf;
035:
036: private TclString() {
037: sbuf = null;
038:
039: if (TclObject.saveObjRecords) {
040: String key = "TclString";
041: Integer num = (Integer) TclObject.objRecordMap.get(key);
042: if (num == null) {
043: num = new Integer(1);
044: } else {
045: num = new Integer(num.intValue() + 1);
046: }
047: TclObject.objRecordMap.put(key, num);
048: }
049: }
050:
051: private TclString(StringBuffer sb) {
052: sbuf = sb;
053:
054: if (TclObject.saveObjRecords) {
055: String key = "TclString";
056: Integer num = (Integer) TclObject.objRecordMap.get(key);
057: if (num == null) {
058: num = new Integer(1);
059: } else {
060: num = new Integer(num.intValue() + 1);
061: }
062: TclObject.objRecordMap.put(key, num);
063: }
064: }
065:
066: /**
067: * Returns a dupilcate of the current object.
068: * @param obj the TclObject that contains this internalRep.
069: */
070:
071: public InternalRep duplicate() {
072: if (TclObject.saveObjRecords) {
073: String key = "TclString.duplicate()";
074: Integer num = (Integer) TclObject.objRecordMap.get(key);
075: if (num == null) {
076: num = new Integer(1);
077: } else {
078: num = new Integer(num.intValue() + 1);
079: }
080: TclObject.objRecordMap.put(key, num);
081: }
082:
083: return dummy;
084: }
085:
086: /**
087: * Implement this no-op for the InternalRep interface.
088: */
089:
090: public void dispose() {
091: }
092:
093: /**
094: * Called to query the string representation of the Tcl object. This
095: * method is called only by TclObject.toString() when
096: * TclObject.stringRep is null.
097: *
098: * @return the string representation of the Tcl object.
099: */
100: public String toString() {
101: if (sbuf == null) {
102: return "";
103: } else {
104: return sbuf.toString();
105: }
106: }
107:
108: /**
109: * Create a new TclObject that has a string representation with
110: * the given string value.
111: */
112: public static TclObject newInstance(String str) {
113: return new TclObject(dummy, str);
114: }
115:
116: /**
117: * Create a new TclObject that makes use of the given StringBuffer
118: * object. The passed in StringBuffer should not be modified after
119: * it is passed to this method.
120: */
121: public static TclObject newInstance(StringBuffer sb) {
122: return new TclObject(new TclString(sb));
123: }
124:
125: static final TclObject newInstance(Object o) {
126: return newInstance(o.toString());
127: }
128:
129: /**
130: * Create a TclObject with an internal TclString representation
131: * whose initial value is a string with the single character.
132: *
133: * @param c initial value of the string.
134: */
135:
136: static final TclObject newInstance(char c) {
137: char charArray[] = new char[1];
138: charArray[0] = c;
139: return newInstance(new String(charArray));
140: }
141:
142: /**
143: * Called to convert the other object's internal rep to string.
144: *
145: * @param tobj the TclObject to convert to use the TclString internal rep.
146: */
147: private static void setStringFromAny(TclObject tobj) {
148: // Create string rep if object did not have one already
149:
150: tobj.toString();
151:
152: // Change the type of the object to TclString.
153:
154: tobj.setInternalRep(dummy);
155:
156: if (TclObject.saveObjRecords) {
157: String key = "String -> TclString";
158: Integer num = (Integer) TclObject.objRecordMap.get(key);
159: if (num == null) {
160: num = new Integer(1);
161: } else {
162: num = new Integer(num.intValue() + 1);
163: }
164: TclObject.objRecordMap.put(key, num);
165: }
166: }
167:
168: /*
169: * public static String get(TclObject tobj) {;}
170: *
171: * There is no "get" class method for TclString representations.
172: * Use tobj.toString() instead.
173: */
174:
175: /**
176: * Appends a string to a TclObject object. This method is equivalent to
177: * Tcl_AppendToObj() in Tcl 8.0.
178: *
179: * @param tobj the TclObject to append a string to.
180: * @param string the string to append to the object.
181: */
182: public static final void append(TclObject tobj, String string) {
183: if (!tobj.isStringType()) {
184: setStringFromAny(tobj);
185: }
186:
187: TclString tstr = (TclString) tobj.getInternalRep();
188: if (tstr == dummy) {
189: tstr = new TclString();
190: tobj.setInternalRep(tstr);
191: }
192: if (tstr.sbuf == null) {
193: tstr.sbuf = new StringBuffer(tobj.toString());
194: }
195: tobj.invalidateStringRep();
196: tstr.sbuf.append(string);
197: }
198:
199: /**
200: * Appends an array of characters to a TclObject Object.
201: * Tcl_AppendUnicodeToObj() in Tcl 8.0.
202: *
203: * @param tobj the TclObject to append a string to.
204: * @param charArr array of characters.
205: * @param offset index of first character to append.
206: * @param length number of characters to append.
207: */
208: public static final void append(TclObject tobj, char[] charArr,
209: int offset, int length) {
210: if (!tobj.isStringType()) {
211: setStringFromAny(tobj);
212: }
213:
214: TclString tstr = (TclString) tobj.getInternalRep();
215: if (tstr == dummy) {
216: tstr = new TclString();
217: tobj.setInternalRep(tstr);
218: }
219: if (tstr.sbuf == null) {
220: tstr.sbuf = new StringBuffer(tobj.toString());
221: }
222: tobj.invalidateStringRep();
223: tstr.sbuf.append(charArr, offset, length);
224: }
225:
226: /**
227: * Appends a TclObject to a TclObject. This method is equivalent to
228: * Tcl_AppendToObj() in Tcl 8.0.
229: *
230: * The type of the TclObject will be a TclString that contains the
231: * string value:
232: * tobj.toString() + tobj2.toString();
233: */
234: static final void append(TclObject tobj, TclObject tobj2) {
235: append(tobj, tobj2.toString());
236: }
237:
238: /**
239: * Appends the String values of multiple TclObject's to a
240: * TclObject. This is an optimized implementation that
241: * will measure the length of each string and expand the
242: * capacity as needed to limit reallocations.
243: *
244: * @param tobj the TclObject to append elements to.
245: * @param objv array containing elements to append.
246: * @param startIdx index to start appending values from
247: * @param endIdx index to stop appending values at
248: */
249:
250: static final void append(TclObject tobj, TclObject[] objv,
251: final int startIdx, final int endIdx) {
252: if (!tobj.isStringType()) {
253: setStringFromAny(tobj);
254: }
255:
256: TclString tstr = (TclString) tobj.getInternalRep();
257: if (tstr == dummy) {
258: tstr = new TclString();
259: tobj.setInternalRep(tstr);
260: }
261: if (tstr.sbuf == null) {
262: tstr.sbuf = new StringBuffer(tobj.toString());
263: }
264: StringBuffer sb = tstr.sbuf;
265: int currentLen = tstr.sbuf.length();
266:
267: tobj.invalidateStringRep();
268:
269: for (int i = 0; i < endIdx; i++) {
270: currentLen += objv[i].toString().length();
271: }
272: // Large enough to holds all bytes, plus a little extra
273: if (currentLen > (1024 * 10)) {
274: currentLen += (currentLen / 10);
275: } else {
276: currentLen += (currentLen / 4);
277: }
278: sb.ensureCapacity(currentLen);
279: for (int i = 0; i < endIdx; i++) {
280: sb.append(objv[i].toString());
281: }
282: }
283:
284: /**
285: * This procedure clears out an existing TclObject so
286: * that it has a string representation of "". This
287: * method is used only in the IO layer.
288: */
289:
290: public static void empty(TclObject tobj) {
291: if (!tobj.isStringType()) {
292: setStringFromAny(tobj);
293: }
294:
295: TclString tstr = (TclString) tobj.getInternalRep();
296: if (tstr == dummy) {
297: tstr = new TclString();
298: tobj.setInternalRep(tstr);
299: }
300: if (tstr.sbuf == null) {
301: tstr.sbuf = new StringBuffer();
302: } else {
303: tstr.sbuf.setLength(0);
304: }
305: tobj.invalidateStringRep();
306: }
307: }
|