From 22bb1e220dfeb679e0f7985503d2ab229694e35a Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 18 Feb 2009 18:31:36 +0000 Subject: * generic/tclStringObj.c: Rewrite GrowStringBuffer() so that it has parallel structure with GrowUnicodeBuffer(). The revision permits allocation attempts to continue all the way up to failure, with no gap. It also directly manipulates the String and Tcl_Obj internals instead of inefficiently operating via Tcl_*SetObjLength() with all of its extra protections and underdocumented special cases. --- ChangeLog | 7 +++++++ generic/tclStringObj.c | 39 +++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index f852e57..00dc9c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-02-18 Don Porter + * generic/tclStringObj.c: Rewrite GrowStringBuffer() so that it + has parallel structure with GrowUnicodeBuffer(). The revision permits + allocation attempts to continue all the way up to failure, with no gap. + It also directly manipulates the String and Tcl_Obj internals instead + of inefficiently operating via Tcl_*SetObjLength() with all of its + extra protections and underdocumented special cases. + * generic/tclStringObj.c: Another round of simplification on the allocation macros. diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 5707c50..24ae5ef 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -33,7 +33,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStringObj.c,v 1.115 2009/02/18 17:45:35 dgp Exp $ */ + * RCS: @(#) $Id: tclStringObj.c,v 1.116 2009/02/18 18:31:55 dgp Exp $ */ #include "tclInt.h" #include "tommath.h" @@ -198,29 +198,36 @@ GrowStringBuffer( * flag || objPtr->bytes != NULL */ String *stringPtr = GET_STRING(objPtr); + char *ptr = NULL; + int attempt; - if (flag && stringPtr->allocated == 0) { - /* First allocation - just big enough */ - if (objPtr->bytes == tclEmptyStringRep) { - objPtr->bytes = ckalloc((unsigned) needed + 1); - } else { - objPtr->bytes = ckrealloc(objPtr->bytes, (unsigned) needed + 1); + if (objPtr->bytes == tclEmptyStringRep) { + objPtr->bytes = NULL; + } + if (flag == 0 || stringPtr->allocated > 0) { + attempt = 2 * needed; + if (attempt >= 0) { + ptr = attemptckrealloc(objPtr->bytes, (unsigned) attempt + 1); } - stringPtr->allocated = needed; - } else { - /* Subsequent appends - apply the growth algorithm. */ - if (Tcl_AttemptSetObjLength(objPtr, 2 * needed) == 0) { + if (ptr == NULL) { /* * Take care computing the amount of modest growth to avoid - * overflow into invalid argument values for Tcl_SetObjLength. + * overflow into invalid argument values for attempt. */ unsigned int limit = INT_MAX - needed; unsigned int extra = needed - objPtr->length + TCL_GROWTH_MIN_ALLOC; int growth = (int) ((extra > limit) ? limit : extra); - - Tcl_SetObjLength(objPtr, needed + growth); + attempt = needed + growth; + ptr = attemptckrealloc(objPtr->bytes, (unsigned) attempt + 1); } } + if (ptr == NULL) { + /* First allocation - just big enough; or last chance fallback. */ + attempt = needed; + ptr = ckrealloc(objPtr->bytes, (unsigned) attempt + 1); + } + objPtr->bytes = ptr; + stringPtr->allocated = attempt; } static void @@ -1548,10 +1555,10 @@ AppendUtfToUtfRep( */ oldLength = objPtr->length; - if (numBytes > INT_MAX - oldLength) { + newLength = numBytes + oldLength; + if (newLength < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } - newLength = numBytes + oldLength; stringPtr = GET_STRING(objPtr); if (newLength > stringPtr->allocated) { -- cgit v0.12