summaryrefslogtreecommitdiffstats
path: root/generic/tclDictObj.c
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2023-08-20 13:26:21 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2023-08-20 13:26:21 (GMT)
commitbc67254346b5726b9d6d1873e558c0cc73b6607c (patch)
treeb44a73f2eb12f5c94ff97cf6945e26e67ec29886 /generic/tclDictObj.c
parentdf59030308f1bd19d2618f47f7e046d6c29695da (diff)
downloadtcl-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.c164
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