summaryrefslogtreecommitdiffstats
path: root/generic/tclExecute.c
diff options
context:
space:
mode:
authorhobbs <hobbs>2002-05-29 09:09:57 (GMT)
committerhobbs <hobbs>2002-05-29 09:09:57 (GMT)
commit3a1941e7d007e93449aa22085687a8fafaddad7e (patch)
tree9794bcbc0e094b9645add8339f0278666543ef7e /generic/tclExecute.c
parent514dd2a61babad4abc78895bdadec335dd9b4c71 (diff)
downloadtcl-3a1941e7d007e93449aa22085687a8fafaddad7e.zip
tcl-3a1941e7d007e93449aa22085687a8fafaddad7e.tar.gz
tcl-3a1941e7d007e93449aa22085687a8fafaddad7e.tar.bz2
* generic/tclInt.decls:
* generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclUtf.c: added TclpUtfNcmp2 private command that mirrors Tcl_UtfNcmp, but takes n in bytes, not utf-8 chars. This provides a faster alternative for comparing utf strings internally. (Tcl_UniCharNcmp, Tcl_UniCharNcasecmp): removed the explicit end of string check as it wasn't correct for the function (by doc and logic). * generic/tclCmdMZ.c (Tcl_StringObjCmd): reworked the string equal comparison code to use TclpUtfNcmp2 as well as short-circuit for equal objects or unequal length strings in the equal case. Removed the use of goto and streamlined the other parts. * generic/tclExecute.c (TclExecuteByteCode): added check for object equality in the comparison instructions. Added short-circuit for != length strings in INST_EQ, INST_NEQ and INST_STR_CMP. Reworked INST_STR_CMP to use TclpUtfNcmp2 where appropriate, and only use Tcl_UniCharNcmp when at least one of the objects is a Unicode obj with no utf bytes.
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r--generic/tclExecute.c91
1 files changed, 59 insertions, 32 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index f6d2ea2..bbe2728 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclExecute.c,v 1.53 2002/04/18 13:04:20 msofer Exp $
+ * RCS: @(#) $Id: tclExecute.c,v 1.54 2002/05/29 09:09:57 hobbs Exp $
*/
#include "tclInt.h"
@@ -2718,7 +2718,7 @@ TclExecuteByteCode(interp, codePtr)
/*
* String compare
*/
- char *s1, *s2;
+ CONST char *s1, *s2;
int s1len, s2len, iResult;
value2Ptr = POP_OBJECT();
@@ -2728,18 +2728,25 @@ TclExecuteByteCode(interp, codePtr)
* The comparison function should compare up to the
* minimum byte length only.
*/
- if ((valuePtr->typePtr == &tclByteArrayType) &&
+ if (valuePtr == value2Ptr) {
+ /*
+ * In the pure equality case, set lengths too for
+ * the checks below (or we could goto beyond it).
+ */
+ iResult = s1len = s2len = 0;
+ } else if ((valuePtr->typePtr == &tclByteArrayType) &&
(value2Ptr->typePtr == &tclByteArrayType)) {
s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
iResult = memcmp(s1, s2,
(size_t) ((s1len < s2len) ? s1len : s2len));
- } else if ((valuePtr->typePtr == &tclStringType) ||
- (value2Ptr->typePtr == &tclStringType)) {
+ } else if (((valuePtr->typePtr == &tclStringType)
+ && (valuePtr->bytes == NULL))
+ || ((value2Ptr->typePtr == &tclStringType)
+ && (value2Ptr->bytes == NULL))) {
/*
- * The alternative is to break this into more code
- * that does type sensitive comparison, as done in
- * Tcl_StringObjCmd.
+ * Do a unicode-specific comparison if one of the args
+ * only has the unicode rep.
*/
Tcl_UniChar *uni1, *uni2;
uni1 = Tcl_GetUnicodeFromObj(valuePtr, &s1len);
@@ -2748,21 +2755,12 @@ TclExecuteByteCode(interp, codePtr)
(unsigned) ((s1len < s2len) ? s1len : s2len));
} else {
/*
- * This solution is less mem intensive, but it is
- * computationally expensive as the string grows. The
- * reason that we can't use a memcmp is that UTF-8 strings
- * that contain a \u0000 can't be compared with memcmp. If
- * we knew that the string was ascii-7 or had no null byte,
- * we could just do memcmp and save all the hassle.
+ * We can't do a simple memcmp in order to handle the
+ * special Tcl \xC0\x80 null encoding for utf-8.
*/
s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
- /*
- * These have to be in true chars
- */
- s1len = Tcl_NumUtfChars(s1, s1len);
- s2len = Tcl_NumUtfChars(s2, s2len);
- iResult = Tcl_UtfNcmp(s1, s2,
+ iResult = TclpUtfNcmp2(s1, s2,
(size_t) ((s1len < s2len) ? s1len : s2len));
}
@@ -2931,6 +2929,26 @@ TclExecuteByteCode(interp, codePtr)
value2Ptr = POP_OBJECT();
valuePtr = POP_OBJECT();
+
+ if (valuePtr == value2Ptr) {
+ /*
+ * Optimize the equal object case.
+ */
+ switch (*pc) {
+ case INST_EQ:
+ case INST_LE:
+ case INST_GE:
+ iResult = 1;
+ break;
+ case INST_NEQ:
+ case INST_LT:
+ case INST_GT:
+ iResult = 0;
+ break;
+ }
+ goto foundResult;
+ }
+
t1Ptr = valuePtr->typePtr;
t2Ptr = value2Ptr->typePtr;
@@ -2967,30 +2985,39 @@ TclExecuteByteCode(interp, codePtr)
if (!IS_NUMERIC_TYPE(t1Ptr) || !IS_NUMERIC_TYPE(t2Ptr)) {
/*
* One operand is not numeric. Compare as strings.
- * NOTE: strcmp is not correct for \x00 < \x01.
+ * NOTE: strcmp is not correct for \x00 < \x01, but
+ * that is unlikely to occur here. We could use the
+ * TclUtfNCmp2 to handle this.
*/
- int cmpValue;
- s1 = TclGetString(valuePtr);
- s2 = TclGetString(value2Ptr);
- cmpValue = strcmp(s1, s2);
+ int s1len, s2len;
+ s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
+ s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
switch (*pc) {
case INST_EQ:
- iResult = (cmpValue == 0);
+ if (s1len == s2len) {
+ iResult = (strcmp(s1, s2) == 0);
+ } else {
+ iResult = 0;
+ }
break;
case INST_NEQ:
- iResult = (cmpValue != 0);
+ if (s1len == s2len) {
+ iResult = (strcmp(s1, s2) != 0);
+ } else {
+ iResult = 1;
+ }
break;
case INST_LT:
- iResult = (cmpValue < 0);
+ iResult = (strcmp(s1, s2) < 0);
break;
case INST_GT:
- iResult = (cmpValue > 0);
+ iResult = (strcmp(s1, s2) > 0);
break;
case INST_LE:
- iResult = (cmpValue <= 0);
+ iResult = (strcmp(s1, s2) <= 0);
break;
case INST_GE:
- iResult = (cmpValue >= 0);
+ iResult = (strcmp(s1, s2) >= 0);
break;
}
} else if ((t1Ptr == &tclDoubleType)
@@ -3094,7 +3121,7 @@ TclExecuteByteCode(interp, codePtr)
/*
* Reuse the valuePtr object already on stack if possible.
*/
-
+ foundResult:
TRACE(("%.20s %.20s => %ld\n",
O2S(valuePtr), O2S(value2Ptr), iResult));
if (Tcl_IsShared(valuePtr)) {