diff options
author | dgp <dgp@users.sourceforge.net> | 2017-06-06 13:14:16 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2017-06-06 13:14:16 (GMT) |
commit | 8fcb14a7340a0079186e9c81589be46e0186e1d7 (patch) | |
tree | 2d8e0ed18f2625b1bd50ccc762327149e90b34d8 | |
parent | 85ce2dad1468be0285a01b680387fb337f1ecb39 (diff) | |
parent | 93784caa4d5d0a0dc6fb02b30f273b4e95a73489 (diff) | |
download | tcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.zip tcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.tar.gz tcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.tar.bz2 |
[716b427f76] Optimize TclStringCatObjv when only one non-empty argument.
-rw-r--r-- | generic/tclExecute.c | 25 | ||||
-rw-r--r-- | generic/tclStringObj.c | 87 |
2 files changed, 56 insertions, 56 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 30ef536..cfcdd26 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2685,34 +2685,11 @@ TEBCresume( opnd = TclGetUInt1AtPtr(pc+1); - objv = &OBJ_AT_DEPTH(opnd-1); - /* minor optimization in simplest cases */ - switch (opnd) { - case 1: /* only one object */ - objResultPtr = *objv; - goto endINST_STR_CONCAT1; - case 2: /* two objects - check empty */ - if (objv[0]->bytes == &tclEmptyString) { - objResultPtr = objv[1]; - goto endINST_STR_CONCAT1; - } - else - if (objv[1]->bytes == &tclEmptyString) { - objResultPtr = objv[0]; - goto endINST_STR_CONCAT1; - } - break; - case 0: /* no objects - use new empty */ - TclNewObj(objResultPtr); - goto endINST_STR_CONCAT1; - } - /* do concat */ if (TCL_OK != TclStringCatObjv(interp, /* inPlace */ 1, - opnd, objv, &objResultPtr)) { + opnd, &OBJ_AT_DEPTH(opnd-1), &objResultPtr)) { TRACE_ERROR(interp); goto gotError; } - endINST_STR_CONCAT1: TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr); NEXT_INST_V(2, opnd, 1); diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 3478cbb..aae52ba 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -2848,10 +2848,18 @@ TclStringCatObjv( Tcl_Obj **objPtrPtr) { Tcl_Obj *objPtr, *objResultPtr, * const *ov; - int oc, length = 0, binary = 1, first = 0; + int oc, length = 0, binary = 1, first = 0, last = 0; int allowUniChar = 1, requestUniChar = 0; - /* assert (objc >= 2) */ + /* assert ( objc >= 0 ) */ + + if (objc <= 1) { + /* Only one or no objects; return first or empty */ + *objPtrPtr = objc ? objv[0] : Tcl_NewObj(); + return TCL_OK; + } + + /* assert ( objc >= 2 ) */ /* * Analyze to determine what representation result should be. @@ -2861,7 +2869,7 @@ TclStringCatObjv( */ ov = objv, oc = objc; - while (oc-- && (binary || allowUniChar)) { + do { objPtr = *ov++; if (objPtr->bytes) { @@ -2892,72 +2900,79 @@ TclStringCatObjv( } } } - } + } while (--oc && (binary || allowUniChar)); if (binary) { /* Result will be pure byte array. Pre-size it */ ov = objv; oc = objc; - while (oc-- && (length >= 0)) { + do { objPtr = *ov++; if (objPtr->bytes == NULL) { int numBytes; Tcl_GetByteArrayFromObj(objPtr, &numBytes); /* PANIC? */ - if (length == 0) { - first = objc - oc - 1; + if (numBytes) { + last = objc - oc; + if (length == 0) { + first = last; + } + if ((length += numBytes) < 0) { + goto overflow; + } } - length += numBytes; } - } + } while (--oc); } else if (allowUniChar && requestUniChar) { /* Result will be pure Tcl_UniChar array. Pre-size it. */ ov = objv; oc = objc; - while (oc-- && (length >= 0)) { + do { objPtr = *ov++; if ((objPtr->bytes == NULL) || (objPtr->length)) { int numChars; Tcl_GetUnicodeFromObj(objPtr, &numChars); /* PANIC? */ - if (length == 0) { - first = objc - oc - 1; + if (numChars) { + last = objc - oc; + if (length == 0) { + first = last; + } + if ((length += numChars) < 0) { + goto overflow; + } } - length += numChars; } - } + } while (--oc); } else { /* Result will be concat of string reps. Pre-size it. */ ov = objv; oc = objc; - while (oc-- && (length >= 0)) { + do { int numBytes; objPtr = *ov++; Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */ - if ((length == 0) && numBytes) { - first = objc - oc - 1; + if (numBytes) { + last = objc - oc; + if (length == 0) { + first = last; + } + if ((length += numBytes) < 0) { + goto overflow; + } } - length += numBytes; - } + } while (--oc); } - if (length < 0) { - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "max size for a Tcl value (%d bytes) exceeded", INT_MAX)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); - } - return TCL_ERROR; - } - - if (length == 0) { - /* Total length of zero means every value has length zero */ - *objPtrPtr = objv[0]; + if (last == first /*|| length == 0 */) { + /* Only one non-empty value or zero length; return first */ + /* NOTE: (length == 0) implies (last == first) */ + *objPtrPtr = objv[first]; return TCL_OK; } - objv += first; objc -= first; + objv += first; objc = (last - first + 1); if (binary) { /* Efficiently produce a pure byte array result */ @@ -3087,6 +3102,14 @@ TclStringCatObjv( } *objPtrPtr = objResultPtr; return TCL_OK; + + overflow: + if (interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "max size for a Tcl value (%d bytes) exceeded", INT_MAX)); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + } + return TCL_ERROR; } /* |