diff options
Diffstat (limited to 'generic/tclObj.c')
| -rw-r--r-- | generic/tclObj.c | 133 |
1 files changed, 132 insertions, 1 deletions
diff --git a/generic/tclObj.c b/generic/tclObj.c index 0c9c405..cdd3b5d 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -202,6 +202,9 @@ static void DupBignum(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); static void UpdateStringOfBignum(Tcl_Obj *objPtr); static int GetBignumFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int copy, mp_int *bignumValue); +static int SetDuplicatePureObj(Tcl_Interp *interp, + Tcl_Obj *dupPtr, Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr); /* * Prototypes for the array hash key methods. @@ -1523,6 +1526,14 @@ TclObjBeingDeleted( * Create and return a new object that is a duplicate of the argument * object. * + * TclDuplicatePureObj -- + * Like Tcl_DuplicateObj, except that it converts the duplicate to the + * specifid typ, does not duplicate the 'bytes' + * field unless it is necessary, i.e. the duplicated Tcl_Obj provides no + * updateStringProc. This can avoid an expensive memory allocation since + * the data in the 'bytes' field of each Tcl_Obj must reside in allocated + * memory. + * * Results: * The return value is a pointer to a newly created Tcl_Obj. This object * has reference count 0 and the same type, if any, as the source object @@ -1574,6 +1585,104 @@ Tcl_DuplicateObj( return dupPtr; } + +/* + *---------------------------------------------------------------------- + * + * Tcl_DuplicatePureObj -- + * + * Duplicates a Tcl_Obj and converts the internal representation of the + * duplicate to the given type, changing neither the 'bytes' field + * nor the internal representation of the original object, and without + * duplicating the bytes field unless necessary, i.e. unless the + * duplicate provides no updateStringProc after conversion. This can + * avoid an expensive memory allocation since the data in the 'bytes' + * field of each Tcl_Obj must reside in allocated memory. + * + * Results: + * A pointer to a newly-created Tcl_Obj or NULL if there was an error. + * This object has reference count 0. Also: + * + *---------------------------------------------------------------------- + */ +int SetDuplicatePureObj( + Tcl_Interp *interp, + Tcl_Obj *dupPtr, + Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr) +{ + char *bytes = objPtr->bytes; + int status = TCL_OK; + + TclInvalidateStringRep(dupPtr); + assert(dupPtr->typePtr == NULL); + + if (objPtr->typePtr && objPtr->typePtr->dupIntRepProc) { + objPtr->typePtr->dupIntRepProc(objPtr, dupPtr); + } else { + dupPtr->internalRep = objPtr->internalRep; + dupPtr->typePtr = objPtr->typePtr; + } + + if (typePtr != NULL && dupPtr->typePtr != typePtr) { + if (bytes) { + dupPtr->bytes = bytes; + dupPtr->length = objPtr->length; + } + /* borrow bytes from original object */ + status = Tcl_ConvertToType(interp, dupPtr, typePtr); + if (bytes) { + dupPtr->bytes = NULL; + dupPtr->length = 0; + } + if (status != TCL_OK) { + return status; + } + } + + /* tclStringType is treated as a special case because a Tcl_Obj having this + * type can not always update the string representation. This happens, for + * example, when Tcl_GetCharLength() converts the internal representation + * to tclStringType in order to store the number of characters, but does + * not store enough information to generate the string representation. + * + * Perhaps in the future this can be remedied and this special treatment + * removed. + */ + + + if (bytes && (dupPtr->typePtr == NULL + || dupPtr->typePtr->updateStringProc == NULL + || typePtr == &tclStringType + ) + ) { + TclInitStringRep(dupPtr, bytes, objPtr->length); + } + return status; +} + +Tcl_Obj * +TclDuplicatePureObj( + Tcl_Interp *interp, + Tcl_Obj *objPtr, + const Tcl_ObjType *typePtr +) /* The object to duplicate. */ +{ + int status; + Tcl_Obj *dupPtr; + + TclNewObj(dupPtr); + status = SetDuplicatePureObj(interp, dupPtr, objPtr, typePtr); + if (status == TCL_OK) { + return dupPtr; + } else { + Tcl_DecrRefCount(dupPtr); + return NULL; + } +} + + + void TclSetDuplicateObj( Tcl_Obj *dupPtr, @@ -3707,7 +3816,7 @@ Tcl_IncrRefCount( * Decrements the reference count of the object. * * Results: - * None. + * The storage for objPtr may be freed. * *---------------------------------------------------------------------- */ @@ -3725,6 +3834,28 @@ Tcl_DecrRefCount( /* *---------------------------------------------------------------------- * + * TclUndoRefCount -- + * + * Decrement the refCount of objPtr without causing it to be freed if it + * drops from 1 to 0. This allows a function increment a refCount but + * then decrement it and still be able to pass return it to a caller, + * possibly with a refCount of 0. The caller must have previously + * incremented the refCount. + * + *---------------------------------------------------------------------- + */ +void +TclUndoRefCount( + Tcl_Obj *objPtr) /* The object we are releasing a reference to. */ +{ + if (objPtr->refCount > 0) { + --objPtr->refCount; + } +} + +/* + *---------------------------------------------------------------------- + * * Tcl_IsShared -- * * Tests if the object has a ref count greater than one. |
