Tcl Source Code

Artifact [523b7846a7]
Login

Artifact 523b7846a725277211f3c2269d4bdf6d51ae28c4:

Attachment "listDiff" to ticket [738900ffff] added by msofer 2007-04-21 02:50:28.
Index: generic/tclListObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclListObj.c,v
retrieving revision 1.43
diff -u -r1.43 tclListObj.c
--- generic/tclListObj.c	20 Mar 2007 19:47:48 -0000	1.43
+++ generic/tclListObj.c	20 Apr 2007 19:48:16 -0000
@@ -1628,34 +1628,69 @@
     Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
     Tcl_Obj *objPtr)		/* The object to convert. */
 {
-    char *string, *s;
+    char *string = NULL, *s;
     const char *elemStart, *nextElem;
     int lenRemain, length, estCount, elemSize, hasBrace, i, j, result;
-    const char *limit;		/* Points just after string's last byte. */
+    const char *limit = NULL;	 /* Points just after string's last byte. */
     register const char *p;
     register Tcl_Obj **elemPtrs;
     register Tcl_Obj *elemPtr;
     List *listRepPtr;
+    Tcl_ObjType *typePtr = objPtr->typePtr;
+    int avoidParse;
 
-    /*
-     * Get the string representation. Make it up-to-date if necessary.
+    /* Only reuse a parsed object if it did not have a string rep to begin 
+     * with, ie, if the string rep is generated from the intRep. 
      */
+    
+    avoidParse = (objPtr->bytes == NULL);
+    
+    estCount = 1;
+    if (objPtr->bytes && (objPtr->length == 0)) {
+	avoidParse = 1;
+	i = 0;
+    } else if ((typePtr == &tclIntType)
+#ifndef NO_WIDE_TYPE
+	    || (typePtr == &tclWideIntType)
+#endif
+	    || (typePtr == &tclDoubleType)
+	    || (typePtr == &tclBignumType)) {
+	avoidParse = 1;
+	i = 1;
+    } else {
 
-    string = Tcl_GetStringFromObj(objPtr, &length);
+        /*
+	 * Get the string representation. Make it up-to-date if necessary.
+	 */
 
-    /*
-     * Parse the string into separate string objects, and create a List
-     * structure that points to the element string objects. We use a modified
-     * version of Tcl_SplitList's implementation to avoid one malloc and a
-     * string copy for each list element. First, estimate the number of
-     * elements by counting the number of space characters in the list.
-     */
+	string = Tcl_GetStringFromObj(objPtr, &length);
+	
+	/*
+	 * Parse the string into separate string objects, and create a List
+	 * structure that points to the element string objects. We use a modified
+	 * version of Tcl_SplitList's implementation to avoid one malloc and a
+	 * string copy for each list element. First, estimate the number of
+	 * elements by counting the number of space characters in the list.
+	 */
+	
+	limit = string + length;
+	for (p = string;  p < limit;  p++) {
+	    if (isspace(UCHAR(*p))) { /* INTL: ISO space. */
+		estCount++;
+	    }
+	}
 
-    limit = string + length;
-    estCount = 1;
-    for (p = string;  p < limit;  p++) {
-	if (isspace(UCHAR(*p))) { /* INTL: ISO space. */
-	    estCount++;
+	i = 1;
+	if (avoidParse) {
+	    if (estCount == 1) {
+		result = TclFindElement(interp, string, length, &elemStart,
+			&nextElem, &elemSize, &hasBrace);
+		if (result != TCL_OK) {
+		    return result;
+		}
+	    } else {
+		avoidParse = 0;
+	    }
 	}
     }
 
@@ -1674,54 +1709,66 @@
     }
     elemPtrs = &listRepPtr->elements;
 
-    for (p=string, lenRemain=length, i=0;
-	    lenRemain > 0;
-	    p=nextElem, lenRemain=limit-nextElem, i++) {
-	result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
-		&elemSize, &hasBrace);
-	if (result != TCL_OK) {
-	    for (j = 0;  j < i;  j++) {
-		elemPtr = elemPtrs[j];
-		Tcl_DecrRefCount(elemPtr);
-	    }
-	    ckfree((char *) listRepPtr);
-	    return result;
-	}
-	if (elemStart >= limit) {
-	    break;
-	}
-	if (i > estCount) {
-	    Tcl_Panic("SetListFromAny: bad size estimate for list");
-	}
-
-	/*
-	 * Allocate a Tcl object for the element and initialize it from the
-	 * "elemSize" bytes starting at "elemStart".
-	 */
 
-	s = ckalloc((unsigned) elemSize + 1);
-	if (hasBrace) {
-	    memcpy(s, elemStart, (size_t) elemSize);
-	    s[elemSize] = 0;
-	} else {
-	    elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
+    if (avoidParse) {
+	if (i) {
+	    /*
+	     * Single element list containing a duplicate of objPtr. 
+	     */
+	    
+	    elemPtr = Tcl_DuplicateObj(objPtr);
+	    elemPtrs[0] = elemPtr;
+	    Tcl_IncrRefCount(elemPtr);
 	}
+    } else {
+	for (p=string, lenRemain=length, i=0;
+	       lenRemain > 0;
+	       p=nextElem, lenRemain=limit-nextElem, i++) {
+	    result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
+		    &elemSize, &hasBrace);
+	    if (result != TCL_OK) {
+		for (j = 0;  j < i;  j++) {
+		    elemPtr = elemPtrs[j];
+		    Tcl_DecrRefCount(elemPtr);
+		}
+		ckfree((char *) listRepPtr);
+		return result;
+	    }
+	    if (elemStart >= limit) {
+		break;
+	    }
+	    if (i > estCount) {
+		Tcl_Panic("SetListFromAny: bad size estimate for list");
+	    }
 
-	TclNewObj(elemPtr);
-	elemPtr->bytes = s;
-	elemPtr->length = elemSize;
-	elemPtrs[i] = elemPtr;
-	Tcl_IncrRefCount(elemPtr);	/* Since list now holds ref to it. */
+	    /*
+	     * Allocate a Tcl object for the element and initialize it from
+	     * the "elemSize" bytes starting at "elemStart".
+	     */
+
+	    s = ckalloc((unsigned) elemSize + 1);
+	    if (hasBrace) {
+		memcpy(s, elemStart, (size_t) elemSize);
+		s[elemSize] = 0;
+	    } else {
+		elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
+	    }
+	    
+	    TclNewObj(elemPtr);
+	    elemPtr->bytes = s;
+	    elemPtr->length = elemSize;
+	    elemPtrs[i] = elemPtr;
+	    Tcl_IncrRefCount(elemPtr);	/* Since list now holds ref to it. */
+	}
     }
 
-    listRepPtr->elemCount = i;
-
     /*
      * Free the old internalRep before setting the new one. We do this as late
      * as possible to allow the conversion code, in particular
      * Tcl_GetStringFromObj, to use that old internalRep.
      */
 
+    listRepPtr->elemCount = i;
     listRepPtr->refCount++;
     TclFreeIntRep(objPtr);
     objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;