summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpooryorick <com.digitalsmarties@pooryorick.com>2016-07-10 23:07:47 (GMT)
committerpooryorick <com.digitalsmarties@pooryorick.com>2016-07-10 23:07:47 (GMT)
commitb72f659998fee56defeaa1dae2d98dafab30a574 (patch)
tree1d858b72944dfa9d5ec698e95ddb33e92e23b6ca
parent2de34a7674bffea69b889e1326b18e442d8e8589 (diff)
downloadtcl-b72f659998fee56defeaa1dae2d98dafab30a574.zip
tcl-b72f659998fee56defeaa1dae2d98dafab30a574.tar.gz
tcl-b72f659998fee56defeaa1dae2d98dafab30a574.tar.bz2
Avoid generating string representation for comparisons against empty string.
-rw-r--r--generic/tclExecute.c59
-rw-r--r--generic/tclInt.h6
-rw-r--r--generic/tclStringObj.c48
3 files changed, 108 insertions, 5 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index ac4076c..67c58fc 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -5443,22 +5443,57 @@ TEBCresume(
}
} else {
/*
- * strcmp can't do a simple memcmp in order to handle the
- * special Tcl \xC0\x80 null encoding for utf-8.
+ * In order to handle the special Tcl \xC0\x80 null encoding
+ * for utf-8, strcmp can't do a simple memcmp.
*/
- s1 = TclGetStringFromObj(valuePtr, &s1len);
- s2 = TclGetStringFromObj(value2Ptr, &s2len);
+ if (TclIsEmpty(valuePtr) > 0) {
+ s1 = "";
+ s1len = 0;
+ switch (TclIsEmpty(value2Ptr)) {
+ case -1:
+ s2 = TclGetStringFromObj(value2Ptr, &s2len);
+ case 0:
+ /* Synthesize a value for comparison */
+ s2 = "1";
+ s2len = 1;
+ break;
+ case 1:
+ s2 = "";
+ s2len = 0;
+ }
+ } else if (TclIsEmpty(value2Ptr) > 0) {
+ s2 = "";
+ s2len = 0;
+ switch (TclIsEmpty(valuePtr)) {
+ case -1:
+ s1 = TclGetStringFromObj(valuePtr, &s1len);
+ break;
+ case 0:
+ /* Synthesize a value for comparison */
+ s1 = "1";
+ s1len = 1;
+ break;
+ case 1:
+ s1 = "";
+ s1len = 0;
+ }
+ } else {
+ s1 = TclGetStringFromObj(valuePtr, &s1len);
+ s2 = TclGetStringFromObj(value2Ptr, &s2len);
+ }
+
if (checkEq) {
memCmpFn = memcmp;
} else {
memCmpFn = (memCmpFn_t) TclpUtfNcmp2;
}
+
}
if (checkEq && (s1len != s2len)) {
match = 1;
- } else {
+ } else {
/*
* The comparison function should compare up to the minimum
* byte length only.
@@ -6169,6 +6204,20 @@ TEBCresume(
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
+ /*
+ Try to determine, without triggering generation of a string
+ representation, whether one value is not a number.
+ */
+# define TclIsNotNumber(objPtr) ( \
+ ( TclIsEmpty((objPtr)) > 0 \
+ || ( (objPtr)->bytes != NULL && \
+ TclParseNumber( \
+ interp, (objPtr), "number", NULL, -1, NULL, 0) != TCL_OK)) \
+ )
+ if (TclIsNotNumber(valuePtr) || TclIsNotNumber(value2Ptr)) {
+ goto stringCompare;
+ }
+
if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
/*
* At least one non-numeric argument - compare as strings.
diff --git a/generic/tclInt.h b/generic/tclInt.h
index c01b0c1..817f17d 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -4411,6 +4411,12 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file,
#define TclIsPureByteArray(objPtr) \
(((objPtr)->typePtr==&tclByteArrayType) && ((objPtr)->bytes==NULL))
+#define TclIsPureDict(objPtr) \
+ (((objPtr)->typePtr==&tclDictType) && ((objPtr)->bytes==NULL))
+
+#define TclIsPureList(objPtr) \
+ (((objPtr)->typePtr==&tclListType) && ((objPtr)->bytes==NULL))
+
/*
*----------------------------------------------------------------
* Macro used by the Tcl core to compare Unicode strings. On big-endian
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c
index e3cede6..de3a82e 100644
--- a/generic/tclStringObj.c
+++ b/generic/tclStringObj.c
@@ -421,6 +421,7 @@ Tcl_GetCharLength(
return length;
}
+
/*
* OK, need to work with the object as a string.
*/
@@ -439,6 +440,53 @@ Tcl_GetCharLength(
}
return numChars;
}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclIsEmpty --
+ *
+ * Determine whether the string value of an object is or would be the
+ * empty string, without generating a string representation.
+ *
+ * Results:
+ * Returns 1 if empty, 0 if not, and -1 if unknown.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+int
+TclIsEmpty (
+ Tcl_Obj *objPtr
+) {
+ int length = -1;
+
+ if (objPtr->bytes == tclEmptyStringRep) {
+ return 1;
+ }
+
+ if (TclIsPureList(objPtr)) {
+ Tcl_ListObjLength(NULL, objPtr, &length);
+ return length == 0;
+ }
+
+ if (TclIsPureDict(objPtr)) {
+ Tcl_DictObjSize(NULL, objPtr, &length);
+ return length == 0;
+ }
+
+ if (objPtr->bytes == NULL) {
+ return -1;
+ }
+ if (objPtr->bytes[0] == '\0') {
+ return 1;
+ }
+ return 0;
+}
/*
*----------------------------------------------------------------------