summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2017-06-06 13:14:16 (GMT)
committerdgp <dgp@users.sourceforge.net>2017-06-06 13:14:16 (GMT)
commit8fcb14a7340a0079186e9c81589be46e0186e1d7 (patch)
tree2d8e0ed18f2625b1bd50ccc762327149e90b34d8 /generic
parent85ce2dad1468be0285a01b680387fb337f1ecb39 (diff)
parent93784caa4d5d0a0dc6fb02b30f273b4e95a73489 (diff)
downloadtcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.zip
tcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.tar.gz
tcl-8fcb14a7340a0079186e9c81589be46e0186e1d7.tar.bz2
[716b427f76] Optimize TclStringCatObjv when only one non-empty argument.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclExecute.c25
-rw-r--r--generic/tclStringObj.c87
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;
}
/*