Tcl Source Code

Check-in [7855873798]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Remove abstractlist extension from dict objtype.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bug28cc67a606a7
Files: files | file ages | folders
SHA3-256: 785587379819603ce0ba2a4217799371980222bed8e3d8b00aa9db4046258775
User & Date: griffin 2024-04-22 01:49:29
Context
2024-04-25
19:49
Fix dict performance bug: Remove abstractlist extension from dict objtype. check-in: 0c1a114cc4 user: griffin tags: trunk, main
2024-04-22
01:49
Remove abstractlist extension from dict objtype. Leaf check-in: 7855873798 user: griffin tags: bug28cc67a606a7
2024-04-21
20:58
TIP #692: Revise Tcl_GetAliasObj, remove Tcl_GetAlias() check-in: f6b34ee2a9 user: jan.nijtmans tags: trunk, main
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclDictObj.c.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
					Tcl_Obj *keyPtr);
static Tcl_NRPostProc		FinalizeDictUpdate;
static Tcl_NRPostProc		FinalizeDictWith;
static Tcl_ObjCmdProc		DictForNRCmd;
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.
 */

static const EnsembleImplMap implementationMap[] = {
    {"append",	DictAppendCmd,	TclCompileDictAppendCmd, NULL, NULL, 0 },







<
<







57
58
59
60
61
62
63


64
65
66
67
68
69
70
					Tcl_Obj *keyPtr);
static Tcl_NRPostProc		FinalizeDictUpdate;
static Tcl_NRPostProc		FinalizeDictWith;
static Tcl_ObjCmdProc		DictForNRCmd;
static Tcl_ObjCmdProc		DictMapNRCmd;
static Tcl_NRPostProc		DictForLoopCallback;
static Tcl_NRPostProc		DictMapLoopCallback;



/*
 * Table of dict subcommand names and implementations.
 */

static const EnsembleImplMap implementationMap[] = {
    {"append",	DictAppendCmd,	TclCompileDictAppendCmd, NULL, NULL, 0 },
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
				 * dictionary. Used for doing traversal of the
				 * entries in the order that they are
				 * created. */
    ChainEntry *entryChainTail;	/* Other end of linked list of all entries in
				 * the dictionary. Used for doing traversal of
				 * the entries in the order that they are
				 * created. */
    size_t epoch; 	/* Epoch counter */
    size_t refCount;		/* Reference counter (see above) */
    Tcl_Obj *chain;		/* Linked list used for invalidating the
				 * string representations of updated nested
				 * dictionaries. */
} Dict;

/*
 * The structure below defines the dictionary object type by means of
 * functions that can be invoked by generic object code.
 */

const Tcl_ObjType tclDictType = {
    "dict",
    FreeDictInternalRep,	/* freeIntRepProc */
    DupDictInternalRep,		/* dupIntRepProc */
    UpdateStringOfDict,		/* updateStringProc */
    SetDictFromAny,		/* setFromAnyProc */
    TCL_OBJTYPE_V2(		/* Extended type for AbstractLists */
    DictAsListLength,		/* return "list" length of dict value w/o
				 * shimmering */
    NULL,			/* return key or value at "list" index
				 * location.  (keysare at even indicies,
				 * values at odd indicies) */
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL)
};

#define DictSetInternalRep(objPtr, dictRepPtr)				\
    do {                                                                \
        Tcl_ObjInternalRep ir;                                               \
        ir.twoPtrValue.ptr1 = (dictRepPtr);                             \
        ir.twoPtrValue.ptr2 = NULL;                                     \
        Tcl_StoreInternalRep((objPtr), &tclDictType, &ir);                   \
    } while (0)

#define DictGetInternalRep(objPtr, dictRepPtr)				\
    do {                                                                \
        const Tcl_ObjInternalRep *irPtr;                                     \
        irPtr = TclFetchInternalRep((objPtr), &tclDictType);                \
        (dictRepPtr) = irPtr ? (Dict *)irPtr->twoPtrValue.ptr1 : NULL;          \
    } while (0)

/*
 * The type of the specially adapted version of the Tcl_Obj*-containing hash
 * table defined in the tclObj.c code. This version differs in that it
 * allocates a bit more space in each hash entry in order to hold the pointers
 * used to keep the hash entries in a linked list.







|

















|
<
<
<
<
<
<
<
<
<
<
<




|


|




|
|
|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150











151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
				 * dictionary. Used for doing traversal of the
				 * entries in the order that they are
				 * created. */
    ChainEntry *entryChainTail;	/* Other end of linked list of all entries in
				 * the dictionary. Used for doing traversal of
				 * the entries in the order that they are
				 * created. */
    size_t epoch; 		/* Epoch counter */
    size_t refCount;		/* Reference counter (see above) */
    Tcl_Obj *chain;		/* Linked list used for invalidating the
				 * string representations of updated nested
				 * dictionaries. */
} Dict;

