summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2008-07-20 17:55:37 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2008-07-20 17:55:37 (GMT)
commitde532c94fa09b0520a3bba6eaa50d3f9f57b8000 (patch)
tree57b34596857bc91b086de0279a1353e7cbecaa4a
parent9626da61ad1682531ef02f2c327a9d7c274ac7dd (diff)
downloadtcl-de532c94fa09b0520a3bba6eaa50d3f9f57b8000.zip
tcl-de532c94fa09b0520a3bba6eaa50d3f9f57b8000.tar.gz
tcl-de532c94fa09b0520a3bba6eaa50d3f9f57b8000.tar.bz2
Fix [Bug 2008248] and make dict->list->dict round trip efficient to boot.
-rw-r--r--ChangeLog7
-rw-r--r--generic/tclDictObj.c11
-rw-r--r--generic/tclListObj.c57
3 files changed, 63 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 7966665..ebe7ee7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2008-07-20 Donal K. Fellows <dkf@users.sf.net>
+ * generic/tclDictObj.c (SetDictFromAny): Make the list->dict
+ transformation a bit more efficient; modern dicts are ordered and so
+ we can round-trip through lists without needing the string rep at all.
+ * generic/tclListObj.c (SetListFromAny): Make the dict->list
+ transformation not lossy of internal representations and hence more
+ efficient. [Bug 2008248] (ajpasadyn) but using a more efficient patch.
+
* tests/fileName.test: Revise to reduce the obscurity of tests. In
particular, all tests should now produce informative messages on
failure and the quantity of [catch]-based obscurity is now greatly
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index 2694cf8..eb56e4a 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclDictObj.c,v 1.65 2008/07/19 22:50:42 nijtmans Exp $
+ * RCS: @(#) $Id: tclDictObj.c,v 1.66 2008/07/20 17:55:50 dkf Exp $
*/
#include "tclInt.h"
@@ -593,15 +593,6 @@ SetDictFromAny(
}
/*
- * If the list is shared its string rep must not be lost so it still
- * is the same list.
- */
-
- if (Tcl_IsShared(objPtr)) {
- (void) TclGetString(objPtr);
- }
-
- /*
* Build the hash of key/value pairs.
*/
diff --git a/generic/tclListObj.c b/generic/tclListObj.c
index d04fb45..6cf903b 100644
--- a/generic/tclListObj.c
+++ b/generic/tclListObj.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclListObj.c,v 1.50 2008/04/27 22:21:30 dkf Exp $
+ * RCS: @(#) $Id: tclListObj.c,v 1.51 2008/07/20 17:55:51 dkf Exp $
*/
#include "tclInt.h"
@@ -1658,6 +1658,58 @@ SetListFromAny(
List *listRepPtr;
/*
+ * Dictionaries are a special case; they have a string representation such
+ * that *all* valid dictionaries are valid lists. Hence we can convert
+ * more directly.
+ */
+
+ if (objPtr->typePtr == &tclDictType) {
+ Tcl_Obj *keyPtr, *valuePtr;
+ Tcl_DictSearch search;
+ int done, size;
+
+ /*
+ * Create the new list representation. Note that we do not need to do
+ * anything with the string representation as the transformation (and
+ * the reverse back to a dictionary) are both order-preserving. Also
+ * note that since we know we've got a valid dictionary (by
+ * representation) we also know that fetching the size of the
+ * dictionary or iterating over it will not fail.
+ */
+
+ Tcl_DictObjSize(NULL, objPtr, &size);
+ listRepPtr = NewListIntRep(size > 0 ? 2*size : 1, NULL);
+ if (!listRepPtr) {
+ Tcl_SetResult(interp,
+ "insufficient memory to allocate list working space",
+ TCL_STATIC);
+ return TCL_ERROR;
+ }
+ listRepPtr->elemCount = 2 * size;
+
+ /*
+ * Populate the list representation.
+ */
+
+ elemPtrs = &listRepPtr->elements;
+ Tcl_DictObjFirst(NULL, objPtr, &search, &keyPtr, &valuePtr, &done);
+ i = 0;
+ while (!done) {
+ elemPtrs[i++] = keyPtr;
+ elemPtrs[i++] = valuePtr;
+ Tcl_IncrRefCount(keyPtr);
+ Tcl_IncrRefCount(valuePtr);
+ Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
+ }
+
+ /*
+ * Swap the representations.
+ */
+
+ goto commitRepresentation;
+ }
+
+ /*
* Get the string representation. Make it up-to-date if necessary.
*/
@@ -1742,9 +1794,10 @@ SetListFromAny(
* Tcl_GetStringFromObj, to use that old internalRep.
*/
+ commitRepresentation:
listRepPtr->refCount++;
TclFreeIntRep(objPtr);
- objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
+ objPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
objPtr->internalRep.twoPtrValue.ptr2 = NULL;
objPtr->typePtr = &tclListType;
return TCL_OK;