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: TclList.java,v 1.15 2006/06/10 04:15:59 mdejong Exp $
011: *
012: */
013:
014: package tcl.lang;
015:
016: import java.util.ArrayList;
017:
018: /**
019: * This class implements the list object type in Tcl.
020: */
021: public class TclList implements InternalRep {
022:
023: /**
024: * Internal representation of a list value.
025: */
026: private ArrayList alist;
027:
028: /**
029: * Create a new empty Tcl List.
030: */
031: private TclList() {
032: alist = new ArrayList();
033:
034: if (TclObject.saveObjRecords) {
035: String key = "TclList";
036: Integer num = (Integer) TclObject.objRecordMap.get(key);
037: if (num == null) {
038: num = new Integer(1);
039: } else {
040: num = new Integer(num.intValue() + 1);
041: }
042: TclObject.objRecordMap.put(key, num);
043: }
044: }
045:
046: /**
047: * Create a new empty Tcl List, with the list pre-allocated to
048: * the given size.
049: *
050: * @param size the number of slots pre-allocated in the alist.
051: */
052: private TclList(int size) {
053: alist = new ArrayList(size);
054:
055: if (TclObject.saveObjRecords) {
056: String key = "TclList";
057: Integer num = (Integer) TclObject.objRecordMap.get(key);
058: if (num == null) {
059: num = new Integer(1);
060: } else {
061: num = new Integer(num.intValue() + 1);
062: }
063: TclObject.objRecordMap.put(key, num);
064: }
065: }
066:
067: /**
068: * Called to free any storage for the type's internal rep.
069: */
070: public void dispose() {
071: final int size = alist.size();
072: for (int i = 0; i < size; i++) {
073: ((TclObject) alist.get(i)).release();
074: }
075: alist.clear();
076: }
077:
078: /**
079: * DupListInternalRep -> duplicate
080: *
081: * Returns a dupilcate of the current object.
082: *
083: */
084: public InternalRep duplicate() {
085: int size = alist.size();
086: TclList newList = new TclList(size);
087:
088: for (int i = 0; i < size; i++) {
089: TclObject tobj = (TclObject) alist.get(i);
090: tobj.preserve();
091: newList.alist.add(tobj);
092: }
093:
094: if (TclObject.saveObjRecords) {
095: String key = "TclList.duplicate()";
096: Integer num = (Integer) TclObject.objRecordMap.get(key);
097: if (num == null) {
098: num = new Integer(1);
099: } else {
100: num = new Integer(num.intValue() + 1);
101: }
102: TclObject.objRecordMap.put(key, num);
103: }
104:
105: return newList;
106: }
107:
108: /**
109: * Called to query the string representation of the Tcl object. This
110: * method is called only by TclObject.toString() when
111: * TclObject.stringRep is null.
112: *
113: * @return the string representation of the Tcl object.
114: */
115: public String toString() {
116: final int size = alist.size();
117: if (size == 0) {
118: return "";
119: }
120: int est = size * 4;
121:
122: StringBuffer sbuf = new StringBuffer((est > 64) ? est : 64);
123: try {
124: for (int i = 0; i < size; i++) {
125: Object elm = alist.get(i);
126: if (elm != null) {
127: Util.appendElement(null, sbuf, elm.toString());
128: } else {
129: Util.appendElement(null, sbuf, "");
130: }
131: }
132: } catch (TclException e) {
133: throw new TclRuntimeError("unexpected TclException: " + e);
134: }
135:
136: return sbuf.toString();
137: }
138:
139: /**
140: * Creates a new instance of a TclObject with a TclList internal
141: * rep.
142: *
143: * @return the TclObject with the given list value.
144: */
145:
146: public static TclObject newInstance() {
147: return new TclObject(new TclList());
148: }
149:
150: /**
151: * Called to convert the other object's internal rep to list.
152: *
153: * @param interp current interpreter.
154: * @param tobj the TclObject to convert to use the List internal rep.
155: * @exception TclException if the object doesn't contain a valid list.
156: */
157: private static void setListFromAny(Interp interp, TclObject tobj)
158: throws TclException {
159: TclList tlist = new TclList();
160: splitList(interp, tlist.alist, tobj.toString());
161: tobj.setInternalRep(tlist);
162:
163: if (TclObject.saveObjRecords) {
164: String key = "TclString -> TclList";
165: Integer num = (Integer) TclObject.objRecordMap.get(key);
166: if (num == null) {
167: num = new Integer(1);
168: } else {
169: num = new Integer(num.intValue() + 1);
170: }
171: TclObject.objRecordMap.put(key, num);
172: }
173: }
174:
175: /**
176: * Splits a list (in string rep) up into its constituent fields.
177: *
178: * @param interp current interpreter.
179: * @param alist store the list elements in this ArraryList.
180: * @param s the string to convert into a list.
181: * @exception TclException if the object doesn't contain a valid list.
182: */
183: private static final void splitList(Interp interp, ArrayList alist,
184: String s) throws TclException {
185: int len = s.length();
186: int i = 0;
187: FindElemResult res = new FindElemResult();
188:
189: while (i < len) {
190: if (!Util.findElement(interp, s, i, len, res)) {
191: break;
192: } else {
193: TclObject tobj = TclString.newInstance(res.elem);
194: tobj.preserve();
195: alist.add(tobj);
196: }
197: i = res.elemEnd;
198: }
199: }
200:
201: /**
202: * Tcl_ListObjAppendElement -> TclList.append()
203: *
204: * Appends a TclObject element to a list object.
205: *
206: * @param interp current interpreter.
207: * @param tobj the TclObject to append an element to.
208: * @param elemObj the element to append to the object.
209: * @exception TclException if tobj cannot be converted into a list.
210: */
211: public static final void append(Interp interp, TclObject tobj,
212: TclObject elemObj) throws TclException {
213: if (tobj.isShared()) {
214: throw new TclRuntimeError(
215: "TclList.append() called with shared object");
216: }
217: if (!tobj.isListType()) {
218: setListFromAny(interp, tobj);
219: }
220: tobj.invalidateStringRep();
221:
222: elemObj.preserve();
223: ((TclList) tobj.getInternalRep()).alist.add(elemObj);
224: }
225:
226: /**
227: * TclList.append()
228: *
229: * Appends multiple TclObject elements to a list object.
230: *
231: * @param interp current interpreter.
232: * @param tobj the TclObject to append elements to.
233: * @param objv array containing elements to append.
234: * @param startIdx index to start appending values from
235: * @param endIdx index to stop appending values at
236: * @exception TclException if tobj cannot be converted into a list.
237: */
238: static final void append(Interp interp, TclObject tobj,
239: TclObject[] objv, final int startIdx, final int endIdx)
240: throws TclException {
241: if (tobj.isShared()) {
242: throw new TclRuntimeError(
243: "TclList.append() called with shared object");
244: }
245: if (!tobj.isListType()) {
246: setListFromAny(interp, tobj);
247: }
248: tobj.invalidateStringRep();
249:
250: ArrayList alist = ((TclList) tobj.getInternalRep()).alist;
251:
252: for (int i = startIdx; i < endIdx; i++) {
253: TclObject elemObj = objv[i];
254: elemObj.preserve();
255: alist.add(elemObj);
256: }
257: }
258:
259: /**
260: * Queries the length of the list. If tobj is not a list object,
261: * an attempt will be made to convert it to a list.
262: *
263: * @param interp current interpreter.
264: * @param tobj the TclObject to use as a list.
265: * @return the length of the list.
266: * @exception TclException if tobj is not a valid list.
267: */
268: public static final int getLength(Interp interp, TclObject tobj)
269: throws TclException {
270: if (!tobj.isListType()) {
271: setListFromAny(interp, tobj);
272: }
273:
274: TclList tlist = (TclList) tobj.getInternalRep();
275: return tlist.alist.size();
276: }
277:
278: /**
279: * Returns a TclObject array of the elements in a list object. If
280: * tobj is not a list object, an attempt will be made to convert
281: * it to a list. <p>
282: *
283: * The objects referenced by the returned array should be treated
284: * as readonly and their ref counts are _not_ incremented; the
285: * caller must do that if it holds on to a reference.
286: *
287: * @param interp the current interpreter.
288: * @param tobj the list to sort.
289: * @return a TclObject array of the elements in a list object.
290: * @exception TclException if tobj is not a valid list.
291: */
292: public static TclObject[] getElements(Interp interp, TclObject tobj)
293: throws TclException {
294: if (!tobj.isListType()) {
295: setListFromAny(interp, tobj);
296: }
297: TclList tlist = (TclList) tobj.getInternalRep();
298:
299: int size = tlist.alist.size();
300: TclObject objArray[] = new TclObject[size];
301: for (int i = 0; i < size; i++) {
302: objArray[i] = (TclObject) tlist.alist.get(i);
303: }
304: return objArray;
305: }
306:
307: /**
308: * This procedure returns a pointer to the index'th object from
309: * the list referenced by tobj. The first element has index
310: * 0. If index is negative or greater than or equal to the number
311: * of elements in the list, a null is returned. If tobj is not a
312: * list object, an attempt will be made to convert it to a list.
313: *
314: * @param interp current interpreter.
315: * @param tobj the TclObject to use as a list.
316: * @param index the index of the requested element.
317: * @return the the requested element.
318: * @exception TclException if tobj is not a valid list.
319: */
320: public static final TclObject index(Interp interp, TclObject tobj,
321: int index) throws TclException {
322: if (!tobj.isListType()) {
323: setListFromAny(interp, tobj);
324: }
325:
326: TclList tlist = (TclList) tobj.getInternalRep();
327: if (index < 0 || index >= tlist.alist.size()) {
328: return null;
329: } else {
330: return (TclObject) tlist.alist.get(index);
331: }
332: }
333:
334: /**
335: * This procedure inserts the elements in elements[] into the list at
336: * the given index. If tobj is not a list object, an attempt will
337: * be made to convert it to a list.
338: *
339: * @param interp current interpreter.
340: * @param tobj the TclObject to use as a list.
341: * @param index the starting index of the insertion operation. <=0 means
342: * the beginning of the list. >= TclList.getLength(tobj) means
343: * the end of the list.
344: * @param elements the element(s) to insert.
345: * @param from insert elements starting from elements[from] (inclusive)
346: * @param to insert elements up to elements[to] (inclusive)
347: * @exception TclException if tobj is not a valid list.
348: */
349: static final void insert(Interp interp, TclObject tobj, int index,
350: TclObject elements[], int from, int to) throws TclException {
351: if (tobj.isShared()) {
352: throw new TclRuntimeError(
353: "TclList.insert() called with shared object");
354: }
355: replace(interp, tobj, index, 0, elements, from, to);
356: }
357:
358: /**
359: * This procedure replaces zero or more elements of the list
360: * referenced by tobj with the objects from an TclObject array.
361: * If tobj is not a list object, an attempt will be made to
362: * convert it to a list.
363: *
364: * @param interp current interpreter.
365: * @param tobj the TclObject to use as a list.
366: * @param index the starting index of the replace operation. <=0 means
367: * the beginning of the list. >= TclList.getLength(tobj) means
368: * the end of the list.
369: * @param count the number of elements to delete from the list. <=0 means
370: * no elements should be deleted and the operation is equivalent to
371: * an insertion operation.
372: * @param elements the element(s) to insert.
373: * @param from insert elements starting from elements[from] (inclusive)
374: * @param to insert elements up to elements[to] (inclusive)
375: * @exception TclException if tobj is not a valid list.
376: */
377: public static final void replace(Interp interp, TclObject tobj,
378: int index, int count, TclObject elements[], int from, int to)
379: throws TclException {
380: if (tobj.isShared()) {
381: throw new TclRuntimeError(
382: "TclList.replace() called with shared object");
383: }
384: if (!tobj.isListType()) {
385: setListFromAny(interp, tobj);
386: }
387: tobj.invalidateStringRep();
388: TclList tlist = (TclList) tobj.getInternalRep();
389:
390: int size = tlist.alist.size();
391: int i;
392:
393: if (index >= size) {
394: // Append to the end of the list. There is no need for deleting
395: // elements.
396: index = size;
397: } else {
398: if (index < 0) {
399: index = 0;
400: }
401: if (count > size - index) {
402: count = size - index;
403: }
404: for (i = 0; i < count; i++) {
405: TclObject obj = (TclObject) tlist.alist.get(index);
406: obj.release();
407: tlist.alist.remove(index);
408: }
409: }
410: for (i = from; i <= to; i++) {
411: elements[i].preserve();
412: tlist.alist.add(index++, elements[i]);
413: }
414: }
415:
416: /**
417: * Sorts the list according to the sort mode and (optional) sort command.
418: * If tobj is not a list object, an attempt will be made to
419: * convert it to a list.
420: *
421: * @param interp the current interpreter.
422: * @param tobj the list to sort.
423: * @param sortMode the sorting mode.
424: * @param sortIncreasing true if to sort the elements in increasing order.
425: * @param command the command to compute the order of two elements.
426: * @exception TclException if tobj is not a valid list.
427: */
428:
429: static void sort(Interp interp, TclObject tobj, int sortMode,
430: int sortIndex, boolean sortIncreasing, String command)
431: throws TclException {
432: if (!tobj.isListType()) {
433: setListFromAny(interp, tobj);
434: }
435: tobj.invalidateStringRep();
436: TclList tlist = (TclList) tobj.getInternalRep();
437:
438: int size = tlist.alist.size();
439:
440: if (size <= 1) {
441: return;
442: }
443:
444: TclObject objArray[] = new TclObject[size];
445: for (int i = 0; i < size; i++) {
446: objArray[i] = (TclObject) tlist.alist.get(i);
447: }
448:
449: QSort s = new QSort();
450: s.sort(interp, objArray, sortMode, sortIndex, sortIncreasing,
451: command);
452:
453: for (int i = 0; i < size; i++) {
454: tlist.alist.set(i, objArray[i]);
455: objArray[i] = null;
456: }
457: }
458: }
|