/*
 * The structure below defines the dictionary object type by means of
 * functions that can be invoked by generic object code.
 */

const Tcl_ObjType tclDictType = {
    "dict",
    FreeDictInternalRep,	/* freeIntRepProc */
    DupDictInternalRep,		/* dupIntRepProc */
    UpdateStringOfDict,		/* updateStringProc */
    SetDictFromAny,		/* setFromAnyProc */
    TCL_OBJTYPE_V0











};

#define DictSetInternalRep(objPtr, dictRepPtr)				\
    do {                                                                \
        Tcl_ObjInternalRep ir;						\
        ir.twoPtrValue.ptr1 = (dictRepPtr);                             \
        ir.twoPtrValue.ptr2 = NULL;                                     \
        Tcl_StoreInternalRep((objPtr), &tclDictType, &ir);		\
    } while (0)

#define DictGetInternalRep(objPtr, dictRepPtr)				\
    do {                                                                \
        const Tcl_ObjInternalRep *irPtr;				\
        irPtr = TclFetchInternalRep((objPtr), &tclDictType);		\
        (dictRepPtr) = irPtr ? (Dict *)irPtr->twoPtrValue.ptr1 : NULL;	\
    } while (0)

/*
 * The type of the specially adapted version of the Tcl_Obj*-containing hash
 * table defined in the tclObj.c code. This version differs in that it
 * allocates a bit more space in each hash entry in order to hold the pointers
 * used to keep the hash entries in a linked list.
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
DictSizeCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    int result;
	Tcl_Size size;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
	return TCL_ERROR;
    }
    result = Tcl_DictObjSize(interp, objv[1], &size);
    if (result == TCL_OK) {







|







2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
DictSizeCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    int result;
    Tcl_Size size;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
	return TCL_ERROR;
    }
    result = Tcl_DictObjSize(interp, objv[1], &size);
    if (result == TCL_OK) {
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017

Tcl_Command
TclInitDictCmd(
    Tcl_Interp *interp)
{
    return TclMakeEnsemble(interp, "dict", implementationMap);
}

/*
 *----------------------------------------------------------------------
 *
 * DictAsListLength --
 *
 *   Compute the length of a list as if the dict value were converted to a
 *   list.
 *
 *   Note: the list length may not match the dict size * 2.  This occurs when
 *   there are duplicate keys in the original string representation.
 *
 * Side Effects --
 *
 *   The intent is to have no side effects.
 */

static Tcl_Size
DictAsListLength(
    Tcl_Obj *objPtr)
{
    Tcl_Size estCount, length, llen;
    const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length);
    Tcl_Obj *elemPtr;

    /*
     * 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();

    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 = TclGetStringFromObj(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
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








3837
3838
3839
3840
3841
3842
3843

























































































































































3844
3845
3846
3847
3848
3849
3850
3851

Tcl_Command
TclInitDictCmd(
    Tcl_Interp *interp)
{
    return TclMakeEnsemble(interp, "dict", implementationMap);
}


























































































































































/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to tests/dict.test.

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
    }}
} -returnCodes error -result {key "d" not known in dictionary}
test dict-3.16 {dict/list shimmering - Bug 3004007} testobj {
    set l [list p 1 p 2 q 3]
    dict get $l q
    list $l [testobj objtype $l]
} {{p 1 p 2 q 3} dict}
test dict-3.17 {dict/list shimmering - Bug 3004007} testobj {
    set l [list p 1 p 2 q 3]
    dict get $l q
    list [llength $l] [testobj objtype $l]
} {6 dict}

test dict-4.1 {dict replace command} {
    dict replace {a b c d}
} {a b c d}
test dict-4.2 {dict replace command} {
    dict replace {a b c d} e f
} {a b c d e f}







<
<
<
<
<







147
148
149
150
151
152
153





154
155
156
157
158
159
160
    }}
} -returnCodes error -result {key "d" not known in dictionary}
test dict-3.16 {dict/list shimmering - Bug 3004007} testobj {
    set l [list p 1 p 2 q 3]
    dict get $l q
    list $l [testobj objtype $l]
} {{p 1 p 2 q 3} dict}






test dict-4.1 {dict replace command} {
    dict replace {a b c d}
} {a b c d}
test dict-4.2 {dict replace command} {
    dict replace {a b c d} e f
} {a b c d e f}