diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2008-07-20 22:02:36 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2008-07-20 22:02:36 (GMT) |
commit | 4102bed2736a6e342da6b5f44520c4bd9f8f993b (patch) | |
tree | 3ba82ab837c22df5e44f381d1fa2f4dd661f4e40 /generic/tclListObj.c | |
parent | 1b5339323d5019362fce5d4438be34421f337dc8 (diff) | |
download | tcl-4102bed2736a6e342da6b5f44520c4bd9f8f993b.zip tcl-4102bed2736a6e342da6b5f44520c4bd9f8f993b.tar.gz tcl-4102bed2736a6e342da6b5f44520c4bd9f8f993b.tar.bz2 |
Fix [Bug 2008248] and make dict->list->dict round trip efficient to boot.
Diffstat (limited to 'generic/tclListObj.c')
-rw-r--r-- | generic/tclListObj.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 556a41d..2bbaa22 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.49 2007/12/13 15:23:18 dgp Exp $ + * RCS: @(#) $Id: tclListObj.c,v 1.49.2.1 2008/07/20 22:02:39 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,6 +1794,7 @@ SetListFromAny( * Tcl_GetStringFromObj, to use that old internalRep. */ + commitRepresentation: listRepPtr->refCount++; TclFreeIntRep(objPtr); objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr; |