diff options
author | apnadkarni <apnmbx-wits@yahoo.com> | 2023-08-20 13:26:21 (GMT) |
---|---|---|
committer | apnadkarni <apnmbx-wits@yahoo.com> | 2023-08-20 13:26:21 (GMT) |
commit | bc67254346b5726b9d6d1873e558c0cc73b6607c (patch) | |
tree | b44a73f2eb12f5c94ff97cf6945e26e67ec29886 /generic/tclDictObj.c | |
parent | df59030308f1bd19d2618f47f7e046d6c29695da (diff) | |
download | tcl-bc67254346b5726b9d6d1873e558c0cc73b6607c.zip tcl-bc67254346b5726b9d6d1873e558c0cc73b6607c.tar.gz tcl-bc67254346b5726b9d6d1873e558c0cc73b6607c.tar.bz2 |
Back out [2a01c62b1a55a] - causes tcllib failures.
Diffstat (limited to 'generic/tclDictObj.c')
-rw-r--r-- | generic/tclDictObj.c | 164 |
1 files changed, 133 insertions, 31 deletions
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 5cb7b64..64d666f 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -62,6 +62,7 @@ static Tcl_ObjCmdProc DictMapNRCmd; static Tcl_NRPostProc DictForLoopCallback; static Tcl_NRPostProc DictMapLoopCallback; static Tcl_ObjTypeLengthProc DictAsListLength; +/* static Tcl_ObjTypeIndexProc DictAsListIndex; Needs rewrite */ /* * Table of dict subcommand names and implementations. @@ -135,7 +136,6 @@ typedef struct Dict { Tcl_Obj *chain; /* Linked list used for invalidating the * string representations of updated nested * dictionaries. */ - Tcl_Size llength; /* cache list length */ } Dict; /* @@ -152,8 +152,9 @@ const Tcl_ObjType tclDictType = { TCL_OBJTYPE_V2( /* Extended type for AbstractLists */ DictAsListLength, /* return "list" length of dict value w/o * shimmering */ - NULL, /* Shimmering here is the most efficient - * option. */ + NULL, /* return key or value at "list" index + * location. (keysare at even indicies, + * values at odd indicies) */ NULL, NULL, NULL, @@ -403,7 +404,6 @@ DupDictInternalRep( newDict->epoch = 1; newDict->chain = NULL; newDict->refCount = 1; - newDict->llength = oldDict->llength; /* * Store in the object. @@ -574,9 +574,6 @@ UpdateStringOfDict( /* Last space overwrote the terminating NUL; cal T_ISR again to restore */ (void)Tcl_InitStringRep(dictPtr, NULL, bytesNeeded - 1); - /* Update cached llength. In this case, llength matches numElems by definition. */ - dict->llength = numElems; - if (flagPtr != localFlags) { Tcl_Free(flagPtr); } @@ -610,7 +607,6 @@ SetDictFromAny( Tcl_HashEntry *hPtr; int isNew; Dict *dict = (Dict *)Tcl_Alloc(sizeof(Dict)); - int llength = 0; InitChainTable(dict); @@ -650,10 +646,6 @@ SetDictFromAny( Tcl_SetHashValue(hPtr, objv[i+1]); Tcl_IncrRefCount(objv[i+1]); /* Since hash now holds ref to it */ } - - /* llength is list length */ - llength = objc; - } else { Tcl_Size length; const char *nextElem = Tcl_GetStringFromObj(objPtr, &length); @@ -690,9 +682,6 @@ SetDictFromAny( TclCopyAndCollapse(elemSize, elemStart, dst)); } - /* count the elements */ - llength++; - if (TclFindDictElement(interp, nextElem, (limit - nextElem), &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) { TclDecrRefCount(keyPtr); @@ -713,9 +702,6 @@ SetDictFromAny( TclCopyAndCollapse(elemSize, elemStart, dst)); } - /* count the elements */ - llength++; - /* Store key and value in the hash table we're building. */ hPtr = CreateChainEntry(dict, keyPtr, &isNew); if (!isNew) { @@ -738,7 +724,6 @@ SetDictFromAny( dict->epoch = 1; dict->chain = NULL; dict->refCount = 1; - dict->llength = llength; DictSetInternalRep(objPtr, dict); return TCL_OK; @@ -979,8 +964,6 @@ Tcl_DictObjPut( Tcl_Obj *oldValuePtr = (Tcl_Obj *)Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); - } else { - dict->llength += 2; } Tcl_SetHashValue(hPtr, valuePtr); dict->epoch++; @@ -1070,7 +1053,6 @@ Tcl_DictObjRemove( if (DeleteChainEntry(dict, keyPtr)) { TclInvalidateStringRep(dictPtr); - dict->llength -= 2; dict->epoch++; } return TCL_OK; @@ -1360,8 +1342,6 @@ Tcl_DictObjPutKeyList( Tcl_Obj *oldValuePtr = (Tcl_Obj *)Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); - } else { - dict->llength += 2; } Tcl_SetHashValue(hPtr, valuePtr); InvalidateDictChain(dictPtr); @@ -1415,7 +1395,6 @@ Tcl_DictObjRemoveKeyList( DictGetInternalRep(dictPtr, dict); assert(dict != NULL); DeleteChainEntry(dict, keyv[keyc-1]); - dict->llength -= 2; InvalidateDictChain(dictPtr); return TCL_OK; } @@ -1459,7 +1438,6 @@ Tcl_NewDictObj(void) InitChainTable(dict); dict->epoch = 1; dict->chain = NULL; - dict->llength = 0; dict->refCount = 1; DictSetInternalRep(dictPtr, dict); return dictPtr; @@ -1508,7 +1486,6 @@ Tcl_DbNewDictObj( InitChainTable(dict); dict->epoch = 1; dict->chain = NULL; - dict->llength = 0; dict->refCount = 1; DictSetInternalRep(dictPtr, dict); return dictPtr; @@ -3844,14 +3821,139 @@ static Tcl_Size DictAsListLength( Tcl_Obj *objPtr) { - Dict *dict; + Tcl_Size estCount, length, llen; + const char *limit, *nextElem = Tcl_GetStringFromObj(objPtr, &length); + Tcl_Obj *elemPtr; - DictGetInternalRep(objPtr, dict); - assert(dict != NULL); + /* + * Allocate enough space to hold a (Tcl_Obj *) for each + * (possible) list element. + */ + + estCount = TclMaxListLength(nextElem, length, &limit); + estCount += (estCount == 0); /* Smallest list struct holds 1 + * element. */ + elemPtr = Tcl_NewObj(); - return dict->llength; + llen = 0; + + while (nextElem < limit) { + const char *elemStart; + char *check; + Tcl_Size elemSize; + int literal; + + if (TCL_OK != TclFindElement(NULL, nextElem, limit - nextElem, + &elemStart, &nextElem, &elemSize, &literal)) { + Tcl_DecrRefCount(elemPtr); + return 0; + } + if (elemStart == limit) { + break; + } + + TclInvalidateStringRep(elemPtr); + check = Tcl_InitStringRep(elemPtr, literal ? elemStart : NULL, + elemSize); + if (elemSize && check == NULL) { + Tcl_DecrRefCount(elemPtr); + return 0; + } + if (!literal) { + Tcl_InitStringRep(elemPtr, NULL, + TclCopyAndCollapse(elemSize, elemStart, check)); + } + llen++; + } + Tcl_DecrRefCount(elemPtr); + return llen; } + +/* + *---------------------------------------------------------------------- + * + * DictAsListIndex -- + * + * Return the key or value at the given "list" index, i.e., as if the string + * value where treated as a list. The intent is to support this list + * operation w/o causing the Obj value to shimmer into a List. + * + * Side Effects -- + * + * The intent is to have no side effects. + * + */ +#if 0 /* Needs rewrite */ +static int +DictAsListIndex( + Tcl_Interp *interp, + struct Tcl_Obj *objPtr, + Tcl_Size index, + Tcl_Obj** elemObjPtr) +{ + Tcl_Size /*estCount,*/ length, llen; + const char *limit, *nextElem = Tcl_GetStringFromObj(objPtr, &length); + Tcl_Obj *elemPtr; + + /* + * Compute limit of the list string + */ + + TclMaxListLength(nextElem, length, &limit); + elemPtr = Tcl_NewObj(); + + llen = 0; + + /* + * parse out each element until reaching the "index"th element. + * Sure this is slow, but shimmering is slower. + */ + while (nextElem < limit) { + const char *elemStart; + char *check; + Tcl_Size elemSize; + int literal; + + if (TCL_OK != TclFindElement(NULL, nextElem, limit - nextElem, + &elemStart, &nextElem, &elemSize, &literal)) { + Tcl_DecrRefCount(elemPtr); + return 0; + } + if (elemStart == limit) { + break; + } + + TclInvalidateStringRep(elemPtr); + check = Tcl_InitStringRep(elemPtr, literal ? elemStart : NULL, + elemSize); + if (elemSize && check == NULL) { + Tcl_DecrRefCount(elemPtr); + if (interp) { + // Need error message here + } + return TCL_ERROR; + } + if (!literal) { + Tcl_InitStringRep(elemPtr, NULL, + TclCopyAndCollapse(elemSize, elemStart, check)); + } + if (llen == index) { + *elemObjPtr = elemPtr; + return TCL_OK; + } + llen++; + } + + /* + * Index is beyond end of list - return empty + */ + Tcl_InitStringRep(elemPtr, NULL, 0); + *elemObjPtr = elemPtr; + return TCL_OK; +} +#endif + /* * Local Variables: * mode: c |