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;