/* * TclList.java * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart * * RCS @(#) $Id: TclList.java,v 1.5 2003/01/09 02:15:39 mdejong Exp $ * */ using System; using System.Collections; using System.Text; namespace tcl.lang { /// This class implements the list object type in Tcl. public class TclList : InternalRep { /// Internal representation of a list value. private ArrayList vector; /// Create a new empty Tcl List. private TclList() { vector = new ArrayList( 10 ); } /// Create a new empty Tcl List, with the vector pre-allocated to /// the given size. /// /// /// the number of slots pre-allocated in the vector. /// private TclList( int size ) { vector = new ArrayList( size ); } /// Called to free any storage for the type's internal rep. /// the TclObject that contains this internalRep. /// public void dispose() { int size = vector.Count; for ( int i = 0; i < size; i++ ) { ( (TclObject)vector[i] ).release(); } } /// DupListInternalRep -> duplicate /// /// Returns a dupilcate of the current object. /// /// /// the TclObject that contains this internalRep. /// public InternalRep duplicate() { int size = vector.Count; TclList newList = new TclList( size ); for ( int i = 0; i < size; i++ ) { TclObject tobj = (TclObject)vector[i]; tobj.preserve(); newList.vector.Add( tobj ); } return newList; } /// Called to query the string representation of the Tcl object. This /// method is called only by TclObject.toString() when /// TclObject.stringRep is null. /// /// /// the string representation of the Tcl object. /// public override string ToString() { StringBuilder sbuf = new StringBuilder(); int size = vector.Count; try { for ( int i = 0; i < size; i++ ) { Object elm = vector[i]; if ( elm != null ) { Util.appendElement( null, sbuf, elm.ToString() ); } else { Util.appendElement( null, sbuf, "" ); } } } catch ( TclException e ) { throw new TclRuntimeError( "unexpected TclException: " + e.Message, e ); } return sbuf.ToString(); } /// Creates a new instance of a TclObject with a TclList internal /// rep. /// /// /// the TclObject with the given list value. /// public static TclObject newInstance() { return new TclObject( new TclList() ); } /// Called to convert the other object's internal rep to list. /// /// /// current interpreter. /// /// the TclObject to convert to use the List internal rep. /// /// TclException if the object doesn't contain a valid list. /// internal static void setListFromAny( Interp interp, TclObject tobj ) { InternalRep rep = tobj.InternalRep; if ( !( rep is TclList ) ) { TclList tlist = new TclList(); splitList( interp, tlist.vector, tobj.ToString() ); tobj.InternalRep = tlist; } } /// Splits a list (in string rep) up into its constituent fields. /// /// /// current interpreter. /// /// store the list elements in this vector. /// /// the string to convert into a list. /// /// TclException if the object doesn't contain a valid list. /// private static void splitList( Interp interp, ArrayList v, string s ) { int len = s.Length; int i = 0; while ( i < len ) { FindElemResult res = Util.findElement( interp, s, i, len ); if ( res == null ) { break; } else { TclObject tobj = TclString.newInstance( res.elem ); tobj.preserve(); v.Add( tobj ); } i = res.elemEnd; } } /// Tcl_ListObjAppendElement -> TclList.append() /// /// Appends a TclObject element to a list object. /// /// /// current interpreter. /// /// the TclObject to append an element to. /// /// the element to append to the object. /// /// TclException if tobj cannot be converted into a list. /// public static void append( Interp interp, TclObject tobj, TclObject elemObj ) { if ( tobj.Shared ) { throw new TclRuntimeError( "TclList.append() called with shared object" ); } setListFromAny( interp, tobj ); tobj.invalidateStringRep(); TclList tlist = (TclList)tobj.InternalRep; elemObj.preserve(); tlist.vector.Add( elemObj ); } /// Queries the length of the list. If tobj is not a list object, /// an attempt will be made to convert it to a list. /// /// /// current interpreter. /// /// the TclObject to use as a list. /// /// the length of the list. /// /// TclException if tobj is not a valid list. /// public static int getLength( Interp interp, TclObject tobj ) { setListFromAny( interp, tobj ); TclList tlist = (TclList)tobj.InternalRep; return tlist.vector.Count; } /// Returns a TclObject array of the elements in a list object. If /// tobj is not a list object, an attempt will be made to convert /// it to a list.

/// /// The objects referenced by the returned array should be treated /// as readonly and their ref counts are _not_ incremented; the /// caller must do that if it holds on to a reference. /// ///

/// the current interpreter. /// /// the list to sort. /// /// a TclObject array of the elements in a list object. /// /// TclException if tobj is not a valid list. /// public static TclObject[] getElements( Interp interp, TclObject tobj ) { setListFromAny( interp, tobj ); TclList tlist = (TclList)tobj.InternalRep; int size = tlist.vector.Count; TclObject[] objArray = new TclObject[size]; for ( int i = 0; i < size; i++ ) { objArray[i] = (TclObject)tlist.vector[i]; } return objArray; } /// This procedure returns a pointer to the index'th object from /// the list referenced by tobj. The first element has index /// 0. If index is negative or greater than or equal to the number /// of elements in the list, a null is returned. If tobj is not a /// list object, an attempt will be made to convert it to a list. /// /// /// current interpreter. /// /// the TclObject to use as a list. /// /// the index of the requested element. /// /// the the requested element. /// /// TclException if tobj is not a valid list. /// public static TclObject index( Interp interp, TclObject tobj, int index ) { setListFromAny( interp, tobj ); TclList tlist = (TclList)tobj.InternalRep; if ( index < 0 || index >= tlist.vector.Count ) { return null; } else { return (TclObject)tlist.vector[index]; } } /// This procedure inserts the elements in elements[] into the list at /// the given index. If tobj is not a list object, an attempt will /// be made to convert it to a list. /// /// /// current interpreter. /// /// the TclObject to use as a list. /// /// the starting index of the insertion operation. <=0 means /// the beginning of the list. >= TclList.getLength(tobj) means /// the end of the list. /// /// the element(s) to insert. /// /// insert elements starting from elements[from] (inclusive) /// /// insert elements up to elements[to] (inclusive) /// /// TclException if tobj is not a valid list. /// internal static void insert( Interp interp, TclObject tobj, int index, TclObject[] elements, int from, int to ) { if ( tobj.Shared ) { throw new TclRuntimeError( "TclList.insert() called with shared object" ); } replace( interp, tobj, index, 0, elements, from, to ); } /// This procedure replaces zero or more elements of the list /// referenced by tobj with the objects from an TclObject array. /// If tobj is not a list object, an attempt will be made to /// convert it to a list. /// /// /// current interpreter. /// /// the TclObject to use as a list. /// /// the starting index of the replace operation. <=0 means /// the beginning of the list. >= TclList.getLength(tobj) means /// the end of the list. /// /// the number of elements to delete from the list. <=0 means /// no elements should be deleted and the operation is equivalent to /// an insertion operation. /// /// the element(s) to insert. /// /// insert elements starting from elements[from] (inclusive) /// /// insert elements up to elements[to] (inclusive) /// /// TclException if tobj is not a valid list. /// public static void replace( Interp interp, TclObject tobj, int index, int count, TclObject[] elements, int from, int to ) { if ( tobj.Shared ) { throw new TclRuntimeError( "TclList.replace() called with shared object" ); } setListFromAny( interp, tobj ); tobj.invalidateStringRep(); TclList tlist = (TclList)tobj.InternalRep; int size = tlist.vector.Count; int i; if ( index >= size ) { // Append to the end of the list. There is no need for deleting // elements. index = size; } else { if ( index < 0 ) { index = 0; } if ( count > size - index ) { count = size - index; } for ( i = 0; i < count; i++ ) { TclObject obj = (TclObject)tlist.vector[index]; obj.release(); tlist.vector.RemoveAt( index ); } } for ( i = from; i <= to; i++ ) { elements[i].preserve(); tlist.vector.Insert( index++, elements[i] ); } } /// Sorts the list according to the sort mode and (optional) sort command. /// The resulting list will contain no duplicates, if argument unique is /// specifed as true. /// If tobj is not a list object, an attempt will be made to /// convert it to a list. /// /// /// the current interpreter. /// /// the list to sort. /// /// the sorting mode. /// /// true if to sort the elements in increasing order. /// /// the command to compute the order of two elements. /// /// true if the result should contain no duplicates. /// /// TclException if tobj is not a valid list. /// internal static void sort( Interp interp, TclObject tobj, int sortMode, int sortIndex, bool sortIncreasing, string command, bool unique ) { setListFromAny( interp, tobj ); tobj.invalidateStringRep(); TclList tlist = (TclList)tobj.InternalRep; int size = tlist.vector.Count; if ( size <= 1 ) { return; } TclObject[] objArray = new TclObject[size]; for ( int i = 0; i < size; i++ ) { objArray[i] = (TclObject)tlist.vector[i]; } QSort s = new QSort(); int newsize = s.sort( interp, objArray, sortMode, sortIndex, sortIncreasing, command, unique ); for ( int i = 0; i < size; i++ ) { if ( i < newsize ) { tlist.vector[i] = objArray[i]; objArray[i] = null; } else tlist.vector.RemoveAt( newsize ); } } } }