summaryrefslogtreecommitdiffstats
path: root/generic/tclDictObj.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2011-05-10 16:05:48 (GMT)
committerdgp <dgp@users.sourceforge.net>2011-05-10 16:05:48 (GMT)
commitf9dece7738d140a66ebb5d47ee85c4d57249258a (patch)
tree1ca2feda250662282a8e77080fef123d9256b839 /generic/tclDictObj.c
parentb1c2f2c9c6fcb329f1e23f9f5f1ef53c84b01bae (diff)
downloadtcl-f9dece7738d140a66ebb5d47ee85c4d57249258a.zip
tcl-f9dece7738d140a66ebb5d47ee85c4d57249258a.tar.gz
tcl-f9dece7738d140a66ebb5d47ee85c4d57249258a.tar.bz2
Completed patch with mucho comments. Merge 8.5.bug_3173086
Diffstat (limited to 'generic/tclDictObj.c')
-rw-r--r--generic/tclDictObj.c192
1 files changed, 69 insertions, 123 deletions
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index 072f3fa..06c5754 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -402,6 +402,7 @@ FreeDictInternalRep(
}
dictPtr->internalRep.otherValuePtr = NULL; /* Belt and braces! */
+ dictPtr->typePtr = NULL;
}
/*
@@ -488,7 +489,7 @@ UpdateStringOfDict(
if (numElems <= LOCAL_SIZE) {
flagPtr = localFlags;
} else if (numElems > maxFlags) {
- Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits");
+ Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
} else {
flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int));
}
@@ -503,7 +504,7 @@ UpdateStringOfDict(
elem = TclGetStringFromObj(keyPtr, &length);
bytesNeeded += TclScanElement(elem, length, flagPtr+i);
if (bytesNeeded < 0) {
- Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits");
+ Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
}
flagPtr[i+1] = TCL_DONT_QUOTE_HASH;
@@ -511,11 +512,11 @@ UpdateStringOfDict(
elem = TclGetStringFromObj(valuePtr, &length);
bytesNeeded += TclScanElement(elem, length, flagPtr+i+1);
if (bytesNeeded < 0) {
- Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits");
+ Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
}
}
if (bytesNeeded > INT_MAX - numElems + 1) {
- Tcl_Panic("UpdateStringOfDict: size requirement exceeds limits");
+ Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
}
bytesNeeded += numElems;
@@ -571,14 +572,11 @@ SetDictFromAny(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
- char *string, *s;
- const char *elemStart, *nextElem;
- int lenRemain, length, elemSize, hasBrace, result, isNew;
- char *limit; /* Points just after string's last byte. */
- register const char *p;
- register Tcl_Obj *keyPtr, *valuePtr;
- Dict *dict;
Tcl_HashEntry *hPtr;
+ int isNew, result;
+ Dict *dict = (Dict *) ckalloc(sizeof(Dict));
+
+ InitChainTable(dict);
/*
* Since lists and dictionaries have very closely-related string
@@ -590,28 +588,15 @@ SetDictFromAny(
int objc, i;
Tcl_Obj **objv;
- if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;
- }
+ /* Cannot fail, we already know the Tcl_ObjType is "list". */
+ TclListObjGetElements(NULL, objPtr, &objc, &objv);
if (objc & 1) {
- if (interp != NULL) {
- Tcl_SetResult(interp, "missing value to go with key",
- TCL_STATIC);
- }
- return TCL_ERROR;
+ goto missingValue;
}
- /*
- * Build the hash of key/value pairs.
- */
-
- dict = (Dict *) ckalloc(sizeof(Dict));
- InitChainTable(dict);
for (i=0 ; i<objc ; i+=2) {
- /*
- * Store key and value in the hash table we're building.
- */
-
+
+ /* Store key and value in the hash table we're building. */
hPtr = CreateChainEntry(dict, objv[i], &isNew);
if (!isNew) {
Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);
@@ -629,106 +614,68 @@ SetDictFromAny(
Tcl_SetHashValue(hPtr, objv[i+1]);
Tcl_IncrRefCount(objv[i+1]); /* Since hash now holds ref to it */
}
+ } else {
+ int length;
+ const char *nextElem = TclGetStringFromObj(objPtr, &length);
+ const char *limit = (nextElem + length);
+
+ while (nextElem < limit) {
+ Tcl_Obj *keyPtr, *valuePtr;
+ const char *elemStart;
+ int elemSize, literal;
+
+ result = TclFindElement(interp, nextElem, (limit - nextElem),
+ &elemStart, &nextElem, &elemSize, &literal);
+ if (result != TCL_OK) {
+ goto errorExit;
+ }
+ if (elemStart == limit) {
+ break;
+ }
+ if (nextElem == limit) {
+ goto missingValue;
+ }
- /*
- * Share type-setting code with the string-conversion case.
- */
-
- goto installHash;
- }
-
- /*
- * Get the string representation. Make it up-to-date if necessary.
- */
-
- string = TclGetStringFromObj(objPtr, &length);
- limit = (string + length);
-
- /*
- * Allocate a new HashTable that has objects for keys and objects for
- * values.
- */
-
- dict = (Dict *) ckalloc(sizeof(Dict));
- InitChainTable(dict);
- for (p = string, lenRemain = length;
- lenRemain > 0;
- p = nextElem, lenRemain = (limit - nextElem)) {
- result = TclFindElement(interp, p, lenRemain,
- &elemStart, &nextElem, &elemSize, &hasBrace);
- if (result != TCL_OK) {
- goto errorExit;
- }
- if (elemStart >= limit) {
- break;
- }
-
- /*
- * 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(keyPtr);
- keyPtr->bytes = s;
- keyPtr->length = elemSize;
-
- p = nextElem;
- lenRemain = (limit - nextElem);
- if (lenRemain <= 0) {
- goto missingKey;
- }
-
- result = TclFindElement(interp, p, lenRemain,
- &elemStart, &nextElem, &elemSize, &hasBrace);
- if (result != TCL_OK) {
- TclDecrRefCount(keyPtr);
- goto errorExit;
- }
- if (elemStart >= limit) {
- goto missingKey;
- }
-
- /*
- * 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((void *) s, (void *) elemStart, (size_t) elemSize);
- s[elemSize] = 0;
- } else {
- elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
- }
+ if (literal) {
+ TclNewStringObj(keyPtr, elemStart, elemSize);
+ } else {
+ /* Avoid double copy */
+ TclNewObj(keyPtr);
+ keyPtr->bytes = ckalloc((unsigned) elemSize + 1);
+ keyPtr->length = TclCopyAndCollapse(elemSize, elemStart,
+ keyPtr->bytes);
+ }
- TclNewObj(valuePtr);
- valuePtr->bytes = s;
- valuePtr->length = elemSize;
+ result = TclFindElement(interp, nextElem, (limit - nextElem),
+ &elemStart, &nextElem, &elemSize, &literal);
+ if (result != TCL_OK) {
+ TclDecrRefCount(keyPtr);
+ goto errorExit;
+ }
- /*
- * Store key and value in the hash table we're building.
- */
+ if (literal) {
+ TclNewStringObj(valuePtr, elemStart, elemSize);
+ } else {
+ /* Avoid double copy */
+ TclNewObj(valuePtr);
+ valuePtr->bytes = ckalloc((unsigned) elemSize + 1);
+ valuePtr->length = TclCopyAndCollapse(elemSize, elemStart,
+ valuePtr->bytes);
+ }
- hPtr = CreateChainEntry(dict, keyPtr, &isNew);
- if (!isNew) {
- Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);
+ /* Store key and value in the hash table we're building. */
+ hPtr = CreateChainEntry(dict, keyPtr, &isNew);
+ if (!isNew) {
+ Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);
- TclDecrRefCount(keyPtr);
- TclDecrRefCount(discardedValue);
+ TclDecrRefCount(keyPtr);
+ TclDecrRefCount(discardedValue);
+ }
+ Tcl_SetHashValue(hPtr, valuePtr);
+ Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */
}
- Tcl_SetHashValue(hPtr, valuePtr);
- Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */
}
- installHash:
/*
* Free the old internalRep before setting the new one. We do this as late
* as possible to allow the conversion code, in particular
@@ -743,11 +690,10 @@ SetDictFromAny(
objPtr->typePtr = &tclDictType;
return TCL_OK;
- missingKey:
+ missingValue:
if (interp != NULL) {
Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC);
}
- TclDecrRefCount(keyPtr);
result = TCL_ERROR;
errorExit: